From c35973bfb04731fa91591044d6d2408099dcccd3 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 6 Nov 2015 23:55:38 +0000 Subject: [PATCH] Add 'notail' marker for call instructions. This marker prevents optimization passes from adding 'tail' or 'musttail' markers to a call. Is is used to prevent tail call optimization from being performed on the call. rdar://problem/22667622 Differential Revision: http://reviews.llvm.org/D12923 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252368 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LangRef.rst | 6 ++++- include/llvm/IR/Instructions.h | 9 +++++-- lib/AsmParser/LLLexer.cpp | 1 + lib/AsmParser/LLParser.cpp | 1 + lib/AsmParser/LLToken.h | 1 + lib/Bitcode/Reader/BitcodeReader.cpp | 2 ++ lib/Bitcode/Writer/BitcodeWriter.cpp | 3 ++- lib/IR/AsmWriter.cpp | 2 ++ .../Scalar/TailRecursionElimination.cpp | 6 +++-- test/Bitcode/compatibility.ll | 7 ++++++ test/Transforms/TailCallElim/notail.ll | 24 +++++++++++++++++++ 11 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 test/Transforms/TailCallElim/notail.ll diff --git a/docs/LangRef.rst b/docs/LangRef.rst index d2bba5c8a74..d58b7b2e4df 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -8386,7 +8386,7 @@ Syntax: :: - = [tail | musttail] call [cconv] [ret attrs] [*] () [fn attrs] + = [tail | musttail | notail ] call [cconv] [ret attrs] [*] () [fn attrs] [ operand bundles ] Overview: @@ -8439,6 +8439,10 @@ This instruction requires several arguments: - `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 diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index c2ade1994f5..263d0918d84 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -1489,16 +1489,21 @@ public: } // 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)); diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 82d6eb7788c..91ce1fd7669 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -527,6 +527,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(caller); KEYWORD(tail); KEYWORD(musttail); + KEYWORD(notail); KEYWORD(target); KEYWORD(triple); KEYWORD(unwind); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 7feb99d555c..aabd9716118 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -4830,6 +4830,7 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB, 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); diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index ecd6481e6fa..6980790c098 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -54,6 +54,7 @@ namespace lltok { kw_caller, kw_tail, kw_musttail, + kw_notail, kw_target, kw_triple, kw_unwind, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index bc846192fcf..a0029b26ff9 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -5002,6 +5002,8 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { 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; diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 941e54765f5..b88e55c92cb 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2131,7 +2131,8 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, 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 diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index db757508594..2f8a3406a37 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -2768,6 +2768,8 @@ void AssemblyWriter::printInstruction(const Instruction &I) { Out << "musttail "; else if (CI->isTailCall()) Out << "tail "; + else if (CI->isNoTailCall()) + Out << "notail "; } // Print out the opcode... diff --git a/lib/Transforms/Scalar/TailRecursionElimination.cpp b/lib/Transforms/Scalar/TailRecursionElimination.cpp index 1eddef7ef94..7e1ba2c3c90 100644 --- a/lib/Transforms/Scalar/TailRecursionElimination.cpp +++ b/lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -304,7 +304,9 @@ bool TailCallElim::markTails(Function &F, bool &AllCallsAreTailCalls) { 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 @@ bool TailCallElim::markTails(Function &F, bool &AllCallsAreTailCalls) { } } - if (Escaped == UNESCAPED && !Tracker.AllocaUsers.count(CI)) { + if (!IsNoTail && Escaped == UNESCAPED && !Tracker.AllocaUsers.count(CI)) { DeferredTails.push_back(CI); } else { AllCallsAreTailCalls = false; diff --git a/test/Bitcode/compatibility.ll b/test/Bitcode/compatibility.ll index 73c24f0370a..49689a99237 100644 --- a/test/Bitcode/compatibility.ll +++ b/test/Bitcode/compatibility.ll @@ -1144,6 +1144,13 @@ define void @instructions.call_musttail(i8* inalloca %val) { 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 diff --git a/test/Transforms/TailCallElim/notail.ll b/test/Transforms/TailCallElim/notail.ll new file mode 100644 index 00000000000..e6fdbd1ec77 --- /dev/null +++ b/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() -- 2.34.1