https://github.com/pcc updated https://github.com/llvm/llvm-project/pull/181301
>From b9c689dbc3163a6b54547570c8d92801eabc857b Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <[email protected]> Date: Thu, 12 Feb 2026 19:38:56 -0800 Subject: [PATCH 1/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?= =?UTF-8?q?anges=20to=20main=20this=20commit=20is=20based=20on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.6-beta.1 [skip ci] --- clang/lib/CodeGen/CGExpr.cpp | 17 +- clang/test/CodeGenCXX/sanitize-trap-loop.cpp | 10 +- llvm/docs/LangRef.rst | 22 +++ llvm/include/llvm/IR/Intrinsics.td | 2 + llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp | 37 +++++ .../PreISelIntrinsicLowering/looptrap.ll | 155 ++++++++++++++++++ 6 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 llvm/test/Transforms/PreISelIntrinsicLowering/looptrap.ll diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 8de1c53b1b213..a0a1a5675654c 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -4438,12 +4438,6 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) { void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID, bool NoMerge, const TrapReason *TR) { - if (CGM.getCodeGenOpts().SanitizeTrapLoop) { - Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::cond_loop), - Builder.CreateNot(Checked)); - return; - } - llvm::BasicBlock *Cont = createBasicBlock("cont"); // If we're optimizing, collapse all calls to trap down to just one per @@ -4495,9 +4489,14 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, ApplyDebugLocation applyTrapDI(*this, TrapLocation); - llvm::CallInst *TrapCall = - Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::ubsantrap), - llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID)); + llvm::CallInst *TrapCall; + if (CGM.getCodeGenOpts().SanitizeTrapLoop) + TrapCall = + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::looptrap)); + else + TrapCall = Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::ubsantrap), + llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID)); if (!CGM.getCodeGenOpts().TrapFuncName.empty()) { auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name", diff --git a/clang/test/CodeGenCXX/sanitize-trap-loop.cpp b/clang/test/CodeGenCXX/sanitize-trap-loop.cpp index ee083c52f5c30..3c7af1af907c0 100644 --- a/clang/test/CodeGenCXX/sanitize-trap-loop.cpp +++ b/clang/test/CodeGenCXX/sanitize-trap-loop.cpp @@ -6,15 +6,17 @@ struct A { void vcall(A *a) { // CHECK: [[TEST:%.*]] = call i1 @llvm.type.test - // CHECK-NEXT: [[NOT:%.*]] = xor i1 [[TEST]], true - // CHECK-NEXT: call void @llvm.cond.loop(i1 [[NOT]]) + // CHECK-NEXT: br i1 [[TEST]], label %cont, label %trap + // CHECK: trap: + // CHECK-NEXT: call void @llvm.looptrap() a->f(); } int overflow(int a, int b) { // CHECK: [[OVERFLOW:%.*]] = extractvalue { i32, i1 } %2, 1, !nosanitize // CHECK-NEXT: [[NOTOVERFLOW:%.*]] = xor i1 [[OVERFLOW]], true, !nosanitize - // CHECK-NEXT: [[NOTNOTOVERFLOW:%.*]] = xor i1 [[NOTOVERFLOW]], true, !nosanitize - // CHECK-NEXT: call void @llvm.cond.loop(i1 [[NOTNOTOVERFLOW]]) + // CHECK-NEXT: br i1 [[NOTOVERFLOW]], label %cont, label %trap + // CHECK: trap: + // CHECK-NEXT: call void @llvm.looptrap() return a + b; } diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 00a4a00c5bf95..801da46d06658 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -32294,3 +32294,25 @@ itself. Specifically, the first byte of the instruction will be between 0x70 and 0x7F, and the second byte will be 0xFE. There are currently no guarantees about instructions used by other backends. + +'``llvm.looptrap``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare void @llvm.looptrap() cold noreturn nounwind + +Overview: +""""""""" + +The '``llvm.looptrap``' intrinsic is equivalent to +``llvm.cond.loop(true)``. Its main raison d'ĂȘtre is that it is also +considered to be ``noreturn``, which enables certain optimizations by +allowing the optimizer to assume that a branch leading to a call to +this intrinsic was not taken. A late optimization pass will convert this +intrinsic to either ``llvm.cond.loop(true)`` or llvm.cond.loop(pred)``, +where ``pred`` is a predicate for a conditional branch leading to the +intrinsic call, if possible. diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 46e7b4b5c9491..a1c91486f7c3c 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1911,6 +1911,8 @@ def int_debugtrap : Intrinsic<[]>, def int_ubsantrap : Intrinsic<[], [llvm_i8_ty], [IntrNoReturn, IntrCold, ImmArg<ArgIndex<0>>, IntrInaccessibleMemOnly, IntrWriteMem]>; +def int_looptrap : Intrinsic<[], [], [IntrNoReturn, IntrCold, + IntrInaccessibleMemOnly, IntrWriteMem]>; // Return true if ubsan check is allowed. def int_allow_ubsan_check : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_i8_ty], diff --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp index a8f94afe8c023..2dbc20c933a1b 100644 --- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp +++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/PreISelIntrinsicLowering.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/ObjCARCInstKind.h" #include "llvm/Analysis/ObjCARCUtil.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -631,6 +632,36 @@ static bool expandCondLoop(Function &Intr) { return true; } +static bool expandLoopTrap(Function &Intr) { + for (User *U : make_early_inc_range(Intr.users())) { + auto *Call = cast<CallInst>(U); + if (!Call->getParent()->isEntryBlock() && + std::all_of(Call->getParent()->begin(), BasicBlock::iterator(Call), + [](Instruction &I) { return !I.mayHaveSideEffects(); })) { + for (auto *BB : predecessors(Call->getParent())) { + auto *BI = dyn_cast<BranchInst>(BB->getTerminator()); + if (!BI || BI->isUnconditional()) + continue; + IRBuilder<> B(BI); + Value *Cond; + if (BI->getSuccessor(0) == Call->getParent()) { + Cond = BI->getCondition(); + BI->setCondition(ConstantInt::getFalse(BI->getContext())); + } else { + Cond = B.CreateNot(BI->getCondition()); + BI->setCondition(ConstantInt::getTrue(BI->getContext())); + } + B.CreateIntrinsic(Intrinsic::cond_loop, Cond); + } + } + IRBuilder<> B(Call); + B.CreateIntrinsic(Intrinsic::cond_loop, + ConstantInt::getTrue(Call->getContext())); + Call->eraseFromParent(); + } + return true; +} + bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const { // Map unique constants to globals. DenseMap<Constant *, GlobalVariable *> CMap; @@ -780,6 +811,12 @@ bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const { if (!TM->canLowerCondLoop()) Changed |= expandCondLoop(F); break; + case Intrinsic::looptrap: + Changed |= expandLoopTrap(F); + if (!TM->canLowerCondLoop()) + if (auto *CondLoop = M.getFunction("llvm.cond.loop")) + Changed |= expandCondLoop(*CondLoop); + break; } } return Changed; diff --git a/llvm/test/Transforms/PreISelIntrinsicLowering/looptrap.ll b/llvm/test/Transforms/PreISelIntrinsicLowering/looptrap.ll new file mode 100644 index 0000000000000..06b96f76d50b8 --- /dev/null +++ b/llvm/test/Transforms/PreISelIntrinsicLowering/looptrap.ll @@ -0,0 +1,155 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; REQUIRES: x86-registered-target, mips-registered-target +; RUN: opt -mtriple=x86_64 -passes=pre-isel-intrinsic-lowering -S < %s | FileCheck --check-prefix=X86 %s +; RUN: opt -mtriple=mips64 -passes=pre-isel-intrinsic-lowering -S < %s | FileCheck --check-prefix=MIPS %s + +define void @f1(i64 %a, i64 %b, i64 %c, i64 %d) { +; X86-LABEL: define void @f1( +; X86-SAME: i64 [[A:%.*]], i64 [[B:%.*]], i64 [[C:%.*]], i64 [[D:%.*]]) { +; X86-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]] +; X86-NEXT: call void @llvm.cond.loop(i1 [[CMP]]) +; X86-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT1:.*]] +; X86: [[CONT1]]: +; X86-NEXT: [[CMP2:%.*]] = icmp ult i64 [[C]], [[D]] +; X86-NEXT: [[TMP1:%.*]] = xor i1 [[CMP2]], true +; X86-NEXT: call void @llvm.cond.loop(i1 [[TMP1]]) +; X86-NEXT: br i1 true, label %[[CONT2:.*]], label %[[TRAP]] +; X86: [[CONT2]]: +; X86-NEXT: ret void +; X86: [[TRAP]]: +; X86-NEXT: call void @llvm.cond.loop(i1 true) +; X86-NEXT: unreachable +; +; MIPS-LABEL: define void @f1( +; MIPS-SAME: i64 [[A:%.*]], i64 [[B:%.*]], i64 [[C:%.*]], i64 [[D:%.*]]) { +; MIPS-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]] +; MIPS-NEXT: br i1 [[CMP]], label %[[BB1:.*]], label %[[BB2:.*]] +; MIPS: [[BB1]]: +; MIPS-NEXT: br label %[[BB1]] +; MIPS: [[BB2]]: +; MIPS-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT1:.*]] +; MIPS: [[CONT1]]: +; MIPS-NEXT: [[CMP2:%.*]] = icmp ult i64 [[C]], [[D]] +; MIPS-NEXT: [[TMP3:%.*]] = xor i1 [[CMP2]], true +; MIPS-NEXT: br i1 [[TMP3]], label %[[BB4:.*]], label %[[BB5:.*]] +; MIPS: [[BB4]]: +; MIPS-NEXT: br label %[[BB4]] +; MIPS: [[BB5]]: +; MIPS-NEXT: br i1 true, label %[[CONT2:.*]], label %[[TRAP]] +; MIPS: [[CONT2]]: +; MIPS-NEXT: ret void +; MIPS: [[TRAP]]: +; MIPS-NEXT: br i1 true, label %[[BB6:.*]], label %[[BB7:.*]] +; MIPS: [[BB6]]: +; MIPS-NEXT: br label %[[BB6]] +; MIPS: [[BB7]]: +; MIPS-NEXT: unreachable +; + %cmp = icmp ult i64 %a, %b + br i1 %cmp, label %trap, label %cont1 + +cont1: + %cmp2 = icmp ult i64 %c, %d + br i1 %cmp2, label %cont2, label %trap + +cont2: + ret void + +trap: + call void @llvm.looptrap() + unreachable +} + +define void @f2() { +; X86-LABEL: define void @f2() { +; X86-NEXT: call void @llvm.cond.loop(i1 true) +; X86-NEXT: ret void +; +; MIPS-LABEL: define void @f2() { +; MIPS-NEXT: br i1 true, label %[[BB1:.*]], label %[[BB2:.*]] +; MIPS: [[BB1]]: +; MIPS-NEXT: br label %[[BB1]] +; MIPS: [[BB2]]: +; MIPS-NEXT: ret void +; + call void @llvm.looptrap() + ret void +} + +define void @f3() personality ptr @foo { +; X86-LABEL: define void @f3() personality ptr @foo { +; X86-NEXT: invoke void @foo() +; X86-NEXT: to label %[[CONT:.*]] unwind label %[[TRAP:.*]] +; X86: [[CONT]]: +; X86-NEXT: ret void +; X86: [[TRAP]]: +; X86-NEXT: [[PAD:%.*]] = landingpad { ptr, i32 } +; X86-NEXT: cleanup +; X86-NEXT: call void @llvm.cond.loop(i1 true) +; X86-NEXT: unreachable +; +; MIPS-LABEL: define void @f3() personality ptr @foo { +; MIPS-NEXT: invoke void @foo() +; MIPS-NEXT: to label %[[CONT:.*]] unwind label %[[TRAP:.*]] +; MIPS: [[CONT]]: +; MIPS-NEXT: ret void +; MIPS: [[TRAP]]: +; MIPS-NEXT: [[PAD:%.*]] = landingpad { ptr, i32 } +; MIPS-NEXT: cleanup +; MIPS-NEXT: br i1 true, label %[[BB1:.*]], label %[[BB2:.*]] +; MIPS: [[BB1]]: +; MIPS-NEXT: br label %[[BB1]] +; MIPS: [[BB2]]: +; MIPS-NEXT: unreachable +; + invoke void @foo() to label %cont unwind label %trap + +cont: + ret void + +trap: + %pad = landingpad { ptr, i32 } cleanup + call void @llvm.looptrap() + unreachable +} + + +define void @f4(i64 %a, i64 %b, ptr %p) { +; X86-LABEL: define void @f4( +; X86-SAME: i64 [[A:%.*]], i64 [[B:%.*]], ptr [[P:%.*]]) { +; X86-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]] +; X86-NEXT: br i1 [[CMP]], label %[[TRAP:.*]], label %[[CONT:.*]] +; X86: [[CONT]]: +; X86-NEXT: ret void +; X86: [[TRAP]]: +; X86-NEXT: store volatile i32 1, ptr [[P]], align 4 +; X86-NEXT: call void @llvm.cond.loop(i1 true) +; X86-NEXT: unreachable +; +; MIPS-LABEL: define void @f4( +; MIPS-SAME: i64 [[A:%.*]], i64 [[B:%.*]], ptr [[P:%.*]]) { +; MIPS-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]] +; MIPS-NEXT: br i1 [[CMP]], label %[[TRAP:.*]], label %[[CONT:.*]] +; MIPS: [[CONT]]: +; MIPS-NEXT: ret void +; MIPS: [[TRAP]]: +; MIPS-NEXT: store volatile i32 1, ptr [[P]], align 4 +; MIPS-NEXT: br i1 true, label %[[BB1:.*]], label %[[BB2:.*]] +; MIPS: [[BB1]]: +; MIPS-NEXT: br label %[[BB1]] +; MIPS: [[BB2]]: +; MIPS-NEXT: unreachable +; + %cmp = icmp ult i64 %a, %b + br i1 %cmp, label %trap, label %cont + +cont: + ret void + +trap: + store volatile i32 1, ptr %p + call void @llvm.looptrap() + unreachable +} + +declare void @foo() >From cbae61b82b36260124b3bd91eb37e7686b836bac Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <[email protected]> Date: Fri, 13 Feb 2026 14:04:11 -0800 Subject: [PATCH 2/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?= =?UTF-8?q?anges=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.6-beta.1 [skip ci] --- llvm/docs/LangRef.rst | 14 +++++++------- llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp | 11 +++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 801da46d06658..50a2515f69189 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -32309,10 +32309,10 @@ Overview: """"""""" The '``llvm.looptrap``' intrinsic is equivalent to -``llvm.cond.loop(true)``. Its main raison d'ĂȘtre is that it is also -considered to be ``noreturn``, which enables certain optimizations by -allowing the optimizer to assume that a branch leading to a call to -this intrinsic was not taken. A late optimization pass will convert this -intrinsic to either ``llvm.cond.loop(true)`` or llvm.cond.loop(pred)``, -where ``pred`` is a predicate for a conditional branch leading to the -intrinsic call, if possible. +``llvm.cond.loop(true)``, but is also considered to be ``noreturn``, +which enables certain optimizations by allowing the optimizer to +assume that a branch leading to a call to this intrinsic was not +taken. A late optimization pass will convert this intrinsic to either +``llvm.cond.loop(true)`` or ``llvm.cond.loop(pred)``, where ``pred`` +is a predicate for a conditional branch leading to the intrinsic call, +if possible. diff --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp index 2dbc20c933a1b..649f422b822c6 100644 --- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp +++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp @@ -644,10 +644,21 @@ static bool expandLoopTrap(Function &Intr) { continue; IRBuilder<> B(BI); Value *Cond; + // The looptrap can either be on the true branch or the false branch. + // We insert the cond loop before the branch, which uses the branch's + // original condition for going to the looptrap as its condition, and + // force the branch to take whichever path does not lead to the + // looptrap, as the original path to the looptrap is now unreachable + // thanks to the cond loop. The codegenprepare pass will clean up our + // "unconditional conditional branch" by combining the two basic blocks + // if possible, or replacing it with an unconditional branch. if (BI->getSuccessor(0) == Call->getParent()) { + // The looptrap is on the true branch. Cond = BI->getCondition(); BI->setCondition(ConstantInt::getFalse(BI->getContext())); } else { + // The looptrap is on the false branch, which means that we need to + // invert the condition. Cond = B.CreateNot(BI->getCondition()); BI->setCondition(ConstantInt::getTrue(BI->getContext())); } >From 1b93b8a5488de67ca6659f610d0614b89bbbd34b Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <[email protected]> Date: Fri, 13 Feb 2026 14:10:51 -0800 Subject: [PATCH 3/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?= =?UTF-8?q?anges=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.6-beta.1 [skip ci] --- llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp index 649f422b822c6..0544995f979f7 100644 --- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp +++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp @@ -653,7 +653,7 @@ static bool expandLoopTrap(Function &Intr) { // "unconditional conditional branch" by combining the two basic blocks // if possible, or replacing it with an unconditional branch. if (BI->getSuccessor(0) == Call->getParent()) { - // The looptrap is on the true branch. + // The looptrap is on the true branch. Cond = BI->getCondition(); BI->setCondition(ConstantInt::getFalse(BI->getContext())); } else { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
