Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LLHD] Add extract field operations #35

Merged
merged 3 commits into from
Jul 16, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions include/circt/Dialect/LLHD/IR/ExtractOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,118 @@ def LLHD_DextsOp : LLHD_Op<"dexts", [
unsigned getTargetWidth() { return getLLHDTypeWidth(target().getType()); }
}];
}

def LLHD_ExtfOp : LLHD_Op<"extf", [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer complete words. IS this "Extend Float?" "Extract field?" "External foobar?" "Example Tensorflow?"

NoSideEffect,
PredOpTrait<"'index' has to be smaller than the 'target' size",
CPred<"$index.cast<IntegerAttr>().getInt() < getTargetWidth()">>,
TypesMatchWith<"'result' type has to match type at 'index' of 'target', in "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems awkwardly worded to me. The description doesn't quite seem to match the predicate?

"case 'target' is a singal, consider the underlying types of the 'target'"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

singal -> signal

" and 'result' signals",
"target", "result",
"($_self.isa<llhd::SigType>() "
"? llhd::SigType::get("
"getElementTypeAtIndex($index.cast<IntegerAttr>().getInt())) "
": getElementTypeAtIndex($index.cast<IntegerAttr>().getInt()))">
]> {
let summary = "Extract an element from a vector or tuple";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or a signal with with vector or tuple type?

let description = [{
The `llhd.extf` operation allows access to an element of the `$target`
operand. The `$index` attribute defines the index of the element to extract.
If `%target` is a signal, a new subsignal aliasing the field will be
returned.

Example:

```mlir
%0 = constant dense<[1,2,3]> : vector<3xi8>
%1 = llhd.extf %0, 0 : vector<3xi8> -> i8

%2 = llhd.sig %0 : vector<3xi8>
%3 = llhd.extf %2, 0 : !llhd.sig<vector<3xi8>> -> !llhd.sig<i8>

%4 = llhd.const 8 : i16
%5 = llhd.tuple %0, %4 : tuple<vector<3xi8>, i16>
%6 = llhd.extf %5, 1 : tuple<vector<3xi8>, i16> -> i16
```
}];

let arguments = (ins AnyTypeOf<[
AnyVector,
AnyTuple,
LLHD_SigType<[AnyVector, AnyTuple]>
]>: $target,
IndexAttr: $index);

let results = (outs AnyType: $result);

let assemblyFormat = [{
$target `,` $index attr-dict `:` type($target) `->` type($result)
}];

let extraClassDeclaration = [{
unsigned getTargetWidth() { return getLLHDTypeWidth(target().getType()); };

Type getElementTypeAtIndex(unsigned index) {
Type targetType = target().getType();
if (auto sig = targetType.dyn_cast<llhd::SigType>())
targetType = sig.getUnderlyingType();
if (auto vec = targetType.dyn_cast<VectorType>())
return vec.getElementType();
return targetType.dyn_cast<TupleType>().getTypes()[index];
}
}];
}

def LLHD_DextfOp : LLHD_Op<"dextf", [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh no, it's random sequence of letters op!

NoSideEffect,
TypesMatchWith<"'result' must be the element type of the 'target' vector, in "
"case 'target' is a signal of a vector, 'result' also is a signal of the "
"vector element type",
"target", "result",
"($_self.isa<llhd::SigType>() ? llhd::SigType::get(getElementType()) "
": getElementType())">
]> {
let summary = [{
Dynamically extract an element from a vector or signal of vector.
}];
let description = [{
The `llhd.dextf` operation allows to dynamically access an element of the
`$target` operand. The `$index` operand defines the index of the element to
extract. If `%target` is a signal, a new subsignal aliasing the element will
be returned.

Example:

```mlir
%index = llhd.const 1 : i2

%0 = constant dense<[1,2,3]> : vector<3xi8>
%1 = llhd.dextf %0, %index : (vector<3xi8>, i2) -> i8

%2 = llhd.sig %0 : vector<3xi8>
%3 = llhd.dextf %2, %index : (!llhd.sig<vector<3xi8>>, i2) -> !llhd.sig<i8>
```
}];

let arguments = (ins
AnyTypeOf<[AnyVector, LLHD_SigType<[AnyVector]>]>: $target,
AnySignlessInteger: $index);

let results = (outs AnyType: $result);

let assemblyFormat = [{
$target `,` $index attr-dict `:` functional-type(operands, results)
}];

let extraClassDeclaration = [{
unsigned getTargetWidth() { return getLLHDTypeWidth(target().getType()); }

Type getElementType() {
Type targetType = target().getType();
if (auto sig = targetType.dyn_cast<llhd::SigType>())
targetType = sig.getUnderlyingType();
return targetType.dyn_cast<VectorType>().getElementType();
}
}];
}
153 changes: 153 additions & 0 deletions test/Dialect/LLHD/IR/ext.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,78 @@ func @dexts_vec(%v1 : vector<1xi1>, %v10 : vector<10xi1>, %i0 : i5, %i1 : i10) {
return
}

