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 @@ -475,8 +475,8 @@ /// a valid clobber in an inline asm statement. This is used by /// Sema. bool TargetInfo::isValidClobber(StringRef Name) const { - return (isValidGCCRegisterName(Name) || - Name == "memory" || Name == "cc"); + return (isValidGCCRegisterName(Name) || 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()) { @@ -2530,23 +2540,28 @@ bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0; llvm::InlineAsm::AsmDialect AsmDialect = isa(&S) ? llvm::InlineAsm::AD_Intel : llvm::InlineAsm::AD_ATT; - llvm::InlineAsm *IA = - llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect, - /* IsAlignStack */ false, AsmDialect); + llvm::InlineAsm *IA = llvm::InlineAsm::get( + FTy, AsmString, Constraints, HasSideEffect, + /* 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