forked from OSchip/llvm-project
[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
This commit is contained in:
parent
718d94187d
commit
ff77397fcf
|
@ -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);
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -60,6 +60,8 @@ public:
|
|||
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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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@+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@+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@+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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]">
|
||||
|
|
Loading…
Reference in New Issue