Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -8386,7 +8386,7 @@ :: - = [tail | musttail] call [cconv] [ret attrs] [*] () [fn attrs] + = [tail | musttail | notail ] call [cconv] [ret attrs] [*] () [fn attrs] [ operand bundles ] Overview: @@ -8439,6 +8439,10 @@ - `Platform-specific constraints are met. `_ +#. The optional ``notail`` marker indicates that the optimizers should not add + ``tail`` or ``musttail`` markers to the call. It is used to prevent tail + call optimization from being performed on the call. + #. The optional "cconv" marker indicates which :ref:`calling convention ` the call should use. If none is specified, the call defaults to using C calling conventions. The Index: llvm/trunk/include/llvm/IR/Instructions.h =================================================================== --- llvm/trunk/include/llvm/IR/Instructions.h +++ llvm/trunk/include/llvm/IR/Instructions.h @@ -1489,16 +1489,21 @@ } // Note that 'musttail' implies 'tail'. - enum TailCallKind { TCK_None = 0, TCK_Tail = 1, TCK_MustTail = 2 }; + enum TailCallKind { TCK_None = 0, TCK_Tail = 1, TCK_MustTail = 2, + TCK_NoTail = 3 }; TailCallKind getTailCallKind() const { return TailCallKind(getSubclassDataFromInstruction() & 3); } bool isTailCall() const { - return (getSubclassDataFromInstruction() & 3) != TCK_None; + unsigned Kind = getSubclassDataFromInstruction() & 3; + return Kind == TCK_Tail || Kind == TCK_MustTail; } bool isMustTailCall() const { return (getSubclassDataFromInstruction() & 3) == TCK_MustTail; } + bool isNoTailCall() const { + return (getSubclassDataFromInstruction() & 3) == TCK_NoTail; + } void setTailCall(bool isTC = true) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~3) | unsigned(isTC ? TCK_Tail : TCK_None)); Index: llvm/trunk/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLLexer.cpp +++ llvm/trunk/lib/AsmParser/LLLexer.cpp @@ -527,6 +527,7 @@ KEYWORD(caller); KEYWORD(tail); KEYWORD(musttail); + KEYWORD(notail); KEYWORD(target); KEYWORD(triple); KEYWORD(unwind); Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -4830,6 +4830,7 @@ case lltok::kw_call: return ParseCall(Inst, PFS, CallInst::TCK_None); case lltok::kw_tail: return ParseCall(Inst, PFS, CallInst::TCK_Tail); case lltok::kw_musttail: return ParseCall(Inst, PFS, CallInst::TCK_MustTail); + case lltok::kw_notail: return ParseCall(Inst, PFS, CallInst::TCK_NoTail); // Memory. case lltok::kw_alloca: return ParseAlloc(Inst, PFS); case lltok::kw_load: return ParseLoad(Inst, PFS); Index: llvm/trunk/lib/AsmParser/LLToken.h =================================================================== --- llvm/trunk/lib/AsmParser/LLToken.h +++ llvm/trunk/lib/AsmParser/LLToken.h @@ -54,6 +54,7 @@ kw_caller, kw_tail, kw_musttail, + kw_notail, kw_target, kw_triple, kw_unwind, Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -5002,6 +5002,8 @@ TCK = CallInst::TCK_Tail; if (CCInfo & (1 << 14)) TCK = CallInst::TCK_MustTail; + if (CCInfo & (1 << 16)) + TCK = CallInst::TCK_NoTail; cast(I)->setTailCallKind(TCK); cast(I)->setAttributes(PAL); break; Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2131,7 +2131,8 @@ Vals.push_back(VE.getAttributeID(CI.getAttributes())); Vals.push_back((CI.getCallingConv() << 1) | unsigned(CI.isTailCall()) | - unsigned(CI.isMustTailCall()) << 14 | 1 << 15); + unsigned(CI.isMustTailCall()) << 14 | 1 << 15 | + unsigned(CI.isNoTailCall()) << 16); Vals.push_back(VE.getTypeID(FTy)); PushValueAndType(CI.getCalledValue(), InstID, Vals, VE); // Callee Index: llvm/trunk/lib/IR/AsmWriter.cpp =================================================================== --- llvm/trunk/lib/IR/AsmWriter.cpp +++ llvm/trunk/lib/IR/AsmWriter.cpp @@ -2768,6 +2768,8 @@ Out << "musttail "; else if (CI->isTailCall()) Out << "tail "; + else if (CI->isNoTailCall()) + Out << "notail "; } // Print out the opcode... Index: llvm/trunk/lib/Transforms/Scalar/TailRecursionElimination.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/TailRecursionElimination.cpp +++ llvm/trunk/lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -304,7 +304,9 @@ if (!CI || CI->isTailCall()) continue; - if (CI->doesNotAccessMemory()) { + bool IsNoTail = CI->isNoTailCall(); + + if (!IsNoTail && CI->doesNotAccessMemory()) { // A call to a readnone function whose arguments are all things computed // outside this function can be marked tail. Even if you stored the // alloca address into a global, a readnone function can't load the @@ -332,7 +334,7 @@ } } - if (Escaped == UNESCAPED && !Tracker.AllocaUsers.count(CI)) { + if (!IsNoTail && Escaped == UNESCAPED && !Tracker.AllocaUsers.count(CI)) { DeferredTails.push_back(CI); } else { AllCallsAreTailCalls = false; Index: llvm/trunk/test/Bitcode/compatibility.ll =================================================================== --- llvm/trunk/test/Bitcode/compatibility.ll +++ llvm/trunk/test/Bitcode/compatibility.ll @@ -1144,6 +1144,13 @@ ret void } +define void @instructions.call_notail() { + notail call void @f1() + ; CHECK: notail call void @f1() + + ret void +} + define void @instructions.landingpad() personality i32 -2 { invoke void @llvm.donothing() to label %proceed unwind label %catch1 invoke void @llvm.donothing() to label %proceed unwind label %catch2 Index: llvm/trunk/test/Transforms/TailCallElim/notail.ll =================================================================== --- llvm/trunk/test/Transforms/TailCallElim/notail.ll +++ llvm/trunk/test/Transforms/TailCallElim/notail.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -tailcallelim -S | FileCheck %s + +; CHECK: tail call void @callee0() +; CHECK: notail call void @callee1() + +define void @foo1(i32 %a) { +entry: + %tobool = icmp eq i32 %a, 0 + br i1 %tobool, label %if.else, label %if.then + +if.then: + call void @callee0() + br label %if.end + +if.else: + notail call void @callee1() + br label %if.end + +if.end: + ret void +} + +declare void @callee0() +declare void @callee1()