diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -473,7 +473,7 @@ /// Sema. bool TargetInfo::isValidClobber(StringRef Name) const { return (isValidGCCRegisterName(Name) || - Name == "memory" || Name == "cc"); + Name == "memory" || Name == "cc" || Name == "unwind"); } /// isValidGCCRegisterName - Returns whether the passed in string diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2115,13 +2115,15 @@ } static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect, - bool ReadOnly, bool ReadNone, bool NoMerge, - const AsmStmt &S, + bool HasUnwindClobber, bool ReadOnly, + bool ReadNone, bool NoMerge, const AsmStmt &S, const std::vector &ResultRegTypes, CodeGenFunction &CGF, std::vector &RegResults) { - Result.addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoUnwind); + if (!HasUnwindClobber) + Result.addAttribute(llvm::AttributeList::FunctionIndex, + llvm::Attribute::NoUnwind); + if (NoMerge) Result.addAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::NoMerge); @@ -2468,13 +2470,18 @@ } Constraints += InOutConstraints; + bool HasUnwindClobber = false; + // Clobbers for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { StringRef Clobber = S.getClobber(i); if (Clobber == "memory") ReadOnly = ReadNone = false; - else if (Clobber != "cc") { + else if (Clobber == "unwind") { + HasUnwindClobber = true; + continue; + } else if (Clobber != "cc") { Clobber = getTarget().getNormalizedGCCRegisterName(Clobber); if (CGM.getCodeGenOpts().StackClashProtector && getTarget().isSPRegName(Clobber)) { @@ -2508,6 +2515,9 @@ Constraints += '}'; } + assert(!(HasUnwindClobber && IsGCCAsmGoto) && + "unwind clobber can't be used with asm goto"); + // Add machine specific clobbers std::string MachineClobbers = getTarget().getClobbers(); if (!MachineClobbers.empty()) { @@ -2532,21 +2542,27 @@ llvm::InlineAsm::AD_Intel : llvm::InlineAsm::AD_ATT; llvm::InlineAsm *IA = llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect, - /* IsAlignStack */ false, AsmDialect); + /* IsAlignStack */ false, AsmDialect, + HasUnwindClobber); std::vector RegResults; if (IsGCCAsmGoto) { llvm::CallBrInst *Result = Builder.CreateCallBr(IA, Fallthrough, Transfer, Args); EmitBlock(Fallthrough); - UpdateAsmCallInst(cast(*Result), HasSideEffect, ReadOnly, - ReadNone, InNoMergeAttributedStmt, S, ResultRegTypes, - *this, RegResults); + UpdateAsmCallInst(cast(*Result), HasSideEffect, false, + ReadOnly, ReadNone, InNoMergeAttributedStmt, S, + ResultRegTypes, *this, RegResults); + } else if (HasUnwindClobber) { + llvm::CallBase *Result = EmitCallOrInvoke(IA, Args, ""); + UpdateAsmCallInst(*Result, HasSideEffect, true, ReadOnly, ReadNone, + InNoMergeAttributedStmt, S, ResultRegTypes, *this, + RegResults); } else { llvm::CallInst *Result = Builder.CreateCall(IA, Args, getBundlesForFunclet(IA)); - UpdateAsmCallInst(cast(*Result), HasSideEffect, ReadOnly, - ReadNone, InNoMergeAttributedStmt, S, ResultRegTypes, - *this, RegResults); + UpdateAsmCallInst(cast(*Result), HasSideEffect, false, + ReadOnly, ReadNone, InNoMergeAttributedStmt, S, + ResultRegTypes, *this, RegResults); } assert(RegResults.size() == ResultRegTypes.size()); diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -228,7 +228,7 @@ StringRef Clobber = Clobbers[i]->getString(); // We only check registers, therefore we don't check cc and memory // clobbers - if (Clobber == "cc" || Clobber == "memory") + if (Clobber == "cc" || Clobber == "memory" || Clobber == "unwind") continue; Clobber = Target.getNormalizedGCCRegisterName(Clobber, true); // Go over the output's registers we collected diff --git a/llvm/bindings/go/llvm/ir.go b/llvm/bindings/go/llvm/ir.go --- a/llvm/bindings/go/llvm/ir.go +++ b/llvm/bindings/go/llvm/ir.go @@ -1304,12 +1304,12 @@ } // Operations on inline assembly -func InlineAsm(t Type, asmString, constraints string, hasSideEffects, isAlignStack bool, dialect InlineAsmDialect) (rv Value) { +func InlineAsm(t Type, asmString, constraints string, hasSideEffects, isAlignStack bool, dialect InlineAsmDialect, canThrow bool) (rv Value) { casm := C.CString(asmString) defer C.free(unsafe.Pointer(casm)) cconstraints := C.CString(constraints) defer C.free(unsafe.Pointer(cconstraints)) - rv.C = C.LLVMGetInlineAsm(t.C, casm, C.size_t(len(asmString)), cconstraints, C.size_t(len(constraints)), boolToLLVMBool(hasSideEffects), boolToLLVMBool(isAlignStack), C.LLVMInlineAsmDialect(dialect)) + rv.C = C.LLVMGetInlineAsm(t.C, casm, C.size_t(len(asmString)), cconstraints, C.size_t(len(constraints)), boolToLLVMBool(hasSideEffects), boolToLLVMBool(isAlignStack), C.LLVMInlineAsmDialect(dialect), boolToLLVMBool(canThrow)) return } diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h --- a/llvm/include/llvm-c/Core.h +++ b/llvm/include/llvm-c/Core.h @@ -864,7 +864,8 @@ char *AsmString, size_t AsmStringSize, char *Constraints, size_t ConstraintsSize, LLVMBool HasSideEffects, LLVMBool IsAlignStack, - LLVMInlineAsmDialect Dialect); + LLVMInlineAsmDialect Dialect, + LLVMBool CanThrow); /** * Obtain the context to which this module is associated. diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -372,11 +372,14 @@ CST_CODE_CE_INBOUNDS_GEP = 20, // INBOUNDS_GEP: [n x operands] CST_CODE_BLOCKADDRESS = 21, // CST_CODE_BLOCKADDRESS [fnty, fnval, bb#] CST_CODE_DATA = 22, // DATA: [n x elements] - CST_CODE_INLINEASM = 23, // INLINEASM: [sideeffect|alignstack| + CST_CODE_INLINEASM_OLD2 = 23, // INLINEASM: [sideeffect|alignstack| // asmdialect,asmstr,conststr] CST_CODE_CE_GEP_WITH_INRANGE_INDEX = 24, // [opty, flags, n x operands] CST_CODE_CE_UNOP = 25, // CE_UNOP: [opcode, opval] CST_CODE_POISON = 26, // POISON + CST_CODE_INLINEASM = 27, // INLINEASM: [sideeffect|alignstack| + // asmdialect|unwind, + // asmstr,conststr] }; /// CastOpcodes - These are values used in the bitcode files to encode which diff --git a/llvm/include/llvm/IR/InlineAsm.h b/llvm/include/llvm/IR/InlineAsm.h --- a/llvm/include/llvm/IR/InlineAsm.h +++ b/llvm/include/llvm/IR/InlineAsm.h @@ -44,10 +44,11 @@ bool HasSideEffects; bool IsAlignStack; AsmDialect Dialect; + bool CanThrow; InlineAsm(FunctionType *Ty, const std::string &AsmString, const std::string &Constraints, bool hasSideEffects, - bool isAlignStack, AsmDialect asmDialect); + bool isAlignStack, AsmDialect asmDialect, bool canThrow); /// When the ConstantUniqueMap merges two types and makes two InlineAsms /// identical, it destroys one of them with this method. @@ -62,11 +63,13 @@ static InlineAsm *get(FunctionType *Ty, StringRef AsmString, StringRef Constraints, bool hasSideEffects, bool isAlignStack = false, - AsmDialect asmDialect = AD_ATT); + AsmDialect asmDialect = AD_ATT, + bool canThrow = false); bool hasSideEffects() const { return HasSideEffects; } bool isAlignStack() const { return IsAlignStack; } AsmDialect getDialect() const { return Dialect; } + bool canThrow() const { return CanThrow; } /// getType - InlineAsm's are always pointers. /// diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -3389,18 +3389,19 @@ case lltok::kw_asm: { // ValID ::= 'asm' SideEffect? AlignStack? IntelDialect? STRINGCONSTANT ',' // STRINGCONSTANT - bool HasSideEffect, AlignStack, AsmDialect; + bool HasSideEffect, AlignStack, AsmDialect, CanThrow; Lex.Lex(); if (parseOptionalToken(lltok::kw_sideeffect, HasSideEffect) || parseOptionalToken(lltok::kw_alignstack, AlignStack) || parseOptionalToken(lltok::kw_inteldialect, AsmDialect) || + parseOptionalToken(lltok::kw_unwind, CanThrow) || parseStringConstant(ID.StrVal) || parseToken(lltok::comma, "expected comma in inline asm expression") || parseToken(lltok::StringConstant, "expected constraint string")) return true; ID.StrVal2 = Lex.getStrVal(); ID.UIntVal = unsigned(HasSideEffect) | (unsigned(AlignStack)<<1) | - (unsigned(AsmDialect)<<2); + (unsigned(AsmDialect)<<2) | (unsigned(CanThrow)<<3); ID.Kind = ValID::t_InlineAsm; return false; } @@ -5467,7 +5468,8 @@ return error(ID.Loc, "invalid type for inline asm constraint string"); V = InlineAsm::get(ID.FTy, ID.StrVal, ID.StrVal2, ID.UIntVal & 1, (ID.UIntVal >> 1) & 1, - (InlineAsm::AsmDialect(ID.UIntVal >> 2))); + (InlineAsm::AsmDialect(ID.UIntVal >> 2)), + (ID.UIntVal >> 3) & 1); return false; } case ValID::t_GlobalName: diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2822,7 +2822,7 @@ } // This version adds support for the asm dialect keywords (e.g., // inteldialect). - case bitc::CST_CODE_INLINEASM: { + case bitc::CST_CODE_INLINEASM_OLD2: { if (Record.size() < 2) return error("Invalid record"); std::string AsmStr, ConstrStr; @@ -2847,6 +2847,33 @@ InlineAsm::AsmDialect(AsmDialect)); break; } + // This version adds support for the unwind keyword. + case bitc::CST_CODE_INLINEASM: { + if (Record.size() < 2) + return error("Invalid record"); + std::string AsmStr, ConstrStr; + bool HasSideEffects = Record[0] & 1; + bool IsAlignStack = (Record[0] >> 1) & 1; + unsigned AsmDialect = Record[0] >> 2; + bool CanThrow = (Record[0] >> 3) & 1; + unsigned AsmStrSize = Record[1]; + if (2+AsmStrSize >= Record.size()) + return error("Invalid record"); + unsigned ConstStrSize = Record[2+AsmStrSize]; + if (3+AsmStrSize+ConstStrSize > Record.size()) + return error("Invalid record"); + + for (unsigned i = 0; i != AsmStrSize; ++i) + AsmStr += (char)Record[2+i]; + for (unsigned i = 0; i != ConstStrSize; ++i) + ConstrStr += (char)Record[3+AsmStrSize+i]; + UpgradeInlineAsmString(&AsmStr); + V = InlineAsm::get( + cast(getPointerElementFlatType(CurFullTy)), AsmStr, + ConstrStr, HasSideEffects, IsAlignStack, + InlineAsm::AsmDialect(AsmDialect), CanThrow); + break; + } case bitc::CST_CODE_BLOCKADDRESS:{ if (Record.size() < 3) return error("Invalid record"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2416,7 +2416,8 @@ if (const InlineAsm *IA = dyn_cast(V)) { Record.push_back(unsigned(IA->hasSideEffects()) | unsigned(IA->isAlignStack()) << 1 | - unsigned(IA->getDialect()&1) << 2); + unsigned(IA->getDialect()&1) << 2 | + unsigned(IA->canThrow()) << 3); // Add the asm string. const std::string &AsmStr = IA->getAsmString(); diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -2423,8 +2423,6 @@ const BasicBlock *EHPadBB = I.getSuccessor(1); const Function *Fn = I.getCalledFunction(); - if (I.isInlineAsm()) - return false; // FIXME: support invoking patchpoint and statepoint intrinsics. if (Fn && Fn->isIntrinsic()) @@ -2442,12 +2440,38 @@ if (!isa(EHPadBB->getFirstNonPHI())) return false; + bool LowerInlineAsm = false; + if (I.isInlineAsm()) { + const InlineAsm *IA = cast(I.getCalledOperand()); + if (!IA->canThrow()) { + // Fast path without emitting EH_LABELs. + + if (!translateInlineAsm(I, MIRBuilder)) + return false; + + MachineBasicBlock *InvokeMBB = &MIRBuilder.getMBB(), + *ReturnMBB = &getMBB(*ReturnBB); + + // Update successor info. + addSuccessorWithProb(InvokeMBB, ReturnMBB, BranchProbability::getOne()); + + MIRBuilder.buildBr(*ReturnMBB); + return true; + } else { + LowerInlineAsm = true; + } + } + // Emit the actual call, bracketed by EH_LABELs so that the MF knows about // the region covered by the try. MCSymbol *BeginSymbol = Context.createTempSymbol(); MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(BeginSymbol); - if (!translateCallBase(I, MIRBuilder)) + if (LowerInlineAsm) { + if (!translateInlineAsm(I, MIRBuilder)) + return false; + } + else if (!translateCallBase(I, MIRBuilder)) return false; MCSymbol *EndSymbol = Context.createTempSymbol(); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -755,7 +755,7 @@ void visitStoreToSwiftError(const StoreInst &I); void visitFreeze(const FreezeInst &I); - void visitInlineAsm(const CallBase &Call); + void visitInlineAsm(const CallBase &Call, const BasicBlock *EHPadBB = nullptr); void visitIntrinsicCall(const CallInst &I, unsigned Intrinsic); void visitTargetIntrinsic(const CallInst &I, unsigned Intrinsic); void visitConstrainedFPIntrinsic(const ConstrainedFPIntrinsic &FPI); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2792,7 +2792,7 @@ const Value *Callee(I.getCalledOperand()); const Function *Fn = dyn_cast(Callee); if (isa(Callee)) - visitInlineAsm(I); + visitInlineAsm(I, EHPadBB); else if (Fn && Fn->isIntrinsic()) { switch (Fn->getIntrinsicID()) { default: @@ -8186,7 +8186,8 @@ } // end anonymous namespace /// visitInlineAsm - Handle a call to an InlineAsm object. -void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call) { +void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call, + const BasicBlock *EHPadBB) { const InlineAsm *IA = cast(Call.getCalledOperand()); /// ConstraintOperands - Information about all of the constraints. @@ -8274,19 +8275,46 @@ ExtraInfo.update(T); } - // We won't need to flush pending loads if this asm doesn't touch // memory and is nonvolatile. SDValue Flag, Chain = (HasSideEffect) ? getRoot() : DAG.getRoot(); + bool EmitEHLabels = isa(Call) && IA->canThrow(); + if (EmitEHLabels) { + assert(EHPadBB && "InvokeInst must have an EHPadBB"); + } bool IsCallBr = isa(Call); - if (IsCallBr) { - // If this is a callbr we need to flush pending exports since inlineasm_br - // is a terminator. We need to do this before nodes are glued to - // the inlineasm_br node. + + if (IsCallBr || EmitEHLabels) { + // If this is a callbr or invoke we need to flush pending exports since + // inlineasm_br and invoke are terminators. + // We need to do this before nodes are glued to the inlineasm_br node. Chain = getControlRoot(); } + MCSymbol *BeginLabel = nullptr; + if (EmitEHLabels) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineModuleInfo &MMI = MF.getMMI(); + + // Insert a label before the invoke call to mark the try range. This can be + // used to detect deletion of the invoke via the MachineModuleInfo. + BeginLabel = MMI.getContext().createTempSymbol(); + + // For SjLj, keep track of which landing pads go with which invokes + // so as to maintain the ordering of pads in the LSDA. + unsigned CallSiteIndex = MMI.getCurrentCallSite(); + if (CallSiteIndex) { + MF.setCallSiteBeginLabel(BeginLabel, CallSiteIndex); + LPadToCallSiteMap[FuncInfo.MBBMap[EHPadBB]].push_back(CallSiteIndex); + + // Now that the call site is handled, stop tracking it. + MMI.setCurrentCallSite(0); + } + + Chain = DAG.getEHLabel(getCurSDLoc(), Chain, BeginLabel); + } + // Second pass over the constraints: compute which constraint option to use. for (SDISelAsmOperandInfo &OpInfo : ConstraintOperands) { // If this is an output operand with a matching input operand, look up the @@ -8677,8 +8705,32 @@ if (!OutChains.empty()) Chain = DAG.getNode(ISD::TokenFactor, getCurSDLoc(), MVT::Other, OutChains); + if (EmitEHLabels) { + assert(BeginLabel && "BeginLabel should've been set"); + + MachineFunction &MF = DAG.getMachineFunction(); + MachineModuleInfo &MMI = MF.getMMI(); + + // Insert a label at the end of the invoke call to mark the try range. This + // can be used to detect deletion of the invoke via the MachineModuleInfo. + MCSymbol *EndLabel = MMI.getContext().createTempSymbol(); + Chain = DAG.getEHLabel(getCurSDLoc(), Chain, EndLabel); + + // Inform MachineModuleInfo of range. + auto Pers = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()); + // There is a platform (e.g. wasm) that uses funclet style IR but does not + // actually use outlined funclets and their LSDA info style. + if (MF.hasEHFunclets() && isFuncletEHPersonality(Pers)) { + WinEHFuncInfo *EHInfo = DAG.getMachineFunction().getWinEHFuncInfo(); + EHInfo->addIPToStateRange(cast(&Call), BeginLabel, EndLabel); + } else if (!isScopedEHPersonality(Pers)) { + MF.addInvoke(FuncInfo.MBBMap[EHPadBB], BeginLabel, EndLabel); + } + } + // Only Update Root if inline assembly has a memory effect. - if (ResultValues.empty() || HasSideEffect || !OutChains.empty() || IsCallBr) + if (ResultValues.empty() || HasSideEffect || !OutChains.empty() || IsCallBr || + EmitEHLabels) DAG.setRoot(Chain); } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2440,6 +2440,8 @@ // We don't emit the AD_ATT dialect as it's the assumed default. if (IA->getDialect() == InlineAsm::AD_Intel) Out << "inteldialect "; + if (IA->canThrow()) + Out << "unwind "; Out << '"'; printEscapedString(IA->getAsmString(), Out); Out << "\", \""; diff --git a/llvm/lib/IR/ConstantsContext.h b/llvm/lib/IR/ConstantsContext.h --- a/llvm/lib/IR/ConstantsContext.h +++ b/llvm/lib/IR/ConstantsContext.h @@ -463,24 +463,26 @@ bool HasSideEffects; bool IsAlignStack; InlineAsm::AsmDialect AsmDialect; + bool CanThrow; InlineAsmKeyType(StringRef AsmString, StringRef Constraints, FunctionType *FTy, bool HasSideEffects, bool IsAlignStack, - InlineAsm::AsmDialect AsmDialect) + InlineAsm::AsmDialect AsmDialect, bool canThrow) : AsmString(AsmString), Constraints(Constraints), FTy(FTy), HasSideEffects(HasSideEffects), IsAlignStack(IsAlignStack), - AsmDialect(AsmDialect) {} + AsmDialect(AsmDialect), CanThrow(canThrow) {} InlineAsmKeyType(const InlineAsm *Asm, SmallVectorImpl &) : AsmString(Asm->getAsmString()), Constraints(Asm->getConstraintString()), FTy(Asm->getFunctionType()), HasSideEffects(Asm->hasSideEffects()), - IsAlignStack(Asm->isAlignStack()), AsmDialect(Asm->getDialect()) {} + IsAlignStack(Asm->isAlignStack()), AsmDialect(Asm->getDialect()), + CanThrow(Asm->canThrow()) {} bool operator==(const InlineAsmKeyType &X) const { return HasSideEffects == X.HasSideEffects && IsAlignStack == X.IsAlignStack && AsmDialect == X.AsmDialect && AsmString == X.AsmString && Constraints == X.Constraints && - FTy == X.FTy; + FTy == X.FTy && CanThrow == X.CanThrow; } bool operator==(const InlineAsm *Asm) const { @@ -489,12 +491,13 @@ AsmDialect == Asm->getDialect() && AsmString == Asm->getAsmString() && Constraints == Asm->getConstraintString() && - FTy == Asm->getFunctionType(); + FTy == Asm->getFunctionType() && + CanThrow == Asm->canThrow(); } unsigned getHash() const { return hash_combine(AsmString, Constraints, HasSideEffects, IsAlignStack, - AsmDialect, FTy); + AsmDialect, FTy, CanThrow); } using TypeClass = ConstantInfo::TypeClass; @@ -502,7 +505,7 @@ InlineAsm *create(TypeClass *Ty) const { assert(PointerType::getUnqual(FTy) == Ty); return new InlineAsm(FTy, std::string(AsmString), std::string(Constraints), - HasSideEffects, IsAlignStack, AsmDialect); + HasSideEffects, IsAlignStack, AsmDialect, CanThrow); } }; diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -448,7 +448,8 @@ char *AsmString, size_t AsmStringSize, char *Constraints, size_t ConstraintsSize, LLVMBool HasSideEffects, LLVMBool IsAlignStack, - LLVMInlineAsmDialect Dialect) { + LLVMInlineAsmDialect Dialect, + LLVMBool CanThrow) { InlineAsm::AsmDialect AD; switch (Dialect) { case LLVMInlineAsmDialectATT: @@ -461,7 +462,7 @@ return wrap(InlineAsm::get(unwrap(Ty), StringRef(AsmString, AsmStringSize), StringRef(Constraints, ConstraintsSize), - HasSideEffects, IsAlignStack, AD)); + HasSideEffects, IsAlignStack, AD, CanThrow)); } diff --git a/llvm/lib/IR/InlineAsm.cpp b/llvm/lib/IR/InlineAsm.cpp --- a/llvm/lib/IR/InlineAsm.cpp +++ b/llvm/lib/IR/InlineAsm.cpp @@ -29,11 +29,11 @@ InlineAsm::InlineAsm(FunctionType *FTy, const std::string &asmString, const std::string &constraints, bool hasSideEffects, - bool isAlignStack, AsmDialect asmDialect) + bool isAlignStack, AsmDialect asmDialect, bool canThrow) : Value(PointerType::getUnqual(FTy), Value::InlineAsmVal), AsmString(asmString), Constraints(constraints), FTy(FTy), HasSideEffects(hasSideEffects), IsAlignStack(isAlignStack), - Dialect(asmDialect) { + Dialect(asmDialect), CanThrow(canThrow) { // Do various checks on the constraint string and type. assert(Verify(getFunctionType(), constraints) && "Function type not legal for constraints!"); @@ -41,9 +41,10 @@ InlineAsm *InlineAsm::get(FunctionType *FTy, StringRef AsmString, StringRef Constraints, bool hasSideEffects, - bool isAlignStack, AsmDialect asmDialect) { + bool isAlignStack, AsmDialect asmDialect, + bool canThrow) { InlineAsmKeyType Key(AsmString, Constraints, FTy, hasSideEffects, - isAlignStack, asmDialect); + isAlignStack, asmDialect, canThrow); LLVMContextImpl *pImpl = FTy->getContext().pImpl; return pImpl->InlineAsms.getOrCreate(PointerType::getUnqual(FTy), Key); } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -56,6 +56,7 @@ #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/IR/ValueHandle.h" +#include "llvm/IR/InlineAsm.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" @@ -2121,9 +2122,13 @@ } if (isa(Callee) && !Call.doesNotThrow()) { - // Inline asm calls cannot throw - mark them 'nounwind'. - Call.setDoesNotThrow(); - Changed = true; + InlineAsm *IA = cast(Callee); + if (!IA->canThrow()) { + // Normal inline asm calls cannot throw - mark them + // 'nounwind'. + Call.setDoesNotThrow(); + Changed = true; + } } // Try to optimize the call if possible, we require DataLayout for most of diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -56,6 +56,7 @@ #include "llvm/IR/Type.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" +#include "llvm/IR/InlineAsm.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" @@ -543,9 +544,16 @@ // instructions require no special handling. CallInst *CI = dyn_cast(I); - if (!CI || CI->doesNotThrow() || CI->isInlineAsm()) + if (!CI || CI->doesNotThrow()) continue; + if (CI->isInlineAsm()) { + InlineAsm *IA = cast(CI->getCalledOperand()); + if (!IA->canThrow()) { + continue; + } + } + // We do not need to (and in fact, cannot) convert possibly throwing calls // to @llvm.experimental_deoptimize (resp. @llvm.experimental.guard) into // invokes. The caller's "segment" of the deoptimization continuation