// CHECK-LABEL: @extf_vectors
// CHECK-SAME: %[[VEC1:.*]]: vector<1xi1>
// CHECK-SAME: %[[VEC5:.*]]: vector<5xi32>
func @extf_vectors(%vec1 : vector<1xi1>, %vec5 : vector<5xi32>) {
// CHECK-NEXT: %{{.*}} = llhd.extf %[[VEC1]], 0 : vector<1xi1> -> i1
%0 = llhd.extf %vec1, 0 : vector<1xi1> -> i1
// CHECK-NEXT: %{{.*}} = llhd.extf %[[VEC5]], 4 : vector<5xi32> -> i32
%1 = llhd.extf %vec5, 4 : vector<5xi32> -> i32

return
}

// CHECK-LABEL: @extf_tuples
// CHECK-SAME: %[[TUP:.*]]: tuple<i1, i2, i3>
func @extf_tuples(%tup : tuple<i1, i2, i3>) {
// CHECK-NEXT: %{{.*}} = llhd.extf %[[TUP]], 0 : tuple<i1, i2, i3> -> i1
%0 = llhd.extf %tup, 0 : tuple<i1, i2, i3> -> i1
// CHECK-NEXT: %{{.*}} = llhd.extf %[[TUP]], 2 : tuple<i1, i2, i3> -> i3
%1 = llhd.extf %tup, 2 : tuple<i1, i2, i3> -> i3

return
}

// CHECK-LABEL: @extf_signals_of_vectors
// CHECK-SAME: %[[VEC1:.*]]: !llhd.sig<vector<1xi1>>
// CHECK-SAME: %[[VEC5:.*]]: !llhd.sig<vector<5xi32>>
func @extf_signals_of_vectors(%vec1 : !llhd.sig<vector<1xi1>>, %vec5 : !llhd.sig<vector<5xi32>>) {
// CHECK-NEXT: %{{.*}} = llhd.extf %[[VEC1]], 0 : !llhd.sig<vector<1xi1>> -> !llhd.sig<i1>
%0 = llhd.extf %vec1, 0 : !llhd.sig<vector<1xi1>> -> !llhd.sig<i1>
// CHECK-NEXT: %{{.*}} = llhd.extf %[[VEC5]], 4 : !llhd.sig<vector<5xi32>> -> !llhd.sig<i32>
%1 = llhd.extf %vec5, 4 : !llhd.sig<vector<5xi32>> -> !llhd.sig<i32>

return
}

// CHECK-LABEL: @extf_signals_of_tuples
// CHECK-SAME: %[[TUP:.*]]: !llhd.sig<tuple<i1, i2, i3>>
func @extf_signals_of_tuples(%tup : !llhd.sig<tuple<i1, i2, i3>>) {
// CHECK-NEXT: %{{.*}} = llhd.extf %[[TUP]], 0 : !llhd.sig<tuple<i1, i2, i3>> -> !llhd.sig<i1>
%0 = llhd.extf %tup, 0 : !llhd.sig<tuple<i1, i2, i3>> -> !llhd.sig<i1>
// CHECK-NEXT: %{{.*}} = llhd.extf %[[TUP]], 2 : !llhd.sig<tuple<i1, i2, i3>> -> !llhd.sig<i3>
%1 = llhd.extf %tup, 2 : !llhd.sig<tuple<i1, i2, i3>> -> !llhd.sig<i3>

return
}

// CHECK-LABEL: @dextf_vectors
// CHECK-SAME: %[[INDEX:.*]]: i32
// CHECK-SAME: %[[VEC1:.*]]: vector<1xi1>
// CHECK-SAME: %[[VEC5:.*]]: vector<5xi32>
func @dextf_vectors(%index : i32, %vec1 : vector<1xi1>, %vec5 : vector<5xi32>) {
// CHECK-NEXT: %{{.*}} = llhd.dextf %[[VEC1]], %[[INDEX]] : (vector<1xi1>, i32) -> i1
%0 = llhd.dextf %vec1, %index : (vector<1xi1>, i32) -> i1
// CHECK-NEXT: %{{.*}} = llhd.dextf %[[VEC5]], %[[INDEX]] : (vector<5xi32>, i32) -> i32
%1 = llhd.dextf %vec5, %index : (vector<5xi32>, i32) -> i32

return
}

