[Mlir-commits] [mlir] ff77397 - [mlir] Added llvm.resume and personality functions in LLVM IR Dialect
Alex Zinenko
llvmlistbot at llvm.org
Thu Mar 19 05:14:33 PDT 2020
Author: Shraiysh Vaishay
Date: 2020-03-19T13:14:25+01:00
New Revision: ff77397fcf6ef74906b28be435c159706ed60d43
URL: https://github.com/llvm/llvm-project/commit/ff77397fcf6ef74906b28be435c159706ed60d43
DIFF: https://github.com/llvm/llvm-project/commit/ff77397fcf6ef74906b28be435c159706ed60d43.diff
LOG: [mlir] Added llvm.resume and personality functions in LLVM IR Dialect
`llvm.resume` is similar to `llvm.return` except that has to be exactly
one operand and that should be derived from a `llvm.landingpad`
instruction. Any function having `llvm.landingpad` instruction must
have a personality attribute.
Example:
LLVM IR
```
define dso_local i32 @main() personality i32 (...)* @__gxx_personality_v0 {
invoke void @foo(i32 42)
to label %3 unwind label %1
1: ; preds = %0
%2 = landingpad i8*
catch i8** @_ZTIi
catch i8* bitcast (i8** @_ZTIi to i8*)
resume i8* %2
3: ; preds = %0
ret i32 1
}
```
MLIR - LLVM IR Dialect
```
llvm.func @main() -> !llvm.i32 attributes {personality = @__gxx_personality_v0} {
%0 = llvm.mlir.constant(1 : i32) : !llvm.i32
%1 = llvm.mlir.addressof @_ZTIi : !llvm<"i8**">
%2 = llvm.bitcast %1 : !llvm<"i8**"> to !llvm<"i8*">
%3 = llvm.mlir.addressof @_ZTIi : !llvm<"i8**">
%4 = llvm.mlir.constant(42 : i32) : !llvm.i32
llvm.invoke @foo(%4) to ^bb2 unwind ^bb1 : (!llvm.i32) -> ()
^bb1: // pred: ^bb0
%5 = llvm.landingpad (catch %3 : !llvm<"i8**">) (catch %2 : !llvm<"i8*">) : !llvm<"i8*">
llvm.resume %5 : !llvm<"i8*">
^bb2: // pred: ^bb0
llvm.return %0 : !llvm.i32
}
```
Differential Revision: https://reviews.llvm.org/D71888
Added:
Modified:
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
mlir/test/Dialect/LLVMIR/invalid.mlir
mlir/test/Dialect/LLVMIR/roundtrip.mlir
mlir/test/Target/import.ll
mlir/test/Target/llvmir.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index c734526ce943..53dea5bec65a 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -506,6 +506,18 @@ def LLVM_ReturnOp : LLVM_TerminatorOp<"return", [NoSideEffect]>,
let parser = [{ return parseReturnOp(parser, result); }];
let printer = [{ printReturnOp(p, *this); }];
}
+def LLVM_ResumeOp : LLVM_TerminatorOp<"resume", []> {
+ let arguments = (ins LLVM_Type:$value);
+ string llvmBuilder = [{ builder.CreateResume($value); }];
+ let verifier = [{
+ if (!isa_and_nonnull<LandingpadOp>(value().getDefiningOp()))
+ return emitOpError("expects landingpad value as operand");
+ // No check for personality of function - landingpad op verifies it.
+ return success();
+ }];
+
+ let assemblyFormat = "$value attr-dict `:` type($value)";
+}
def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable", []> {
string llvmBuilder = [{ builder.CreateUnreachable(); }];
let parser = [{ return success(); }];
@@ -650,7 +662,8 @@ def LLVM_GlobalOp
def LLVM_LLVMFuncOp
: LLVM_ZeroResultOp<"func", [IsolatedFromAbove, FunctionLike, Symbol]>,
Arguments<(ins DefaultValuedAttr<Linkage,
- "Linkage::External">:$linkage)> {
+ "Linkage::External">:$linkage,
+ OptionalAttr<FlatSymbolRefAttr>:$personality)> {
let summary = "LLVM dialect function, has wrapped LLVM IR function type";
let regions = (region AnyRegion:$body);
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 2a2e6699fee5..c69530b28e29 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -407,6 +407,11 @@ static ParseResult parseInvokeOp(OpAsmParser &parser, OperationState &result) {
static LogicalResult verify(LandingpadOp op) {
Value value;
+ if (LLVMFuncOp func = op.getParentOfType<LLVMFuncOp>()) {
+ if (!func.personality().hasValue())
+ return op.emitError(
+ "llvm.landingpad needs to be in a function with a personality");
+ }
if (!op.cleanup() && op.getOperands().empty())
return op.emitError("landingpad instruction expects at least one clause or "
diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
index 86351bd689ad..8a71762e956d 100644
--- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
+++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
@@ -60,6 +60,8 @@ class Importer {
GlobalOp processGlobal(llvm::GlobalVariable *GV);
private:
+ /// Returns personality of `f` as a FlatSymbolRefAttr.
+ FlatSymbolRefAttr getPersonalityAsAttr(llvm::Function *f);
/// Imports `bb` into `block`, which must be initially empty.
LogicalResult processBasicBlock(llvm::BasicBlock *bb, Block *block);
/// Imports `inst` and populates instMap[inst] with the imported Value.
@@ -471,7 +473,7 @@ static const DenseMap<unsigned, StringRef> opcMap = {
// FIXME: switch
// FIXME: indirectbr
// FIXME: invoke
- // FIXME: resume
+ INST(Resume, Resume),
// FIXME: unreachable
// FIXME: cleanupret
// FIXME: catchret
@@ -604,6 +606,7 @@ LogicalResult Importer::processInstruction(llvm::Instruction *inst) {
case llvm::Instruction::Load:
case llvm::Instruction::Store:
case llvm::Instruction::Ret:
+ case llvm::Instruction::Resume:
case llvm::Instruction::Trunc:
case llvm::Instruction::ZExt:
case llvm::Instruction::SExt:
@@ -726,8 +729,11 @@ LogicalResult Importer::processInstruction(llvm::Instruction *inst) {
for (unsigned i = 0, ie = lpi->getNumClauses(); i < ie; i++)
ops.push_back(processConstant(lpi->getClause(i)));
- b.create<LandingpadOp>(loc, processType(lpi->getType()), lpi->isCleanup(),
- ops);
+ Type ty = processType(lpi->getType());
+ if (!ty)
+ return failure();
+
+ v = b.create<LandingpadOp>(loc, ty, lpi->isCleanup(), ops);
return success();
}
case llvm::Instruction::Invoke: {
@@ -798,6 +804,28 @@ LogicalResult Importer::processInstruction(llvm::Instruction *inst) {
}
}
+FlatSymbolRefAttr Importer::getPersonalityAsAttr(llvm::Function *f) {
+ if (!f->hasPersonalityFn())
+ return nullptr;
+
+ llvm::Constant *pf = f->getPersonalityFn();
+
+ // If it directly has a name, we can use it.
+ if (pf->hasName())
+ return b.getSymbolRefAttr(pf->getName());
+
+ // If it doesn't have a name, currently, only function pointers that are
+ // bitcast to i8* are parsed.
+ if (auto ce = dyn_cast<llvm::ConstantExpr>(pf)) {
+ if (ce->getOpcode() == llvm::Instruction::BitCast &&
+ ce->getType() == llvm::Type::getInt8PtrTy(dialect->getLLVMContext())) {
+ if (auto func = dyn_cast<llvm::Function>(ce->getOperand(0)))
+ return b.getSymbolRefAttr(func->getName());
+ }
+ }
+ return FlatSymbolRefAttr();
+}
+
LogicalResult Importer::processFunction(llvm::Function *f) {
blocks.clear();
instMap.clear();
@@ -810,6 +838,13 @@ LogicalResult Importer::processFunction(llvm::Function *f) {
b.setInsertionPoint(module.getBody(), getFuncInsertPt());
LLVMFuncOp fop = b.create<LLVMFuncOp>(UnknownLoc::get(context), f->getName(),
functionType);
+
+ if (FlatSymbolRefAttr personality = getPersonalityAsAttr(f))
+ fop.setAttr(b.getIdentifier("personality"), personality);
+ else if (f->hasPersonalityFn())
+ emitWarning(UnknownLoc::get(context),
+ "could not deduce personality, skipping it");
+
if (f->isDeclaration())
return success();
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index dfb4f58472e1..8bc76870e8f7 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -99,7 +99,8 @@ llvm::Constant *ModuleTranslation::getLLVMConstant(llvm::Type *llvmType,
if (auto floatAttr = attr.dyn_cast<FloatAttr>())
return llvm::ConstantFP::get(llvmType, floatAttr.getValue());
if (auto funcAttr = attr.dyn_cast<FlatSymbolRefAttr>())
- return functionMapping.lookup(funcAttr.getValue());
+ return llvm::ConstantExpr::getBitCast(
+ functionMapping.lookup(funcAttr.getValue()), llvmType);
if (auto splatAttr = attr.dyn_cast<SplatElementsAttr>()) {
auto *sequentialType = cast<llvm::SequentialType>(llvmType);
auto elementType = sequentialType->getElementType();
@@ -353,6 +354,7 @@ LogicalResult ModuleTranslation::convertOperation(Operation &opInst,
if (auto constOperand = dyn_cast<llvm::Constant>(operand))
lpi->addClause(constOperand);
}
+ valueMapping[lpOp.getResult()] = lpi;
return success();
}
@@ -585,6 +587,14 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
argIdx++;
}
+ // Check the personality and set it.
+ if (func.personality().hasValue()) {
+ llvm::Type *ty = llvm::Type::getInt8PtrTy(llvmFunc->getContext());
+ if (llvm::Constant *pfunc =
+ getLLVMConstant(ty, func.personalityAttr(), func.getLoc()))
+ llvmFunc->setPersonalityFn(pfunc);
+ }
+
// First, create all blocks so we can jump to them.
llvm::LLVMContext &llvmContext = llvmFunc->getContext();
for (auto &bb : func) {
@@ -646,8 +656,10 @@ SmallVector<llvm::Value *, 8>
ModuleTranslation::lookupValues(ValueRange values) {
SmallVector<llvm::Value *, 8> remapped;
remapped.reserve(values.size());
- for (Value v : values)
+ for (Value v : values) {
+ assert(valueMapping.count(v) && "referencing undefined value");
remapped.push_back(valueMapping.lookup(v));
+ }
return remapped;
}
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index 03de594083dd..710328c1cfc8 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -515,7 +515,7 @@ func @cmpxchg_failure_acq_rel(%i32_ptr : !llvm<"i32*">, %i32 : !llvm.i32) {
llvm.func @foo(!llvm.i32) -> !llvm.i32
llvm.func @__gxx_personality_v0(...) -> !llvm.i32
-llvm.func @bad_landingpad(%arg0: !llvm<"i8**">) {
+llvm.func @bad_landingpad(%arg0: !llvm<"i8**">) attributes { personality = @__gxx_personality_v0} {
%0 = llvm.mlir.constant(3 : i32) : !llvm.i32
%1 = llvm.mlir.constant(2 : i32) : !llvm.i32
%2 = llvm.invoke @foo(%1) to ^bb1 unwind ^bb2 : (!llvm.i32) -> !llvm.i32
@@ -532,7 +532,7 @@ llvm.func @bad_landingpad(%arg0: !llvm<"i8**">) {
llvm.func @foo(!llvm.i32) -> !llvm.i32
llvm.func @__gxx_personality_v0(...) -> !llvm.i32
-llvm.func @caller(%arg0: !llvm.i32) -> !llvm.i32 {
+llvm.func @caller(%arg0: !llvm.i32) -> !llvm.i32 attributes { personality = @__gxx_personality_v0} {
%0 = llvm.mlir.constant(1 : i32) : !llvm.i32
%1 = llvm.alloca %0 x !llvm<"i8*"> : (!llvm.i32) -> !llvm<"i8**">
// expected-note at +1 {{global addresses expected as operand to bitcast used in clauses for landingpad}}
@@ -551,7 +551,7 @@ llvm.func @caller(%arg0: !llvm.i32) -> !llvm.i32 {
llvm.func @foo(!llvm.i32) -> !llvm.i32
llvm.func @__gxx_personality_v0(...) -> !llvm.i32
-llvm.func @caller(%arg0: !llvm.i32) -> !llvm.i32 {
+llvm.func @caller(%arg0: !llvm.i32) -> !llvm.i32 attributes { personality = @__gxx_personality_v0} {
%0 = llvm.mlir.constant(1 : i32) : !llvm.i32
%1 = llvm.invoke @foo(%0) to ^bb1 unwind ^bb2 : (!llvm.i32) -> !llvm.i32
^bb1: // pred: ^bb0
@@ -564,6 +564,37 @@ llvm.func @caller(%arg0: !llvm.i32) -> !llvm.i32 {
// -----
+llvm.func @foo(!llvm.i32) -> !llvm.i32
+llvm.func @__gxx_personality_v0(...) -> !llvm.i32
+
+llvm.func @caller(%arg0: !llvm.i32) -> !llvm.i32 attributes { personality = @__gxx_personality_v0 } {
+ %0 = llvm.mlir.constant(1 : i32) : !llvm.i32
+ %1 = llvm.invoke @foo(%0) to ^bb1 unwind ^bb2 : (!llvm.i32) -> !llvm.i32
+^bb1: // pred: ^bb0
+ llvm.return %0 : !llvm.i32
+^bb2: // pred: ^bb0
+ %2 = llvm.landingpad cleanup : !llvm<"{ i8*, i32 }">
+ // expected-error at +1 {{'llvm.resume' op expects landingpad value as operand}}
+ llvm.resume %0 : !llvm.i32
+}
+
+// -----
+
+llvm.func @foo(!llvm.i32) -> !llvm.i32
+
+llvm.func @caller(%arg0: !llvm.i32) -> !llvm.i32 {
+ %0 = llvm.mlir.constant(1 : i32) : !llvm.i32
+ %1 = llvm.invoke @foo(%0) to ^bb1 unwind ^bb2 : (!llvm.i32) -> !llvm.i32
+^bb1: // pred: ^bb0
+ llvm.return %0 : !llvm.i32
+^bb2: // pred: ^bb0
+ // expected-error at +1 {{llvm.landingpad needs to be in a function with a personality}}
+ %2 = llvm.landingpad cleanup : !llvm<"{ i8*, i32 }">
+ llvm.resume %2 : !llvm<"{ i8*, i32 }">
+}
+
+// -----
+
func @invalid_ordering_in_fence() {
// expected-error @+1 {{can be given only acquire, release, acq_rel, and seq_cst orderings}}
llvm.fence syncscope("agent") monotonic
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 32fe4c496523..8e08d5004d69 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -238,7 +238,7 @@ llvm.func @bar(!llvm<"i8*">, !llvm<"i8*">, !llvm<"i8*">)
llvm.func @__gxx_personality_v0(...) -> !llvm.i32
// CHECK-LABEL: @invokeLandingpad
-llvm.func @invokeLandingpad() -> !llvm.i32 {
+llvm.func @invokeLandingpad() -> !llvm.i32 attributes { personality = @__gxx_personality_v0 } {
// CHECK-NEXT: %[[a0:[0-9]+]] = llvm.mlir.constant(0 : i32) : !llvm.i32
// CHECK-NEXT: %{{[0-9]+}} = llvm.mlir.constant(3 : i32) : !llvm.i32
// CHECK-NEXT: %[[a2:[0-9]+]] = llvm.mlir.constant("\01") : !llvm<"[1 x i8]">
@@ -261,11 +261,11 @@ llvm.func @invokeLandingpad() -> !llvm.i32 {
%9 = llvm.invoke @foo(%7) to ^bb2 unwind ^bb1 : (!llvm.i32) -> !llvm<"{ i32, double, i32 }">
// CHECK-NEXT: ^bb1:
-// CHECK-NEXT: %{{[0-9]+}} = llvm.landingpad cleanup (catch %[[a3]] : !llvm<"i8**">) (catch %[[a6]] : !llvm<"i8*">) (filter %[[a2]] : !llvm<"[1 x i8]">) : !llvm<"{ i8*, i32 }">
-// CHECK-NEXT: llvm.br ^bb3
+// CHECK-NEXT: %[[lp:[0-9]+]] = llvm.landingpad cleanup (catch %[[a3]] : !llvm<"i8**">) (catch %[[a6]] : !llvm<"i8*">) (filter %[[a2]] : !llvm<"[1 x i8]">) : !llvm<"{ i8*, i32 }">
+// CHECK-NEXT: llvm.resume %[[lp]] : !llvm<"{ i8*, i32 }">
^bb1:
%10 = llvm.landingpad cleanup (catch %3 : !llvm<"i8**">) (catch %6 : !llvm<"i8*">) (filter %2 : !llvm<"[1 x i8]">) : !llvm<"{ i8*, i32 }">
- llvm.br ^bb3
+ llvm.resume %10 : !llvm<"{ i8*, i32 }">
// CHECK-NEXT: ^bb2:
// CHECK-NEXT: llvm.return %[[a7]] : !llvm.i32
diff --git a/mlir/test/Target/import.ll b/mlir/test/Target/import.ll
index 0394309093f2..23fc21916888 100644
--- a/mlir/test/Target/import.ll
+++ b/mlir/test/Target/import.ll
@@ -282,8 +282,7 @@ define i32 @invokeLandingpad() personality i8* bitcast (i32 (...)* @__gxx_person
; FIXME: Change filter to a constant array once they are handled.
; Currently, even though it parses this, LLVM module is broken
filter [1 x i8] [i8 1]
- ; CHECK: llvm.br ^bb3
- br label %5
+ resume { i8*, i32 } %3
; CHECK: ^bb2:
; CHECK: llvm.return %{{[0-9]+}} : !llvm.i32
diff --git a/mlir/test/Target/llvmir.mlir b/mlir/test/Target/llvmir.mlir
index 43cc7d804dae..59c43b82cca5 100644
--- a/mlir/test/Target/llvmir.mlir
+++ b/mlir/test/Target/llvmir.mlir
@@ -1137,7 +1137,7 @@ llvm.func @bar(!llvm<"i8*">) -> !llvm<"i8*">
llvm.func @__gxx_personality_v0(...) -> !llvm.i32
// CHECK-LABEL: @invokeLandingpad
-llvm.func @invokeLandingpad() -> !llvm.i32 {
+llvm.func @invokeLandingpad() -> !llvm.i32 attributes { personality = @__gxx_personality_v0 } {
// CHECK: %[[a1:[0-9]+]] = alloca i8
%0 = llvm.mlir.constant(0 : i32) : !llvm.i32
%1 = llvm.mlir.constant("\01") : !llvm<"[1 x i8]">
More information about the Mlir-commits
mailing list