Index: mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td =================================================================== --- mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -489,6 +489,18 @@ 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(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(); }]; @@ -629,7 +641,8 @@ def LLVM_LLVMFuncOp : LLVM_ZeroResultOp<"func", [IsolatedFromAbove, FunctionLike, Symbol]>, Arguments<(ins DefaultValuedAttr:$linkage)> { + "Linkage::External">:$linkage, + OptionalAttr:$personality)> { let summary = "LLVM dialect function, has wrapped LLVM IR function type"; let regions = (region AnyRegion:$body); @@ -655,6 +668,9 @@ bool isVarArg() { return getType().getUnderlyingType()->isFunctionVarArg(); } + void setPersonalityFn(FlatSymbolRefAttr personality) { + setAttr("personality", personality); + } // Hook for OpTrait::FunctionLike, returns the number of function arguments. // Depends on the type attribute being correct as checked by verifyType. Index: mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp =================================================================== --- mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -372,6 +372,11 @@ static LogicalResult verify(LandingpadOp op) { Value value; + if (LLVMFuncOp func = op.getParentOfType()) { + 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 " Index: mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp =================================================================== --- mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp +++ mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp @@ -60,6 +60,8 @@ 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. @@ -465,7 +467,7 @@ // FIXME: switch // FIXME: indirectbr // FIXME: invoke - // FIXME: resume + INST(Resume, Resume), // FIXME: unreachable // FIXME: cleanupret // FIXME: catchret @@ -579,6 +581,7 @@ 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: @@ -692,8 +695,11 @@ for (unsigned i = 0, ie = lpi->getNumClauses(); i < ie; i++) ops.push_back(processConstant(lpi->getClause(i))); - b.create(loc, processType(lpi->getType()), lpi->isCleanup(), - ops); + Type ty = processType(lpi->getType()); + if (!ty) + return failure(); + + v = b.create(loc, ty, lpi->isCleanup(), ops); return success(); } case llvm::Instruction::Invoke: { @@ -747,6 +753,34 @@ } } +FlatSymbolRefAttr Importer::getPersonalityAsAttr(llvm::Function *f) { + FlatSymbolRefAttr personality; + if (f->hasPersonalityFn()) { + llvm::Constant *pf = f->getPersonalityFn(); + + // If it directly has a name, we can use it. + if (pf->hasName()) + personality = 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(pf)) { + if (auto bc = + dyn_cast_or_null(ce->getAsInstruction())) { + if (bc->getDestTy() == + llvm::Type::getInt8PtrTy(b.getContext() + ->getRegisteredDialect() + ->getLLVMContext())) { + if (auto func = dyn_cast(bc->getOperand(0))) + personality = b.getSymbolRefAttr(func->getName()); + } + // Delete the zombie instruction. + bc->deleteValue(); + } + } + } + return personality; +} + LogicalResult Importer::processFunction(llvm::Function *f) { blocks.clear(); instMap.clear(); @@ -759,6 +793,13 @@ b.setInsertionPoint(module.getBody(), getFuncInsertPt()); LLVMFuncOp fop = b.create(UnknownLoc::get(context), f->getName(), functionType); + + if (FlatSymbolRefAttr personality = getPersonalityAsAttr(f)) + fop.setPersonalityFn(personality); + else if (f->hasPersonalityFn()) + emitWarning(UnknownLoc::get(context), + "could not deduce personality, skipping it"); + if (f->isDeclaration()) return success(); Index: mlir/lib/Target/LLVMIR/ModuleTranslation.cpp =================================================================== --- mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -95,7 +95,8 @@ if (auto floatAttr = attr.dyn_cast()) return llvm::ConstantFP::get(llvmType, floatAttr.getValue()); if (auto funcAttr = attr.dyn_cast()) - return functionMapping.lookup(funcAttr.getValue()); + return llvm::ConstantExpr::getBitCast( + functionMapping.lookup(funcAttr.getValue()), llvmType); if (auto splatAttr = attr.dyn_cast()) { auto *sequentialType = cast(llvmType); auto elementType = sequentialType->getElementType(); @@ -346,6 +347,7 @@ if (auto constOperand = dyn_cast(operand)) lpi->addClause(constOperand); } + valueMapping[lpOp.getResult()] = lpi; return success(); } @@ -562,6 +564,14 @@ 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) { @@ -623,8 +633,10 @@ ModuleTranslation::lookupValues(ValueRange values) { SmallVector 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; } Index: mlir/test/Dialect/LLVMIR/invalid.mlir =================================================================== --- mlir/test/Dialect/LLVMIR/invalid.mlir +++ mlir/test/Dialect/LLVMIR/invalid.mlir @@ -515,7 +515,7 @@ 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 @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 @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 @@ -561,3 +561,51 @@ %2 = llvm.landingpad : !llvm<"{ i8*, i32 }"> llvm.return %0 : !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 {{expected SSA operand}} + llvm.resume : !llvm<"{ i8*, 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 @__gxx_personality_v0(...) -> !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 }"> +} Index: mlir/test/Dialect/LLVMIR/roundtrip.mlir =================================================================== --- mlir/test/Dialect/LLVMIR/roundtrip.mlir +++ mlir/test/Dialect/LLVMIR/roundtrip.mlir @@ -238,7 +238,7 @@ 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 @@ %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 Index: mlir/test/Target/import.ll =================================================================== --- mlir/test/Target/import.ll +++ mlir/test/Target/import.ll @@ -282,8 +282,7 @@ ; 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 Index: mlir/test/Target/llvmir.mlir =================================================================== --- mlir/test/Target/llvmir.mlir +++ mlir/test/Target/llvmir.mlir @@ -1137,7 +1137,7 @@ 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]">