LLVM IR Dialect: unify call and call0 operations

When the LLVM IR dialect was implemented, TableGen operation definition scheme
did not support operations with variadic results.  Therefore, the `call`
instruction was split into `call` and `call0` for the single- and zero-result
calls (LLVM does not support multi-result operations).  Unify `call` and
`call0` using the recently added TableGen support for operations with Variadic
results.  Explicitly verify that the new operation has 0 or 1 results.  As a
side effect, this change enables clean-ups in the conversion to the LLVM IR
dialect that no longer needs to rely on wrapped LLVM IR void types when
constructing zero-result calls.

PiperOrigin-RevId: 236119197
This commit is contained in:
Alex Zinenko 2019-02-28 07:36:17 -08:00 committed by jpienaar
parent d9cc3c31cc
commit 8cc50208a6
7 changed files with 108 additions and 128 deletions

View File

@ -39,15 +39,12 @@ def LLVM_Type : Type<CPred<"{0}.isa<::mlir::LLVM::LLVMType>()">,
class LLVM_Op<string mnemonic, list<OpTrait> traits = []> :
Op<!strconcat("llvm.", mnemonic), traits>;
// Base class for LLVM operations with one result.
class LLVM_OneResultOp<string mnemonic, list<OpTrait> traits = []> :
LLVM_Op<mnemonic, traits>, Results<(outs LLVM_Type)> {
let builder = [{
static void build(Builder *builder, OperationState *result, Type resultType,
ArrayRef<Value *> operands,
ArrayRef<NamedAttribute> attributes = {}) {
(void) builder;
result->addTypes(resultType);
def LLVM_OneResultOpBuilder {
code builder = [{
static void build(Builder *, OperationState *result,
Type resultType, ArrayRef<Value *> operands,
ArrayRef<NamedAttribute> attributes = {}) {
if (resultType) result->addTypes(resultType);
result->addOperands(operands);
for (auto namedAttr : attributes) {
result->addAttribute(namedAttr.first, namedAttr.second);
@ -56,10 +53,33 @@ class LLVM_OneResultOp<string mnemonic, list<OpTrait> traits = []> :
}];
}
def LLVM_ZeroResultOpBuilder {
code builder = [{
static void build(Builder *, OperationState *result,
ArrayRef<Value *> operands,
ArrayRef<NamedAttribute> attributes = {}) {
result->addOperands(operands);
for (auto namedAttr : attributes) {
result->addAttribute(namedAttr.first, namedAttr.second);
}
}
}];
}
class LLVM_TwoBuilders<code b1, code b2> {
code builder = !cast<code>(!strconcat(!cast<string>(b1), !cast<string>(b2)));
}
// Base class for LLVM operations with one result.
class LLVM_OneResultOp<string mnemonic, list<OpTrait> traits = []> :
LLVM_Op<mnemonic, traits>, Results<(outs LLVM_Type)> {
let builder = LLVM_OneResultOpBuilder.builder;
}
// Base class for LLVM operations with zero results.
class LLVM_ZeroResultOp<string mnemonic, list<OpTrait> traits = []> :
LLVM_Op<mnemonic, traits>, Results<(outs)> {
let builder = [{
let builder = LLVM_TwoBuilders<[{
// Compatibility builder that takes an instance of wrapped llvm::VoidType
// to indicate no result.
static void build(Builder *builder, OperationState *result, Type resultType,
@ -72,18 +92,8 @@ class LLVM_ZeroResultOp<string mnemonic, list<OpTrait> traits = []> :
"for zero-result operands, only 'void' is accepted as result type");
build(builder, result, operands, attributes);
}
// Convenience builder that does not take a return type.
static void build(Builder *builder, OperationState *result,
ArrayRef<Value *> operands,
ArrayRef<NamedAttribute> attributes = {}) {
(void) builder;
result->addOperands(operands);
for (auto namedAttr : attributes) {
result->addAttribute(namedAttr.first, namedAttr.second);
}
}
}];
}],
LLVM_ZeroResultOpBuilder.builder>.builder;
}
// Base class for LLVM terminator operations. All terminator operations have
@ -149,10 +159,21 @@ def LLVM_StoreOp : LLVM_ZeroResultOp<"store">,
def LLVM_BitcastOp : LLVM_OneResultOp<"bitcast", [NoSideEffect]>,
Arguments<(ins LLVM_Type)>;
// Call-related instructions.
def LLVM_CallOp : LLVM_VariadicOneResultOp<"call">;
def LLVM_Call0Op : LLVM_ZeroResultOp<"call0", []>,
Arguments<(ins Variadic<LLVM_Type>)>;
def LLVM_CallOp : LLVM_Op<"call">, Arguments<(ins Variadic<LLVM_Type>)>,
Results<(outs Variadic<LLVM_Type>)> {
let builder = LLVM_TwoBuilders<
LLVM_OneResultOpBuilder.builder,
LLVM_ZeroResultOpBuilder.builder
>.builder;
let verifier = [{
if (getNumResults() > 1)
return emitOpError("must have 0 or 1 result");
return false;
}];
}
def LLVM_ExtractValueOp : LLVM_OneResultOp<"extractvalue", [NoSideEffect]>,
Arguments<(ins LLVM_Type)>;
def LLVM_InsertValueOp : LLVM_OneResultOp<"insertvalue", [NoSideEffect]>,

View File

@ -441,18 +441,14 @@ struct OneToOneLLVMOpLowering : public LLVMLegalizationPattern<SourceOp> {
unsigned numResults = op->getNumResults();
auto *mlirContext = op->getContext();
// FIXME: using void here because there is a special case in the
// builder... change this to use an empty type instead.
auto voidType = LLVM::LLVMType::get(
mlirContext, llvm::Type::getVoidTy(this->dialect.getLLVMContext()));
auto packedType =
numResults == 0
? voidType
: TypeConverter::pack(getTypes(op->getResults()),
this->dialect.getLLVMModule(), *mlirContext);
assert(
packedType &&
"type conversion failed, such operation should not have been matched");
Type packedType;
if (numResults != 0) {
packedType =
TypeConverter::pack(getTypes(op->getResults()),
this->dialect.getLLVMModule(), *mlirContext);
assert(packedType && "type conversion failed, such operation should not "
"have been matched");
}
auto newOp = rewriter.create<TargetOp>(op->getLoc(), packedType, operands,
op->getAttrs());
@ -525,53 +521,13 @@ struct SelectOpLowering
: public OneToOneLLVMOpLowering<SelectOp, LLVM::SelectOp> {
using Super::Super;
};
// Refine the matcher for call operations that return one result or more.
// Since tablegen'ed MLIR Ops cannot have variadic results, we separate calls
// that have 0 or 1 result (LLVM calls cannot have more than 1).
template <typename SourceOp>
struct NonZeroResultCallLowering
: public OneToOneLLVMOpLowering<SourceOp, LLVM::CallOp> {
using OneToOneLLVMOpLowering<SourceOp, LLVM::CallOp>::OneToOneLLVMOpLowering;
using Super = NonZeroResultCallLowering<SourceOp>;
PatternMatchResult match(Instruction *op) const override {
if (op->getNumResults() > 0)
return OneToOneLLVMOpLowering<SourceOp, LLVM::CallOp>::match(op);
return this->matchFailure();
}
};
// Refine the matcher for call operations that return zero results.
// Since tablegen'ed MLIR Ops cannot have variadic results, we separate calls
// that have 0 or 1 result (LLVM calls cannot have more than 1).
template <typename SourceOp>
struct ZeroResultCallLowering
: public OneToOneLLVMOpLowering<SourceOp, LLVM::Call0Op> {
using OneToOneLLVMOpLowering<SourceOp, LLVM::Call0Op>::OneToOneLLVMOpLowering;
using Super = ZeroResultCallLowering<SourceOp>;
PatternMatchResult match(Instruction *op) const override {
if (op->getNumResults() == 0)
return OneToOneLLVMOpLowering<SourceOp, LLVM::Call0Op>::match(op);
return this->matchFailure();
}
};
struct Call0OpLowering : public ZeroResultCallLowering<CallOp> {
using Super::Super;
};
struct CallOpLowering : public NonZeroResultCallLowering<CallOp> {
using Super::Super;
};
struct CallIndirect0OpLowering : public ZeroResultCallLowering<CallIndirectOp> {
struct CallOpLowering : public OneToOneLLVMOpLowering<CallOp, LLVM::CallOp> {
using Super::Super;
};
struct CallIndirectOpLowering
: public NonZeroResultCallLowering<CallIndirectOp> {
: public OneToOneLLVMOpLowering<CallIndirectOp, LLVM::CallOp> {
using Super::Super;
};
struct ConstLLVMOpLowering
: public OneToOneLLVMOpLowering<ConstantOp, LLVM::ConstantOp> {
using Super::Super;
@ -657,10 +613,12 @@ struct AllocOpLowering : public LLVMLegalizationPattern<AllocOp> {
// descriptor.
auto mallocNamedAttr = NamedAttribute{rewriter.getIdentifier("callee"),
rewriter.getFunctionAttr(mallocFunc)};
Value *allocated = rewriter.create<LLVM::CallOp>(
op->getLoc(), getVoidPtrType(), ArrayRef<Value *>(cumulativeSize),
llvm::makeArrayRef(mallocNamedAttr));
Value *allocated =
rewriter
.create<LLVM::CallOp>(op->getLoc(), getVoidPtrType(),
ArrayRef<Value *>(cumulativeSize),
llvm::makeArrayRef(mallocNamedAttr))
->getResult(0);
auto structElementType = TypeConverter::convert(elementType, getModule());
auto elementPtrType = LLVM::LLVMType::get(
op->getContext(), structElementType.cast<LLVM::LLVMType>()
@ -734,8 +692,8 @@ struct DeallocOpLowering : public LLVMLegalizationPattern<DeallocOp> {
op->getLoc(), getVoidPtrType(), bufferPtr);
auto freeNamedAttr = NamedAttribute{rewriter.getIdentifier("callee"),
rewriter.getFunctionAttr(freeFunc)};
rewriter.create<LLVM::Call0Op>(op->getLoc(), casted,
llvm::makeArrayRef(freeNamedAttr));
rewriter.create<LLVM::CallOp>(op->getLoc(), casted,
llvm::makeArrayRef(freeNamedAttr));
return {};
}
};
@ -1165,13 +1123,13 @@ protected:
// FIXME: this should be tablegen'ed
return ConversionListBuilder<
AddFOpLowering, AddIOpLowering, AllocOpLowering, BranchOpLowering,
Call0OpLowering, CallIndirect0OpLowering, CallIndirectOpLowering,
CallOpLowering, CmpIOpLowering, CondBranchOpLowering,
ConstLLVMOpLowering, DeallocOpLowering, DimOpLowering, DivISOpLowering,
DivIUOpLowering, DivFOpLowering, LoadOpLowering, MemRefCastOpLowering,
MulFOpLowering, MulIOpLowering, RemISOpLowering, RemIUOpLowering,
RemFOpLowering, ReturnOpLowering, SelectOpLowering, StoreOpLowering,
SubFOpLowering, SubIOpLowering>::build(&converterStorage, *llvmDialect);
CallIndirectOpLowering, CallOpLowering, CmpIOpLowering,
CondBranchOpLowering, ConstLLVMOpLowering, DeallocOpLowering,
DimOpLowering, DivISOpLowering, DivIUOpLowering, DivFOpLowering,
LoadOpLowering, MemRefCastOpLowering, MulFOpLowering, MulIOpLowering,
RemISOpLowering, RemIUOpLowering, RemFOpLowering, ReturnOpLowering,
SelectOpLowering, StoreOpLowering, SubFOpLowering,
SubIOpLowering>::build(&converterStorage, *llvmDialect);
}
// Convert types using the stored LLVM IR module.

View File

@ -263,14 +263,15 @@ bool ModuleTranslation::convertInstruction(const Instruction &inst,
};
// Emit calls. If the called function has a result, remap the corresponding
// value.
// value. Note that LLVM IR dialect CallOp has either 0 or 1 result.
if (auto op = inst.dyn_cast<LLVM::CallOp>()) {
valueMapping[op->getResult()] = convertCall(inst);
return false;
}
if (inst.isa<LLVM::Call0Op>()) {
convertCall(inst);
return false;
llvm::Value *result = convertCall(inst);
if (inst.getNumResults() != 0) {
valueMapping[inst.getResult(0)] = result;
return false;
}
// Check that LLVM call returns void for 0-result functions.
return !result->getType()->isVoidTy();
}
// Emit branches. We need to look up the remapped blocks and ignore the block

View File

@ -36,7 +36,7 @@ func @body(i32)
func @indirect_const_call(%arg0: i32) {
// CHECK-NEXT: %0 = "llvm.constant"() {value: @body : (!llvm<"i32">) -> ()} : () -> !llvm<"void (i32)*">
%0 = constant @body : (i32) -> ()
// CHECK-NEXT: "llvm.call0"(%0, %arg0) : (!llvm<"void (i32)*">, !llvm<"i32">) -> ()
// CHECK-NEXT: "llvm.call"(%0, %arg0) : (!llvm<"void (i32)*">, !llvm<"i32">) -> ()
call_indirect %0(%arg0) : (i32) -> ()
// CHECK-NEXT: "llvm.return"() : () -> ()
return

View File

@ -34,7 +34,7 @@ func @mixed_alloc(%arg0: index, %arg1: index) -> memref<?x42x?xf32> {
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.call0"(%1) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
// CHECK-NEXT: "llvm.call"(%1) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
dealloc %arg0 : memref<?x42x?xf32>
// CHECK-NEXT: "llvm.return"() : () -> ()
return
@ -59,7 +59,7 @@ func @dynamic_alloc(%arg0: index, %arg1: index) -> memref<?x?xf32> {
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.call0"(%1) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
// CHECK-NEXT: "llvm.call"(%1) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
dealloc %arg0 : memref<?x?xf32>
return
}
@ -80,7 +80,7 @@ func @static_alloc() -> 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.call0"(%0) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
// CHECK-NEXT: "llvm.call"(%0) {callee: @free : (!llvm<"i8*">) -> ()} : (!llvm<"i8*">) -> ()
dealloc %static : memref<10x8xf32>
return
}

View File

@ -34,7 +34,7 @@ func @simple_loop() {
cond_br %1, ^bb3, ^bb4
// CHECK: ^bb3: // pred: ^bb2
// CHECK-NEXT: "llvm.call0"({{.*}}) {callee: @body : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// 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">)] : () -> ()
@ -51,7 +51,7 @@ func @simple_loop() {
}
// CHECK-LABEL: func @simple_caller() {
// CHECK-NEXT: "llvm.call0"() {callee: @simple_loop : () -> ()} : () -> ()
// CHECK-NEXT: "llvm.call"() {callee: @simple_loop : () -> ()} : () -> ()
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: }
func @simple_caller() {
@ -61,8 +61,8 @@ func @simple_caller() {
}
// CHECK-LABEL: func @ml_caller() {
// CHECK-NEXT: "llvm.call0"() {callee: @simple_loop : () -> ()} : () -> ()
// CHECK-NEXT: "llvm.call0"() {callee: @more_imperfectly_nested_loops : () -> ()} : () -> ()
// CHECK-NEXT: "llvm.call"() {callee: @simple_loop : () -> ()} : () -> ()
// CHECK-NEXT: "llvm.call"() {callee: @more_imperfectly_nested_loops : () -> ()} : () -> ()
// CHECK-NEXT: "llvm.return"() : () -> ()
// CHECK-NEXT: }
func @ml_caller() {
@ -160,7 +160,7 @@ func @imperfectly_nested_loops() {
cond_br %1, ^bb3, ^bb8
// CHECK-NEXT: ^bb3:
// CHECK-NEXT: "llvm.call0"({{.*}}) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// CHECK-NEXT: "llvm.call"({{.*}}) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// CHECK-NEXT: "llvm.br"()[^bb4] : () -> ()
^bb3: // pred: ^bb2
call @pre(%0) : (index) -> ()
@ -183,7 +183,7 @@ func @imperfectly_nested_loops() {
cond_br %3, ^bb6, ^bb7
// CHECK-NEXT: ^bb6: // pred: ^bb5
// CHECK-NEXT: "llvm.call0"({{.*}}, {{.*}}) {callee: @body2 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
// 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">)] : () -> ()
@ -194,7 +194,7 @@ func @imperfectly_nested_loops() {
br ^bb5(%4 : index)
// CHECK-NEXT: ^bb7: // pred: ^bb5
// CHECK-NEXT: "llvm.call0"({{.*}}) {callee: @post : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// 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">)] : () -> ()
@ -227,7 +227,7 @@ func @body3(index, index)
// 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.call0"({{.*}}) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// 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">
@ -237,12 +237,12 @@ func @body3(index, index)
// 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.call0"({{.*}}, {{.*}}) {callee: @body2 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
// 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.call0"({{.*}}) {callee: @mid : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// 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">
@ -252,12 +252,12 @@ func @body3(index, index)
// 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.call0"({{.*}}, {{.*}}) {callee: @body3 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
// 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.call0"({{.*}}) {callee: @post : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
// 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">)] : () -> ()

View File

@ -51,7 +51,7 @@ func @simple_loop() {
// CHECK-NEXT: %{{[0-9]+}} = add i64 %{{[0-9]+}}, 1
// CHECK-NEXT: br label %[[SIMPLE_bb2]]
^bb3: // pred: ^bb2
"llvm.call0"(%2) {callee: @body : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"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">)] : () -> ()
@ -67,7 +67,7 @@ func @simple_loop() {
// CHECK-NEXT: ret void
// CHECK-NEXT: }
func @simple_caller() {
"llvm.call0"() {callee: @simple_loop : () -> ()} : () -> ()
"llvm.call"() {callee: @simple_loop : () -> ()} : () -> ()
"llvm.return"() : () -> ()
}
@ -84,8 +84,8 @@ func @simple_caller() {
// CHECK-NEXT: ret void
// CHECK-NEXT: }
func @ml_caller() {
"llvm.call0"() {callee: @simple_loop : () -> ()} : () -> ()
"llvm.call0"() {callee: @more_imperfectly_nested_loops : () -> ()} : () -> ()
"llvm.call"() {callee: @simple_loop : () -> ()} : () -> ()
"llvm.call"() {callee: @more_imperfectly_nested_loops : () -> ()} : () -> ()
"llvm.return"() : () -> ()
}
@ -173,7 +173,7 @@ func @imperfectly_nested_loops() {
// CHECK-NEXT: call void @pre(i64 %3)
// CHECK-NEXT: br label %[[IMPER_bb4:[0-9]+]]
^bb3: // pred: ^bb2
"llvm.call0"(%2) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"llvm.call"(%2) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"llvm.br"()[^bb4] : () -> ()
// CHECK: <label>:[[IMPER_bb4]]:
@ -196,7 +196,7 @@ func @imperfectly_nested_loops() {
// CHECK-NEXT: %11 = add i64 %8, 2
// CHECK-NEXT: br label %[[IMPER_bb5]]
^bb6: // pred: ^bb5
"llvm.call0"(%2, %6) {callee: @body2 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
"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">)] : () -> ()
@ -206,7 +206,7 @@ func @imperfectly_nested_loops() {
// CHECK-NEXT: %13 = add i64 %3, 1
// CHECK-NEXT: br label %[[IMPER_bb2]]
^bb7: // pred: ^bb5
"llvm.call0"(%2) {callee: @post : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"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">)] : () -> ()
@ -275,7 +275,7 @@ func @more_imperfectly_nested_loops() {
%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.call0"(%2) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"llvm.call"(%2) {callee: @pre : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"llvm.br"()[^bb4] : () -> ()
^bb4: // pred: ^bb3
%4 = "llvm.constant"() {value: 7 : index} : () -> !llvm<"i64">
@ -285,12 +285,12 @@ func @more_imperfectly_nested_loops() {
%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.call0"(%2, %6) {callee: @body2 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
"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.call0"(%2) {callee: @mid : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"llvm.call"(%2) {callee: @mid : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"llvm.br"()[^bb8] : () -> ()
^bb8: // pred: ^bb7
%10 = "llvm.constant"() {value: 18 : index} : () -> !llvm<"i64">
@ -300,12 +300,12 @@ func @more_imperfectly_nested_loops() {
%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.call0"(%2, %12) {callee: @body3 : (!llvm<"i64">, !llvm<"i64">) -> ()} : (!llvm<"i64">, !llvm<"i64">) -> ()
"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.call0"(%2) {callee: @post : (!llvm<"i64">) -> ()} : (!llvm<"i64">) -> ()
"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">)] : () -> ()
@ -754,7 +754,7 @@ func @ops(%arg0: !llvm<"float">, %arg1: !llvm<"float">, %arg2: !llvm<"i32">, %ar
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.call0"(%0, %arg0) : (!llvm<"void (i64)*">, !llvm<"i64">) -> ()
"llvm.call"(%0, %arg0) : (!llvm<"void (i64)*">, !llvm<"i64">) -> ()
// CHECK-NEXT: ret void
"llvm.return"() : () -> ()
}