Author: Florian Mayer Date: 2026-06-03T16:46:48-07:00 New Revision: 5be046268f78dc1eef49a080228aadaf506b44ff
URL: https://github.com/llvm/llvm-project/commit/5be046268f78dc1eef49a080228aadaf506b44ff DIFF: https://github.com/llvm/llvm-project/commit/5be046268f78dc1eef49a080228aadaf506b44ff.diff LOG: Revert "Remove the optional bitcast between a musttail call and its ret (#201…" This reverts commit 91b00526a599fa21e43da82438f1e9c8a8e1b7b3. Added: Modified: llvm/lib/Bitcode/Reader/BitcodeReader.cpp llvm/lib/IR/BasicBlock.cpp llvm/lib/IR/Verifier.cpp llvm/lib/Transforms/Utils/InlineFunction.cpp llvm/test/Instrumentation/AddressSanitizer/musttail.ll llvm/test/Instrumentation/ThreadSanitizer/tsan_musttail.ll llvm/test/Transforms/CallSiteSplitting/musttail.ll llvm/test/Transforms/SafeStack/X86/musttail.ll llvm/test/Verifier/musttail-invalid.ll Removed: llvm/test/Bitcode/musttail-bitcast-upgrade.ll llvm/test/Bitcode/musttail-bitcast-upgrade.ll.bc ################################################################################ diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 4df54f259ad10..3e863f4786e1a 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -7149,19 +7149,6 @@ Error BitcodeReader::materialize(GlobalValue *GV) { UpgradeIntrinsicCall(CI, It->second); } } - - // Old bitcode allowed an optional bitcast between a musttail call and its - // return. Under opaque pointers that cast is always a no-op, and the - // verifier no longer accepts it, so drop it. - if (auto *BC = dyn_cast<BitCastInst>(&I); - BC && BC->getSrcTy() == BC->getDestTy() && - isa_and_nonnull<ReturnInst>(BC->getNextNode())) { - if (auto *CI = dyn_cast<CallInst>(BC->getOperand(0)); - CI && CI->isMustTailCall() && CI->getNextNode() == BC) { - BC->replaceAllUsesWith(CI); - BC->eraseFromParent(); - } - } } // Look for functions that rely on old function attribute behavior. diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp index 03e38b3b89061..d611e9c2d0a96 100644 --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -239,6 +239,14 @@ const CallInst *BasicBlock::getTerminatingMustTailCall() const { if (Value *RV = RI->getReturnValue()) { if (RV != Prev) return nullptr; + + // Look through the optional bitcast. + if (auto *BI = dyn_cast<BitCastInst>(Prev)) { + RV = BI->getOperand(0); + Prev = BI->getPrevNode(); + if (!Prev || RV != Prev) + return nullptr; + } } if (auto *CI = dyn_cast<CallInst>(Prev)) { diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 344314e39c38a..c9639d1420bfc 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -4246,6 +4246,18 @@ void Verifier::verifyTailCCMustTailAttrs(const AttrBuilder &Attrs, Twine("byref attribute not allowed in ") + Context); } +/// Two types are "congruent" if they are identical, or if they are both pointer +/// types with diff erent pointee types and the same address space. +static bool isTypeCongruent(Type *L, Type *R) { + if (L == R) + return true; + PointerType *PL = dyn_cast<PointerType>(L); + PointerType *PR = dyn_cast<PointerType>(R); + if (!PL || !PR) + return false; + return PL->getAddressSpace() == PR->getAddressSpace(); +} + static AttrBuilder getParameterABIAttributes(LLVMContext& C, unsigned I, AttributeList Attrs) { static const Attribute::AttrKind ABIAttrs[] = { Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca, @@ -4275,21 +4287,32 @@ void Verifier::verifyMustTailCall(CallInst &CI) { FunctionType *CalleeTy = CI.getFunctionType(); Check(CallerTy->isVarArg() == CalleeTy->isVarArg(), "cannot guarantee tail call due to mismatched varargs", &CI); - Check(CallerTy->getReturnType() == CalleeTy->getReturnType(), + Check(isTypeCongruent(CallerTy->getReturnType(), CalleeTy->getReturnType()), "cannot guarantee tail call due to mismatched return types", &CI); // - The calling conventions of the caller and callee must match. Check(F->getCallingConv() == CI.getCallingConv(), "cannot guarantee tail call due to mismatched calling conv", &CI); - // - The call must immediately precede a :ref:`ret <i_ret>` instruction. - // - The ret instruction must return the value produced by the call or void. + // - The call must immediately precede a :ref:`ret <i_ret>` instruction, + // or a pointer bitcast followed by a ret instruction. + // - The ret instruction must return the (possibly bitcasted) value + // produced by the call or void. + Value *RetVal = &CI; Instruction *Next = CI.getNextNode(); + // Handle the optional bitcast. + if (BitCastInst *BI = dyn_cast_or_null<BitCastInst>(Next)) { + Check(BI->getOperand(0) == RetVal, + "bitcast following musttail call must use the call", BI); + RetVal = BI; + Next = BI->getNextNode(); + } + // Check the return. ReturnInst *Ret = dyn_cast_or_null<ReturnInst>(Next); - Check(Ret, "musttail call must precede a ret", &CI); - Check(!Ret->getReturnValue() || Ret->getReturnValue() == &CI || + Check(Ret, "musttail call must precede a ret with an optional bitcast", &CI); + Check(!Ret->getReturnValue() || Ret->getReturnValue() == RetVal || isa<UndefValue>(Ret->getReturnValue()), "musttail call result must be returned", Ret); @@ -4318,14 +4341,16 @@ void Verifier::verifyMustTailCall(CallInst &CI) { return; } - // - The caller and callee prototypes must match. + // - The caller and callee prototypes must match. Pointer types of + // parameters or return types may diff er in pointee type, but not + // address space. if (!CI.getIntrinsicID()) { Check(CallerTy->getNumParams() == CalleeTy->getNumParams(), "cannot guarantee tail call due to mismatched parameter counts", &CI); for (unsigned I = 0, E = CallerTy->getNumParams(); I != E; ++I) { - Check(CallerTy->getParamType(I) == CalleeTy->getParamType(I), - "cannot guarantee tail call due to mismatched parameter types", - &CI); + Check( + isTypeCongruent(CallerTy->getParamType(I), CalleeTy->getParamType(I)), + "cannot guarantee tail call due to mismatched parameter types", &CI); } } diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index be186ffbf7e42..1d3f66509b1c5 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -3300,13 +3300,32 @@ void llvm::InlineFunctionImpl(CallBase &CB, InlineFunctionInfo &IFI, // musttail. Therefore it's safe to return without merging control into the // phi below. if (InlinedMustTailCalls) { + // Check if we need to bitcast the result of any musttail calls. + Type *NewRetTy = Caller->getReturnType(); + bool NeedBitCast = !CB.use_empty() && CB.getType() != NewRetTy; + // Handle the returns preceded by musttail calls separately. SmallVector<ReturnInst *, 8> NormalReturns; for (ReturnInst *RI : Returns) { CallInst *ReturnedMustTail = RI->getParent()->getTerminatingMustTailCall(); - if (!ReturnedMustTail) + if (!ReturnedMustTail) { NormalReturns.push_back(RI); + continue; + } + if (!NeedBitCast) + continue; + + // Delete the old return and any preceding bitcast. + BasicBlock *CurBB = RI->getParent(); + auto *OldCast = dyn_cast_or_null<BitCastInst>(RI->getReturnValue()); + RI->eraseFromParent(); + if (OldCast) + OldCast->eraseFromParent(); + + // Insert a new bitcast and return with the right type. + IRBuilder<> Builder(CurBB); + Builder.CreateRet(Builder.CreateBitCast(ReturnedMustTail, NewRetTy)); } // Leave behind the normal returns so we can merge control flow. @@ -3528,7 +3547,7 @@ void llvm::InlineFunctionImpl(CallBase &CB, InlineFunctionInfo &IFI, CB.eraseFromParent(); // If we inlined any musttail calls and the original return is now - // unreachable, delete it. It can only contain a ret. + // unreachable, delete it. It can only contain a bitcast and ret. if (InlinedMustTailCalls && pred_empty(AfterCallBB)) AfterCallBB->eraseFromParent(); diff --git a/llvm/test/Bitcode/musttail-bitcast-upgrade.ll b/llvm/test/Bitcode/musttail-bitcast-upgrade.ll deleted file mode 100644 index 63c24778a067c..0000000000000 --- a/llvm/test/Bitcode/musttail-bitcast-upgrade.ll +++ /dev/null @@ -1,32 +0,0 @@ -; RUN: llvm-dis %s.bc -o - | FileCheck %s -; RUN: verify-uselistorder %s.bc - -; musttail-bitcast-upgrade.ll.bc was produced from the IR below using an -; llvm-as that still emitted the optional no-op bitcast between a musttail call -; and its return. The reader must drop that bitcast so the module verifies. - -; CHECK-LABEL: define ptr @caller(ptr %a) -; CHECK-NEXT: %c = musttail call ptr @callee(ptr %a) -; CHECK-NEXT: ret ptr %c - -define ptr @callee(ptr %a) { - ret ptr %a -} - -define ptr @caller(ptr %a) { - %c = musttail call ptr @callee(ptr %a) - %b = bitcast ptr %c to ptr - ret ptr %b -} - -; CHECK-LABEL: define i32 @caller_i32(ptr %a) -; CHECK-NEXT: %c = musttail call i32 @callee_i32(ptr %a) -; CHECK-NEXT: ret i32 %c - -declare i32 @callee_i32(ptr %a) - -define i32 @caller_i32(ptr %a) { - %c = musttail call i32 @callee_i32(ptr %a) - %b = bitcast i32 %c to i32 - ret i32 %b -} diff --git a/llvm/test/Bitcode/musttail-bitcast-upgrade.ll.bc b/llvm/test/Bitcode/musttail-bitcast-upgrade.ll.bc deleted file mode 100644 index 57c6bade7ebfe..0000000000000 Binary files a/llvm/test/Bitcode/musttail-bitcast-upgrade.ll.bc and /dev/null diff er diff --git a/llvm/test/Instrumentation/AddressSanitizer/musttail.ll b/llvm/test/Instrumentation/AddressSanitizer/musttail.ll index 8ec87693d1859..fed4521c195a4 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/musttail.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/musttail.ll @@ -18,3 +18,17 @@ define i32 @call_foo(ptr %a) sanitize_address { ; CHECK-LABEL: define i32 @call_foo(ptr %a) ; CHECK: %r = musttail call i32 @foo(ptr %a) ; CHECK-NEXT: ret i32 %r + + +define i32 @call_foo_cast(ptr %a) sanitize_address { + %x = alloca [10 x i8], align 1 + call void @alloca_test_use(ptr %x) + %r = musttail call i32 @foo(ptr %a) + %t = bitcast i32 %r to i32 + ret i32 %t +} + +; CHECK-LABEL: define i32 @call_foo_cast(ptr %a) +; CHECK: %r = musttail call i32 @foo(ptr %a) +; CHECK-NEXT: %t = bitcast i32 %r to i32 +; CHECK-NEXT: ret i32 %t diff --git a/llvm/test/Instrumentation/ThreadSanitizer/tsan_musttail.ll b/llvm/test/Instrumentation/ThreadSanitizer/tsan_musttail.ll index 2d16a82f666d1..5e56aa2d11068 100644 --- a/llvm/test/Instrumentation/ThreadSanitizer/tsan_musttail.ll +++ b/llvm/test/Instrumentation/ThreadSanitizer/tsan_musttail.ll @@ -15,3 +15,16 @@ define i32 @call_preallocated_musttail(ptr preallocated(i32) %a) sanitize_thread ; CHECK: call void @__tsan_func_exit() ; CHECK-NEXT: %r = musttail call i32 @preallocated_musttail(ptr preallocated(i32) %a) ; CHECK-NEXT: ret i32 %r + + +define i32 @call_preallocated_musttail_cast(ptr preallocated(i32) %a) sanitize_thread { + %r = musttail call i32 @preallocated_musttail(ptr preallocated(i32) %a) + %t = bitcast i32 %r to i32 + ret i32 %t +} + +; CHECK-LABEL: define i32 @call_preallocated_musttail_cast(ptr preallocated(i32) %a) +; CHECK: call void @__tsan_func_exit() +; CHECK-NEXT: %r = musttail call i32 @preallocated_musttail(ptr preallocated(i32) %a) +; CHECK-NEXT: %t = bitcast i32 %r to i32 +; CHECK-NEXT: ret i32 %t diff --git a/llvm/test/Transforms/CallSiteSplitting/musttail.ll b/llvm/test/Transforms/CallSiteSplitting/musttail.ll index 1993e1e97e403..0f989a2ae4ad1 100644 --- a/llvm/test/Transforms/CallSiteSplitting/musttail.ll +++ b/llvm/test/Transforms/CallSiteSplitting/musttail.ll @@ -1,5 +1,29 @@ ; RUN: opt < %s -passes=callsite-splitting -verify-dom-info -S | FileCheck %s +;CHECK-LABEL: @caller +;CHECK-LABEL: Top.split: +;CHECK: %ca1 = musttail call ptr @callee(ptr null, ptr %b) +;CHECK: %cb2 = bitcast ptr %ca1 to ptr +;CHECK: ret ptr %cb2 +;CHECK-LABEL: TBB.split +;CHECK: %ca3 = musttail call ptr @callee(ptr nonnull %a, ptr null) +;CHECK: %cb4 = bitcast ptr %ca3 to ptr +;CHECK: ret ptr %cb4 +define ptr @caller(ptr %a, ptr %b) { +Top: + %c = icmp eq ptr %a, null + br i1 %c, label %Tail, label %TBB +TBB: + %c2 = icmp eq ptr %b, null + br i1 %c2, label %Tail, label %End +Tail: + %ca = musttail call ptr @callee(ptr %a, ptr %b) + %cb = bitcast ptr %ca to ptr + ret ptr %cb +End: + ret ptr null +} + define ptr @callee(ptr %a, ptr %b) noinline { ret ptr %a } diff --git a/llvm/test/Transforms/SafeStack/X86/musttail.ll b/llvm/test/Transforms/SafeStack/X86/musttail.ll index 317bc3920fb1b..0289729f53b50 100644 --- a/llvm/test/Transforms/SafeStack/X86/musttail.ll +++ b/llvm/test/Transforms/SafeStack/X86/musttail.ll @@ -24,3 +24,22 @@ define i32 @call_foo(ptr %a) safestack { %r = musttail call i32 @foo(ptr %a) ret i32 %r } + +define i32 @call_foo_cast(ptr %a) safestack { +; CHECK-LABEL: @call_foo_cast( +; CHECK-NEXT: [[UNSAFE_STACK_PTR:%.*]] = load ptr, ptr @__safestack_unsafe_stack_ptr, align 8 +; CHECK-NEXT: [[UNSAFE_STACK_STATIC_TOP:%.*]] = getelementptr i8, ptr [[UNSAFE_STACK_PTR]], i32 -16 +; CHECK-NEXT: store ptr [[UNSAFE_STACK_STATIC_TOP]], ptr @__safestack_unsafe_stack_ptr, align 8 +; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[UNSAFE_STACK_PTR]], i32 -10 +; CHECK-NEXT: call void @alloca_test_use(ptr [[TMP1]]) +; CHECK-NEXT: store ptr [[UNSAFE_STACK_PTR]], ptr @__safestack_unsafe_stack_ptr, align 8 +; CHECK-NEXT: [[R:%.*]] = musttail call i32 @foo(ptr [[A:%.*]]) +; CHECK-NEXT: [[T:%.*]] = bitcast i32 [[R]] to i32 +; CHECK-NEXT: ret i32 [[T]] +; + %x = alloca [10 x i8], align 1 + call void @alloca_test_use(ptr %x) + %r = musttail call i32 @foo(ptr %a) + %t = bitcast i32 %r to i32 + ret i32 %t +} diff --git a/llvm/test/Verifier/musttail-invalid.ll b/llvm/test/Verifier/musttail-invalid.ll index 849967ee9d487..b9109a09bb543 100644 --- a/llvm/test/Verifier/musttail-invalid.ll +++ b/llvm/test/Verifier/musttail-invalid.ll @@ -69,7 +69,7 @@ define void @mismatched_alignment(ptr byval(i32) align 4 %a) { declare i32 @not_tail_pos_callee() define i32 @not_tail_pos() { -; CHECK: musttail call must precede a ret +; CHECK: musttail call must precede a ret with an optional bitcast %v = musttail call i32 @not_tail_pos_callee() %w = add i32 %v, 1 ret i32 %w _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
