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

Reply via email to