Introduce custom format for the LLVM IR Dialect

Historically, the LLVM IR dialect has been using the generic form of MLIR
    operation syntax.  It is verbose and often redundant.  Introduce the custom
    printing and parsing for all existing operations in the LLVM IR dialect.
    Update the relevant documentation and tests.

--

PiperOrigin-RevId: 241617393
This commit is contained in:
Alex Zinenko 2019-04-02 15:33:54 -07:00 committed by Mehdi Amini
parent 04f766c2ed
commit 736bef7386
12 changed files with 1918 additions and 815 deletions

View File

@ -207,21 +207,21 @@ func @bar() {
func @foo(%arg0: !llvm.type<"i32">, %arg1: !llvm.type<"i64">) -> !llvm.type<"{i32, i64}"> {
// insert the vales into a structure
%0 = "llvm.undef"() : () -> !llvm.type<"{i32, i64}">
%1 = "llvm.insertvalue"(%arg0, %0) {position: [0]} : (!llvm.type<"i32">, !llvm.type<"{i32, i64}">) -> !llvm.type<"{i32, i64}">
%2 = "llvm.insertvalue"(%arg1, %1) {position: [1]} : (!llvm.type<"i64">, !llvm.type<"{i32, i64}">) -> !llvm.type<"{i32, i64}">
%0 = llvm.undef : !llvm.type<"{i32, i64}">
%1 = llvm.insertvalue %arg0, %0[0] : !llvm.type<"{i32, i64}">
%2 = llvm.insertvalue %arg1, %1[1] : !llvm.type<"{i32, i64}">
// return the structure value
"llvm.return"(%2) : !llvm.type<"{i32, i64}"> -> ()
llvm.return %2 : !llvm.type<"{i32, i64}">
}
func @bar() {
%0 = "llvm.constant" {value: 42} : !llvm.type<"i32">
%1 = "llvm.constant" {value: 17} : !llvm.type<"i64">
%0 = llvm.constant(42 : i32) : !llvm.type<"i32">
%1 = llvm.constant(17) : !llvm.type<"i64">
// call and extract the values from the structure
%2 = "llvm.call"(%0, %1) {callee: @bar} : (%arg0: !llvm.type<"i32">, %arg1: !llvm.type<"i64">) -> !llvm.type<"{i32, i64}">
%3 = "llvm.extractvalue"(%2) {position: [0]} : (!llvm.type<"{i32, i64}"> -> !llvm.type<"i32">
%4 = "llvm.extractvalue"(%2) {position: [1]} : (!llvm.type<"{i32, i64}"> -> !llvm.type<"i64">
%2 = llvm.call @bar(%0, %1) : (%arg0: !llvm.type<"i32">, %arg1: !llvm.type<"i64">) -> !llvm.type<"{i32, i64}">
%3 = llvm.extractvalue %2[0] : !llvm.type<"{i32, i64}">
%4 = llvm.extractvalue %2[1] : !llvm.type<"{i32, i64}">
// use as before
"use_i32"(%3) : (!llvm.type<"i32">) -> ()
@ -264,11 +264,11 @@ leads to a new basic block being inserted,
before the conversion to the LLVM IR dialect:
```mlir {.mlir}
"llvm.cond_br"(%0)[^bb1(%1 : !llvm.type<"i32">), ^dummy] : (!llvm.type<"i1">) -> ()
llvm.cond_br %0, ^bb1(%1 : !llvm.type<"i32">), ^dummy
^bb1(%3 : !llvm.type<"i32">):
"use"(%3) : (!llvm.type<"i32">) -> ()
^dummy:
"llvm.br"()[^bb1(%2 : !llvm.type<"i32">)] : () -> ()
llvm.br ^bb1(%2 : !llvm.type<"i32">)
```
## Memref Model
@ -308,7 +308,7 @@ An access to a zero-dimensional memref is converted into a plain load:
%0 = load %m[] : memref<f32>
// after
%0 = "llvm.load"(%m) : (!llvm.type<"float*">) -> (!llvm.type<"float">)
%0 = llvm.load %m : !llvm.type<"float*">
```
An access to a memref with indices:
@ -321,34 +321,34 @@ is transformed into the equivalent of the following code:
```mlir {.mlir}
// obtain the buffer pointer
%b = "llvm.extractvalue"(%m) {position: [0]} : (!llvm.type<"{float*, i64, i64}">) -> !llvm.type<"float*">
%b = llvm.extractvalue %m[0] : !llvm.type<"{float*, i64, i64}">
// obtain the components for the index
%sub1 = "llvm.constant" {value: 1} : () -> !llvm.type<"i64"> // first subscript
%sz2 = "llvm.extractvalue"(%m) {position: [1]}
: (!llvm.type<"{float*, i64, i64}">) -> !llvm.type<"float*"> // second size (dynamic, second descriptor element)
%sub2 = "llvm.constant" {value: 2} : () -> !llvm.type<"i64"> // second subscript
%sz3 = "llvm.constant" {value: 13} : () -> !llvm.type<"i64"> // third size (static)
%sub3 = "llvm.constant" {value: 3} : () -> !llvm.type<"i64"> // third subscript
%sz4 = "llvm.extractvalue"(%m) {position: [1]}
: (!llvm.type<"{float*, i64, i64}">) -> !llvm.type<"float*"> // fourth size (dynamic, third descriptor element)
%sub4 = "llvm.constant" {value: 4} : () -> !llvm.type<"i64"> // fourth subscript
%sub1 = llvm.constant(1) : !llvm.type<"i64"> // first subscript
%sz2 = llvm.extractvalue %m[1]
: !llvm.type<"{float*, i64, i64}"> // second size (dynamic, second descriptor element)
%sub2 = llvm.constant(2) : !llvm.type<"i64"> // second subscript
%sz3 = llvm.constant(13) : !llvm.type<"i64"> // third size (static)
%sub3 = llvm.constant(3) : !llvm.type<"i64"> // third subscript
%sz4 = llvm.extractvalue %m[1]
: !llvm.type<"{float*, i64, i64}"> // fourth size (dynamic, third descriptor element)
%sub4 = llvm.constant(4) : !llvm.type<"i64"> // fourth subscript
// compute the linearized index
// %sub4 + %sub3 * %sz4 + %sub2 * (%sz3 * %sz4) + %sub1 * (%sz2 * %sz3 * %sz4) =
// = ((%sub1 * %sz2 + %sub2) * %sz3 + %sub3) * %sz4 + %sub4
%idx0 = "llvm.mul"(%sub1, %sz2) : (!llvm.type<"i64">, !llvm.type<"i64">) -> !llvm.type<"i64">
%idx1 = "llvm.add"(%idx0, %sub2) : (!llvm.type<"i64">, !llvm.type<"i64">) -> !llvm.type<"i64">
%idx2 = "llvm.mul"(%idx1, %sz3) : (!llvm.type<"i64">, !llvm.type<"i64">) -> !llvm.type<"i64">
%idx3 = "llvm.add"(%idx2, %sub3) : (!llvm.type<"i64">, !llvm.type<"i64">) -> !llvm.type<"i64">
%idx4 = "llvm.mul"(%idx3, %sz4) : (!llvm.type<"i64">, !llvm.type<"i64">) -> !llvm.type<"i64">
%idx5 = "llvm.add"(%idx4, %sub4) : (!llvm.type<"i64">, !llvm.type<"i64">) -> !llvm.type<"i64">
%idx0 = llvm.mul %sub1, %sz2 : !llvm.type<"i64">
%idx1 = llvm.add %idx0, %sub : !llvm.type<"i64">
%idx2 = llvm.mul %idx1, %sz3 : !llvm.type<"i64">
%idx3 = llvm.add %idx2, %sub3 : !llvm.type<"i64">
%idx4 = llvm.mul %idx3, %sz4 : !llvm.type<"i64">
%idx5 = llvm.add %idx4, %sub4 : !llvm.type<"i64">
// obtain the element address
%a = "llvm.getelementptr"(%b, %idx5) : (!llvm.type<"float*">, !llvm.type<"i64">) -> !llvm.type<"float*">
%a = llvm.getelementptr %b[%idx5] : (!llvm.type<"float*">, !llvm.type<"i64">) -> !llvm.type<"float*">
// perform the actual load
%0 = "llvm.load"(%a) : (!llvm.type<"float*">) -> !llvm.type<"float">
%0 = llvm.load %a : !llvm.type<"float*">
```
In practice, the subscript and size extraction will be interleaved with the

View File

@ -47,9 +47,8 @@ specific LLVM IR type.
## Operations {#operations}
All operations in the LLVM IR dialect use the generic (verbose) form of MLIR
operations. The mnemonic of an operation is that used in LLVM IR prefixed with
"`llvm.`".
All operations in the LLVM IR dialect have a custom form in MLIR. The mnemonic
of an operation is that used in LLVM IR prefixed with "`llvm.`".
### LLVM IR operations
@ -74,10 +73,10 @@ Examples:
```mlir {.mlir}
// Integer addition.
%0 = "llvm.add"(%a, %b) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%0 = llvm.add %a, %b : !llvm<"i32">
// Unsigned integer division.
%1 = "llvm.udiv"(%a, %b) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%1 = llvm.udiv %a, %b : !llvm<"i32">
```
#### Floating point binary arithmetic operations
@ -95,16 +94,16 @@ Examples:
```mlir {.mlir}
// Float addition.
%0 = "llvm.fadd"(%a, %b) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%0 = llvm.fadd %a, %b : !llvm<"float">
// Float division.
%1 = "llvm.fdiv"(%a, %b) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%1 = llvm.fdiv %a, %b : !llvm<"float">
```
#### Memory-related operations
- `<r> = alloca <size>`
- `<r> = getelementptr <address>, <index> (, <index>)+`
- `<r> = alloca <size> x <type>`
- `<r> = getelementptr <address>[<index> (, <index>)+]`
- `<r> = load <address>`
- `store <value>, <address>`
@ -120,45 +119,44 @@ Examples:
```mlir {.mlir}
// Allocate an array of 4 floats on stack
%c4 = "llvm.constant" {value: 4 : i64} : !llvm<"i64">
%0 = "llvm.alloca"(%c4) : (!llvm<"i64">) -> !llvm<"float*">
%c4 = llvm.constant(4) : !llvm<"i64">
%0 = llvm.alloca %c4 x !llvm<"float"> : (!llvm<"i64">) -> !llvm<"float*">
// Get the second element of the array (note 0-based indexing).
%c1 = "llvm.constant" {value: 1 : i64} : !llvm<"i64">
%1 = "llvm.getelementptr"(%0, %c1) : (!llvm<"float*">, !llvm<"i64">)
%c1 = llvm.constant(1) : !llvm<"i64">
%1 = llvm.getelementptr %0[%c1] : (!llvm<"float*">, !llvm<"i64">)
-> !llvm<"float*">
// Store a constant into this element.
%cf = "llvm.constant" {value: 42.0 : f32} : !llvm<"float">
"llvm.store" %cf, %1 : (!llvm<"float">, !llvm<"float*">) -> ()
%cf = llvm.constant(42.0 : f32) : !llvm<"float">
llvm.store %cf, %1 : !llvm<"float*">
// Load the value from this element.
%3 = "llvm.load" %1 : (!llvm<"float*">) -> (!llvm<"float">)
%3 = llvm.load %1 : !llvm<"float*">
```
#### Operations on values of aggregate type.
- `<value> = extractvalue <struct> {position: [<index> (, <index>)+]}`
- `<struct> = insertvalue <value>,<struct> {position: [<index> (, <index>)+]}`
- `<value> = extractvalue <struct>[<index> (, <index>)+]`
- `<struct> = insertvalue <value>, <struct>[<index> (, <index>)+]`
In these operations, `<struct>` must be a value of wrapped LLVM IR structure
type and `<value>` must be a value that corresponds to one of the (nested)
structure element types.
The `position` attribute is a mandatory array attribute containing integer
attributes. It identifies the 0-based position of the element in the (nested)
structure type.
Note the use of integer literals to designate subscripts, which is made possbile
by `extractvalue` and `insertvalue` must have constant subscripts. Internally,
they are modeled as array attributes.
Examples:
```mlir {.mlir}
// Get the value third element of the second element of a structure.
%0 = "llvm.extractvalue"(%s) {position: [1, 2]} : (!llvm<"{i32, {i1, i8, i16}">) -> !llvm<"i16">
%0 = llvm.extractvalue %s[1, 2] : !llvm<"{i32, {i1, i8, i16}">
// Insert the value to the third element of the second element of a structure.
// Note that this returns a new structure-typed value.
%1 = "llvm.insertvalue"(%0, %s) {position: [1, 2]} :
(!llvm<"i16">, !llvm<"{i32, {i1, i8, i16}">) -> !llvm<"{i32, {i1, i8, i16}">
%1 = llvm.insertvalue %0, %s[1, 2] : !llvm<"{i32, {i1, i8, i16}">
```
#### Terminator operations.
@ -185,21 +183,20 @@ Examples:
```mlir {.mlir}
// Branch without arguments.
^bb0:
"llvm.br"() [^bb0] : () -> ()
llvm.br ^bb0
// Branch and pass arguments.
^bb1(%arg: !llvm<"i32">):
"llvm.br"() [^bb1(%arg : !llvm<"i32">)] : () -> ()
llvm.br ^bb1(%arg : !llvm<"i32">)
// Conditionally branch and pass arguments to one of the blocks.
"llvm.cond_br"(%cond) [^bb0, %bb1(%arg : !llvm<"i32">)] : (!llvm<"i1">) -> ()
llvm.cond_br %cond, ^bb0, %bb1(%arg : !llvm<"i32">)
// It's okay to use the same block without arguments, but probably useless.
"llvm.cond_br"(%cond) [^bb0, ^bb0] : (!llvm<"i1">) -> ()
llvm.cond_br %cond, ^bb0, ^bb0
// ERROR: Passing different arguments to the same block in a conditional branch.
"llvm.cond_br"(%cond) [^bb1(%0 : !llvm<"i32">),
^bb1(%1 : !llvm<"i32">)] : (!llvm<"i1">) -> ()
llvm.cond_br %cond, ^bb1(%0 : !llvm<"i32">), ^bb1(%1 : !llvm<"i32">)
```
@ -213,42 +210,41 @@ this behavior by providing a variadic `call` operation for 0- and 1-result
functions. Even though MLIR supports multi-result functions, LLVM IR dialect
disallows them.
The `call` operation supports both direct and indirect calls. Direct calls
require the `callee` attribute of function type to be present. Otherwise, the
call is considered indirect and expects the function as its first argument.
The `call` instruction supports both direct and indirect calls. Direct calls
start with a function name (`@`-prefixed) and indirect calls start with an SSA
value (`%`-prefixed). The direct callee, if present, is stored as a function
attribute `callee`. The trailing type of the instruction is always the MLIR
function type, which may be different from the indirect callee that has the
wrapped LLVM IR function type.
Examples:
```mlir {.mlir}
// Direct call without arguments and with one result.
%0 = "llvm.call"() {callee: @foo : () -> (!llvm<"float">)}
: () -> (!llvm<"float">)
%0 = llvm.call @foo() : () -> (!llvm<"float">)
// Direct call with arguments and without a result.
"llvm.call"(%0) {callee: @bar : (!llvm<"float">) -> ()}
: (!llvm<"float">) -> ()
llvm.call @bar(%0) : (!llvm<"float">) -> ()
// Indirect call with an argument and without a result.
"llvm.call"(%1, %0) : ((!llvm<"float">) -> (), !llvm<"float">) -> ()
llvm.call %1(%0) : (!llvm<"float">) -> ()
```
#### Miscellaneous operations.
Integer comparisons: `icmp <lhs>, <rhs> {predicate: <int>}`. The following
predicate values are supported:
Integer comparisons: `icmp "predicate" <lhs>, <rhs>`. The following predicate
values are supported:
- `0` - equality comparison;
- `1` - inequality comparison;
- `2` - signed less-than comparison
- `3` - signed less-than-or-equal comparison
- `4` - signed greater-than comparison
- `5` - signed greater-than-or-equal comparison
- `6` - unsigned less-than comparison
- `7` - unsigned less-than-or-equal comparison
- `8` - unsigned greater-than comparison
- `9` - unsigned greater-than-or-equal comparison
Note: these constant values correspond to those used by MLIR's `cmpi` operation.
- `eq` - equality comparison;
- `ne` - inequality comparison;
- `slt` - signed less-than comparison
- `sle` - signed less-than-or-equal comparison
- `sgt` - signed greater-than comparison
- `sge` - signed greater-than-or-equal comparison
- `ult` - unsigned less-than comparison
- `ule` - unsigned less-than-or-equal comparison
- `ugt` - unsigned greater-than comparison
- `uge` - unsigned greater-than-or-equal comparison
Bitwise reinterpretation: `bitcast <value>`.
@ -266,21 +262,25 @@ constants must be created as SSA values before being used in other operations.
`llvm.constant` creates such values for scalars and vectors. It has a mandatory
`value` attribute, which may be an integer, floating point attribute; splat,
dense or sparse attribute containing integers or floats. The type of the
attribute is one the corresponding MLIR standard types. The operation produces a
new SSA value of the specified LLVM IR dialect type.
attribute is one the corresponding MLIR standard types. It may be omitted for
`i64` and `f64` types that are implied. The operation produces a new SSA value
of the specified LLVM IR dialect type. The type of that value _must_ correspond
to the attribute type converted to LLVM IR.
Examples:
```mlir {.mlir}
// Integer constant
%0 = "llvm.constant"() {value: 42 : i32} -> !llvm<"i32">
// Integer constant, internal i32 is mandatory
%0 = llvm.constant(42 : i32) : !llvm<"i32">
// Floating point constant
%1 = "llvm.constant"() {value: 42.0 : f32} -> !llvm<"float">
// It's okay to omit i64.
%1 = llvm.constant(42) : !llvm<"i64">
// Splat vector constant
%2 = "llvm.constant"() {value: splat<vector<4xf32>, 1.0>}
-> !llvm<"<4 x float>">
// Floating point constant.
%2 = llvm.constant(42.0 : f32) : !llvm<"float">
// Splat vector constant,.
%3 = llvm.constant(splat<vector<4xf32>, 1.0>) : !llvm<"<4 x float>">
```
#### `llvm.undef` {#undef-operation}
@ -294,5 +294,5 @@ Example:
```mlir {.mlir}
// Create a structure with a 32-bit integer followed by a float.
%0 = "llvm.undef"() -> !llvm<"{i32, float}">
%0 = llvm.undef : !llvm<"{i32, float}">
```

View File

@ -170,6 +170,15 @@ public:
/// This parses... a comma!
virtual bool parseComma() = 0;
/// Parse a `:` token.
virtual bool parseColon() = 0;
/// Parse a '(' token.
virtual bool parseLParen() = 0;
/// Parse a ')' token.
virtual bool parseRParen() = 0;
/// This parses an equal(=) token!
virtual bool parseEqual() = 0;
@ -270,6 +279,12 @@ public:
/// be passed to resolveFunctionName when a function type is available.
virtual bool parseFunctionName(StringRef &result, llvm::SMLoc &loc) = 0;
/// Parse a function name like '@foo` if present and return the name without
/// the sigil in `result`. Return true if the next token is not a function
/// name and keep `result` unchanged.
virtual bool parseOptionalFunctionName(StringRef &result,
llvm::SMLoc &loc) = 0;
/// This is the representation of an operand reference.
struct OperandType {
llvm::SMLoc location; // Location of the token.

View File

@ -135,7 +135,10 @@ class LLVM_ArithmeticOp<string mnemonic, string builderFunc,
LLVM_OneResultOp<mnemonic,
!listconcat([NoSideEffect, SameValueType], traits)>,
Arguments<(ins LLVM_Type:$lhs, LLVM_Type:$rhs)>,
LLVM_Builder<"$res = builder." # builderFunc # "($lhs, $rhs);">;
LLVM_Builder<"$res = builder." # builderFunc # "($lhs, $rhs);"> {
let parser = [{ return impl::parseBinaryOp(parser, result); }];
let printer = [{ printLLVMBinaryOp(p, this->getOperation()); }];
}
// Integer binary operations.
def LLVM_AddOp : LLVM_ArithmeticOp<"add", "CreateAdd", [Commutative]>;
@ -154,6 +157,8 @@ def LLVM_ICmpOp : LLVM_OneResultOp<"icmp", [NoSideEffect]>,
$res = builder.CreateICmp(getLLVMCmpPredicate(
static_cast<CmpIPredicate>($predicate.getZExtValue())), $lhs, $rhs);
}];
let parser = [{ return parseICmpOp(parser, result); }];
let printer = [{ printICmpOp(p, *this); }];
}
// Floating point binary operations.
@ -169,20 +174,33 @@ def LLVM_AllocaOp : LLVM_OneResultOp<"alloca">,
string llvmBuilder = [{
$res = builder.CreateAlloca($_resultType, $arraySize);
}];
let parser = [{ return parseAllocaOp(parser, result); }];
let printer = [{ printAllocaOp(p, *this); }];
}
def LLVM_GEPOp : LLVM_OneResultOp<"getelementptr", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$base, Variadic<LLVM_Type>:$indices)>,
LLVM_Builder<"$res = builder.CreateGEP($base, $indices);">;
LLVM_Builder<"$res = builder.CreateGEP($base, $indices);"> {
let parser = [{ return parseGEPOp(parser, result); }];
let printer = [{ printGEPOp(p, *this); }];
}
def LLVM_LoadOp : LLVM_OneResultOp<"load">, Arguments<(ins LLVM_Type:$addr)>,
LLVM_Builder<"$res = builder.CreateLoad($addr);">;
LLVM_Builder<"$res = builder.CreateLoad($addr);"> {
let parser = [{ return parseLoadOp(parser, result); }];
let printer = [{ printLoadOp(p, *this); }];
}
def LLVM_StoreOp : LLVM_ZeroResultOp<"store">,
Arguments<(ins LLVM_Type:$value, LLVM_Type:$addr)>,
LLVM_Builder<"builder.CreateStore($value, $addr);">;
LLVM_Builder<"builder.CreateStore($value, $addr);"> {
let parser = [{ return parseStoreOp(parser, result); }];
let printer = [{ printStoreOp(p, *this); }];
}
def LLVM_BitcastOp
: LLVM_OneResultOp<"bitcast", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$arg)>,
LLVM_Builder<"$res = builder.CreateBitCast($arg, $_resultType);">;
LLVM_Builder<"$res = builder.CreateBitCast($arg, $_resultType);"> {
let parser = [{ return parseBitcastOp(parser, result); }];
let printer = [{ printBitcastOp(p, *this); }];
}
// Call-related operations.
def LLVM_CallOp : LLVM_Op<"call">,
@ -196,6 +214,8 @@ def LLVM_CallOp : LLVM_Op<"call">,
return emitOpError("must have 0 or 1 result");
return success();
}];
let parser = [{ return parseCallOp(parser, result); }];
let printer = [{ printCallOp(p, *this); }];
}
def LLVM_ExtractValueOp : LLVM_OneResultOp<"extractvalue", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$container,
@ -203,6 +223,8 @@ def LLVM_ExtractValueOp : LLVM_OneResultOp<"extractvalue", [NoSideEffect]>,
string llvmBuilder = [{
$res = builder.CreateExtractValue($container, extractPosition($position));
}];
let parser = [{ return parseExtractValueOp(parser, result); }];
let printer = [{ printExtractValueOp(p, *this); }];
}
def LLVM_InsertValueOp : LLVM_OneResultOp<"insertvalue", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$container, LLVM_Type:$value,
@ -211,6 +233,8 @@ def LLVM_InsertValueOp : LLVM_OneResultOp<"insertvalue", [NoSideEffect]>,
$res = builder.CreateInsertValue($container, $value,
extractPosition($position));
}];
let parser = [{ return parseInsertValueOp(parser, result); }];
let printer = [{ printInsertValueOp(p, *this); }];
}
// Misc operations.
@ -219,16 +243,24 @@ def LLVM_SelectOp
Arguments<(ins LLVM_Type:$condition, LLVM_Type:$trueValue,
LLVM_Type:$falseValue)>,
LLVM_Builder<
"$res = builder.CreateSelect($condition, $trueValue, $falseValue);">;
"$res = builder.CreateSelect($condition, $trueValue, $falseValue);"> {
let parser = [{ return parseSelectOp(parser, result); }];
let printer = [{ printSelectOp(p, *this); }];
}
// Terminators.
def LLVM_BrOp : LLVM_TerminatorOp<"br", [NoSideEffect]>;
def LLVM_BrOp : LLVM_TerminatorOp<"br", [NoSideEffect]> {
let parser = [{ return parseBrOp(parser, result); }];
let printer = [{ printBrOp(p, *this); }];
}
def LLVM_CondBrOp : LLVM_TerminatorOp<"cond_br", [NoSideEffect]> {
let verifier = [{
if (getNumSuccessors() != 2)
return emitOpError("expected exactly two successors");
return success();
}];
let parser = [{ return parseCondBrOp(parser, result); }];
let printer = [{ printCondBrOp(p, *this); }];
}
def LLVM_ReturnOp : LLVM_TerminatorOp<"return", [NoSideEffect]> {
string llvmBuilder = [{
@ -243,15 +275,25 @@ def LLVM_ReturnOp : LLVM_TerminatorOp<"return", [NoSideEffect]> {
return emitOpError("expects at most 1 operand");
return success();
}];
let parser = [{ return parseReturnOp(parser, result); }];
let printer = [{ printReturnOp(p, *this); }];
}
// Pseudo-operations (do not appear in LLVM IR but necessary for the dialect to
// work correctly).
def LLVM_UndefOp : LLVM_OneResultOp<"undef", [NoSideEffect]>,
LLVM_Builder<"$res = llvm::UndefValue::get($_resultType);">;
LLVM_Builder<"$res = llvm::UndefValue::get($_resultType);"> {
let parser = [{ return parseUndefOp(parser, result); }];
let printer = [{ printUndefOp(p, *this); }];
}
def LLVM_ConstantOp
: LLVM_OneResultOp<"constant", [NoSideEffect]>,
Arguments<(ins AnyAttr:$value)>,
LLVM_Builder<"$res = getLLVMConstant($_resultType, $value, $_location);">;
LLVM_Builder<"$res = getLLVMConstant($_resultType, $value, $_location);">
{
let parser = [{ return parseConstantOp(parser, result); }];
let printer = [{ printConstantOp(p, *this); }];
}
#endif // LLVMIR_OPS

View File

@ -20,11 +20,13 @@
//
//===----------------------------------------------------------------------===//
#include "mlir/LLVMIR/LLVMDialect.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/MLIRContext.h"
#include "llvm/IR/Function.h"
#include "mlir/IR/StandardTypes.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/SourceMgr.h"
@ -60,7 +62,806 @@ llvm::Type *LLVMType::getUnderlyingType() const {
return getImpl()->underlyingType;
}
/*---- LLVM IR Dialect and its registration ----------------------------- */
static void printLLVMBinaryOp(OpAsmPrinter *p, Operation *op) {
// Fallback to the generic form if the op is not well-formed (may happen
// during incomplete rewrites, and used for debugging).
const auto *abstract = op->getAbstractOperation();
assert(abstract && "pretty printing an unregistered operation");
auto resultType = op->getResult(0)->getType();
if (resultType != op->getOperand(0)->getType() ||
resultType != op->getOperand(1)->getType())
return p->printGenericOp(op);
*p << op->getName().getStringRef() << ' ' << *op->getOperand(0) << ", "
<< *op->getOperand(1);
p->printOptionalAttrDict(op->getAttrs());
*p << " : " << op->getResult(0)->getType();
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::ICmpOp.
//===----------------------------------------------------------------------===//
// Return an array of mnemonics for ICmpPredicates indexed by its value.
static const char *const *getICmpPredicateNames() {
static const char *predicateNames[]{/*EQ*/ "eq",
/*NE*/ "ne",
/*SLT*/ "slt",
/*SLE*/ "sle",
/*SGT*/ "sgt",
/*SGE*/ "sge",
/*ULT*/ "ult",
/*ULE*/ "ule",
/*UGT*/ "ugt",
/*UGE*/ "uge"};
return predicateNames;
};
// Returns a value of the ICmp predicate corresponding to the given mnemonic.
// Returns -1 if there is no such mnemonic.
static int getICmpPredicateByName(StringRef name) {
return llvm::StringSwitch<int>(name)
.Case("eq", 0)
.Case("ne", 1)
.Case("slt", 2)
.Case("sle", 3)
.Case("sgt", 4)
.Case("sge", 5)
.Case("ult", 6)
.Case("ule", 7)
.Case("ugt", 8)
.Case("uge", 9)
.Default(-1);
}
static void printICmpOp(OpAsmPrinter *p, ICmpOp &op) {
*p << op.getOperationName() << " \""
<< getICmpPredicateNames()[op.predicate().getZExtValue()] << "\" "
<< *op.getOperand(0) << ", " << *op.getOperand(1);
p->printOptionalAttrDict(op.getAttrs(), {"predicate"});
*p << " : " << op.lhs()->getType();
}
// <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use
// attribute-dict? `:` type
static bool parseICmpOp(OpAsmParser *parser, OperationState *result) {
Builder &builder = parser->getBuilder();
Attribute predicate;
SmallVector<NamedAttribute, 4> attrs;
OpAsmParser::OperandType lhs, rhs;
Type type;
llvm::SMLoc predicateLoc, trailingTypeLoc;
if (parser->getCurrentLocation(&predicateLoc) ||
parser->parseAttribute(predicate, "predicate", attrs) ||
parser->parseOperand(lhs) || parser->parseComma() ||
parser->parseOperand(rhs) || parser->parseOptionalAttributeDict(attrs) ||
parser->parseColon() || parser->getCurrentLocation(&trailingTypeLoc) ||
parser->parseType(type) ||
parser->resolveOperand(lhs, type, result->operands) ||
parser->resolveOperand(rhs, type, result->operands))
return true;
// Replace the string attribute `predicate` with an integer attribute.
auto predicateStr = predicate.dyn_cast<StringAttr>();
if (!predicateStr)
return parser->emitError(predicateLoc,
"expected 'predicate' attribute of string type");
int predicateValue = getICmpPredicateByName(predicateStr.getValue());
if (predicateValue == -1)
return parser->emitError(
predicateLoc,
"'" + Twine(predicateStr.getValue()) +
"' is an incorrect value of the 'predicate' attribute");
attrs[0].second = parser->getBuilder().getI64IntegerAttr(predicateValue);
// The result type is either i1 or a vector type <? x i1> if the inputs are
// vectors.
LLVMDialect *dialect = static_cast<LLVMDialect *>(
builder.getContext()->getRegisteredDialect("llvm"));
llvm::Type *llvmResultType = llvm::Type::getInt1Ty(dialect->getLLVMContext());
auto argType = type.dyn_cast<LLVM::LLVMType>();
if (!argType)
return parser->emitError(trailingTypeLoc, "expected LLVM IR dialect type");
if (argType.getUnderlyingType()->isVectorTy())
llvmResultType = llvm::VectorType::get(
llvmResultType, argType.getUnderlyingType()->getVectorNumElements());
auto resultType = builder.getType<LLVM::LLVMType>(llvmResultType);
result->attributes = attrs;
result->addTypes({resultType});
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::AllocaOp.
//===----------------------------------------------------------------------===//
static void printAllocaOp(OpAsmPrinter *p, AllocaOp &op) {
auto *llvmPtrTy = op.getType().cast<LLVM::LLVMType>().getUnderlyingType();
auto *llvmElemTy = llvm::cast<llvm::PointerType>(llvmPtrTy)->getElementType();
auto elemTy = LLVM::LLVMType::get(op.getContext(), llvmElemTy);
auto funcTy = FunctionType::get({op.arraySize()->getType()}, {op.getType()},
op.getContext());
*p << op.getOperationName() << ' ' << *op.arraySize() << " x " << elemTy;
p->printOptionalAttrDict(op.getAttrs());
*p << " : " << funcTy;
}
// <operation> ::= `llvm.alloca` ssa-use `x` type attribute-dict?
// `:` type `,` type
static bool parseAllocaOp(OpAsmParser *parser, OperationState *result) {
SmallVector<NamedAttribute, 4> attrs;
OpAsmParser::OperandType arraySize;
Type type, elemType;
llvm::SMLoc trailingTypeLoc;
if (parser->parseOperand(arraySize) || parser->parseKeyword("x") ||
parser->parseType(elemType) ||
parser->parseOptionalAttributeDict(attrs) || parser->parseColon() ||
parser->getCurrentLocation(&trailingTypeLoc) || parser->parseType(type))
return true;
// Extract the result type from the trailing function type.
auto funcType = type.dyn_cast<FunctionType>();
if (!funcType || funcType.getNumInputs() != 1 ||
funcType.getNumResults() != 1)
return parser->emitError(
trailingTypeLoc,
"expected trailing function type with one argument and one result");
if (parser->resolveOperand(arraySize, funcType.getInput(0), result->operands))
return true;
result->attributes = attrs;
result->addTypes({funcType.getResult(0)});
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::GEPOp.
//===----------------------------------------------------------------------===//
static void printGEPOp(OpAsmPrinter *p, GEPOp &op) {
SmallVector<Type, 8> types;
for (auto *operand : op.getOperands())
types.push_back(operand->getType());
auto funcTy =
FunctionType::get(types, op.getResult()->getType(), op.getContext());
*p << op.getOperationName() << ' ' << *op.base() << '[';
p->printOperands(std::next(op.operand_begin()), op.operand_end());
*p << ']';
p->printOptionalAttrDict(op.getAttrs());
*p << " : " << funcTy;
}
// <operation> ::= `llvm.getelementptr` ssa-use `[` ssa-use-list `]`
// attribute-dict? `:` type
static bool parseGEPOp(OpAsmParser *parser, OperationState *result) {
SmallVector<NamedAttribute, 4> attrs;
OpAsmParser::OperandType base;
SmallVector<OpAsmParser::OperandType, 8> indices;
Type type;
llvm::SMLoc trailingTypeLoc;
if (parser->parseOperand(base) ||
parser->parseOperandList(indices, /*requiredOperandCount=*/-1,
OpAsmParser::Delimiter::Square) ||
parser->parseOptionalAttributeDict(attrs) || parser->parseColon() ||
parser->getCurrentLocation(&trailingTypeLoc) || parser->parseType(type))
return true;
// Deconstruct the trailing function type to extract the types of the base
// pointer and result (same type) and the types of the indices.
auto funcType = type.dyn_cast<FunctionType>();
if (!funcType || funcType.getNumResults() != 1 ||
funcType.getNumInputs() == 0)
return parser->emitError(trailingTypeLoc,
"expected trailing function type with at least "
"one argument and one result");
if (parser->resolveOperand(base, funcType.getInput(0), result->operands) ||
parser->resolveOperands(indices, funcType.getInputs().drop_front(),
parser->getNameLoc(), result->operands))
return true;
result->attributes = attrs;
result->addTypes(funcType.getResults());
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::LoadOp.
//===----------------------------------------------------------------------===//
static void printLoadOp(OpAsmPrinter *p, LoadOp &op) {
*p << op.getOperationName() << ' ' << *op.addr();
p->printOptionalAttrDict(op.getAttrs());
*p << " : " << op.addr()->getType();
}
// Extract the pointee type from the LLVM pointer type wrapped in MLIR. Return
// the resulting type wrapped in MLIR, or nullptr on error.
static Type getLoadStoreElementType(OpAsmParser *parser, Type type,
llvm::SMLoc trailingTypeLoc) {
auto llvmTy = type.dyn_cast<LLVM::LLVMType>();
if (!llvmTy)
return parser->emitError(trailingTypeLoc, "expected LLVM IR dialect type"),
nullptr;
auto *llvmPtrTy = dyn_cast<llvm::PointerType>(llvmTy.getUnderlyingType());
if (!llvmPtrTy)
return parser->emitError(trailingTypeLoc, "expected LLVM pointer type"),
nullptr;
auto elemTy = LLVM::LLVMType::get(parser->getBuilder().getContext(),
llvmPtrTy->getElementType());
return elemTy;
}
// <operation> ::= `llvm.load` ssa-use attribute-dict? `:` type
static bool parseLoadOp(OpAsmParser *parser, OperationState *result) {
SmallVector<NamedAttribute, 4> attrs;
OpAsmParser::OperandType addr;
Type type;
llvm::SMLoc trailingTypeLoc;
if (parser->parseOperand(addr) || parser->parseOptionalAttributeDict(attrs) ||
parser->parseColon() || parser->getCurrentLocation(&trailingTypeLoc) ||
parser->parseType(type) ||
parser->resolveOperand(addr, type, result->operands))
return true;
Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc);
result->attributes = attrs;
result->addTypes(elemTy);
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::StoreOp.
//===----------------------------------------------------------------------===//
static void printStoreOp(OpAsmPrinter *p, StoreOp &op) {
*p << op.getOperationName() << ' ' << *op.value() << ", " << *op.addr();
p->printOptionalAttrDict(op.getAttrs());
*p << " : " << op.addr()->getType();
}
// <operation> ::= `llvm.store` ssa-use `,` ssa-use attribute-dict? `:` type
static bool parseStoreOp(OpAsmParser *parser, OperationState *result) {
SmallVector<NamedAttribute, 4> attrs;
OpAsmParser::OperandType addr, value;
Type type;
llvm::SMLoc trailingTypeLoc;
if (parser->parseOperand(value) || parser->parseComma() ||
parser->parseOperand(addr) || parser->parseOptionalAttributeDict(attrs) ||
parser->parseColon() || parser->getCurrentLocation(&trailingTypeLoc) ||
parser->parseType(type))
return true;
Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc);
if (!elemTy)
return true;
if (parser->resolveOperand(value, elemTy, result->operands) ||
parser->resolveOperand(addr, type, result->operands))
return true;
result->attributes = attrs;
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::BitcastOp.
//===----------------------------------------------------------------------===//
static void printBitcastOp(OpAsmPrinter *p, BitcastOp &op) {
*p << op.getOperationName() << ' ' << *op.arg();
p->printOptionalAttrDict(op.getAttrs());
*p << " : " << op.arg()->getType() << " to " << op.getType();
}
// <operation> ::= `llvm.bitcast` ssa-use attribute-dict? `:` type `to` type
static bool parseBitcastOp(OpAsmParser *parser, OperationState *result) {
SmallVector<NamedAttribute, 4> attrs;
OpAsmParser::OperandType arg;
Type sourceType, type;
if (parser->parseOperand(arg) || parser->parseOptionalAttributeDict(attrs) ||
parser->parseColonType(sourceType) || parser->parseKeyword("to") ||
parser->parseType(type) ||
parser->resolveOperand(arg, sourceType, result->operands))
return true;
result->attributes = attrs;
result->addTypes(type);
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::CallOp.
//===----------------------------------------------------------------------===//
static void printCallOp(OpAsmPrinter *p, CallOp &op) {
auto callee = op.callee();
bool isDirect = callee.hasValue();
// Print the direct callee if present as a function attribute, or an indirect
// callee (first operand) otherwise.
*p << op.getOperationName() << ' ';
if (isDirect)
*p << '@' << callee.getValue()->getName().strref();
else
*p << *op.getOperand(0);
*p << '(';
p->printOperands(std::next(op.operand_begin(), callee.hasValue() ? 0 : 1),
op.operand_end());
*p << ')';
p->printOptionalAttrDict(op.getAttrs(), {"callee"});
if (isDirect) {
*p << " : " << callee.getValue()->getType();
return;
}
// Reconstruct the function MLIR function type from LLVM function type,
// and print it.
auto operandType = op.getOperand(0)->getType().cast<LLVM::LLVMType>();
auto *llvmPtrType =
dyn_cast<llvm::PointerType>(operandType.getUnderlyingType());
assert(llvmPtrType &&
"operand #0 must have LLVM pointer type for indirect calls");
auto *llvmType = dyn_cast<llvm::FunctionType>(llvmPtrType->getElementType());
assert(llvmType &&
"operand #0 must have LLVM Function pointer type for indirect calls");
auto *llvmResultType = llvmType->getReturnType();
SmallVector<Type, 1> resultTypes;
if (!llvmResultType->isVoidTy())
resultTypes.push_back(LLVM::LLVMType::get(op.getContext(), llvmResultType));
SmallVector<Type, 8> argTypes;
argTypes.reserve(llvmType->getNumParams());
for (int i = 0, e = llvmType->getNumParams(); i < e; ++i)
argTypes.push_back(
LLVM::LLVMType::get(op.getContext(), llvmType->getParamType(i)));
*p << " : " << FunctionType::get(argTypes, resultTypes, op.getContext());
}
// <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)`
// attribute-dict? `:` function-type
static bool parseCallOp(OpAsmParser *parser, OperationState *result) {
SmallVector<NamedAttribute, 4> attrs;
SmallVector<OpAsmParser::OperandType, 8> operands;
Type type;
StringRef calleeName;
llvm::SMLoc calleeLoc, trailingTypeLoc;
// Parse an operand list that will, in practice, contain 0 or 1 operand. In
// case of an indirect call, there will be 1 operand before `(`. In case of a
// direct call, there will be no operands and the parser will stop at the
// function identifier without complaining.
if (parser->parseOperandList(operands))
return true;
bool isDirect = operands.empty();
// Optionally parse a function identifier.
if (isDirect)
if (parser->parseFunctionName(calleeName, calleeLoc))
return true;
if (parser->parseOperandList(operands, /*requiredOperandCount=*/-1,
OpAsmParser::Delimiter::Paren) ||
parser->parseOptionalAttributeDict(attrs) || parser->parseColon() ||
parser->getCurrentLocation(&trailingTypeLoc) || parser->parseType(type))
return true;
auto funcType = type.dyn_cast<FunctionType>();
if (!funcType)
return parser->emitError(trailingTypeLoc, "expected function type");
if (isDirect) {
// Add the direct callee as an Op attribute.
Function *func;
if (parser->resolveFunctionName(calleeName, funcType, calleeLoc, func))
return true;
auto funcAttr = parser->getBuilder().getFunctionAttr(func);
attrs.push_back(parser->getBuilder().getNamedAttr("callee", funcAttr));
// Make sure types match.
if (parser->resolveOperands(operands, funcType.getInputs(),
parser->getNameLoc(), result->operands))
return true;
result->addTypes(funcType.getResults());
} else {
// Construct the LLVM IR Dialect function type that the first operand
// should match.
if (funcType.getNumResults() > 1)
return parser->emitError(trailingTypeLoc,
"expected function with 0 or 1 result");
Builder &builder = parser->getBuilder();
auto *llvmDialect = static_cast<LLVM::LLVMDialect *>(
builder.getContext()->getRegisteredDialect("llvm"));
llvm::Type *llvmResultType;
Type wrappedResultType;
if (funcType.getNumResults() == 0) {
llvmResultType = llvm::Type::getVoidTy(llvmDialect->getLLVMContext());
wrappedResultType = builder.getType<LLVM::LLVMType>(llvmResultType);
} else {
wrappedResultType = funcType.getResult(0);
auto wrappedLLVMResultType = wrappedResultType.dyn_cast<LLVM::LLVMType>();
if (!wrappedLLVMResultType)
return parser->emitError(trailingTypeLoc,
"expected result to have LLVM type");
llvmResultType = wrappedLLVMResultType.getUnderlyingType();
}
SmallVector<llvm::Type *, 8> argTypes;
argTypes.reserve(funcType.getNumInputs());
for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) {
auto argType = funcType.getInput(i).dyn_cast<LLVM::LLVMType>();
if (!argType)
return parser->emitError(trailingTypeLoc,
"expected LLVM types as inputs");
argTypes.push_back(argType.getUnderlyingType());
}
auto *llvmFuncType = llvm::FunctionType::get(llvmResultType, argTypes,
/*isVarArg=*/false);
auto wrappedFuncType =
builder.getType<LLVM::LLVMType>(llvmFuncType->getPointerTo());
auto funcArguments =
ArrayRef<OpAsmParser::OperandType>(operands).drop_front();
// Make sure that the first operand (indirect callee) matches the wrapped
// LLVM IR function type, and that the types of the other call operands
// match the types of the function arguments.
if (parser->resolveOperand(operands[0], wrappedFuncType,
result->operands) ||
parser->resolveOperands(funcArguments, funcType.getInputs(),
parser->getNameLoc(), result->operands))
return true;
result->addTypes(wrappedResultType);
}
result->attributes = attrs;
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::ExtractValueOp.
//===----------------------------------------------------------------------===//
static void printExtractValueOp(OpAsmPrinter *p, ExtractValueOp &op) {
*p << op.getOperationName() << ' ' << *op.container() << op.position();
p->printOptionalAttrDict(op.getAttrs(), {"position"});
*p << " : " << op.container()->getType();
}
// Extract the type at `position` in the wrapped LLVM IR aggregate type
// `containerType`. Position is an integer array attribute where each value
// is a zero-based position of the element in the aggregate type. Return the
// resulting type wrapped in MLIR, or nullptr on error.
static LLVM::LLVMType getInsertExtractValueElementType(OpAsmParser *parser,
Type containerType,
Attribute positionAttr,
llvm::SMLoc attributeLoc,
llvm::SMLoc typeLoc) {
auto wrappedContainerType = containerType.dyn_cast<LLVM::LLVMType>();
if (!wrappedContainerType)
return parser->emitError(typeLoc, "expected LLVM IR Dialect type"), nullptr;
auto positionArrayAttr = positionAttr.dyn_cast<ArrayAttr>();
if (!positionArrayAttr)
return parser->emitError(attributeLoc, "expected an array attribute"),
nullptr;
// Infer the element type from the structure type: iteratively step inside the
// type by taking the element type, indexed by the position attribute for
// stuctures. Check the position index before accessing, it is supposed to be
// in bounds.
llvm::Type *llvmContainerType = wrappedContainerType.getUnderlyingType();
for (Attribute subAttr : positionArrayAttr) {
auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>();
if (!positionElementAttr)
return parser->emitError(attributeLoc,
"expected an array of integer literals"),
nullptr;
int position = positionElementAttr.getInt();
if (llvmContainerType->isArrayTy()) {
if (position < 0 || position >= llvmContainerType->getArrayNumElements())
return parser->emitError(attributeLoc, "position out of bounds"),
nullptr;
llvmContainerType = llvmContainerType->getArrayElementType();
} else if (llvmContainerType->isStructTy()) {
if (position < 0 || position >= llvmContainerType->getStructNumElements())
return parser->emitError(attributeLoc, "position out of bounds"),
nullptr;
llvmContainerType = llvmContainerType->getStructElementType(position);
} else {
return parser->emitError(typeLoc,
"expected wrapped LLVM IR structure/array type"),
nullptr;
}
}
Builder &builder = parser->getBuilder();
return builder.getType<LLVM::LLVMType>(llvmContainerType);
}
// <operation> ::= `llvm.extractvalue` ssa-use
// `[` integer-literal (`,` integer-literal)* `]`
// attribute-dict? `:` type
static bool parseExtractValueOp(OpAsmParser *parser, OperationState *result) {
SmallVector<NamedAttribute, 4> attrs;
OpAsmParser::OperandType container;
Type containerType;
Attribute positionAttr;
llvm::SMLoc attributeLoc, trailingTypeLoc;
if (parser->parseOperand(container) ||
parser->getCurrentLocation(&attributeLoc) ||
parser->parseAttribute(positionAttr, "position", attrs) ||
parser->parseOptionalAttributeDict(attrs) || parser->parseColon() ||
parser->getCurrentLocation(&trailingTypeLoc) ||
parser->parseType(containerType) ||
parser->resolveOperand(container, containerType, result->operands))
return true;
auto elementType = getInsertExtractValueElementType(
parser, containerType, positionAttr, attributeLoc, trailingTypeLoc);
if (!elementType)
return true;
result->attributes = attrs;
result->addTypes(elementType);
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::InsertValueOp.
//===----------------------------------------------------------------------===//
static void printInsertValueOp(OpAsmPrinter *p, InsertValueOp &op) {
*p << op.getOperationName() << ' ' << *op.value() << ", " << *op.container()
<< op.position();
p->printOptionalAttrDict(op.getAttrs(), {"position"});
*p << " : " << op.container()->getType();
}
// <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use
// `[` integer-literal (`,` integer-literal)* `]`
// attribute-dict? `:` type
static bool parseInsertValueOp(OpAsmParser *parser, OperationState *result) {
OpAsmParser::OperandType container, value;
Type containerType;
Attribute positionAttr;
llvm::SMLoc attributeLoc, trailingTypeLoc;
if (parser->parseOperand(value) || parser->parseComma() ||
parser->parseOperand(container) ||
parser->getCurrentLocation(&attributeLoc) ||
parser->parseAttribute(positionAttr, "position", result->attributes) ||
parser->parseOptionalAttributeDict(result->attributes) ||
parser->parseColon() || parser->getCurrentLocation(&trailingTypeLoc) ||
parser->parseType(containerType))
return true;
auto valueType = getInsertExtractValueElementType(
parser, containerType, positionAttr, attributeLoc, trailingTypeLoc);
if (!valueType)
return true;
if (parser->resolveOperand(container, containerType, result->operands) ||
parser->resolveOperand(value, valueType, result->operands))
return true;
result->addTypes(containerType);
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::SelectOp.
//===----------------------------------------------------------------------===//
static void printSelectOp(OpAsmPrinter *p, SelectOp &op) {
*p << op.getOperationName() << ' ' << *op.condition() << ", "
<< *op.trueValue() << ", " << *op.falseValue();
p->printOptionalAttrDict(op.getAttrs());
*p << " : " << op.condition()->getType() << ", " << op.trueValue()->getType();
}
// <operation> ::= `llvm.select` ssa-use `,` ssa-use `,` ssa-use
// attribute-dict? `:` type, type
static bool parseSelectOp(OpAsmParser *parser, OperationState *result) {
OpAsmParser::OperandType condition, trueValue, falseValue;
Type conditionType, argType;
if (parser->parseOperand(condition) || parser->parseComma() ||
parser->parseOperand(trueValue) || parser->parseComma() ||
parser->parseOperand(falseValue) ||
parser->parseOptionalAttributeDict(result->attributes) ||
parser->parseColonType(conditionType) || parser->parseComma() ||
parser->parseType(argType))
return true;
if (parser->resolveOperand(condition, conditionType, result->operands) ||
parser->resolveOperand(trueValue, argType, result->operands) ||
parser->resolveOperand(falseValue, argType, result->operands))
return true;
result->addTypes(argType);
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::BrOp.
//===----------------------------------------------------------------------===//
static void printBrOp(OpAsmPrinter *p, BrOp &op) {
*p << op.getOperationName() << ' ';
p->printSuccessorAndUseList(op.getOperation(), 0);
p->printOptionalAttrDict(op.getAttrs());
}
// <operation> ::= `llvm.br` bb-id (`[` ssa-use-and-type-list `]`)?
// attribute-dict?
static bool parseBrOp(OpAsmParser *parser, OperationState *result) {
Block *dest;
SmallVector<Value *, 4> operands;
if (parser->parseSuccessorAndUseList(dest, operands) ||
parser->parseOptionalAttributeDict(result->attributes))
return true;
result->addSuccessor(dest, operands);
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::CondBrOp.
//===----------------------------------------------------------------------===//
static void printCondBrOp(OpAsmPrinter *p, CondBrOp &op) {
*p << op.getOperationName() << ' ' << *op.getOperand(0) << ", ";
p->printSuccessorAndUseList(op.getOperation(), 0);
*p << ", ";
p->printSuccessorAndUseList(op.getOperation(), 1);
p->printOptionalAttrDict(op.getAttrs());
}
// <operation> ::= `llvm.cond_br` ssa-use `,`
// bb-id (`[` ssa-use-and-type-list `]`)? `,`
// bb-id (`[` ssa-use-and-type-list `]`)? attribute-dict?
static bool parseCondBrOp(OpAsmParser *parser, OperationState *result) {
Block *trueDest;
Block *falseDest;
SmallVector<Value *, 4> trueOperands;
SmallVector<Value *, 4> falseOperands;
OpAsmParser::OperandType condition;
Builder &builder = parser->getBuilder();
auto *llvmDialect = static_cast<LLVM::LLVMDialect *>(
builder.getContext()->getRegisteredDialect("llvm"));
auto i1Type = builder.getType<LLVM::LLVMType>(
llvm::Type::getInt1Ty(llvmDialect->getLLVMContext()));
if (parser->parseOperand(condition) || parser->parseComma() ||
parser->parseSuccessorAndUseList(trueDest, trueOperands) ||
parser->parseComma() ||
parser->parseSuccessorAndUseList(falseDest, falseOperands) ||
parser->parseOptionalAttributeDict(result->attributes) ||
parser->resolveOperand(condition, i1Type, result->operands))
return true;
result->addSuccessor(trueDest, trueOperands);
result->addSuccessor(falseDest, falseOperands);
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::ReturnOp.
//===----------------------------------------------------------------------===//
static void printReturnOp(OpAsmPrinter *p, ReturnOp &op) {
*p << op.getOperationName();
p->printOptionalAttrDict(op.getAttrs());
assert(op.getNumOperands() <= 1);
if (op.getNumOperands() == 0)
return;
*p << ' ' << *op.getOperand(0) << " : " << op.getOperand(0)->getType();
}
// <operation> ::= `llvm.return` ssa-use-list attribute-dict? `:`
// type-list-no-parens
static bool parseReturnOp(OpAsmParser *parser, OperationState *result) {
SmallVector<OpAsmParser::OperandType, 1> operands;
Type type;
if (parser->parseOperandList(operands) ||
parser->parseOptionalAttributeDict(result->attributes))
return true;
if (operands.empty())
return false;
if (parser->parseColonType(type) ||
parser->resolveOperand(operands[0], type, result->operands))
return true;
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::UndefOp.
//===----------------------------------------------------------------------===//
static void printUndefOp(OpAsmPrinter *p, UndefOp &op) {
*p << op.getOperationName();
p->printOptionalAttrDict(op.getAttrs());
*p << " : " << op.res()->getType();
}
// <operation> ::= `llvm.undef` attribute-dict? : type
static bool parseUndefOp(OpAsmParser *parser, OperationState *result) {
Type type;
if (parser->parseOptionalAttributeDict(result->attributes) ||
parser->parseColonType(type))
return true;
result->addTypes(type);
return false;
}
//===----------------------------------------------------------------------===//
// Printing/parsing for LLVM::ConstantOp.
//===----------------------------------------------------------------------===//
static void printConstantOp(OpAsmPrinter *p, ConstantOp &op) {
*p << op.getOperationName() << '(' << op.value();
// Print attribute types other than i64 and f64 because attribute parsing will
// assume those in absence of explicit attribute type.
if (auto intAttr = op.value().dyn_cast<IntegerAttr>()) {
auto type = intAttr.getType();
if (!type.isInteger(64))
*p << " : " << intAttr.getType();
} else if (auto floatAttr = op.value().dyn_cast<FloatAttr>()) {
auto type = floatAttr.getType();
if (!type.isF64())
*p << " : " << type;
}
*p << ')';
p->printOptionalAttrDict(op.getAttrs(), {"value"});
*p << " : " << op.res()->getType();
}
// <operation> ::= `llvm.constant` `(` attribute `)` attribute-list? : type
static bool parseConstantOp(OpAsmParser *parser, OperationState *result) {
Attribute valueAttr;
Type type;
if (parser->parseLParen() ||
parser->parseAttribute(valueAttr, "value", result->attributes) ||
parser->parseRParen() ||
parser->parseOptionalAttributeDict(result->attributes) ||
parser->parseColonType(type))
return true;
result->addTypes(type);
return false;
}
//===----------------------------------------------------------------------===//
// LLVMDialect initialization, type parsing, and registration.
//===----------------------------------------------------------------------===//
LLVMDialect::LLVMDialect(MLIRContext *context)
: Dialect("llvm", context), module("LLVMDialectModule", llvmContext) {

View File

@ -3057,6 +3057,9 @@ public:
bool parseComma() override {
return parser.parseToken(Token::comma, "expected ','");
}
bool parseColon() override {
return parser.parseToken(Token::colon, "expected ':'");
}
bool parseEqual() override {
return parser.parseToken(Token::equal, "expected '='");
}
@ -3142,10 +3145,19 @@ public:
/// Parse a function name like '@foo' and return the name in a form that can
/// be passed to resolveFunctionName when a function type is available.
virtual bool parseFunctionName(StringRef &result, llvm::SMLoc &loc) {
if (parseOptionalFunctionName(result, loc))
return emitError(loc, "expected function name");
return false;
}
/// Parse a function name like '@foo` if present and return the name without
/// the sigil in `result`. Return true if the next token is not a function
/// name and keep `result` unchanged.
bool parseOptionalFunctionName(StringRef &result, llvm::SMLoc &loc) override {
loc = parser.getToken().getLoc();
if (parser.getToken().isNot(Token::at_identifier))
return emitError(loc, "expected function name");
return true;
result = parser.getTokenSpelling();
parser.consumeToken(Token::at_identifier);
@ -3167,6 +3179,14 @@ public:
return parser.parseSuccessorAndUseList(dest, operands);
}
bool parseLParen() override {
return parser.parseToken(Token::l_paren, "expected '('");
}
bool parseRParen() override {
return parser.parseToken(Token::r_paren, "expected ')'");
}
bool parseOperandList(SmallVectorImpl<OperandType> &result,
int requiredOperandCount = -1,
Delimiter delimiter = Delimiter::None) override {

View File

@ -20,12 +20,12 @@ func @fifth_order_right(%arg0: () -> (() -> (() -> (() -> ()))))
//CHECK-LABEL: func @pass_through(%arg0: !llvm<"void ()*">) -> !llvm<"void ()*"> {
func @pass_through(%arg0: () -> ()) -> (() -> ()) {
//CHECK-NEXT: "llvm.br"()[^bb1(%arg0 : !llvm<"void ()*">)] : () -> ()
// CHECK-NEXT: llvm.br ^bb1(%arg0 : !llvm<"void ()*">)
br ^bb1(%arg0 : () -> ())
//CHECK-NEXT: ^bb1(%0: !llvm<"void ()*">): // pred: ^bb0
^bb1(%bbarg: () -> ()):
//CHECK-NEXT: "llvm.return"(%0) : (!llvm<"void ()*">) -> ()
// CHECK-NEXT: llvm.return %0 : !llvm<"void ()*">
return %bbarg : () -> ()
}
@ -34,19 +34,19 @@ func @body(i32)
// CHECK-LABEL: func @indirect_const_call(%arg0: !llvm<"i32">) {
func @indirect_const_call(%arg0: i32) {
// CHECK-NEXT: %0 = "llvm.constant"() {value: @body : (!llvm<"i32">) -> ()} : () -> !llvm<"void (i32)*">
// CHECK-NEXT: %0 = llvm.constant(@body : (!llvm<"i32">) -> ()) : !llvm<"void (i32)*">
%0 = constant @body : (i32) -> ()
// CHECK-NEXT: "llvm.call"(%0, %arg0) : (!llvm<"void (i32)*">, !llvm<"i32">) -> ()
// CHECK-NEXT: llvm.call %0(%arg0) : (!llvm<"i32">) -> ()
call_indirect %0(%arg0) : (i32) -> ()
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: llvm.return
return
}
// CHECK-LABEL: func @indirect_call(%arg0: !llvm<"i32 (float)*">, %arg1: !llvm<"float">) -> !llvm<"i32"> {
func @indirect_call(%arg0: (f32) -> i32, %arg1: f32) -> i32 {
// CHECK-NEXT: %0 = "llvm.call"(%arg0, %arg1) : (!llvm<"i32 (float)*">, !llvm<"float">) -> !llvm<"i32">
// CHECK-NEXT: %0 = llvm.call %arg0(%arg1) : (!llvm<"float">) -> !llvm<"i32">
%0 = call_indirect %arg0(%arg1) : (f32) -> i32
// CHECK-NEXT: "llvm.return"(%0) : (!llvm<"i32">) -> ()
// CHECK-NEXT: llvm.return %0 : !llvm<"i32">
return %0 : i32
}

View File

@ -8,288 +8,288 @@ func @check_arguments(%static: memref<10x20xf32>, %dynamic : memref<?x?xf32>, %m
// CHECK-LABEL: func @check_static_return(%arg0: !llvm<"float*">) -> !llvm<"float*"> {
func @check_static_return(%static : memref<32x18xf32>) -> memref<32x18xf32> {
// CHECK-NEXT: "llvm.return"(%arg0) : (!llvm<"float*">) -> ()
// CHECK-NEXT: llvm.return %arg0 : !llvm<"float*">
return %static : memref<32x18xf32>
}
// CHECK-LABEL: func @zero_d_alloc() -> !llvm<"float*"> {
func @zero_d_alloc() -> memref<f32> {
// CHECK-NEXT: %0 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%0, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.call"(%2) {callee: @malloc : (!llvm<"i64">) -> !llvm<"i8*">} : (!llvm<"i64">) -> !llvm<"i8*">
// CHECK-NEXT: %4 = "llvm.bitcast"(%3) : (!llvm<"i8*">) -> !llvm<"float*">
// CHECK-NEXT: %0 = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: %1 = llvm.constant(4 : index) : !llvm<"i64">
// CHECK-NEXT: %2 = llvm.mul %0, %1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.call @malloc(%2) : (!llvm<"i64">) -> !llvm<"i8*">
// CHECK-NEXT: %4 = llvm.bitcast %3 : !llvm<"i8*"> to !llvm<"float*">
%0 = alloc() : memref<f32>
return %0 : memref<f32>
}
// CHECK-LABEL: func @zero_d_dealloc(%arg0: !llvm<"float*">) {
func @zero_d_dealloc(%arg0: memref<f32>) {
// CHECK-NEXT: %0 = "llvm.bitcast"(%arg0) : (!llvm<"float*">) -> !llvm<"i8*">
// CHECK-NEXT: "llvm.call"(%0) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
// CHECK-NEXT: %0 = llvm.bitcast %arg0 : !llvm<"float*"> to !llvm<"i8*">
// CHECK-NEXT: llvm.call @free(%0) : (!llvm<"i8*">) -> ()
dealloc %arg0 : memref<f32>
return
}
// CHECK-LABEL: func @mixed_alloc(%arg0: !llvm<"i64">, %arg1: !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }"> {
func @mixed_alloc(%arg0: index, %arg1: index) -> memref<?x42x?xf32> {
// CHECK-NEXT: %0 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.mul"(%arg0, %0) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%1, %arg1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.mul"(%2, %3) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %5 = "llvm.call"(%4) {callee: @malloc : (!llvm<"i64">) -> !llvm<"i8*">} : (!llvm<"i64">) -> !llvm<"i8*">
// CHECK-NEXT: %6 = "llvm.bitcast"(%5) : (!llvm<"i8*">) -> !llvm<"float*">
// CHECK-NEXT: %7 = "llvm.undef"() : () -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %8 = "llvm.insertvalue"(%7, %6) {position: [0]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %9 = "llvm.insertvalue"(%8, %arg0) {position: [1]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %10 = "llvm.insertvalue"(%9, %arg1) {position: [2]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %0 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: %1 = llvm.mul %arg0, %0 : !llvm<"i64">
// CHECK-NEXT: %2 = llvm.mul %1, %arg1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.constant(4 : index) : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.mul %2, %3 : !llvm<"i64">
// CHECK-NEXT: %5 = llvm.call @malloc(%4) : (!llvm<"i64">) -> !llvm<"i8*">
// CHECK-NEXT: %6 = llvm.bitcast %5 : !llvm<"i8*"> to !llvm<"float*">
// CHECK-NEXT: %7 = llvm.undef : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %8 = llvm.insertvalue %6, %7[0] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %9 = llvm.insertvalue %arg0, %8[1] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %10 = llvm.insertvalue %arg1, %9[2] : !llvm<"{ float*, i64, i64 }">
%0 = alloc(%arg0, %arg1) : memref<?x42x?xf32>
return %0 : memref<?x42x?xf32>
}
// CHECK-LABEL: func @mixed_dealloc(%arg0: !llvm<"{ float*, i64, i64 }">) {
func @mixed_dealloc(%arg0: memref<?x42x?xf32>) {
// CHECK-NEXT: %0 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %1 = "llvm.bitcast"(%0) : (!llvm<"float*">) -> !llvm<"i8*">
// CHECK-NEXT: "llvm.call"(%1) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %1 = llvm.bitcast %0 : !llvm<"float*"> to !llvm<"i8*">
// CHECK-NEXT: llvm.call @free(%1) : (!llvm<"i8*">) -> ()
dealloc %arg0 : memref<?x42x?xf32>
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: llvm.return
return
}
// CHECK-LABEL: func @dynamic_alloc(%arg0: !llvm<"i64">, %arg1: !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }"> {
func @dynamic_alloc(%arg0: index, %arg1: index) -> memref<?x?xf32> {
// CHECK-NEXT: %0 = "llvm.mul"(%arg0, %arg1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%0, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.call"(%2) {callee: @malloc : (!llvm<"i64">) -> !llvm<"i8*">} : (!llvm<"i64">) -> !llvm<"i8*">
// CHECK-NEXT: %4 = "llvm.bitcast"(%3) : (!llvm<"i8*">) -> !llvm<"float*">
// CHECK-NEXT: %5 = "llvm.undef"() : () -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %6 = "llvm.insertvalue"(%5, %4) {position: [0]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %7 = "llvm.insertvalue"(%6, %arg0) {position: [1]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %8 = "llvm.insertvalue"(%7, %arg1) {position: [2]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %0 = llvm.mul %arg0, %arg1 : !llvm<"i64">
// CHECK-NEXT: %1 = llvm.constant(4 : index) : !llvm<"i64">
// CHECK-NEXT: %2 = llvm.mul %0, %1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.call @malloc(%2) : (!llvm<"i64">) -> !llvm<"i8*">
// CHECK-NEXT: %4 = llvm.bitcast %3 : !llvm<"i8*"> to !llvm<"float*">
// CHECK-NEXT: %5 = llvm.undef : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %6 = llvm.insertvalue %4, %5[0] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %7 = llvm.insertvalue %arg0, %6[1] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %8 = llvm.insertvalue %arg1, %7[2] : !llvm<"{ float*, i64, i64 }">
%0 = alloc(%arg0, %arg1) : memref<?x?xf32>
return %0 : memref<?x?xf32>
}
// CHECK-LABEL: func @dynamic_dealloc(%arg0: !llvm<"{ float*, i64, i64 }">) {
func @dynamic_dealloc(%arg0: memref<?x?xf32>) {
// CHECK-NEXT: %0 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %1 = "llvm.bitcast"(%0) : (!llvm<"float*">) -> !llvm<"i8*">
// CHECK-NEXT: "llvm.call"(%1) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %1 = llvm.bitcast %0 : !llvm<"float*"> to !llvm<"i8*">
// CHECK-NEXT: llvm.call @free(%1) : (!llvm<"i8*">) -> ()
dealloc %arg0 : memref<?x?xf32>
return
}
// CHECK-LABEL: func @static_alloc() -> !llvm<"float*"> {
func @static_alloc() -> memref<32x18xf32> {
// CHECK-NEXT: %0 = "llvm.constant"() {value: 32 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.constant"() {value: 18 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%0, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.mul"(%2, %3) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %5 = "llvm.call"(%4) {callee: @malloc : (!llvm<"i64">) -> !llvm<"i8*">} : (!llvm<"i64">) -> !llvm<"i8*">
// CHECK-NEXT: %6 = "llvm.bitcast"(%5) : (!llvm<"i8*">) -> !llvm<"float*">
// CHECK-NEXT: %0 = llvm.constant(32 : index) : !llvm<"i64">
// CHECK-NEXT: %1 = llvm.constant(18 : index) : !llvm<"i64">
// CHECK-NEXT: %2 = llvm.mul %0, %1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.constant(4 : index) : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.mul %2, %3 : !llvm<"i64">
// CHECK-NEXT: %5 = llvm.call @malloc(%4) : (!llvm<"i64">) -> !llvm<"i8*">
// CHECK-NEXT: %6 = llvm.bitcast %5 : !llvm<"i8*"> to !llvm<"float*">
%0 = alloc() : memref<32x18xf32>
return %0 : memref<32x18xf32>
}
// CHECK-LABEL: func @static_dealloc(%arg0: !llvm<"float*">) {
func @static_dealloc(%static: memref<10x8xf32>) {
// CHECK-NEXT: %0 = "llvm.bitcast"(%arg0) : (!llvm<"float*">) -> !llvm<"i8*">
// CHECK-NEXT: "llvm.call"(%0) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
// CHECK-NEXT: %0 = llvm.bitcast %arg0 : !llvm<"float*"> to !llvm<"i8*">
// CHECK-NEXT: llvm.call @free(%0) : (!llvm<"i8*">) -> ()
dealloc %static : memref<10x8xf32>
return
}
// CHECK-LABEL: func @zero_d_load(%arg0: !llvm<"float*">) -> !llvm<"float"> {
func @zero_d_load(%arg0: memref<f32>) -> f32 {
// CHECK-NEXT: %0 = "llvm.load"(%arg0) : (!llvm<"float*">) -> !llvm<"float">
// CHECK-NEXT: %0 = llvm.load %arg0 : !llvm<"float*">
%0 = load %arg0[] : memref<f32>
return %0 : f32
}
// CHECK-LABEL: func @static_load
func @static_load(%static : memref<10x42xf32>, %i : index, %j : index) {
// CHECK-NEXT: %0 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%arg1, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.add"(%2, %arg2) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.getelementptr"(%arg0, %3) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: %5 = "llvm.load"(%4) : (!llvm<"float*">) -> !llvm<"float">
// CHECK-NEXT: %0 = llvm.constant(10 : index) : !llvm<"i64">
// CHECK-NEXT: %1 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.getelementptr %arg0[%3] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: %5 = llvm.load %4 : !llvm<"float*">
%0 = load %static[%i, %j] : memref<10x42xf32>
return
}
// CHECK-LABEL: func @mixed_load
func @mixed_load(%mixed : memref<42x?xf32>, %i : index, %j : index) {
// CHECK-NEXT: %0 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.extractvalue"(%arg0) {position: [1]} : (!llvm<"{ float*, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%arg1, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.add"(%2, %arg2) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %5 = "llvm.getelementptr"(%4, %3) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: %6 = "llvm.load"(%5) : (!llvm<"float*">) -> !llvm<"float">
// CHECK-NEXT: %0 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %5 = llvm.getelementptr %4[%3] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: %6 = llvm.load %5 : !llvm<"float*">
%0 = load %mixed[%i, %j] : memref<42x?xf32>
return
}
// CHECK-LABEL: func @dynamic_load
func @dynamic_load(%dynamic : memref<?x?xf32>, %i : index, %j : index) {
// CHECK-NEXT: %0 = "llvm.extractvalue"(%arg0) {position: [1]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.extractvalue"(%arg0) {position: [2]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%arg1, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.add"(%2, %arg2) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %5 = "llvm.getelementptr"(%4, %3) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: %6 = "llvm.load"(%5) : (!llvm<"float*">) -> !llvm<"float">
// CHECK-NEXT: %0 = llvm.extractvalue %arg0[1] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %1 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %5 = llvm.getelementptr %4[%3] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: %6 = llvm.load %5 : !llvm<"float*">
%0 = load %dynamic[%i, %j] : memref<?x?xf32>
return
}
// CHECK-LABEL: func @zero_d_store(%arg0: !llvm<"float*">, %arg1: !llvm<"float">) {
func @zero_d_store(%arg0: memref<f32>, %arg1: f32) {
// CHECK-NEXT: "llvm.store"(%arg1, %arg0) : (!llvm<"float">, !llvm<"float*">) -> ()
// CHECK-NEXT: llvm.store %arg1, %arg0 : !llvm<"float*">
store %arg1, %arg0[] : memref<f32>
return
}
// CHECK-LABEL: func @static_store
func @static_store(%static : memref<10x42xf32>, %i : index, %j : index, %val : f32) {
// CHECK-NEXT: %0 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%arg1, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.add"(%2, %arg2) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.getelementptr"(%arg0, %3) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: "llvm.store"(%arg3, %4) : (!llvm<"float">, !llvm<"float*">) -> ()
// CHECK-NEXT: %0 = llvm.constant(10 : index) : !llvm<"i64">
// CHECK-NEXT: %1 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.getelementptr %arg0[%3] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: llvm.store %arg3, %4 : !llvm<"float*">
store %val, %static[%i, %j] : memref<10x42xf32>
return
}
// CHECK-LABEL: func @dynamic_store
func @dynamic_store(%dynamic : memref<?x?xf32>, %i : index, %j : index, %val : f32) {
// CHECK-NEXT: %0 = "llvm.extractvalue"(%arg0) {position: [1]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.extractvalue"(%arg0) {position: [2]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%arg1, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.add"(%2, %arg2) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %5 = "llvm.getelementptr"(%4, %3) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: "llvm.store"(%arg3, %5) : (!llvm<"float">, !llvm<"float*">) -> ()
// CHECK-NEXT: %0 = llvm.extractvalue %arg0[1] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %1 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %5 = llvm.getelementptr %4[%3] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: llvm.store %arg3, %5 : !llvm<"float*">
store %val, %dynamic[%i, %j] : memref<?x?xf32>
return
}
// CHECK-LABEL: func @mixed_store
func @mixed_store(%mixed : memref<42x?xf32>, %i : index, %j : index, %val : f32) {
// CHECK-NEXT: %0 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %1 = "llvm.extractvalue"(%arg0) {position: [1]} : (!llvm<"{ float*, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %2 = "llvm.mul"(%arg1, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.add"(%2, %arg2) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %5 = "llvm.getelementptr"(%4, %3) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: "llvm.store"(%arg3, %5) : (!llvm<"float">, !llvm<"float*">) -> ()
// CHECK-NEXT: %0 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %5 = llvm.getelementptr %4[%3] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
// CHECK-NEXT: llvm.store %arg3, %5 : !llvm<"float*">
store %val, %mixed[%i, %j] : memref<42x?xf32>
return
}
// CHECK-LABEL: func @memref_cast_static_to_dynamic
func @memref_cast_static_to_dynamic(%static : memref<10x42xf32>) {
// CHECK-NEXT: %0 = "llvm.undef"() : () -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %1 = "llvm.insertvalue"(%0, %arg0) {position: [0]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %2 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.insertvalue"(%1, %2) {position: [1]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %4 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %5 = "llvm.insertvalue"(%3, %4) {position: [2]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %0 = llvm.undef : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %1 = llvm.insertvalue %arg0, %0[0] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %2 = llvm.constant(10 : index) : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.insertvalue %2, %1[1] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %4 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: %5 = llvm.insertvalue %4, %3[2] : !llvm<"{ float*, i64, i64 }">
%0 = memref_cast %static : memref<10x42xf32> to memref<?x?xf32>
return
}
// CHECK-LABEL: func @memref_cast_static_to_mixed
func @memref_cast_static_to_mixed(%static : memref<10x42xf32>) {
// CHECK-NEXT: %0 = "llvm.undef"() : () -> !llvm<"{ float*, i64 }">
// CHECK-NEXT: %1 = "llvm.insertvalue"(%0, %arg0) {position: [0]} : (!llvm<"{ float*, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64 }">
// CHECK-NEXT: %2 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %3 = "llvm.insertvalue"(%1, %2) {position: [1]} : (!llvm<"{ float*, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64 }">
// CHECK-NEXT: %0 = llvm.undef : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %1 = llvm.insertvalue %arg0, %0[0] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %2 = llvm.constant(10 : index) : !llvm<"i64">
// CHECK-NEXT: %3 = llvm.insertvalue %2, %1[1] : !llvm<"{ float*, i64 }">
%0 = memref_cast %static : memref<10x42xf32> to memref<?x42xf32>
return
}
// CHECK-LABEL: func @memref_cast_dynamic_to_static
func @memref_cast_dynamic_to_static(%dynamic : memref<?x?xf32>) {
// CHECK-NEXT: %0 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }">
%0 = memref_cast %dynamic : memref<?x?xf32> to memref<10x12xf32>
return
}
// CHECK-LABEL: func @memref_cast_dynamic_to_mixed
func @memref_cast_dynamic_to_mixed(%dynamic : memref<?x?xf32>) {
// CHECK-NEXT: %0 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %1 = "llvm.undef"() : () -> !llvm<"{ float*, i64 }">
// CHECK-NEXT: %2 = "llvm.insertvalue"(%1, %0) {position: [0]} : (!llvm<"{ float*, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64 }">
// CHECK-NEXT: %3 = "llvm.extractvalue"(%arg0) {position: [1]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.insertvalue"(%2, %3) {position: [1]} : (!llvm<"{ float*, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64 }">
// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %1 = llvm.undef : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %2 = llvm.insertvalue %0, %1[0] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %3 = llvm.extractvalue %arg0[1] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %4 = llvm.insertvalue %3, %2[1] : !llvm<"{ float*, i64 }">
%0 = memref_cast %dynamic : memref<?x?xf32> to memref<?x12xf32>
return
}
// CHECK-LABEL: func @memref_cast_mixed_to_dynamic
func @memref_cast_mixed_to_dynamic(%mixed : memref<42x?xf32>) {
// CHECK-NEXT: %0 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %1 = "llvm.undef"() : () -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %2 = "llvm.insertvalue"(%1, %0) {position: [0]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %3 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.insertvalue"(%2, %3) {position: [1]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %5 = "llvm.extractvalue"(%arg0) {position: [1]} : (!llvm<"{ float*, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %6 = "llvm.insertvalue"(%4, %5) {position: [2]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %1 = llvm.undef : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %2 = llvm.insertvalue %0, %1[0] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %3 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.insertvalue %3, %2[1] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %5 = llvm.extractvalue %arg0[1] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %6 = llvm.insertvalue %5, %4[2] : !llvm<"{ float*, i64, i64 }">
%0 = memref_cast %mixed : memref<42x?xf32> to memref<?x?xf32>
return
}
// CHECK-LABEL: func @memref_cast_mixed_to_static
func @memref_cast_mixed_to_static(%mixed : memref<42x?xf32>) {
// CHECK-NEXT: %0 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64 }">
%0 = memref_cast %mixed : memref<42x?xf32> to memref<42x1xf32>
return
}
// CHECK-LABEL: func @memref_cast_mixed_to_mixed
func @memref_cast_mixed_to_mixed(%mixed : memref<42x?xf32>) {
// CHECK-NEXT: %0 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float*, i64 }">) -> !llvm<"float*">
// CHECK-NEXT: %1 = "llvm.undef"() : () -> !llvm<"{ float*, i64 }">
// CHECK-NEXT: %2 = "llvm.insertvalue"(%1, %0) {position: [0]} : (!llvm<"{ float*, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64 }">
// CHECK-NEXT: %3 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %4 = "llvm.insertvalue"(%2, %3) {position: [1]} : (!llvm<"{ float*, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64 }">
// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %1 = llvm.undef : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %2 = llvm.insertvalue %0, %1[0] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: %3 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: %4 = llvm.insertvalue %3, %2[1] : !llvm<"{ float*, i64 }">
%0 = memref_cast %mixed : memref<42x?xf32> to memref<?x1xf32>
return
}
// CHECK-LABEL: func @mixed_memref_dim(%arg0: !llvm<"{ float*, i64, i64, i64 }">)
func @mixed_memref_dim(%mixed : memref<42x?x?x13x?xf32>) {
// CHECK-NEXT: %0 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %0 = llvm.constant(42 : index) : !llvm<"i64">
%0 = dim %mixed, 0 : memref<42x?x?x13x?xf32>
// CHECK-NEXT: %1 = "llvm.extractvalue"(%arg0) {position: [1]} : (!llvm<"{ float*, i64, i64, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1] : !llvm<"{ float*, i64, i64, i64 }">
%1 = dim %mixed, 1 : memref<42x?x?x13x?xf32>
// CHECK-NEXT: %2 = "llvm.extractvalue"(%arg0) {position: [2]} : (!llvm<"{ float*, i64, i64, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %2 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64, i64 }">
%2 = dim %mixed, 2 : memref<42x?x?x13x?xf32>
// CHECK-NEXT: %3 = "llvm.constant"() {value: 13 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %3 = llvm.constant(13 : index) : !llvm<"i64">
%3 = dim %mixed, 3 : memref<42x?x?x13x?xf32>
// CHECK-NEXT: %4 = "llvm.extractvalue"(%arg0) {position: [3]} : (!llvm<"{ float*, i64, i64, i64 }">) -> !llvm<"i64">
// CHECK-NEXT: %4 = llvm.extractvalue %arg0[3] : !llvm<"{ float*, i64, i64, i64 }">
%4 = dim %mixed, 4 : memref<42x?x?x13x?xf32>
return
}
// CHECK-LABEL: func @static_memref_dim(%arg0: !llvm<"float*">)
func @static_memref_dim(%static : memref<42x32x15x13x27xf32>) {
// CHECK-NEXT: %0 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %0 = llvm.constant(42 : index) : !llvm<"i64">
%0 = dim %static, 0 : memref<42x32x15x13x27xf32>
// CHECK-NEXT: %1 = "llvm.constant"() {value: 32 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %1 = llvm.constant(32 : index) : !llvm<"i64">
%1 = dim %static, 1 : memref<42x32x15x13x27xf32>
// CHECK-NEXT: %2 = "llvm.constant"() {value: 15 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %2 = llvm.constant(15 : index) : !llvm<"i64">
%2 = dim %static, 2 : memref<42x32x15x13x27xf32>
// CHECK-NEXT: %3 = "llvm.constant"() {value: 13 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %3 = llvm.constant(13 : index) : !llvm<"i64">
%3 = dim %static, 3 : memref<42x32x15x13x27xf32>
// CHECK-NEXT: %4 = "llvm.constant"() {value: 27 : index} : () -> !llvm<"i64">
// CHECK-NEXT: %4 = llvm.constant(27 : index) : !llvm<"i64">
%4 = dim %static, 4 : memref<42x32x15x13x27xf32>
return
}

View File

@ -1,7 +1,7 @@
// RUN: mlir-opt -convert-to-llvmir %s | FileCheck %s
// CHECK-LABEL: func @empty() {
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: llvm.return
// CHECK-NEXT: }
func @empty() {
^bb0:
@ -14,30 +14,30 @@ func @body(index)
// CHECK-LABEL: func @simple_loop() {
func @simple_loop() {
^bb0:
// CHECK-NEXT: "llvm.br"()[^bb1] : () -> ()
// CHECK-NEXT: llvm.br ^bb1
br ^bb1
// CHECK-NEXT: ^bb1: // pred: ^bb0
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb2({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb2({{.*}} : !llvm<"i64">)
^bb1: // pred: ^bb0
%c1 = constant 1 : index
%c42 = constant 42 : index
br ^bb2(%c1 : index)
// CHECK: ^bb2({{.*}}: !llvm<"i64">): // 2 preds: ^bb1, ^bb3
// CHECK-NEXT: {{.*}} = "llvm.icmp"({{.*}}, {{.*}}) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
// CHECK-NEXT: "llvm.cond_br"({{.*}})[^bb3, ^bb4] : (!llvm<"i1">) -> ()
// CHECK-NEXT: {{.*}} = llvm.icmp "slt" {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.cond_br {{.*}}, ^bb3, ^bb4
^bb2(%0: index): // 2 preds: ^bb1, ^bb3
%1 = cmpi "slt", %0, %c42 : index
cond_br %1, ^bb3, ^bb4
// CHECK: ^bb3: // pred: ^bb2
// CHECK-NEXT: "llvm.call"({{.*}}) {callee: @body : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.add"({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb2({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: llvm.call @body({{.*}}) : (!llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb2({{.*}} : !llvm<"i64">)
^bb3: // pred: ^bb2
call @body(%0) : (index) -> ()
%c1_0 = constant 1 : index
@ -45,14 +45,14 @@ func @simple_loop() {
br ^bb2(%2 : index)
// CHECK: ^bb4: // pred: ^bb2
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: llvm.return
^bb4: // pred: ^bb2
return
}
// CHECK-LABEL: func @simple_caller() {
// CHECK-NEXT: "llvm.call"() {callee: @simple_loop : () -> ()} : () -> ()
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: llvm.call @simple_loop() : () -> ()
// CHECK-NEXT: llvm.return
// CHECK-NEXT: }
func @simple_caller() {
^bb0:
@ -61,9 +61,9 @@ func @simple_caller() {
}
// CHECK-LABEL: func @ml_caller() {
// CHECK-NEXT: "llvm.call"() {callee: @simple_loop : () -> ()} : () -> ()
// CHECK-NEXT: "llvm.call"() {callee: @more_imperfectly_nested_loops : () -> ()} : () -> ()
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: llvm.call @simple_loop() : () -> ()
// CHECK-NEXT: llvm.call @more_imperfectly_nested_loops() : () -> ()
// CHECK-NEXT: llvm.return
// CHECK-NEXT: }
func @ml_caller() {
^bb0:
@ -78,37 +78,37 @@ func @body_args(index) -> index
func @other(index, i32) -> i32
// CHECK-LABEL: func @func_args(%arg0: !llvm<"i32">, %arg1: !llvm<"i32">) -> !llvm<"i32"> {
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 0 : i32} : () -> !llvm<"i32">
// CHECK-NEXT: "llvm.br"()[^bb1] : () -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(0 : i32) : !llvm<"i32">
// CHECK-NEXT: llvm.br ^bb1
func @func_args(i32, i32) -> i32 {
^bb0(%arg0: i32, %arg1: i32):
%c0_i32 = constant 0 : i32
br ^bb1
// CHECK-NEXT: ^bb1: // pred: ^bb0
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb2({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(0 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb2({{.*}} : !llvm<"i64">)
^bb1: // pred: ^bb0
%c0 = constant 0 : index
%c42 = constant 42 : index
br ^bb2(%c0 : index)
// CHECK-NEXT: ^bb2({{.*}}: !llvm<"i64">): // 2 preds: ^bb1, ^bb3
// CHECK-NEXT: {{.*}} = "llvm.icmp"({{.*}}, {{.*}}) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
// CHECK-NEXT: "llvm.cond_br"({{.*}})[^bb3, ^bb4] : (!llvm<"i1">) -> ()
// CHECK-NEXT: {{.*}} = llvm.icmp "slt" {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.cond_br {{.*}}, ^bb3, ^bb4
^bb2(%0: index): // 2 preds: ^bb1, ^bb3
%1 = cmpi "slt", %0, %c42 : index
cond_br %1, ^bb3, ^bb4
// CHECK-NEXT: ^bb3: // pred: ^bb2
// CHECK-NEXT: {{.*}} = "llvm.call"({{.*}}) {callee: @body_args : (!llvm<"i64">) -> !llvm<"i64">} : (!llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.call"({{.*}}, %arg0) {callee: @other : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">} : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: {{.*}} = "llvm.call"({{.*}}, {{.*}}) {callee: @other : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">} : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: {{.*}} = "llvm.call"({{.*}}, %arg1) {callee: @other : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">} : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.add"({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb2({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: {{.*}} = llvm.call @body_args({{.*}}) : (!llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.call @other({{.*}}, %arg0) : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: {{.*}} = llvm.call @other({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: {{.*}} = llvm.call @other({{.*}}, %arg1) : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: {{.*}} = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb2({{.*}} : !llvm<"i64">)
^bb3: // pred: ^bb2
%2 = call @body_args(%0) : (index) -> index
%3 = call @other(%2, %arg0) : (index, i32) -> i32
@ -119,9 +119,9 @@ func @func_args(i32, i32) -> i32 {
br ^bb2(%6 : index)
// CHECK-NEXT: ^bb4: // pred: ^bb2
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.call"({{.*}}, {{.*}}) {callee: @other : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">} : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: "llvm.return"({{.*}}) : (!llvm<"i32">) -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(0 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.call @other({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: llvm.return {{.*}} : !llvm<"i32">
^bb4: // pred: ^bb2
%c0_0 = constant 0 : index
%7 = call @other(%c0_0, %c0_i32) : (index, i32) -> i32
@ -138,55 +138,55 @@ func @body2(index, index)
func @post(index)
// CHECK-LABEL: func @imperfectly_nested_loops() {
// CHECK-NEXT: "llvm.br"()[^bb1] : () -> ()
// CHECK-NEXT: llvm.br ^bb1
func @imperfectly_nested_loops() {
^bb0:
br ^bb1
// CHECK-NEXT: ^bb1: // pred: ^bb0
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb2({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(0 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb2({{.*}} : !llvm<"i64">)
^bb1: // pred: ^bb0
%c0 = constant 0 : index
%c42 = constant 42 : index
br ^bb2(%c0 : index)
// CHECK-NEXT: ^bb2({{.*}}: !llvm<"i64">): // 2 preds: ^bb1, ^bb7
// CHECK-NEXT: {{.*}} = "llvm.icmp"({{.*}}, {{.*}}) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
// CHECK-NEXT: "llvm.cond_br"({{.*}})[^bb3, ^bb8] : (!llvm<"i1">) -> ()
// CHECK-NEXT: {{.*}} = llvm.icmp "slt" {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.cond_br {{.*}}, ^bb3, ^bb8
^bb2(%0: index): // 2 preds: ^bb1, ^bb7
%1 = cmpi "slt", %0, %c42 : index
cond_br %1, ^bb3, ^bb8
// CHECK-NEXT: ^bb3:
// CHECK-NEXT: "llvm.call"({{.*}}) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// CHECK-NEXT: "llvm.br"()[^bb4] : () -> ()
// CHECK-NEXT: llvm.call @pre({{.*}}) : (!llvm<"i64">) -> ()
// CHECK-NEXT: llvm.br ^bb4
^bb3: // pred: ^bb2
call @pre(%0) : (index) -> ()
br ^bb4
// CHECK-NEXT: ^bb4: // pred: ^bb3
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 7 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 56 : index} : () -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb5({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(7 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.constant(56 : index) : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb5({{.*}} : !llvm<"i64">)
^bb4: // pred: ^bb3
%c7 = constant 7 : index
%c56 = constant 56 : index
br ^bb5(%c7 : index)
// CHECK-NEXT: ^bb5({{.*}}: !llvm<"i64">): // 2 preds: ^bb4, ^bb6
// CHECK-NEXT: {{.*}} = "llvm.icmp"({{.*}}, {{.*}}) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
// CHECK-NEXT: "llvm.cond_br"({{.*}})[^bb6, ^bb7] : (!llvm<"i1">) -> ()
// CHECK-NEXT: {{.*}} = llvm.icmp "slt" {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.cond_br {{.*}}, ^bb6, ^bb7
^bb5(%2: index): // 2 preds: ^bb4, ^bb6
%3 = cmpi "slt", %2, %c56 : index
cond_br %3, ^bb6, ^bb7
// CHECK-NEXT: ^bb6: // pred: ^bb5
// CHECK-NEXT: "llvm.call"({{.*}}, {{.*}}) {callee: @body2 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 2 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.add"({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb5({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: llvm.call @body2({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(2 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb5({{.*}} : !llvm<"i64">)
^bb6: // pred: ^bb5
call @body2(%0, %2) : (index, index) -> ()
%c2 = constant 2 : index
@ -194,10 +194,10 @@ func @imperfectly_nested_loops() {
br ^bb5(%4 : index)
// CHECK-NEXT: ^bb7: // pred: ^bb5
// CHECK-NEXT: "llvm.call"({{.*}}) {callee: @post : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.add"({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb2({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: llvm.call @post({{.*}}) : (!llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb2({{.*}} : !llvm<"i64">)
^bb7: // pred: ^bb5
call @post(%0) : (index) -> ()
%c1 = constant 1 : index
@ -205,7 +205,7 @@ func @imperfectly_nested_loops() {
br ^bb2(%5 : index)
// CHECK-NEXT: ^bb8: // pred: ^bb2
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: llvm.return
^bb8: // pred: ^bb2
return
}
@ -218,51 +218,51 @@ func @body3(index, index)
// A complete function transformation check.
// CHECK-LABEL: func @more_imperfectly_nested_loops() {
// CHECK-NEXT: "llvm.br"()[^bb1] : () -> ()
// CHECK-NEXT: ^bb1: // pred: ^bb0
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb2({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: ^bb2({{.*}}: !llvm<"i64">): // 2 preds: ^bb1, ^bb11
// CHECK-NEXT: {{.*}} = "llvm.icmp"({{.*}}, {{.*}}) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
// CHECK-NEXT: "llvm.cond_br"({{.*}})[^bb3, ^bb12] : (!llvm<"i1">) -> ()
// CHECK-NEXT: ^bb3: // pred: ^bb2
// CHECK-NEXT: "llvm.call"({{.*}}) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// CHECK-NEXT: "llvm.br"()[^bb4] : () -> ()
// CHECK-NEXT: ^bb4: // pred: ^bb3
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 7 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 56 : index} : () -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb5({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: ^bb5({{.*}}: !llvm<"i64">): // 2 preds: ^bb4, ^bb6
// CHECK-NEXT: {{.*}} = "llvm.icmp"({{.*}}, {{.*}}) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
// CHECK-NEXT: "llvm.cond_br"({{.*}})[^bb6, ^bb7] : (!llvm<"i1">) -> ()
// CHECK-NEXT: ^bb6: // pred: ^bb5
// CHECK-NEXT: "llvm.call"({{.*}}, {{.*}}) {callee: @body2 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 2 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.add"({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb5({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: ^bb7: // pred: ^bb5
// CHECK-NEXT: "llvm.call"({{.*}}) {callee: @mid : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// CHECK-NEXT: "llvm.br"()[^bb8] : () -> ()
// CHECK-NEXT: ^bb8: // pred: ^bb7
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 18 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 37 : index} : () -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb9({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: ^bb9({{.*}}: !llvm<"i64">): // 2 preds: ^bb8, ^bb10
// CHECK-NEXT: {{.*}} = "llvm.icmp"({{.*}}, {{.*}}) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
// CHECK-NEXT: "llvm.cond_br"({{.*}})[^bb10, ^bb11] : (!llvm<"i1">) -> ()
// CHECK-NEXT: ^bb10: // pred: ^bb9
// CHECK-NEXT: "llvm.call"({{.*}}, {{.*}}) {callee: @body3 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 3 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.add"({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb9({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: ^bb11: // pred: ^bb9
// CHECK-NEXT: "llvm.call"({{.*}}) {callee: @post : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.add"({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK-NEXT: "llvm.br"()[^bb2({{.*}} : !llvm<"i64">)] : () -> ()
// CHECK-NEXT: ^bb12: // pred: ^bb2
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: llvm.br ^bb1
// CHECK-NEXT:^bb1: // pred: ^bb0
// CHECK-NEXT: {{.*}} = llvm.constant(0 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb2({{.*}} : !llvm<"i64">)
// CHECK-NEXT:^bb2({{.*}}: !llvm<"i64">): // 2 preds: ^bb1, ^bb11
// CHECK-NEXT: {{.*}} = llvm.icmp "slt" {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.cond_br {{.*}}, ^bb3, ^bb12
// CHECK-NEXT:^bb3: // pred: ^bb2
// CHECK-NEXT: llvm.call @pre({{.*}}) : (!llvm<"i64">) -> ()
// CHECK-NEXT: llvm.br ^bb4
// CHECK-NEXT:^bb4: // pred: ^bb3
// CHECK-NEXT: {{.*}} = llvm.constant(7 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.constant(56 : index) : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb5({{.*}} : !llvm<"i64">)
// CHECK-NEXT:^bb5({{.*}}: !llvm<"i64">): // 2 preds: ^bb4, ^bb6
// CHECK-NEXT: {{.*}} = llvm.icmp "slt" {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.cond_br {{.*}}, ^bb6, ^bb7
// CHECK-NEXT:^bb6: // pred: ^bb5
// CHECK-NEXT: llvm.call @body2({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(2 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb5({{.*}} : !llvm<"i64">)
// CHECK-NEXT:^bb7: // pred: ^bb5
// CHECK-NEXT: llvm.call @mid({{.*}}) : (!llvm<"i64">) -> ()
// CHECK-NEXT: llvm.br ^bb8
// CHECK-NEXT:^bb8: // pred: ^bb7
// CHECK-NEXT: {{.*}} = llvm.constant(18 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.constant(37 : index) : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb9({{.*}} : !llvm<"i64">)
// CHECK-NEXT:^bb9({{.*}}: !llvm<"i64">): // 2 preds: ^bb8, ^bb10
// CHECK-NEXT: {{.*}} = llvm.icmp "slt" {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.cond_br {{.*}}, ^bb10, ^bb11
// CHECK-NEXT:^bb10: // pred: ^bb9
// CHECK-NEXT: llvm.call @body3({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(3 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb9({{.*}} : !llvm<"i64">)
// CHECK-NEXT:^bb11: // pred: ^bb9
// CHECK-NEXT: llvm.call @post({{.*}}) : (!llvm<"i64">) -> ()
// CHECK-NEXT: {{.*}} = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm<"i64">
// CHECK-NEXT: llvm.br ^bb2({{.*}} : !llvm<"i64">)
// CHECK-NEXT:^bb12: // pred: ^bb2
// CHECK-NEXT: llvm.return
// CHECK-NEXT: }
func @more_imperfectly_nested_loops() {
^bb0:
@ -323,17 +323,17 @@ func @get_memref() -> (memref<42x?x10x?xf32>)
// CHECK-LABEL: func @multireturn() -> !llvm<"{ i64, float, { float*, i64, i64 } }"> {
func @multireturn() -> (i64, f32, memref<42x?x10x?xf32>) {
^bb0:
// CHECK-NEXT: {{.*}} = "llvm.call"() {callee: @get_i64 : () -> !llvm<"i64">} : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.call"() {callee: @get_f32 : () -> !llvm<"float">} : () -> !llvm<"float">
// CHECK-NEXT: {{.*}} = "llvm.call"() {callee: @get_memref : () -> !llvm<"{ float*, i64, i64 }">} : () -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: {{.*}} = llvm.call @get_i64() : () -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = llvm.call @get_f32() : () -> !llvm<"float">
// CHECK-NEXT: {{.*}} = llvm.call @get_memref() : () -> !llvm<"{ float*, i64, i64 }">
%0 = call @get_i64() : () -> (i64)
%1 = call @get_f32() : () -> (f32)
%2 = call @get_memref() : () -> (memref<42x?x10x?xf32>)
// CHECK-NEXT: {{.*}} = "llvm.undef"() : () -> !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = "llvm.insertvalue"({{.*}}, {{.*}}) {position: [0]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">, !llvm<"i64">) -> !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = "llvm.insertvalue"({{.*}}, {{.*}}) {position: [1]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">, !llvm<"float">) -> !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = "llvm.insertvalue"({{.*}}, {{.*}}) {position: [2]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">, !llvm<"{ float*, i64, i64 }">) -> !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: "llvm.return"({{.*}}) : (!llvm<"{ i64, float, { float*, i64, i64 } }">) -> ()
// CHECK-NEXT: {{.*}} = llvm.undef : !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = llvm.insertvalue {{.*}}, {{.*}}[0] : !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = llvm.insertvalue {{.*}}, {{.*}}[1] : !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = llvm.insertvalue {{.*}}, {{.*}}[2] : !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: llvm.return {{.*}} : !llvm<"{ i64, float, { float*, i64, i64 } }">
return %0, %1, %2 : i64, f32, memref<42x?x10x?xf32>
}
@ -341,16 +341,16 @@ func @multireturn() -> (i64, f32, memref<42x?x10x?xf32>) {
// CHECK-LABEL: func @multireturn_caller() {
func @multireturn_caller() {
^bb0:
// CHECK-NEXT: {{.*}} = "llvm.call"() {callee: @multireturn : () -> !llvm<"{ i64, float, { float*, i64, i64 } }">} : () -> !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = "llvm.extractvalue"({{.*}}) {position: [0]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">) -> !llvm<"i64">
// CHECK-NEXT: {{.*}} = "llvm.extractvalue"({{.*}}) {position: [1]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">) -> !llvm<"float">
// CHECK-NEXT: {{.*}} = "llvm.extractvalue"({{.*}}) {position: [2]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">) -> !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: {{.*}} = llvm.call @multireturn() : () -> !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[0] : !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[1] : !llvm<"{ i64, float, { float*, i64, i64 } }">
// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[2] : !llvm<"{ i64, float, { float*, i64, i64 } }">
%0:3 = call @multireturn() : () -> (i64, f32, memref<42x?x10x?xf32>)
%1 = constant 42 : i64
// CHECK: {{.*}} = "llvm.add"({{.*}}, {{.*}}) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
// CHECK: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm<"i64">
%2 = addi %0#0, %1 : i64
%3 = constant 42.0 : f32
// CHECK: {{.*}} = "llvm.fadd"({{.*}}, {{.*}}) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
// CHECK: {{.*}} = llvm.fadd {{.*}}, {{.*}} : !llvm<"float">
%4 = addf %0#1, %3 : f32
%5 = constant 0 : index
return
@ -359,21 +359,21 @@ func @multireturn_caller() {
// CHECK-LABEL: func @vector_ops(%arg0: !llvm<"<4 x float>">, %arg1: !llvm<"<4 x i1>">, %arg2: !llvm<"<4 x i64>">) -> !llvm<"<4 x float>"> {
func @vector_ops(vector<4xf32>, vector<4xi1>, vector<4xi64>) -> vector<4xf32> {
^bb0(%arg0: vector<4xf32>, %arg1: vector<4xi1>, %arg2: vector<4xi64>):
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: splat<vector<4xf32>, 4.200000e+01>} : () -> !llvm<"<4 x float>">
// CHECK-NEXT: %0 = llvm.constant(splat<vector<4xf32>, 4.200000e+01>) : !llvm<"<4 x float>">
%0 = constant splat<vector<4xf32>, 42.> : vector<4xf32>
// CHECK-NEXT: {{.*}} = "llvm.fadd"(%arg0, {{.*}}) : (!llvm<"<4 x float>">, !llvm<"<4 x float>">) -> !llvm<"<4 x float>">
// CHECK-NEXT: %1 = llvm.fadd %arg0, %0 : !llvm<"<4 x float>">
%1 = addf %arg0, %0 : vector<4xf32>
// CHECK-NEXT: {{.*}} = "llvm.sdiv"(%arg2, %arg2) : (!llvm<"<4 x i64>">, !llvm<"<4 x i64>">) -> !llvm<"<4 x i64>">
// CHECK-NEXT: %2 = llvm.sdiv %arg2, %arg2 : !llvm<"<4 x i64>">
%3 = divis %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: {{.*}} = "llvm.udiv"(%arg2, %arg2) : (!llvm<"<4 x i64>">, !llvm<"<4 x i64>">) -> !llvm<"<4 x i64>">
// CHECK-NEXT: %3 = llvm.udiv %arg2, %arg2 : !llvm<"<4 x i64>">
%4 = diviu %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: {{.*}} = "llvm.srem"(%arg2, %arg2) : (!llvm<"<4 x i64>">, !llvm<"<4 x i64>">) -> !llvm<"<4 x i64>">
// CHECK-NEXT: %4 = llvm.srem %arg2, %arg2 : !llvm<"<4 x i64>">
%5 = remis %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: {{.*}} = "llvm.urem"(%arg2, %arg2) : (!llvm<"<4 x i64>">, !llvm<"<4 x i64>">) -> !llvm<"<4 x i64>">
// CHECK-NEXT: %5 = llvm.urem %arg2, %arg2 : !llvm<"<4 x i64>">
%6 = remiu %arg2, %arg2 : vector<4xi64>
// CHECK-NEXT: {{.*}} = "llvm.fdiv"(%arg0, {{.*}}) : (!llvm<"<4 x float>">, !llvm<"<4 x float>">) -> !llvm<"<4 x float>">
// CHECK-NEXT: %6 = llvm.fdiv %arg0, %0 : !llvm<"<4 x float>">
%7 = divf %arg0, %0 : vector<4xf32>
// CHECK-NEXT: {{.*}} = "llvm.frem"(%arg0, {{.*}}) : (!llvm<"<4 x float>">, !llvm<"<4 x float>">) -> !llvm<"<4 x float>">
// CHECK-NEXT: %7 = llvm.frem %arg0, %0 : !llvm<"<4 x float>">
%8 = remf %arg0, %0 : vector<4xf32>
return %1 : vector<4xf32>
}
@ -381,25 +381,25 @@ func @vector_ops(vector<4xf32>, vector<4xi1>, vector<4xi64>) -> vector<4xf32> {
// CHECK-LABEL: @ops
func @ops(f32, f32, i32, i32) -> (f32, i32) {
^bb0(%arg0: f32, %arg1: f32, %arg2: i32, %arg3: i32):
// CHECK-NEXT: {{.*}} = "llvm.fsub"(%arg0, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
// CHECK-NEXT: %0 = llvm.fsub %arg0, %arg1 : !llvm<"float">
%0 = subf %arg0, %arg1: f32
// CHECK-NEXT: {{.*}} = "llvm.sub"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %1 = llvm.sub %arg2, %arg3 : !llvm<"i32">
%1 = subi %arg2, %arg3: i32
// CHECK-NEXT: {{.*}} = "llvm.icmp"(%arg2, {{.*}}) {predicate: 2} : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i1">
// CHECK-NEXT: %2 = llvm.icmp "slt" %arg2, %1 : !llvm<"i32">
%2 = cmpi "slt", %arg2, %1 : i32
// CHECK-NEXT: {{.*}} = "llvm.sdiv"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %3 = llvm.sdiv %arg2, %arg3 : !llvm<"i32">
%4 = divis %arg2, %arg3 : i32
// CHECK-NEXT: {{.*}} = "llvm.udiv"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %4 = llvm.udiv %arg2, %arg3 : !llvm<"i32">
%5 = diviu %arg2, %arg3 : i32
// CHECK-NEXT: {{.*}} = "llvm.srem"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %5 = llvm.srem %arg2, %arg3 : !llvm<"i32">
%6 = remis %arg2, %arg3 : i32
// CHECK-NEXT: {{.*}} = "llvm.urem"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %6 = llvm.urem %arg2, %arg3 : !llvm<"i32">
%7 = remiu %arg2, %arg3 : i32
// CHECK-NEXT: {{.*}} = "llvm.select"({{.*}}, %arg2, %arg3) : (!llvm<"i1">, !llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %7 = llvm.select %2, %arg2, %arg3 : !llvm<"i1">, !llvm<"i32">
%8 = select %2, %arg2, %arg3 : i32
// CHECK-NEXT: {{.*}} = "llvm.fdiv"(%arg0, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
// CHECK-NEXT: %8 = llvm.fdiv %arg0, %arg1 : !llvm<"float">
%9 = divf %arg0, %arg1 : f32
// CHECK-NEXT: {{.*}} = "llvm.frem"(%arg0, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
// CHECK-NEXT: %9 = llvm.frem %arg0, %arg1 : !llvm<"float">
%10 = remf %arg0, %arg1 : f32
return %0, %4 : f32, i32
@ -407,35 +407,35 @@ func @ops(f32, f32, i32, i32) -> (f32, i32) {
// CHECK-LABEL: @dfs_block_order
func @dfs_block_order() -> (i32) {
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 42 : i32} : () -> !llvm<"i32">
// CHECK-NEXT: %0 = llvm.constant(42 : i32) : !llvm<"i32">
%0 = constant 42 : i32
// CHECK-NEXT: "llvm.br"()[^bb2] : () -> ()
// CHECK-NEXT: llvm.br ^bb2
br ^bb2
// CHECK-NEXT: ^bb1:
// CHECK-NEXT: {{.*}} = "llvm.add"({{.*}}, {{.*}}) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: "llvm.return"({{.*}}) : (!llvm<"i32">) -> ()
// CHECK-NEXT: %1 = llvm.add %0, %2 : !llvm<"i32">
// CHECK-NEXT: llvm.return %1 : !llvm<"i32">
^bb1:
%2 = addi %0, %1 : i32
return %2 : i32
// CHECK-NEXT: ^bb2:
^bb2:
// CHECK-NEXT: {{.*}} = "llvm.constant"() {value: 55 : i32} : () -> !llvm<"i32">
// CHECK-NEXT: %2 = llvm.constant(55 : i32) : !llvm<"i32">
%1 = constant 55 : i32
// CHECK-NEXT: "llvm.br"()[^bb1] : () -> ()
// CHECK-NEXT: llvm.br ^bb1
br ^bb1
}
// CHECK-LABEL: func @cond_br_same_target(%arg0: !llvm<"i1">, %arg1: !llvm<"i32">, %arg2: !llvm<"i32">)
func @cond_br_same_target(%arg0: i1, %arg1: i32, %arg2 : i32) -> (i32) {
// CHECK-NEXT: "llvm.cond_br"(%arg0)[^[[origBlock:bb[0-9]+]](%arg1 : !llvm<"i32">), ^[[dummyBlock:bb[0-9]+]]] : (!llvm<"i1">) -> ()
// CHECK-NEXT: llvm.cond_br %arg0, ^[[origBlock:bb[0-9]+]](%arg1 : !llvm<"i32">), ^[[dummyBlock:bb[0-9]+]]
cond_br %arg0, ^bb1(%arg1 : i32), ^bb1(%arg2 : i32)
// CHECK: ^[[origBlock]](%0: !llvm<"i32">):
// CHECK-NEXT: "llvm.return"(%0) : (!llvm<"i32">) -> ()
// CHECK-NEXT: llvm.return %0 : !llvm<"i32">
^bb1(%0 : i32):
return %0 : i32
// CHECK: ^[[dummyBlock]]:
// CHECK-NEXT: "llvm.br"()[^[[origBlock]](%arg2 : !llvm<"i32">)] : () -> ()
// CHECK-NEXT: llvm.br ^[[origBlock]](%arg2 : !llvm<"i32">)
}

View File

@ -1,6 +1,226 @@
// RUN: mlir-opt %s -verify
// RUN: mlir-opt %s -split-input-file -verify
// expected-error@+1{{llvm.noalias argument attribute of non boolean type}}
func @invalid_noalias(%arg0: !llvm<"i32"> {llvm.noalias: 3}) {
"llvm.return"() : () -> ()
}
////////////////////////////////////////////////////////////////////////////////
// Check that parser errors are properly produced and do not crash the compiler.
// -----
func @icmp_non_string(%arg0 : !llvm<"i32">, %arg1 : !llvm<"i16">) {
// expected-error@+1 {{expected 'predicate' attribute of string type}}
llvm.icmp 42 %arg0, %arg0 : !llvm<"i32">
return
}
// -----
func @icmp_wrong_string(%arg0 : !llvm<"i32">, %arg1 : !llvm<"i16">) {
// expected-error@+1 {{'foo' is an incorrect value of the 'predicate' attribute}}
llvm.icmp "foo" %arg0, %arg0 : !llvm<"i32">
return
}
// -----
func @alloca_missing_input_result_type(%size : !llvm<"i64">) {
// expected-error@+1 {{expected trailing function type with one argument and one result}}
llvm.alloca %size x !llvm<"i32"> : () -> ()
}
// -----
func @alloca_missing_input_type() {
// expected-error@+1 {{expected trailing function type with one argument and one result}}
llvm.alloca %size x !llvm<"i32"> : () -> (!llvm<"i32*">)
}
// -----
func @alloca_mising_result_type() {
// expected-error@+1 {{expected trailing function type with one argument and one result}}
llvm.alloca %size x !llvm<"i32"> : (!llvm<"i64">) -> ()
}
// -----
func @alloca_non_function_type() {
// expected-error@+1 {{expected trailing function type with one argument and one result}}
llvm.alloca %size x !llvm<"i32"> : !llvm<"i32*">
}
// -----
func @gep_missing_input_result_type(%pos : !llvm<"i64">, %base : !llvm<"float*">) {
// expected-error@+1 {{expected trailing function type with at least one argument and one result}}
llvm.getelementptr %base[%pos] : () -> ()
}
// -----
func @gep_missing_input_type(%pos : !llvm<"i64">, %base : !llvm<"float*">) {
// expected-error@+1 {{expected trailing function type with at least one argument and one result}}
llvm.getelementptr %base[%pos] : () -> (!llvm<"float*">)
}
// -----
func @gep_missing_result_type(%pos : !llvm<"i64">, %base : !llvm<"float*">) {
// expected-error@+1 {{expected trailing function type with at least one argument and one result}}
llvm.getelementptr %base[%pos] : (!llvm<"float *">, !llvm<"i64">) -> ()
}
// -----
func @gep_non_function_type(%pos : !llvm<"i64">, %base : !llvm<"float*">) {
// expected-error@+1 {{expected trailing function type with at least one argument and one result}}
llvm.getelementptr %base[%pos] : !llvm<"float*">
}
// -----
func @load_non_llvm_type(%foo : memref<f32>) {
// expected-error@+1 {{expected LLVM IR dialect type}}
llvm.load %foo : memref<f32>
}
// -----
func @load_non_ptr_type(%foo : !llvm<"float">) {
// expected-error@+1 {{expected LLVM pointer type}}
llvm.load %foo : !llvm<"float">
}
// -----
func @store_non_llvm_type(%foo : memref<f32>, %bar : !llvm<"float">) {
// expected-error@+1 {{expected LLVM IR dialect type}}
llvm.store %bar, %foo : memref<f32>
}
// -----
func @store_non_ptr_type(%foo : !llvm<"float">, %bar : !llvm<"float">) {
// expected-error@+1 {{expected LLVM pointer type}}
llvm.store %bar, %foo : !llvm<"float">
}
// -----
func @call_non_function_type(%callee : !llvm<"i8(i8)">, %arg : !llvm<"i8">) {
// expected-error@+1 {{expected function type}}
llvm.call %callee(%arg) : !llvm<"i8(i8)">
}
// -----
func @call_too_many_results(%callee : () -> (i32,i32)) {
// expected-error@+1 {{expected function with 0 or 1 result}}
llvm.call %callee() : () -> (i32, i32)
}
// -----
func @call_non_llvm_result(%callee : () -> (i32)) {
// expected-error@+1 {{expected result to have LLVM type}}
llvm.call %callee() : () -> (i32)
}
// -----
func @call_non_llvm_input(%callee : (i32) -> (), %arg : i32) {
// expected-error@+1 {{expected LLVM types as inputs}}
llvm.call %callee(%arg) : (i32) -> ()
}
// -----
func @insertvalue_non_llvm_type(%a : i32, %b : i32) {
// expected-error@+1 {{expected LLVM IR Dialect type}}
llvm.insertvalue %a, %b[0] : i32
}
// -----
func @insertvalue_non_array_position() {
// Note the double-type, otherwise attribute parsing consumes the trailing
// type of the op as the (wrong) attribute type.
// expected-error@+1 {{expected an array attribute}}
llvm.insertvalue %a, %b 0 : i32 : !llvm<"{i32}">
}
// -----
func @insertvlaue_non_integer_position() {
// expected-error@+1 {{expected an array of integer literals}}
llvm.insertvalue %a, %b[0.0] : !llvm<"{i32}">
}
// -----
func @insertvalue_struct_out_of_bounds() {
// expected-error@+1 {{position out of bounds}}
llvm.insertvalue %a, %b[1] : !llvm<"{i32}">
}
// -----
func @insertvalue_array_out_of_bounds() {
// expected-error@+1 {{position out of bounds}}
llvm.insertvalue %a, %b[1] : !llvm<"[1 x i32]">
}
// -----
func @insertvalue_wrong_nesting() {
// expected-error@+1 {{expected wrapped LLVM IR structure/array type}}
llvm.insertvalue %a, %b[0,0] : !llvm<"{i32}">
}
// -----
func @extractvalue_non_llvm_type(%a : i32, %b : i32) {
// expected-error@+1 {{expected LLVM IR Dialect type}}
llvm.extractvalue %b[0] : i32
}
// -----
func @extractvalue_non_array_position() {
// Note the double-type, otherwise attribute parsing consumes the trailing
// type of the op as the (wrong) attribute type.
// expected-error@+1 {{expected an array attribute}}
llvm.extractvalue %b 0 : i32 : !llvm<"{i32}">
}
// -----
func @extractvlaue_non_integer_position() {
// expected-error@+1 {{expected an array of integer literals}}
llvm.extractvalue %b[0.0] : !llvm<"{i32}">
}
// -----
func @extractvalue_struct_out_of_bounds() {
// expected-error@+1 {{position out of bounds}}
llvm.extractvalue %b[1] : !llvm<"{i32}">
}
// -----
func @extractvalue_array_out_of_bounds() {
// expected-error@+1 {{position out of bounds}}
llvm.extractvalue %b[1] : !llvm<"[1 x i32]">
}
// -----
func @extractvalue_wrong_nesting() {
// expected-error@+1 {{expected wrapped LLVM IR structure/array type}}
llvm.extractvalue %b[0,0] : !llvm<"{i32}">
}

View File

@ -4,135 +4,140 @@
func @ops(%arg0 : !llvm<"i32">, %arg1 : !llvm<"float">) {
// Integer artithmetics binary operations.
//
// CHECK-NEXT: %0 = "llvm.add"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %1 = "llvm.sub"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %2 = "llvm.mul"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %3 = "llvm.udiv"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %4 = "llvm.sdiv"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %5 = "llvm.urem"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %6 = "llvm.srem"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %7 = "llvm.icmp"(%arg0, %arg0) {predicate: 1} : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i1">
%0 = "llvm.add"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%1 = "llvm.sub"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%2 = "llvm.mul"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%3 = "llvm.udiv"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%4 = "llvm.sdiv"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%5 = "llvm.urem"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%6 = "llvm.srem"(%arg0, %arg0) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%7 = "llvm.icmp"(%arg0, %arg0) {predicate: 1} : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i1">
// CHECK-NEXT: %0 = llvm.add %arg0, %arg0 : !llvm<"i32">
// CHECK-NEXT: %1 = llvm.sub %arg0, %arg0 : !llvm<"i32">
// CHECK-NEXT: %2 = llvm.mul %arg0, %arg0 : !llvm<"i32">
// CHECK-NEXT: %3 = llvm.udiv %arg0, %arg0 : !llvm<"i32">
// CHECK-NEXT: %4 = llvm.sdiv %arg0, %arg0 : !llvm<"i32">
// CHECK-NEXT: %5 = llvm.urem %arg0, %arg0 : !llvm<"i32">
// CHECK-NEXT: %6 = llvm.srem %arg0, %arg0 : !llvm<"i32">
// CHECK-NEXT: %7 = llvm.icmp "ne" %arg0, %arg0 : !llvm<"i32">
%0 = llvm.add %arg0, %arg0 : !llvm<"i32">
%1 = llvm.sub %arg0, %arg0 : !llvm<"i32">
%2 = llvm.mul %arg0, %arg0 : !llvm<"i32">
%3 = llvm.udiv %arg0, %arg0 : !llvm<"i32">
%4 = llvm.sdiv %arg0, %arg0 : !llvm<"i32">
%5 = llvm.urem %arg0, %arg0 : !llvm<"i32">
%6 = llvm.srem %arg0, %arg0 : !llvm<"i32">
%7 = llvm.icmp "ne" %arg0, %arg0 : !llvm<"i32">
// Floating point binary operations.
//
// CHECK-NEXT: %8 = "llvm.fadd"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
// CHECK-NEXT: %9 = "llvm.fsub"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
// CHECK-NEXT: %10 = "llvm.fmul"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
// CHECK-NEXT: %11 = "llvm.fdiv"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
// CHECK-NEXT: %12 = "llvm.frem"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%8 = "llvm.fadd"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%9 = "llvm.fsub"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%10 = "llvm.fmul"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%11 = "llvm.fdiv"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%12 = "llvm.frem"(%arg1, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
// CHECK-NEXT: %8 = llvm.fadd %arg1, %arg1 : !llvm<"float">
// CHECK-NEXT: %9 = llvm.fsub %arg1, %arg1 : !llvm<"float">
// CHECK-NEXT: %10 = llvm.fmul %arg1, %arg1 : !llvm<"float">
// CHECK-NEXT: %11 = llvm.fdiv %arg1, %arg1 : !llvm<"float">
// CHECK-NEXT: %12 = llvm.frem %arg1, %arg1 : !llvm<"float">
%8 = llvm.fadd %arg1, %arg1 : !llvm<"float">
%9 = llvm.fsub %arg1, %arg1 : !llvm<"float">
%10 = llvm.fmul %arg1, %arg1 : !llvm<"float">
%11 = llvm.fdiv %arg1, %arg1 : !llvm<"float">
%12 = llvm.frem %arg1, %arg1 : !llvm<"float">
// Memory-related operations.
//
// CHECK-NEXT: %13 = "llvm.alloca"(%arg0) : (!llvm<"i32">) -> !llvm<"double*">
// CHECK-NEXT: %14 = "llvm.getelementptr"(%13, %arg0, %arg0) : (!llvm<"double*">, !llvm<"i32">, !llvm<"i32">) -> !llvm<"double*">
// CHECK-NEXT: %15 = "llvm.load"(%14) : (!llvm<"double*">) -> !llvm<"double">
// CHECK-NEXT: "llvm.store"(%15, %13) : (!llvm<"double">, !llvm<"double*">) -> ()
// CHECK-NEXT: %16 = "llvm.bitcast"(%13) : (!llvm<"double*">) -> !llvm<"i64*">
%13 = "llvm.alloca"(%arg0) : (!llvm<"i32">) -> !llvm<"double*">
%14 = "llvm.getelementptr"(%13, %arg0, %arg0) : (!llvm<"double*">, !llvm<"i32">, !llvm<"i32">) -> !llvm<"double*">
%15 = "llvm.load"(%14) : (!llvm<"double*">) -> !llvm<"double">
"llvm.store"(%15, %13) : (!llvm<"double">, !llvm<"double*">) -> ()
%16 = "llvm.bitcast"(%13) : (!llvm<"double*">) -> !llvm<"i64*">
// CHECK-NEXT: %13 = llvm.alloca %arg0 x !llvm<"double"> : (!llvm<"i32">) -> !llvm<"double*">
// CHECK-NEXT: %14 = llvm.getelementptr %13[%arg0, %arg0] : (!llvm<"double*">, !llvm<"i32">, !llvm<"i32">) -> !llvm<"double*">
// CHECK-NEXT: %15 = llvm.load %14 : !llvm<"double*">
// CHECK-NEXT: llvm.store %15, %13 : !llvm<"double*">
// CHECK-NEXT: %16 = llvm.bitcast %13 : !llvm<"double*"> to !llvm<"i64*">
%13 = llvm.alloca %arg0 x !llvm<"double"> : (!llvm<"i32">) -> !llvm<"double*">
%14 = llvm.getelementptr %13[%arg0, %arg0] : (!llvm<"double*">, !llvm<"i32">, !llvm<"i32">) -> !llvm<"double*">
%15 = llvm.load %14 : !llvm<"double*">
llvm.store %15, %13 : !llvm<"double*">
%16 = llvm.bitcast %13 : !llvm<"double*"> to !llvm<"i64*">
// Function call-related operations.
//
// CHECK-NEXT: %17 = "llvm.call"(%arg0) {callee: @foo : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">} : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %18 = "llvm.extractvalue"(%17) {position: [0]} : (!llvm<"{ i32, double, i32 }">) -> !llvm<"i32">
// CHECK-NEXT: %19 = "llvm.insertvalue"(%17, %18) {position: [2]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
%17 = "llvm.call"(%arg0) {callee: @foo : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">}
: (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
%18 = "llvm.extractvalue"(%17) {position: [0]} : (!llvm<"{ i32, double, i32 }">) -> !llvm<"i32">
%19 = "llvm.insertvalue"(%17, %18) {position: [2]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %17 = llvm.call @foo(%arg0) : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %18 = llvm.extractvalue %17[0] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %19 = llvm.insertvalue %18, %17[2] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %20 = llvm.constant(@foo : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">) : !llvm<"{ i32, double, i32 } (i32)*">
// CHECK-NEXT: %21 = llvm.call %20(%arg0) : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
%17 = llvm.call @foo(%arg0) : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
%18 = llvm.extractvalue %17[0] : !llvm<"{ i32, double, i32 }">
%19 = llvm.insertvalue %18, %17[2] : !llvm<"{ i32, double, i32 }">
%20 = llvm.constant(@foo : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">) : !llvm<"{ i32, double, i32 } (i32)*">
%21 = llvm.call %20(%arg0) : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// Terminator operations and their successors.
//
// CHECK: "llvm.br"()[^bb1] : () -> ()
"llvm.br"()[^bb1] : () -> ()
// CHECK: llvm.br ^bb1
llvm.br ^bb1
^bb1:
// CHECK: "llvm.cond_br"(%7)[^bb2, ^bb1] : (!llvm<"i1">) -> ()
"llvm.cond_br"(%7)[^bb2,^bb1] : (!llvm<"i1">) -> ()
// CHECK: llvm.cond_br %7, ^bb2, ^bb1
llvm.cond_br %7, ^bb2, ^bb1
^bb2:
// CHECK: %20 = "llvm.pseudo.undef"() : () -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %21 = "llvm.pseudo.constant"() {value: 42} : () -> !llvm<"i47">
%20 = "llvm.pseudo.undef"() : () -> !llvm<"{ i32, double, i32 }">
%21 = "llvm.pseudo.constant"() {value: 42} : () -> !llvm<"i47">
// CHECK: %22 = llvm.undef : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %23 = llvm.constant(42) : !llvm<"i47">
%22 = llvm.undef : !llvm<"{ i32, double, i32 }">
%23 = llvm.constant(42) : !llvm<"i47">
// Misc operations.
// CHECK: %22 = "llvm.select"(%7, %0, %1) : (!llvm<"i1">, !llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: "llvm.return"() : () -> ()
%22 = "llvm.select"(%7, %0, %1) : (!llvm<"i1">, !llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
"llvm.return"() : () -> ()
// CHECK: %24 = llvm.select %7, %0, %1 : !llvm<"i1">, !llvm<"i32">
// CHECK-NEXT: llvm.return
%24 = llvm.select %7, %0, %1 : !llvm<"i1">, !llvm<"i32">
llvm.return
}
// An larger self-contained function.
// CHECK-LABEL:func @foo(%arg0: !llvm<"i32">) -> !llvm<"{ i32, double, i32 }"> {
func @foo(%arg0: !llvm<"i32">) -> !llvm<"{ i32, double, i32 }"> {
// CHECK-NEXT: %0 = "llvm.pseudo.constant"() {value: 3} : () -> !llvm<"i32">
// CHECK-NEXT: %1 = "llvm.pseudo.constant"() {value: 3} : () -> !llvm<"i32">
// CHECK-NEXT: %2 = "llvm.pseudo.constant"() {value: 4.200000e+01} : () -> !llvm<"double">
// CHECK-NEXT: %3 = "llvm.pseudo.constant"() {value: 4.200000e+01} : () -> !llvm<"double">
// CHECK-NEXT: %4 = "llvm.add"(%0, %1) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %5 = "llvm.mul"(%4, %1) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-NEXT: %6 = "llvm.fadd"(%2, %3) : (!llvm<"double">, !llvm<"double">) -> !llvm<"double">
// CHECK-NEXT: %7 = "llvm.fsub"(%3, %6) : (!llvm<"double">, !llvm<"double">) -> !llvm<"double">
// CHECK-NEXT: %8 = "llvm.pseudo.constant"() {value: 1} : () -> !llvm<"i1">
// CHECK-NEXT: "llvm.cond_br"(%8)[^bb1(%4 : !llvm<"i32">), ^bb2(%4 : !llvm<"i32">)] : (!llvm<"i1">) -> ()
%0 = "llvm.pseudo.constant"() {value: 3} : () -> !llvm<"i32">
%1 = "llvm.pseudo.constant"() {value: 3} : () -> !llvm<"i32">
%2 = "llvm.pseudo.constant"() {value: 4.200000e+01} : () -> !llvm<"double">
%3 = "llvm.pseudo.constant"() {value: 4.200000e+01} : () -> !llvm<"double">
%4 = "llvm.add"(%0, %1) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%5 = "llvm.mul"(%4, %1) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%6 = "llvm.fadd"(%2, %3) : (!llvm<"double">, !llvm<"double">) -> !llvm<"double">
%7 = "llvm.fsub"(%3, %6) : (!llvm<"double">, !llvm<"double">) -> !llvm<"double">
%8 = "llvm.pseudo.constant"() {value: 1} : () -> !llvm<"i1">
"llvm.cond_br"(%8)[^bb1(%4 : !llvm<"i32">), ^bb2(%4 : !llvm<"i32">)] : (!llvm<"i1">) -> ()
// CHECK-NEXT:^bb1(%9: !llvm<"i32">): // pred: ^bb0
// CHECK-NEXT: %10 = "llvm.call"(%9) {callee: @foo : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">} : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %11 = "llvm.extractvalue"(%10) {position: [0]} : (!llvm<"{ i32, double, i32 }">) -> !llvm<"i32">
// CHECK-NEXT: %12 = "llvm.extractvalue"(%10) {position: [1]} : (!llvm<"{ i32, double, i32 }">) -> !llvm<"double">
// CHECK-NEXT: %13 = "llvm.extractvalue"(%10) {position: [2]} : (!llvm<"{ i32, double, i32 }">) -> !llvm<"i32">
// CHECK-NEXT: %14 = "llvm.pseudo.undef"() : () -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %15 = "llvm.insertvalue"(%14, %5) {position: [0]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %16 = "llvm.insertvalue"(%15, %7) {position: [1]} : (!llvm<"{ i32, double, i32 }">, !llvm<"double">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %17 = "llvm.insertvalue"(%16, %11) {position: [2]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: "llvm.return"(%17) : (!llvm<"{ i32, double, i32 }">) -> ()
^bb1(%9: !llvm<"i32">): // pred: ^bb0
%10 = "llvm.call"(%9) {callee: @foo : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">} : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
%11 = "llvm.extractvalue"(%10) {position: [0]} : (!llvm<"{ i32, double, i32 }">) -> !llvm<"i32">
%12 = "llvm.extractvalue"(%10) {position: [1]} : (!llvm<"{ i32, double, i32 }">) -> !llvm<"double">
%13 = "llvm.extractvalue"(%10) {position: [2]} : (!llvm<"{ i32, double, i32 }">) -> !llvm<"i32">
%14 = "llvm.pseudo.undef"() : () -> !llvm<"{ i32, double, i32 }">
%15 = "llvm.insertvalue"(%14, %5) {position: [0]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
%16 = "llvm.insertvalue"(%15, %7) {position: [1]} : (!llvm<"{ i32, double, i32 }">, !llvm<"double">) -> !llvm<"{ i32, double, i32 }">
%17 = "llvm.insertvalue"(%16, %11) {position: [2]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
"llvm.return"(%17) : (!llvm<"{ i32, double, i32 }">) -> ()
// CHECK-NEXT:^bb2(%18: !llvm<"i32">): // pred: ^bb0
// CHECK-NEXT: %19 = "llvm.pseudo.undef"() : () -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %20 = "llvm.insertvalue"(%19, %18) {position: [0]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %21 = "llvm.insertvalue"(%20, %7) {position: [1]} : (!llvm<"{ i32, double, i32 }">, !llvm<"double">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %22 = "llvm.insertvalue"(%21, %5) {position: [2]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: "llvm.return"(%22) : (!llvm<"{ i32, double, i32 }">) -> ()
^bb2(%18: !llvm<"i32">): // pred: ^bb0
%19 = "llvm.pseudo.undef"() : () -> !llvm<"{ i32, double, i32 }">
%20 = "llvm.insertvalue"(%19, %18) {position: [0]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
%21 = "llvm.insertvalue"(%20, %7) {position: [1]} : (!llvm<"{ i32, double, i32 }">, !llvm<"double">) -> !llvm<"{ i32, double, i32 }">
%22 = "llvm.insertvalue"(%21, %5) {position: [2]} : (!llvm<"{ i32, double, i32 }">, !llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
"llvm.return"(%22) : (!llvm<"{ i32, double, i32 }">) -> ()
}
// CHECK-NEXT: %0 = llvm.constant(3) : !llvm<"i32">
// CHECK-NEXT: %1 = llvm.constant(3) : !llvm<"i32">
// CHECK-NEXT: %2 = llvm.constant(4.200000e+01) : !llvm<"double">
// CHECK-NEXT: %3 = llvm.constant(4.200000e+01) : !llvm<"double">
// CHECK-NEXT: %4 = llvm.add %0, %1 : !llvm<"i32">
// CHECK-NEXT: %5 = llvm.mul %4, %1 : !llvm<"i32">
// CHECK-NEXT: %6 = llvm.fadd %2, %3 : !llvm<"double">
// CHECK-NEXT: %7 = llvm.fsub %3, %6 : !llvm<"double">
// CHECK-NEXT: %8 = llvm.constant(1) : !llvm<"i1">
// CHECK-NEXT: llvm.cond_br %8, ^bb1(%4 : !llvm<"i32">), ^bb2(%4 : !llvm<"i32">)
%0 = llvm.constant(3) : !llvm<"i32">
%1 = llvm.constant(3) : !llvm<"i32">
%2 = llvm.constant(4.200000e+01) : !llvm<"double">
%3 = llvm.constant(4.200000e+01) : !llvm<"double">
%4 = llvm.add %0, %1 : !llvm<"i32">
%5 = llvm.mul %4, %1 : !llvm<"i32">
%6 = llvm.fadd %2, %3 : !llvm<"double">
%7 = llvm.fsub %3, %6 : !llvm<"double">
%8 = llvm.constant(1) : !llvm<"i1">
llvm.cond_br %8, ^bb1(%4 : !llvm<"i32">), ^bb2(%4 : !llvm<"i32">)
// CHECK-NEXT:^bb1(%9: !llvm<"i32">):
// CHECK-NEXT: %10 = llvm.call @foo(%9) : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %11 = llvm.extractvalue %10[0] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %12 = llvm.extractvalue %10[1] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %13 = llvm.extractvalue %10[2] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %14 = llvm.undef : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %15 = llvm.insertvalue %5, %14[0] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %16 = llvm.insertvalue %7, %15[1] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %17 = llvm.insertvalue %11, %16[2] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: llvm.return %17 : !llvm<"{ i32, double, i32 }">
^bb1(%9: !llvm<"i32">):
%10 = llvm.call @foo(%9) : (!llvm<"i32">) -> !llvm<"{ i32, double, i32 }">
%11 = llvm.extractvalue %10[0] : !llvm<"{ i32, double, i32 }">
%12 = llvm.extractvalue %10[1] : !llvm<"{ i32, double, i32 }">
%13 = llvm.extractvalue %10[2] : !llvm<"{ i32, double, i32 }">
%14 = llvm.undef : !llvm<"{ i32, double, i32 }">
%15 = llvm.insertvalue %5, %14[0] : !llvm<"{ i32, double, i32 }">
%16 = llvm.insertvalue %7, %15[1] : !llvm<"{ i32, double, i32 }">
%17 = llvm.insertvalue %11, %16[2] : !llvm<"{ i32, double, i32 }">
llvm.return %17 : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT:^bb2(%18: !llvm<"i32">): // pred: ^bb0
// CHECK-NEXT: %19 = llvm.undef : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %20 = llvm.insertvalue %18, %19[0] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %21 = llvm.insertvalue %7, %20[1] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: %22 = llvm.insertvalue %5, %21[2] : !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: llvm.return %22 : !llvm<"{ i32, double, i32 }">
^bb2(%18: !llvm<"i32">): // pred: ^bb0
%19 = llvm.undef : !llvm<"{ i32, double, i32 }">
%20 = llvm.insertvalue %18, %19[0] : !llvm<"{ i32, double, i32 }">
%21 = llvm.insertvalue %7, %20[1] : !llvm<"{ i32, double, i32 }">
%22 = llvm.insertvalue %5, %21[2] : !llvm<"{ i32, double, i32 }">
llvm.return %22 : !llvm<"{ i32, double, i32 }">
}

View File

@ -18,7 +18,7 @@ func @malloc(!llvm<"i64">) -> !llvm<"i8*">
// CHECK-NEXT: ret void
// CHECK-NEXT: }
func @empty() {
"llvm.return"() : () -> ()
llvm.return
}
// CHECK-LABEL: declare void @body(i64)
@ -28,38 +28,38 @@ func @body(!llvm<"i64">)
// CHECK-LABEL: define void @simple_loop() {
func @simple_loop() {
// CHECK: br label %[[SIMPLE_bb1:[0-9]+]]
"llvm.br"()[^bb1] : () -> ()
llvm.br ^bb1
// Constants are inlined in LLVM rather than a separate instruction.
// CHECK: [[SIMPLE_bb1]]:
// CHECK-NEXT: br label %[[SIMPLE_bb2:[0-9]+]]
^bb1: // pred: ^bb0
%0 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%1 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb2(%0 : !llvm<"i64">)] : () -> ()
%0 = llvm.constant(1 : index) : !llvm<"i64">
%1 = llvm.constant(42 : index) : !llvm<"i64">
llvm.br ^bb2(%0 : !llvm<"i64">)
// CHECK: [[SIMPLE_bb2]]:
// CHECK-NEXT: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %[[SIMPLE_bb3:[0-9]+]] ], [ 1, %[[SIMPLE_bb1]] ]
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, 42
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %[[SIMPLE_bb3]], label %[[SIMPLE_bb4:[0-9]+]]
^bb2(%2: !llvm<"i64">): // 2 preds: ^bb1, ^bb3
%3 = "llvm.icmp"(%2, %1) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
"llvm.cond_br"(%3)[^bb3, ^bb4] : (!llvm<"i1">) -> ()
%3 = llvm.icmp "slt" %2, %1 : !llvm<"i64">
llvm.cond_br %3, ^bb3, ^bb4
// CHECK: [[SIMPLE_bb3]]:
// CHECK-NEXT: call void @body(i64 %{{[0-9]+}})
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
// CHECK-NEXT: br label %[[SIMPLE_bb2]]
^bb3: // pred: ^bb2
"llvm.call"(%2) {callee: @body : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
%4 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%5 = "llvm.add"(%2, %4) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
"llvm.br"()[^bb2(%5 : !llvm<"i64">)] : () -> ()
llvm.call @body(%2) : (!llvm<"i64">) -> ()
%4 = llvm.constant(1 : index) : !llvm<"i64">
%5 = llvm.add %2, %4 : !llvm<"i64">
llvm.br ^bb2(%5 : !llvm<"i64">)
// CHECK: [[SIMPLE_bb4]]:
// CHECK-NEXT: ret void
^bb4: // pred: ^bb2
"llvm.return"() : () -> ()
llvm.return
}
// CHECK-LABEL: define void @simple_caller() {
@ -67,8 +67,8 @@ func @simple_loop() {
// CHECK-NEXT: ret void
// CHECK-NEXT: }
func @simple_caller() {
"llvm.call"() {callee: @simple_loop : () -> ()} : () -> ()
"llvm.return"() : () -> ()
llvm.call @simple_loop() : () -> ()
llvm.return
}
//func @simple_indirect_caller() {
@ -84,9 +84,9 @@ func @simple_caller() {
// CHECK-NEXT: ret void
// CHECK-NEXT: }
func @ml_caller() {
"llvm.call"() {callee: @simple_loop : () -> ()} : () -> ()
"llvm.call"() {callee: @more_imperfectly_nested_loops : () -> ()} : () -> ()
"llvm.return"() : () -> ()
llvm.call @simple_loop() : () -> ()
llvm.call @more_imperfectly_nested_loops() : () -> ()
llvm.return
}
// CHECK-LABEL: declare i64 @body_args(i64)
@ -97,23 +97,23 @@ func @other(!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
// CHECK-LABEL: define i32 @func_args(i32, i32) {
// CHECK-NEXT: br label %[[ARGS_bb1:[0-9]+]]
func @func_args(%arg0: !llvm<"i32">, %arg1: !llvm<"i32">) -> !llvm<"i32"> {
%0 = "llvm.constant"() {value: 0 : i32} : () -> !llvm<"i32">
"llvm.br"()[^bb1] : () -> ()
%0 = llvm.constant(0 : i32) : !llvm<"i32">
llvm.br ^bb1
// CHECK: [[ARGS_bb1]]:
// CHECK-NEXT: br label %[[ARGS_bb2:[0-9]+]]
^bb1: // pred: ^bb0
%1 = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
%2 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb2(%1 : !llvm<"i64">)] : () -> ()
%1 = llvm.constant(0 : index) : !llvm<"i64">
%2 = llvm.constant(42 : index) : !llvm<"i64">
llvm.br ^bb2(%1 : !llvm<"i64">)
// CHECK: [[ARGS_bb2]]:
// CHECK-NEXT: %5 = phi i64 [ %12, %[[ARGS_bb3:[0-9]+]] ], [ 0, %[[ARGS_bb1]] ]
// CHECK-NEXT: %6 = icmp slt i64 %5, 42
// CHECK-NEXT: br i1 %6, label %[[ARGS_bb3]], label %[[ARGS_bb4:[0-9]+]]
^bb2(%3: !llvm<"i64">): // 2 preds: ^bb1, ^bb3
%4 = "llvm.icmp"(%3, %2) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
"llvm.cond_br"(%4)[^bb3, ^bb4] : (!llvm<"i1">) -> ()
%4 = llvm.icmp "slt" %3, %2 : !llvm<"i64">
llvm.cond_br %4, ^bb3, ^bb4
// CHECK: [[ARGS_bb3]]:
// CHECK-NEXT: %8 = call i64 @body_args(i64 %5)
@ -123,21 +123,21 @@ func @func_args(%arg0: !llvm<"i32">, %arg1: !llvm<"i32">) -> !llvm<"i32"> {
// CHECK-NEXT: %12 = add i64 %5, 1
// CHECK-NEXT: br label %[[ARGS_bb2]]
^bb3: // pred: ^bb2
%5 = "llvm.call"(%3) {callee: @body_args : (!llvm<"i64">) -> !llvm<"i64">} : (!llvm<"i64">) -> !llvm<"i64">
%6 = "llvm.call"(%5, %arg0) {callee: @other : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">} : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
%7 = "llvm.call"(%5, %6) {callee: @other : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">} : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
%8 = "llvm.call"(%5, %arg1) {callee: @other : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">} : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
%9 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%10 = "llvm.add"(%3, %9) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
"llvm.br"()[^bb2(%10 : !llvm<"i64">)] : () -> ()
%5 = llvm.call @body_args(%3) : (!llvm<"i64">) -> !llvm<"i64">
%6 = llvm.call @other(%5, %arg0) : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
%7 = llvm.call @other(%5, %6) : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
%8 = llvm.call @other(%5, %arg1) : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
%9 = llvm.constant(1 : index) : !llvm<"i64">
%10 = llvm.add %3, %9 : !llvm<"i64">
llvm.br ^bb2(%10 : !llvm<"i64">)
// CHECK: [[ARGS_bb4]]:
// CHECK-NEXT: %14 = call i32 @other(i64 0, i32 0)
// CHECK-NEXT: ret i32 %14
^bb4: // pred: ^bb2
%11 = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
%12 = "llvm.call"(%11, %0) {callee: @other : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">} : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
"llvm.return"(%12) : (!llvm<"i32">) -> ()
%11 = llvm.constant(0 : index) : !llvm<"i64">
%12 = llvm.call @other(%11, %0) : (!llvm<"i64">, !llvm<"i32">) -> !llvm<"i32">
llvm.return %12 : !llvm<"i32">
}
// CHECK: declare void @pre(i64)
@ -152,69 +152,69 @@ func @post(!llvm<"i64">)
// CHECK-LABEL: define void @imperfectly_nested_loops() {
// CHECK-NEXT: br label %[[IMPER_bb1:[0-9]+]]
func @imperfectly_nested_loops() {
"llvm.br"()[^bb1] : () -> ()
llvm.br ^bb1
// CHECK: [[IMPER_bb1]]:
// CHECK-NEXT: br label %[[IMPER_bb2:[0-9]+]]
^bb1: // pred: ^bb0
%0 = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
%1 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb2(%0 : !llvm<"i64">)] : () -> ()
%0 = llvm.constant(0 : index) : !llvm<"i64">
%1 = llvm.constant(42 : index) : !llvm<"i64">
llvm.br ^bb2(%0 : !llvm<"i64">)
// CHECK: [[IMPER_bb2]]:
// CHECK-NEXT: %3 = phi i64 [ %13, %[[IMPER_bb7:[0-9]+]] ], [ 0, %[[IMPER_bb1]] ]
// CHECK-NEXT: %4 = icmp slt i64 %3, 42
// CHECK-NEXT: br i1 %4, label %[[IMPER_bb3:[0-9]+]], label %[[IMPER_bb8:[0-9]+]]
^bb2(%2: !llvm<"i64">): // 2 preds: ^bb1, ^bb7
%3 = "llvm.icmp"(%2, %1) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
"llvm.cond_br"(%3)[^bb3, ^bb8] : (!llvm<"i1">) -> ()
%3 = llvm.icmp "slt" %2, %1 : !llvm<"i64">
llvm.cond_br %3, ^bb3, ^bb8
// CHECK: [[IMPER_bb3]]:
// CHECK-NEXT: call void @pre(i64 %3)
// CHECK-NEXT: br label %[[IMPER_bb4:[0-9]+]]
^bb3: // pred: ^bb2
"llvm.call"(%2) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"llvm.br"()[^bb4] : () -> ()
llvm.call @pre(%2) : (!llvm<"i64">) -> ()
llvm.br ^bb4
// CHECK: [[IMPER_bb4]]:
// CHECK-NEXT: br label %[[IMPER_bb5:[0-9]+]]
^bb4: // pred: ^bb3
%4 = "llvm.constant"() {value: 7 : index} : () -> !llvm<"i64">
%5 = "llvm.constant"() {value: 56 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb5(%4 : !llvm<"i64">)] : () -> ()
%4 = llvm.constant(7 : index) : !llvm<"i64">
%5 = llvm.constant(56 : index) : !llvm<"i64">
llvm.br ^bb5(%4 : !llvm<"i64">)
// CHECK: [[IMPER_bb5]]:
// CHECK-NEXT: %8 = phi i64 [ %11, %[[IMPER_bb6:[0-9]+]] ], [ 7, %[[IMPER_bb4]] ]
// CHECK-NEXT: %9 = icmp slt i64 %8, 56
// CHECK-NEXT: br i1 %9, label %[[IMPER_bb6]], label %[[IMPER_bb7]]
^bb5(%6: !llvm<"i64">): // 2 preds: ^bb4, ^bb6
%7 = "llvm.icmp"(%6, %5) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
"llvm.cond_br"(%7)[^bb6, ^bb7] : (!llvm<"i1">) -> ()
%7 = llvm.icmp "slt" %6, %5 : !llvm<"i64">
llvm.cond_br %7, ^bb6, ^bb7
// CHECK: [[IMPER_bb6]]:
// CHECK-NEXT: call void @body2(i64 %3, i64 %8)
// CHECK-NEXT: %11 = add i64 %8, 2
// CHECK-NEXT: br label %[[IMPER_bb5]]
^bb6: // pred: ^bb5
"llvm.call"(%2, %6) {callee: @body2 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
%8 = "llvm.constant"() {value: 2 : index} : () -> !llvm<"i64">
%9 = "llvm.add"(%6, %8) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
"llvm.br"()[^bb5(%9 : !llvm<"i64">)] : () -> ()
llvm.call @body2(%2, %6) : (!llvm<"i64">, !llvm<"i64">) -> ()
%8 = llvm.constant(2 : index) : !llvm<"i64">
%9 = llvm.add %6, %8 : !llvm<"i64">
llvm.br ^bb5(%9 : !llvm<"i64">)
// CHECK: [[IMPER_bb7]]:
// CHECK-NEXT: call void @post(i64 %3)
// CHECK-NEXT: %13 = add i64 %3, 1
// CHECK-NEXT: br label %[[IMPER_bb2]]
^bb7: // pred: ^bb5
"llvm.call"(%2) {callee: @post : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
%10 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%11 = "llvm.add"(%2, %10) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
"llvm.br"()[^bb2(%11 : !llvm<"i64">)] : () -> ()
llvm.call @post(%2) : (!llvm<"i64">) -> ()
%10 = llvm.constant(1 : index) : !llvm<"i64">
%11 = llvm.add %2, %10 : !llvm<"i64">
llvm.br ^bb2(%11 : !llvm<"i64">)
// CHECK: [[IMPER_bb8]]:
// CHECK-NEXT: ret void
^bb8: // pred: ^bb2
"llvm.return"() : () -> ()
llvm.return
}
// CHECK: declare void @mid(i64)
@ -266,51 +266,51 @@ func @body3(!llvm<"i64">, !llvm<"i64">)
// CHECK-NEXT: ret void
// CHECK-NEXT: }
func @more_imperfectly_nested_loops() {
"llvm.br"()[^bb1] : () -> ()
^bb1: // pred: ^bb0
%0 = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
%1 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb2(%0 : !llvm<"i64">)] : () -> ()
^bb2(%2: !llvm<"i64">): // 2 preds: ^bb1, ^bb11
%3 = "llvm.icmp"(%2, %1) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
"llvm.cond_br"(%3)[^bb3, ^bb12] : (!llvm<"i1">) -> ()
^bb3: // pred: ^bb2
"llvm.call"(%2) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"llvm.br"()[^bb4] : () -> ()
^bb4: // pred: ^bb3
%4 = "llvm.constant"() {value: 7 : index} : () -> !llvm<"i64">
%5 = "llvm.constant"() {value: 56 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb5(%4 : !llvm<"i64">)] : () -> ()
^bb5(%6: !llvm<"i64">): // 2 preds: ^bb4, ^bb6
%7 = "llvm.icmp"(%6, %5) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
"llvm.cond_br"(%7)[^bb6, ^bb7] : (!llvm<"i1">) -> ()
^bb6: // pred: ^bb5
"llvm.call"(%2, %6) {callee: @body2 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
%8 = "llvm.constant"() {value: 2 : index} : () -> !llvm<"i64">
%9 = "llvm.add"(%6, %8) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
"llvm.br"()[^bb5(%9 : !llvm<"i64">)] : () -> ()
^bb7: // pred: ^bb5
"llvm.call"(%2) {callee: @mid : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"llvm.br"()[^bb8] : () -> ()
^bb8: // pred: ^bb7
%10 = "llvm.constant"() {value: 18 : index} : () -> !llvm<"i64">
%11 = "llvm.constant"() {value: 37 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb9(%10 : !llvm<"i64">)] : () -> ()
^bb9(%12: !llvm<"i64">): // 2 preds: ^bb8, ^bb10
%13 = "llvm.icmp"(%12, %11) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
"llvm.cond_br"(%13)[^bb10, ^bb11] : (!llvm<"i1">) -> ()
^bb10: // pred: ^bb9
"llvm.call"(%2, %12) {callee: @body3 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
%14 = "llvm.constant"() {value: 3 : index} : () -> !llvm<"i64">
%15 = "llvm.add"(%12, %14) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
"llvm.br"()[^bb9(%15 : !llvm<"i64">)] : () -> ()
^bb11: // pred: ^bb9
"llvm.call"(%2) {callee: @post : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
%16 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%17 = "llvm.add"(%2, %16) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
"llvm.br"()[^bb2(%17 : !llvm<"i64">)] : () -> ()
^bb12: // pred: ^bb2
"llvm.return"() : () -> ()
llvm.br ^bb1
^bb1: // pred: ^bb0
%0 = llvm.constant(0 : index) : !llvm<"i64">
%1 = llvm.constant(42 : index) : !llvm<"i64">
llvm.br ^bb2(%0 : !llvm<"i64">)
^bb2(%2: !llvm<"i64">): // 2 preds: ^bb1, ^bb11
%3 = llvm.icmp "slt" %2, %1 : !llvm<"i64">
llvm.cond_br %3, ^bb3, ^bb12
^bb3: // pred: ^bb2
llvm.call @pre(%2) : (!llvm<"i64">) -> ()
llvm.br ^bb4
^bb4: // pred: ^bb3
%4 = llvm.constant(7 : index) : !llvm<"i64">
%5 = llvm.constant(56 : index) : !llvm<"i64">
llvm.br ^bb5(%4 : !llvm<"i64">)
^bb5(%6: !llvm<"i64">): // 2 preds: ^bb4, ^bb6
%7 = llvm.icmp "slt" %6, %5 : !llvm<"i64">
llvm.cond_br %7, ^bb6, ^bb7
^bb6: // pred: ^bb5
llvm.call @body2(%2, %6) : (!llvm<"i64">, !llvm<"i64">) -> ()
%8 = llvm.constant(2 : index) : !llvm<"i64">
%9 = llvm.add %6, %8 : !llvm<"i64">
llvm.br ^bb5(%9 : !llvm<"i64">)
^bb7: // pred: ^bb5
llvm.call @mid(%2) : (!llvm<"i64">) -> ()
llvm.br ^bb8
^bb8: // pred: ^bb7
%10 = llvm.constant(18 : index) : !llvm<"i64">
%11 = llvm.constant(37 : index) : !llvm<"i64">
llvm.br ^bb9(%10 : !llvm<"i64">)
^bb9(%12: !llvm<"i64">): // 2 preds: ^bb8, ^bb10
%13 = llvm.icmp "slt" %12, %11 : !llvm<"i64">
llvm.cond_br %13, ^bb10, ^bb11
^bb10: // pred: ^bb9
llvm.call @body3(%2, %12) : (!llvm<"i64">, !llvm<"i64">) -> ()
%14 = llvm.constant(3 : index) : !llvm<"i64">
%15 = llvm.add %12, %14 : !llvm<"i64">
llvm.br ^bb9(%15 : !llvm<"i64">)
^bb11: // pred: ^bb9
llvm.call @post(%2) : (!llvm<"i64">) -> ()
%16 = llvm.constant(1 : index) : !llvm<"i64">
%17 = llvm.add %2, %16 : !llvm<"i64">
llvm.br ^bb2(%17 : !llvm<"i64">)
^bb12: // pred: ^bb2
llvm.return
}
//
@ -322,17 +322,17 @@ func @memref_alloc() {
// CHECK-NEXT: %{{[0-9]+}} = call i8* @malloc(i64 400)
// CHECK-NEXT: %{{[0-9]+}} = bitcast i8* %{{[0-9]+}} to float*
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float* } undef, float* %{{[0-9]+}}, 0
%0 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%1 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%2 = "llvm.mul"(%0, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%3 = "llvm.undef"() : () -> !llvm<"{ float* }">
%4 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
%5 = "llvm.mul"(%2, %4) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%6 = "llvm.call"(%5) {callee: @malloc : (!llvm<"i64">) -> !llvm<"i8*">} : (!llvm<"i64">) -> !llvm<"i8*">
%7 = "llvm.bitcast"(%6) : (!llvm<"i8*">) -> !llvm<"float*">
%8 = "llvm.insertvalue"(%3, %7) {position: [0]} : (!llvm<"{ float* }">, !llvm<"float*">) -> !llvm<"{ float* }">
%0 = llvm.constant(10 : index) : !llvm<"i64">
%1 = llvm.constant(10 : index) : !llvm<"i64">
%2 = llvm.mul %0, %1 : !llvm<"i64">
%3 = llvm.undef : !llvm<"{ float* }">
%4 = llvm.constant(4 : index) : !llvm<"i64">
%5 = llvm.mul %2, %4 : !llvm<"i64">
%6 = llvm.call @malloc(%5) : (!llvm<"i64">) -> !llvm<"i8*">
%7 = llvm.bitcast %6 : !llvm<"i8*"> to !llvm<"float*">
%8 = llvm.insertvalue %7, %3[0] : !llvm<"{ float* }">
// CHECK-NEXT: ret void
"llvm.return"() : () -> ()
llvm.return
}
// CHECK-LABEL: declare i64 @get_index()
@ -344,66 +344,66 @@ func @store_load_static() {
// CHECK-NEXT: %{{[0-9]+}} = call i8* @malloc(i64 40)
// CHECK-NEXT: %{{[0-9]+}} = bitcast i8* %{{[0-9]+}} to float*
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float* } undef, float* %{{[0-9]+}}, 0
%0 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%1 = "llvm.undef"() : () -> !llvm<"{ float* }">
%2 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
%3 = "llvm.mul"(%0, %2) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%4 = "llvm.call"(%3) {callee: @malloc : (!llvm<"i64">) -> !llvm<"i8*">} : (!llvm<"i64">) -> !llvm<"i8*">
%5 = "llvm.bitcast"(%4) : (!llvm<"i8*">) -> !llvm<"float*">
%6 = "llvm.insertvalue"(%1, %5) {position: [0]} : (!llvm<"{ float* }">, !llvm<"float*">) -> !llvm<"{ float* }">
%7 = "llvm.constant"() {value: 1.000000e+00 : f32} : () -> !llvm<"float">
"llvm.br"()[^bb1] : () -> ()
%0 = llvm.constant(10 : index) : !llvm<"i64">
%1 = llvm.undef : !llvm<"{ float* }">
%2 = llvm.constant(4 : index) : !llvm<"i64">
%3 = llvm.mul %0, %2 : !llvm<"i64">
%4 = llvm.call @malloc(%3) : (!llvm<"i64">) -> !llvm<"i8*">
%5 = llvm.bitcast %4 : !llvm<"i8*"> to !llvm<"float*">
%6 = llvm.insertvalue %5, %1[0] : !llvm<"{ float* }">
%7 = llvm.constant(1.000000e+00 : f32) : !llvm<"float">
llvm.br ^bb1
^bb1: // pred: ^bb0
%8 = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
%9 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb2(%8 : !llvm<"i64">)] : () -> ()
%8 = llvm.constant(0 : index) : !llvm<"i64">
%9 = llvm.constant(10 : index) : !llvm<"i64">
llvm.br ^bb2(%8 : !llvm<"i64">)
// CHECK: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ]
^bb2(%10: !llvm<"i64">): // 2 preds: ^bb1, ^bb3
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, 10
%11 = "llvm.icmp"(%10, %9) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
%11 = llvm.icmp "slt" %10, %9 : !llvm<"i64">
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}
"llvm.cond_br"(%11)[^bb3, ^bb4] : (!llvm<"i1">) -> ()
llvm.cond_br %11, ^bb3, ^bb4
^bb3: // pred: ^bb2
// CHECK: %{{[0-9]+}} = extractvalue { float* } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: store float 1.000000e+00, float* %{{[0-9]+}}
%12 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%13 = "llvm.extractvalue"(%6) {position: [0]} : (!llvm<"{ float* }">) -> !llvm<"float*">
%14 = "llvm.getelementptr"(%13, %10) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
"llvm.store"(%7, %14) : (!llvm<"float">, !llvm<"float*">) -> ()
%15 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%12 = llvm.constant(10 : index) : !llvm<"i64">
%13 = llvm.extractvalue %6[0] : !llvm<"{ float* }">
%14 = llvm.getelementptr %13[%10] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
llvm.store %7, %14 : !llvm<"float*">
%15 = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
%16 = "llvm.add"(%10, %15) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%16 = llvm.add %10, %15 : !llvm<"i64">
// CHECK-NEXT: br label %{{[0-9]+}}
"llvm.br"()[^bb2(%16 : !llvm<"i64">)] : () -> ()
llvm.br ^bb2(%16 : !llvm<"i64">)
^bb4: // pred: ^bb2
"llvm.br"()[^bb5] : () -> ()
llvm.br ^bb5
^bb5: // pred: ^bb4
%17 = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
%18 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb6(%17 : !llvm<"i64">)] : () -> ()
%17 = llvm.constant(0 : index) : !llvm<"i64">
%18 = llvm.constant(10 : index) : !llvm<"i64">
llvm.br ^bb6(%17 : !llvm<"i64">)
// CHECK: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ]
^bb6(%19: !llvm<"i64">): // 2 preds: ^bb5, ^bb7
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, 10
%20 = "llvm.icmp"(%19, %18) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
%20 = llvm.icmp "slt" %19, %18 : !llvm<"i64">
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}
"llvm.cond_br"(%20)[^bb7, ^bb8] : (!llvm<"i1">) -> ()
llvm.cond_br %20, ^bb7, ^bb8
^bb7: // pred: ^bb6
// CHECK: %{{[0-9]+}} = extractvalue { float* } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = load float, float* %{{[0-9]+}}
%21 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%22 = "llvm.extractvalue"(%6) {position: [0]} : (!llvm<"{ float* }">) -> !llvm<"float*">
%23 = "llvm.getelementptr"(%22, %19) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
%24 = "llvm.load"(%23) : (!llvm<"float*">) -> !llvm<"float">
%25 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%21 = llvm.constant(10 : index) : !llvm<"i64">
%22 = llvm.extractvalue %6[0] : !llvm<"{ float* }">
%23 = llvm.getelementptr %22[%19] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
%24 = llvm.load %23 : !llvm<"float*">
%25 = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
%26 = "llvm.add"(%19, %25) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%26 = llvm.add %19, %25 : !llvm<"i64">
// CHECK-NEXT: br label %{{[0-9]+}}
"llvm.br"()[^bb6(%26 : !llvm<"i64">)] : () -> ()
llvm.br ^bb6(%26 : !llvm<"i64">)
^bb8: // pred: ^bb6
// CHECK: ret void
"llvm.return"() : () -> ()
llvm.return
}
// CHECK-LABEL: define void @store_load_dynamic(i64)
@ -413,72 +413,72 @@ func @store_load_dynamic(%arg0: !llvm<"i64">) {
// CHECK-NEXT: %{{[0-9]+}} = bitcast i8* %{{[0-9]+}} to float*
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64 } undef, float* %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64 } %{{[0-9]+}}, i64 %{{[0-9]+}}, 1
%0 = "llvm.undef"() : () -> !llvm<"{ float*, i64 }">
%1 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
%2 = "llvm.mul"(%arg0, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%3 = "llvm.call"(%2) {callee: @malloc : (!llvm<"i64">) -> !llvm<"i8*">} : (!llvm<"i64">) -> !llvm<"i8*">
%4 = "llvm.bitcast"(%3) : (!llvm<"i8*">) -> !llvm<"float*">
%5 = "llvm.insertvalue"(%0, %4) {position: [0]} : (!llvm<"{ float*, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64 }">
%6 = "llvm.insertvalue"(%5, %arg0) {position: [1]} : (!llvm<"{ float*, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64 }">
%7 = "llvm.constant"() {value: 1.000000e+00 : f32} : () -> !llvm<"float">
%0 = llvm.undef : !llvm<"{ float*, i64 }">
%1 = llvm.constant(4 : index) : !llvm<"i64">
%2 = llvm.mul %arg0, %1 : !llvm<"i64">
%3 = llvm.call @malloc(%2) : (!llvm<"i64">) -> !llvm<"i8*">
%4 = llvm.bitcast %3 : !llvm<"i8*"> to !llvm<"float*">
%5 = llvm.insertvalue %4, %0[0] : !llvm<"{ float*, i64 }">
%6 = llvm.insertvalue %arg0, %5[1] : !llvm<"{ float*, i64 }">
%7 = llvm.constant(1.000000e+00 : f32) : !llvm<"float">
// CHECK-NEXT: br label %{{[0-9]+}}
"llvm.br"()[^bb1] : () -> ()
llvm.br ^bb1
^bb1: // pred: ^bb0
%8 = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb2(%8 : !llvm<"i64">)] : () -> ()
%8 = llvm.constant(0 : index) : !llvm<"i64">
llvm.br ^bb2(%8 : !llvm<"i64">)
// CHECK: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ]
^bb2(%9: !llvm<"i64">): // 2 preds: ^bb1, ^bb3
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, %{{[0-9]+}}
%10 = "llvm.icmp"(%9, %arg0) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
%10 = llvm.icmp "slt" %9, %arg0 : !llvm<"i64">
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}
"llvm.cond_br"(%10)[^bb3, ^bb4] : (!llvm<"i1">) -> ()
llvm.cond_br %10, ^bb3, ^bb4
^bb3: // pred: ^bb2
// CHECK: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: store float 1.000000e+00, float* %{{[0-9]+}}
%11 = "llvm.extractvalue"(%6) {position: [1]} : (!llvm<"{ float*, i64 }">) -> !llvm<"i64">
%12 = "llvm.extractvalue"(%6) {position: [0]} : (!llvm<"{ float*, i64 }">) -> !llvm<"float*">
%13 = "llvm.getelementptr"(%12, %9) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
"llvm.store"(%7, %13) : (!llvm<"float">, !llvm<"float*">) -> ()
%14 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%11 = llvm.extractvalue %6[1] : !llvm<"{ float*, i64 }">
%12 = llvm.extractvalue %6[0] : !llvm<"{ float*, i64 }">
%13 = llvm.getelementptr %12[%9] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
llvm.store %7, %13 : !llvm<"float*">
%14 = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
%15 = "llvm.add"(%9, %14) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%15 = llvm.add %9, %14 : !llvm<"i64">
// CHECK-NEXT: br label %{{[0-9]+}}
"llvm.br"()[^bb2(%15 : !llvm<"i64">)] : () -> ()
llvm.br ^bb2(%15 : !llvm<"i64">)
^bb4: // pred: ^bb3
"llvm.br"()[^bb5] : () -> ()
llvm.br ^bb5
^bb5: // pred: ^bb4
%16 = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
"llvm.br"()[^bb6(%16 : !llvm<"i64">)] : () -> ()
%16 = llvm.constant(0 : index) : !llvm<"i64">
llvm.br ^bb6(%16 : !llvm<"i64">)
// CHECK: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ]
^bb6(%17: !llvm<"i64">): // 2 preds: ^bb5, ^bb7
// CHECK-NEXT: %{{[0-9]+}} = icmp slt i64 %{{[0-9]+}}, %{{[0-9]+}}
%18 = "llvm.icmp"(%17, %arg0) {predicate: 2} : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i1">
%18 = llvm.icmp "slt" %17, %arg0 : !llvm<"i64">
// CHECK-NEXT: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}
"llvm.cond_br"(%18)[^bb7, ^bb8] : (!llvm<"i1">) -> ()
llvm.cond_br %18, ^bb7, ^bb8
^bb7: // pred: ^bb6
// CHECK: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = load float, float* %{{[0-9]+}}
%19 = "llvm.extractvalue"(%6) {position: [1]} : (!llvm<"{ float*, i64 }">) -> !llvm<"i64">
%20 = "llvm.extractvalue"(%6) {position: [0]} : (!llvm<"{ float*, i64 }">) -> !llvm<"float*">
%21 = "llvm.getelementptr"(%20, %17) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
%22 = "llvm.load"(%21) : (!llvm<"float*">) -> !llvm<"float">
%23 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%19 = llvm.extractvalue %6[1] : !llvm<"{ float*, i64 }">
%20 = llvm.extractvalue %6[0] : !llvm<"{ float*, i64 }">
%21 = llvm.getelementptr %20[%17] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
%22 = llvm.load %21 : !llvm<"float*">
%23 = llvm.constant(1 : index) : !llvm<"i64">
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
%24 = "llvm.add"(%17, %23) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%24 = llvm.add %17, %23 : !llvm<"i64">
// CHECK-NEXT: br label %{{[0-9]+}}
"llvm.br"()[^bb6(%24 : !llvm<"i64">)] : () -> ()
llvm.br ^bb6(%24 : !llvm<"i64">)
^bb8: // pred: ^bb6
// CHECK: ret void
"llvm.return"() : () -> ()
llvm.return
}
// CHECK-LABEL: define void @store_load_mixed(i64)
func @store_load_mixed(%arg0: !llvm<"i64">) {
%0 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%0 = llvm.constant(10 : index) : !llvm<"i64">
// CHECK-NEXT: %{{[0-9]+}} = mul i64 2, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 4
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 10
@ -488,28 +488,28 @@ func @store_load_mixed(%arg0: !llvm<"i64">) {
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64, i64 } undef, float* %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64, i64 } %{{[0-9]+}}, i64 %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64, i64 } %{{[0-9]+}}, i64 10, 2
%1 = "llvm.constant"() {value: 2 : index} : () -> !llvm<"i64">
%2 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
%3 = "llvm.mul"(%1, %arg0) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%4 = "llvm.mul"(%3, %2) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%5 = "llvm.mul"(%4, %0) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%6 = "llvm.undef"() : () -> !llvm<"{ float*, i64, i64 }">
%7 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
%8 = "llvm.mul"(%5, %7) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%9 = "llvm.call"(%8) {callee: @malloc : (!llvm<"i64">) -> !llvm<"i8*">} : (!llvm<"i64">) -> !llvm<"i8*">
%10 = "llvm.bitcast"(%9) : (!llvm<"i8*">) -> !llvm<"float*">
%11 = "llvm.insertvalue"(%6, %10) {position: [0]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64, i64 }">
%12 = "llvm.insertvalue"(%11, %arg0) {position: [1]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
%13 = "llvm.insertvalue"(%12, %0) {position: [2]} : (!llvm<"{ float*, i64, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64, i64 }">
%1 = llvm.constant(2 : index) : !llvm<"i64">
%2 = llvm.constant(4 : index) : !llvm<"i64">
%3 = llvm.mul %1, %arg0 : !llvm<"i64">
%4 = llvm.mul %3, %2 : !llvm<"i64">
%5 = llvm.mul %4, %0 : !llvm<"i64">
%6 = llvm.undef : !llvm<"{ float*, i64, i64 }">
%7 = llvm.constant(4 : index) : !llvm<"i64">
%8 = llvm.mul %5, %7 : !llvm<"i64">
%9 = llvm.call @malloc(%8) : (!llvm<"i64">) -> !llvm<"i8*">
%10 = llvm.bitcast %9 : !llvm<"i8*"> to !llvm<"float*">
%11 = llvm.insertvalue %10, %6[0] : !llvm<"{ float*, i64, i64 }">
%12 = llvm.insertvalue %arg0, %11[1] : !llvm<"{ float*, i64, i64 }">
%13 = llvm.insertvalue %0, %12[2] : !llvm<"{ float*, i64, i64 }">
// CHECK-NEXT: %{{[0-9]+}} = call i64 @get_index()
// CHECK-NEXT: %{{[0-9]+}} = call i64 @get_index()
%14 = "llvm.constant"() {value: 1 : index} : () -> !llvm<"i64">
%15 = "llvm.constant"() {value: 2 : index} : () -> !llvm<"i64">
%16 = "llvm.call"() {callee: @get_index : () -> !llvm<"i64">} : () -> !llvm<"i64">
%17 = "llvm.call"() {callee: @get_index : () -> !llvm<"i64">} : () -> !llvm<"i64">
%18 = "llvm.constant"() {value: 4.200000e+01 : f32} : () -> !llvm<"float">
%19 = "llvm.constant"() {value: 2 : index} : () -> !llvm<"i64">
%14 = llvm.constant(1 : index) : !llvm<"i64">
%15 = llvm.constant(2 : index) : !llvm<"i64">
%16 = llvm.call @get_index() : () -> !llvm<"i64">
%17 = llvm.call @get_index() : () -> !llvm<"i64">
%18 = llvm.constant(4.200000e+01 : f32) : !llvm<"float">
%19 = llvm.constant(2 : index) : !llvm<"i64">
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 2
// CHECK-NEXT: %{{[0-9]+}} = mul i64 1, %{{[0-9]+}}
@ -521,18 +521,18 @@ func @store_load_mixed(%arg0: !llvm<"i64">) {
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: store float 4.200000e+01, float* %{{[0-9]+}}
%20 = "llvm.extractvalue"(%13) {position: [1]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
%21 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
%22 = "llvm.extractvalue"(%13) {position: [2]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
%23 = "llvm.mul"(%14, %20) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%24 = "llvm.add"(%23, %15) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%25 = "llvm.mul"(%24, %21) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%26 = "llvm.add"(%25, %16) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%27 = "llvm.mul"(%26, %22) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%28 = "llvm.add"(%27, %17) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%29 = "llvm.extractvalue"(%13) {position: [0]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"float*">
%30 = "llvm.getelementptr"(%29, %28) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
"llvm.store"(%18, %30) : (!llvm<"float">, !llvm<"float*">) -> ()
%20 = llvm.extractvalue %13[1] : !llvm<"{ float*, i64, i64 }">
%21 = llvm.constant(4 : index) : !llvm<"i64">
%22 = llvm.extractvalue %13[2] : !llvm<"{ float*, i64, i64 }">
%23 = llvm.mul %14, %20 : !llvm<"i64">
%24 = llvm.add %23, %15 : !llvm<"i64">
%25 = llvm.mul %24, %21 : !llvm<"i64">
%26 = llvm.add %25, %16 : !llvm<"i64">
%27 = llvm.mul %26, %22 : !llvm<"i64">
%28 = llvm.add %27, %17 : !llvm<"i64">
%29 = llvm.extractvalue %13[0] : !llvm<"{ float*, i64, i64 }">
%30 = llvm.getelementptr %29[%28] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
llvm.store %18, %30 : !llvm<"float*">
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 2
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}
@ -544,97 +544,97 @@ func @store_load_mixed(%arg0: !llvm<"i64">) {
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = load float, float* %{{[0-9]+}}
%31 = "llvm.constant"() {value: 2 : index} : () -> !llvm<"i64">
%32 = "llvm.extractvalue"(%13) {position: [1]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
%33 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
%34 = "llvm.extractvalue"(%13) {position: [2]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
%35 = "llvm.mul"(%17, %32) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%36 = "llvm.add"(%35, %16) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%37 = "llvm.mul"(%36, %33) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%38 = "llvm.add"(%37, %15) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%39 = "llvm.mul"(%38, %34) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%40 = "llvm.add"(%39, %14) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%41 = "llvm.extractvalue"(%13) {position: [0]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"float*">
%42 = "llvm.getelementptr"(%41, %40) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
%43 = "llvm.load"(%42) : (!llvm<"float*">) -> !llvm<"float">
%31 = llvm.constant(2 : index) : !llvm<"i64">
%32 = llvm.extractvalue %13[1] : !llvm<"{ float*, i64, i64 }">
%33 = llvm.constant(4 : index) : !llvm<"i64">
%34 = llvm.extractvalue %13[2] : !llvm<"{ float*, i64, i64 }">
%35 = llvm.mul %17, %32 : !llvm<"i64">
%36 = llvm.add %35, %16 : !llvm<"i64">
%37 = llvm.mul %36, %33 : !llvm<"i64">
%38 = llvm.add %37, %15 : !llvm<"i64">
%39 = llvm.mul %38, %34 : !llvm<"i64">
%40 = llvm.add %39, %14 : !llvm<"i64">
%41 = llvm.extractvalue %13[0] : !llvm<"{ float*, i64, i64 }">
%42 = llvm.getelementptr %41[%40] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
%43 = llvm.load %42 : !llvm<"float*">
// CHECK-NEXT: ret void
"llvm.return"() : () -> ()
llvm.return
}
// CHECK-LABEL: define { float*, i64 } @memref_args_rets({ float* }, { float*, i64 }, { float*, i64 }) {
func @memref_args_rets(%arg0: !llvm<"{ float* }">, %arg1: !llvm<"{ float*, i64 }">, %arg2: !llvm<"{ float*, i64 }">) -> !llvm<"{ float*, i64 }"> {
%0 = "llvm.constant"() {value: 7 : index} : () -> !llvm<"i64">
%0 = llvm.constant(7 : index) : !llvm<"i64">
// CHECK-NEXT: %{{[0-9]+}} = call i64 @get_index()
%1 = "llvm.call"() {callee: @get_index : () -> !llvm<"i64">} : () -> !llvm<"i64">
%2 = "llvm.constant"() {value: 4.200000e+01 : f32} : () -> !llvm<"float">
%1 = llvm.call @get_index() : () -> !llvm<"i64">
%2 = llvm.constant(4.200000e+01 : f32) : !llvm<"float">
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float* } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 7
// CHECK-NEXT: store float 4.200000e+01, float* %{{[0-9]+}}
%3 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%4 = "llvm.extractvalue"(%arg0) {position: [0]} : (!llvm<"{ float* }">) -> !llvm<"float*">
%5 = "llvm.getelementptr"(%4, %0) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
"llvm.store"(%2, %5) : (!llvm<"float">, !llvm<"float*">) -> ()
%3 = llvm.constant(10 : index) : !llvm<"i64">
%4 = llvm.extractvalue %arg0[0] : !llvm<"{ float* }">
%5 = llvm.getelementptr %4[%0] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
llvm.store %2, %5 : !llvm<"float*">
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 7
// CHECK-NEXT: store float 4.200000e+01, float* %{{[0-9]+}}
%6 = "llvm.extractvalue"(%arg1) {position: [1]} : (!llvm<"{ float*, i64 }">) -> !llvm<"i64">
%7 = "llvm.extractvalue"(%arg1) {position: [0]} : (!llvm<"{ float*, i64 }">) -> !llvm<"float*">
%8 = "llvm.getelementptr"(%7, %0) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
"llvm.store"(%2, %8) : (!llvm<"float">, !llvm<"float*">) -> ()
%6 = llvm.extractvalue %arg1[1] : !llvm<"{ float*, i64 }">
%7 = llvm.extractvalue %arg1[0] : !llvm<"{ float*, i64 }">
%8 = llvm.getelementptr %7[%0] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
llvm.store %2, %8 : !llvm<"float*">
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = mul i64 7, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = extractvalue { float*, i64 } %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = getelementptr float, float* %{{[0-9]+}}, i64 %{{[0-9]+}}
// CHECK-NEXT: store float 4.200000e+01, float* %{{[0-9]+}}
%9 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%10 = "llvm.extractvalue"(%arg2) {position: [1]} : (!llvm<"{ float*, i64 }">) -> !llvm<"i64">
%11 = "llvm.mul"(%0, %10) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%12 = "llvm.add"(%11, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%13 = "llvm.extractvalue"(%arg2) {position: [0]} : (!llvm<"{ float*, i64 }">) -> !llvm<"float*">
%14 = "llvm.getelementptr"(%13, %12) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
"llvm.store"(%2, %14) : (!llvm<"float">, !llvm<"float*">) -> ()
%9 = llvm.constant(10 : index) : !llvm<"i64">
%10 = llvm.extractvalue %arg2[1] : !llvm<"{ float*, i64 }">
%11 = llvm.mul %0, %10 : !llvm<"i64">
%12 = llvm.add %11, %1 : !llvm<"i64">
%13 = llvm.extractvalue %arg2[0] : !llvm<"{ float*, i64 }">
%14 = llvm.getelementptr %13[%12] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
llvm.store %2, %14 : !llvm<"float*">
// CHECK-NEXT: %{{[0-9]+}} = mul i64 10, %{{[0-9]+}}
// CHECK-NEXT: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, 4
// CHECK-NEXT: %{{[0-9]+}} = call i8* @malloc(i64 %{{[0-9]+}})
// CHECK-NEXT: %{{[0-9]+}} = bitcast i8* %{{[0-9]+}} to float*
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64 } undef, float* %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { float*, i64 } %{{[0-9]+}}, i64 %{{[0-9]+}}, 1
%15 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%16 = "llvm.mul"(%15, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%17 = "llvm.undef"() : () -> !llvm<"{ float*, i64 }">
%18 = "llvm.constant"() {value: 4 : index} : () -> !llvm<"i64">
%19 = "llvm.mul"(%16, %18) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%20 = "llvm.call"(%19) {callee: @malloc : (!llvm<"i64">) -> !llvm<"i8*">} : (!llvm<"i64">) -> !llvm<"i8*">
%21 = "llvm.bitcast"(%20) : (!llvm<"i8*">) -> !llvm<"float*">
%22 = "llvm.insertvalue"(%17, %21) {position: [0]} : (!llvm<"{ float*, i64 }">, !llvm<"float*">) -> !llvm<"{ float*, i64 }">
%23 = "llvm.insertvalue"(%22, %1) {position: [1]} : (!llvm<"{ float*, i64 }">, !llvm<"i64">) -> !llvm<"{ float*, i64 }">
%15 = llvm.constant(10 : index) : !llvm<"i64">
%16 = llvm.mul %15, %1 : !llvm<"i64">
%17 = llvm.undef : !llvm<"{ float*, i64 }">
%18 = llvm.constant(4 : index) : !llvm<"i64">
%19 = llvm.mul %16, %18 : !llvm<"i64">
%20 = llvm.call @malloc(%19) : (!llvm<"i64">) -> !llvm<"i8*">
%21 = llvm.bitcast %20 : !llvm<"i8*"> to !llvm<"float*">
%22 = llvm.insertvalue %21, %17[0] : !llvm<"{ float*, i64 }">
%23 = llvm.insertvalue %1, %22[1] : !llvm<"{ float*, i64 }">
// CHECK-NEXT: ret { float*, i64 } %{{[0-9]+}}
"llvm.return"(%23) : (!llvm<"{ float*, i64 }">) -> ()
llvm.return %23 : !llvm<"{ float*, i64 }">
}
// CHECK-LABEL: define i64 @memref_dim({ float*, i64, i64 })
func @memref_dim(%arg0: !llvm<"{ float*, i64, i64 }">) -> !llvm<"i64"> {
// Expecting this to create an LLVM constant.
%0 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
%0 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK-NEXT: %2 = extractvalue { float*, i64, i64 } %0, 1
%1 = "llvm.extractvalue"(%arg0) {position: [1]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
%1 = llvm.extractvalue %arg0[1] : !llvm<"{ float*, i64, i64 }">
// Expecting this to create an LLVM constant.
%2 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%2 = llvm.constant(10 : index) : !llvm<"i64">
// CHECK-NEXT: %3 = extractvalue { float*, i64, i64 } %0, 2
%3 = "llvm.extractvalue"(%arg0) {position: [2]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
%3 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64 }">
// Checking that the constant for d0 has been created.
// CHECK-NEXT: %4 = add i64 42, %2
%4 = "llvm.add"(%0, %1) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%4 = llvm.add %0, %1 : !llvm<"i64">
// Checking that the constant for d2 has been created.
// CHECK-NEXT: %5 = add i64 10, %3
%5 = "llvm.add"(%2, %3) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%5 = llvm.add %2, %3 : !llvm<"i64">
// CHECK-NEXT: %6 = add i64 %4, %5
%6 = "llvm.add"(%4, %5) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%6 = llvm.add %4, %5 : !llvm<"i64">
// CHECK-NEXT: ret i64 %6
"llvm.return"(%6) : (!llvm<"i64">) -> ()
llvm.return %6 : !llvm<"i64">
}
func @get_i64() -> !llvm<"i64">
@ -643,18 +643,18 @@ func @get_memref() -> !llvm<"{ float*, i64, i64 }">
// CHECK-LABEL: define { i64, float, { float*, i64, i64 } } @multireturn() {
func @multireturn() -> !llvm<"{ i64, float, { float*, i64, i64 } }"> {
%0 = "llvm.call"() {callee: @get_i64 : () -> !llvm<"i64">} : () -> !llvm<"i64">
%1 = "llvm.call"() {callee: @get_f32 : () -> !llvm<"float">} : () -> !llvm<"float">
%2 = "llvm.call"() {callee: @get_memref : () -> !llvm<"{ float*, i64, i64 }">} : () -> !llvm<"{ float*, i64, i64 }">
%0 = llvm.call @get_i64() : () -> !llvm<"i64">
%1 = llvm.call @get_f32() : () -> !llvm<"float">
%2 = llvm.call @get_memref() : () -> !llvm<"{ float*, i64, i64 }">
// CHECK: %{{[0-9]+}} = insertvalue { i64, float, { float*, i64, i64 } } undef, i64 %{{[0-9]+}}, 0
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { i64, float, { float*, i64, i64 } } %{{[0-9]+}}, float %{{[0-9]+}}, 1
// CHECK-NEXT: %{{[0-9]+}} = insertvalue { i64, float, { float*, i64, i64 } } %{{[0-9]+}}, { float*, i64, i64 } %{{[0-9]+}}, 2
// CHECK-NEXT: ret { i64, float, { float*, i64, i64 } } %{{[0-9]+}}
%3 = "llvm.undef"() : () -> !llvm<"{ i64, float, { float*, i64, i64 } }">
%4 = "llvm.insertvalue"(%3, %0) {position: [0]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">, !llvm<"i64">) -> !llvm<"{ i64, float, { float*, i64, i64 } }">
%5 = "llvm.insertvalue"(%4, %1) {position: [1]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">, !llvm<"float">) -> !llvm<"{ i64, float, { float*, i64, i64 } }">
%6 = "llvm.insertvalue"(%5, %2) {position: [2]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">, !llvm<"{ float*, i64, i64 }">) -> !llvm<"{ i64, float, { float*, i64, i64 } }">
"llvm.return"(%6) : (!llvm<"{ i64, float, { float*, i64, i64 } }">) -> ()
%3 = llvm.undef : !llvm<"{ i64, float, { float*, i64, i64 } }">
%4 = llvm.insertvalue %0, %3[0] : !llvm<"{ i64, float, { float*, i64, i64 } }">
%5 = llvm.insertvalue %1, %4[1] : !llvm<"{ i64, float, { float*, i64, i64 } }">
%6 = llvm.insertvalue %2, %5[2] : !llvm<"{ i64, float, { float*, i64, i64 } }">
llvm.return %6 : !llvm<"{ i64, float, { float*, i64, i64 } }">
}
@ -664,86 +664,86 @@ func @multireturn_caller() {
// CHECK-NEXT: [[ret0:%[0-9]+]] = extractvalue { i64, float, { float*, i64, i64 } } %1, 0
// CHECK-NEXT: [[ret1:%[0-9]+]] = extractvalue { i64, float, { float*, i64, i64 } } %1, 1
// CHECK-NEXT: [[ret2:%[0-9]+]] = extractvalue { i64, float, { float*, i64, i64 } } %1, 2
%0 = "llvm.call"() {callee: @multireturn : () -> !llvm<"{ i64, float, { float*, i64, i64 } }">} : () -> !llvm<"{ i64, float, { float*, i64, i64 } }">
%1 = "llvm.extractvalue"(%0) {position: [0]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">) -> !llvm<"i64">
%2 = "llvm.extractvalue"(%0) {position: [1]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">) -> !llvm<"float">
%3 = "llvm.extractvalue"(%0) {position: [2]} : (!llvm<"{ i64, float, { float*, i64, i64 } }">) -> !llvm<"{ float*, i64, i64 }">
%4 = "llvm.constant"() {value: 42} : () -> !llvm<"i64">
%0 = llvm.call @multireturn() : () -> !llvm<"{ i64, float, { float*, i64, i64 } }">
%1 = llvm.extractvalue %0[0] : !llvm<"{ i64, float, { float*, i64, i64 } }">
%2 = llvm.extractvalue %0[1] : !llvm<"{ i64, float, { float*, i64, i64 } }">
%3 = llvm.extractvalue %0[2] : !llvm<"{ i64, float, { float*, i64, i64 } }">
%4 = llvm.constant(42) : !llvm<"i64">
// CHECK: add i64 [[ret0]], 42
%5 = "llvm.add"(%1, %4) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%6 = "llvm.constant"() {value: 4.200000e+01 : f32} : () -> !llvm<"float">
%5 = llvm.add %1, %4 : !llvm<"i64">
%6 = llvm.constant(4.200000e+01 : f32) : !llvm<"float">
// CHECK: fadd float [[ret1]], 4.200000e+01
%7 = "llvm.fadd"(%2, %6) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%8 = "llvm.constant"() {value: 0 : index} : () -> !llvm<"i64">
%9 = "llvm.constant"() {value: 42 : index} : () -> !llvm<"i64">
%7 = llvm.fadd %2, %6 : !llvm<"float">
%8 = llvm.constant(0 : index) : !llvm<"i64">
%9 = llvm.constant(42 : index) : !llvm<"i64">
// CHECK: extractvalue { float*, i64, i64 } [[ret2]], 0
%10 = "llvm.extractvalue"(%3) {position: [1]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
%11 = "llvm.constant"() {value: 10 : index} : () -> !llvm<"i64">
%12 = "llvm.extractvalue"(%3) {position: [2]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"i64">
%13 = "llvm.mul"(%8, %10) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%14 = "llvm.add"(%13, %8) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%15 = "llvm.mul"(%14, %11) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%16 = "llvm.add"(%15, %8) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%17 = "llvm.mul"(%16, %12) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%18 = "llvm.add"(%17, %8) : (!llvm<"i64">, !llvm<"i64">) -> !llvm<"i64">
%19 = "llvm.extractvalue"(%3) {position: [0]} : (!llvm<"{ float*, i64, i64 }">) -> !llvm<"float*">
%20 = "llvm.getelementptr"(%19, %18) : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
%21 = "llvm.load"(%20) : (!llvm<"float*">) -> !llvm<"float">
"llvm.return"() : () -> ()
%10 = llvm.extractvalue %3[1] : !llvm<"{ float*, i64, i64 }">
%11 = llvm.constant(10 : index) : !llvm<"i64">
%12 = llvm.extractvalue %3[2] : !llvm<"{ float*, i64, i64 }">
%13 = llvm.mul %8, %10 : !llvm<"i64">
%14 = llvm.add %13, %8 : !llvm<"i64">
%15 = llvm.mul %14, %11 : !llvm<"i64">
%16 = llvm.add %15, %8 : !llvm<"i64">
%17 = llvm.mul %16, %12 : !llvm<"i64">
%18 = llvm.add %17, %8 : !llvm<"i64">
%19 = llvm.extractvalue %3[0] : !llvm<"{ float*, i64, i64 }">
%20 = llvm.getelementptr %19[%18] : (!llvm<"float*">, !llvm<"i64">) -> !llvm<"float*">
%21 = llvm.load %20 : !llvm<"float*">
llvm.return
}
// CHECK-LABEL: define <4 x float> @vector_ops(<4 x float>, <4 x i1>, <4 x i64>) {
func @vector_ops(%arg0: !llvm<"<4 x float>">, %arg1: !llvm<"<4 x i1>">, %arg2: !llvm<"<4 x i64>">) -> !llvm<"<4 x float>"> {
%0 = "llvm.constant"() {value: splat<vector<4xf32>, 4.200000e+01>} : () -> !llvm<"<4 x float>">
%0 = llvm.constant(splat<vector<4xf32>, 4.200000e+01>) : !llvm<"<4 x float>">
// CHECK-NEXT: %4 = fadd <4 x float> %0, <float 4.200000e+01, float 4.200000e+01, float 4.200000e+01, float 4.200000e+01>
%1 = "llvm.fadd"(%arg0, %0) : (!llvm<"<4 x float>">, !llvm<"<4 x float>">) -> !llvm<"<4 x float>">
%1 = llvm.fadd %arg0, %0 : !llvm<"<4 x float>">
// CHECK-NEXT: %5 = select <4 x i1> %1, <4 x float> %4, <4 x float> %0
%2 = "llvm.select"(%arg1, %1, %arg0) : (!llvm<"<4 x i1>">, !llvm<"<4 x float>">, !llvm<"<4 x float>">) -> !llvm<"<4 x float>">
%2 = llvm.select %arg1, %1, %arg0 : !llvm<"<4 x i1>">, !llvm<"<4 x float>">
// CHECK-NEXT: %6 = sdiv <4 x i64> %2, %2
%3 = "llvm.sdiv"(%arg2, %arg2) : (!llvm<"<4 x i64>">, !llvm<"<4 x i64>">) -> !llvm<"<4 x i64>">
%3 = llvm.sdiv %arg2, %arg2 : !llvm<"<4 x i64>">
// CHECK-NEXT: %7 = udiv <4 x i64> %2, %2
%4 = "llvm.udiv"(%arg2, %arg2) : (!llvm<"<4 x i64>">, !llvm<"<4 x i64>">) -> !llvm<"<4 x i64>">
%4 = llvm.udiv %arg2, %arg2 : !llvm<"<4 x i64>">
// CHECK-NEXT: %8 = srem <4 x i64> %2, %2
%5 = "llvm.srem"(%arg2, %arg2) : (!llvm<"<4 x i64>">, !llvm<"<4 x i64>">) -> !llvm<"<4 x i64>">
%5 = llvm.srem %arg2, %arg2 : !llvm<"<4 x i64>">
// CHECK-NEXT: %9 = urem <4 x i64> %2, %2
%6 = "llvm.urem"(%arg2, %arg2) : (!llvm<"<4 x i64>">, !llvm<"<4 x i64>">) -> !llvm<"<4 x i64>">
%6 = llvm.urem %arg2, %arg2 : !llvm<"<4 x i64>">
// CHECK-NEXT: %10 = fdiv <4 x float> %0, <float 4.200000e+01, float 4.200000e+01, float 4.200000e+01, float 4.200000e+01>
%7 = "llvm.fdiv"(%arg0, %0) : (!llvm<"<4 x float>">, !llvm<"<4 x float>">) -> !llvm<"<4 x float>">
%7 = llvm.fdiv %arg0, %0 : !llvm<"<4 x float>">
// CHECK-NEXT: %11 = frem <4 x float> %0, <float 4.200000e+01, float 4.200000e+01, float 4.200000e+01, float 4.200000e+01>
%8 = "llvm.frem"(%arg0, %0) : (!llvm<"<4 x float>">, !llvm<"<4 x float>">) -> !llvm<"<4 x float>">
%8 = llvm.frem %arg0, %0 : !llvm<"<4 x float>">
// CHECK-NEXT: ret <4 x float> %4
"llvm.return"(%1) : (!llvm<"<4 x float>">) -> ()
llvm.return %1 : !llvm<"<4 x float>">
}
// CHECK-LABEL: @ops
func @ops(%arg0: !llvm<"float">, %arg1: !llvm<"float">, %arg2: !llvm<"i32">, %arg3: !llvm<"i32">) -> !llvm<"{ float, i32 }"> {
// CHECK-NEXT: fsub float %0, %1
%0 = "llvm.fsub"(%arg0, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%0 = llvm.fsub %arg0, %arg1 : !llvm<"float">
// CHECK-NEXT: %6 = sub i32 %2, %3
%1 = "llvm.sub"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%1 = llvm.sub %arg2, %arg3 : !llvm<"i32">
// CHECK-NEXT: %7 = icmp slt i32 %2, %6
%2 = "llvm.icmp"(%arg2, %1) {predicate: 2} : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i1">
%2 = llvm.icmp "slt" %arg2, %1 : !llvm<"i32">
// CHECK-NEXT: %8 = select i1 %7, i32 %2, i32 %6
%3 = "llvm.select"(%2, %arg2, %1) : (!llvm<"i1">, !llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%3 = llvm.select %2, %arg2, %1 : !llvm<"i1">, !llvm<"i32">
// CHECK-NEXT: %9 = sdiv i32 %2, %3
%4 = "llvm.sdiv"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%4 = llvm.sdiv %arg2, %arg3 : !llvm<"i32">
// CHECK-NEXT: %10 = udiv i32 %2, %3
%5 = "llvm.udiv"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%5 = llvm.udiv %arg2, %arg3 : !llvm<"i32">
// CHECK-NEXT: %11 = srem i32 %2, %3
%6 = "llvm.srem"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%6 = llvm.srem %arg2, %arg3 : !llvm<"i32">
// CHECK-NEXT: %12 = urem i32 %2, %3
%7 = "llvm.urem"(%arg2, %arg3) : (!llvm<"i32">, !llvm<"i32">) -> !llvm<"i32">
%7 = llvm.urem %arg2, %arg3 : !llvm<"i32">
%8 = "llvm.undef"() : () -> !llvm<"{ float, i32 }">
%9 = "llvm.insertvalue"(%8, %0) {position: [0]} : (!llvm<"{ float, i32 }">, !llvm<"float">) -> !llvm<"{ float, i32 }">
%10 = "llvm.insertvalue"(%9, %3) {position: [1]} : (!llvm<"{ float, i32 }">, !llvm<"i32">) -> !llvm<"{ float, i32 }">
%8 = llvm.undef : !llvm<"{ float, i32 }">
%9 = llvm.insertvalue %0, %8[0] : !llvm<"{ float, i32 }">
%10 = llvm.insertvalue %3, %9[1] : !llvm<"{ float, i32 }">
// CHECK: %15 = fdiv float %0, %1
%11 = "llvm.fdiv"(%arg0, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%11 = llvm.fdiv %arg0, %arg1 : !llvm<"float">
// CHECK-NEXT: %16 = frem float %0, %1
%12 = "llvm.frem"(%arg0, %arg1) : (!llvm<"float">, !llvm<"float">) -> !llvm<"float">
%12 = llvm.frem %arg0, %arg1 : !llvm<"float">
"llvm.return"(%10) : (!llvm<"{ float, i32 }">) -> ()
llvm.return %10 : !llvm<"{ float, i32 }">
}
//
@ -753,18 +753,18 @@ func @ops(%arg0: !llvm<"float">, %arg1: !llvm<"float">, %arg2: !llvm<"i32">, %ar
// CHECK-LABEL: define void @indirect_const_call(i64) {
func @indirect_const_call(%arg0: !llvm<"i64">) {
// CHECK-NEXT: call void @body(i64 %0)
%0 = "llvm.constant"() {value: @body : (!llvm<"i64">) -> ()} : () -> !llvm<"void (i64)*">
"llvm.call"(%0, %arg0) : (!llvm<"void (i64)*">, !llvm<"i64">) -> ()
%0 = llvm.constant(@body : (!llvm<"i64">) -> ()) : !llvm<"void (i64)*">
llvm.call %0(%arg0) : (!llvm<"i64">) -> ()
// CHECK-NEXT: ret void
"llvm.return"() : () -> ()
llvm.return
}
// CHECK-LABEL: define i32 @indirect_call(i32 (float)*, float) {
func @indirect_call(%arg0: !llvm<"i32 (float)*">, %arg1: !llvm<"float">) -> !llvm<"i32"> {
// CHECK-NEXT: %3 = call i32 %0(float %1)
%0 = "llvm.call"(%arg0, %arg1) : (!llvm<"i32 (float)*">, !llvm<"float">) -> !llvm<"i32">
%0 = llvm.call %arg0(%arg1) : (!llvm<"float">) -> !llvm<"i32">
// CHECK-NEXT: ret i32 %3
"llvm.return"(%0) : (!llvm<"i32">) -> ()
llvm.return %0 : !llvm<"i32">
}
//
@ -775,21 +775,21 @@ func @indirect_call(%arg0: !llvm<"i32 (float)*">, %arg1: !llvm<"float">) -> !llv
// CHECK-LABEL: define void @cond_br_arguments(i1, i1) {
func @cond_br_arguments(%arg0: !llvm<"i1">, %arg1: !llvm<"i1">) {
// CHECK-NEXT: br i1 %0, label %3, label %5
"llvm.cond_br"(%arg0)[^bb2(%arg0 : !llvm<"i1">), ^bb3] : (!llvm<"i1">) -> ()
llvm.cond_br %arg0, ^bb1(%arg0 : !llvm<"i1">), ^bb2
// CHECK: 3:
// CHECK-NEXT: %4 = phi i1 [ %1, %5 ], [ %0, %2 ]
^bb2(%0 : !llvm<"i1">):
^bb1(%0 : !llvm<"i1">):
// CHECK-NEXT: ret void
"llvm.return"() : () -> ()
llvm.return
// CHECK: 5:
^bb3:
^bb2:
// CHECK-NEXT: br label %3
"llvm.br"()[^bb2(%arg1 : !llvm<"i1">)] : () -> ()
llvm.br ^bb1(%arg1 : !llvm<"i1">)
}
// CHECK-LABEL: define void @llvm_noalias(float* noalias) {
func @llvm_noalias(%arg0: !llvm<"float*"> {llvm.noalias: true}) {
"llvm.return"() : () -> ()
llvm.return
}