// CHECK-LABEL: @dextf_signals_of_vectors
// CHECK-SAME: %[[INDEX:.*]]: i32
// CHECK-SAME: %[[VEC1:.*]]: !llhd.sig<vector<1xi1>>
// CHECK-SAME: %[[VEC5:.*]]: !llhd.sig<vector<5xi32>>
func @dextf_signals_of_vectors(%index : i32, %vec1 : !llhd.sig<vector<1xi1>>, %vec5 : !llhd.sig<vector<5xi32>>) {
// CHECK-NEXT: %{{.*}} = llhd.dextf %[[VEC1]], %[[INDEX]] : (!llhd.sig<vector<1xi1>>, i32) -> !llhd.sig<i1>
%0 = llhd.dextf %vec1, %index : (!llhd.sig<vector<1xi1>>, i32) -> !llhd.sig<i1>
// CHECK-NEXT: %{{.*}} = llhd.dextf %[[VEC5]], %[[INDEX]] : (!llhd.sig<vector<5xi32>>, i32) -> !llhd.sig<i32>
%1 = llhd.dextf %vec5, %index : (!llhd.sig<vector<5xi32>>, i32) -> !llhd.sig<i32>

return
}

// -----

func @illegal_vector_to_signal(%vec : vector<3xi32>) {
Expand Down Expand Up @@ -217,3 +289,84 @@ func @dexts_illegal_vec_element_conversion(%c : vector<1xi1>, %i : i1) {

return
}

// -----

func @extf_vector_index_out_of_bounds(%vec : vector<3xi1>) {
// expected-error @+1 {{'index' has to be smaller than the 'target' size}}
%0 = llhd.extf %vec, 3 : vector<3xi1> -> i1

return
}

// -----

func @extf_tuple_index_out_of_bounds(%tup : tuple<i1, i2, i3>) {
// expected-error @+1 {{'index' has to be smaller than the 'target' size}}
%0 = llhd.extf %tup, 3 : tuple<i1, i2, i3> -> i3

return
}

// -----

func @extf_vector_type_mismatch(%vec : vector<3xi1>) {
// expected-error @+1 {{'result' type has to match type at 'index' of 'target', in case 'target' is a singal, consider the underlying types of the 'target' and 'result' signals}}
%0 = llhd.extf %vec, 0 : vector<3xi1> -> i2

return
}

// -----

func @extf_tuple_type_mismatch(%tup : tuple<i1, i2, i3>) {
// expected-error @+1 {{'result' type has to match type at 'index' of 'target', in case 'target' is a singal, consider the underlying types of the 'target' and 'result' signals}}
%0 = llhd.extf %tup, 0 : tuple<i1, i2, i3> -> i2

return
}

// -----

func @extf_signal_type_mismatch(%sig : !llhd.sig<tuple<i1, i2, i3>>) {
// expected-error @+1 {{'result' type has to match type at 'index' of 'target', in case 'target' is a singal, consider the underlying types of the 'target' and 'result' signals}}
%0 = llhd.extf %sig, 0 : !llhd.sig<tuple<i1, i2, i3>> -> !llhd.sig<i2>

return
}

// -----

func @extf_illegal_signal_alias(%sig : !llhd.sig<tuple<i1, i2, i3>>) {
// expected-error @+1 {{'result' type has to match type at 'index' of 'target', in case 'target' is a singal, consider the underlying types of the 'target' and 'result' signals}}
%0 = llhd.extf %sig, 0 : !llhd.sig<tuple<i1, i2, i3>> -> i1

return
}

// -----

func @dextf_vector_type_mismatch(%index : i2, %vec : vector<3xi1>) {
// expected-error @+1 {{'result' must be the element type of the 'target' vector, in case 'target' is a signal of a vector, 'result' also is a signal of the vector element type}}
%0 = llhd.dextf %vec, %index : (vector<3xi1>, i2) -> i2

return
}

// -----

func @dextf_signal_type_mismatch(%index : i2, %sig : !llhd.sig<vector<3xi1>>) {
// expected-error @+1 {{'result' must be the element type of the 'target' vector, in case 'target' is a signal of a vector, 'result' also is a signal of the vector element type}}
%0 = llhd.dextf %sig, %index : (!llhd.sig<vector<3xi1>>, i2) -> !llhd.sig<i2>

return
}

// -----

func @dextf_illegal_signal_alias(%index : i2, %sig : !llhd.sig<vector<3xi1>>) {
// expected-error @+1 {{'result' must be the element type of the 'target' vector, in case 'target' is a signal of a vector, 'result' also is a signal of the vector element type}}
%0 = llhd.dextf %sig, %index : (!llhd.sig<vector<3xi1>>, i2) -> i1

return
}