[clang] [clang][CodeGen] Add range metadata for atomic load of boolean type. #131476 (PR #133546)

Jan Górski via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 11 05:33:02 PDT 2025


https://github.com/janagor updated https://github.com/llvm/llvm-project/pull/133546

>From 4581169d6fbe72357bb83b95fe36c8cc606efa1e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20G=C3=B3rski?= <jan.a.gorski at wp.pl>
Date: Fri, 28 Mar 2025 23:36:18 +0100
Subject: [PATCH 1/9] [clang][CodeGen] Added llvm ir pre-commit test.

---
 clang/test/CodeGen/atomic-ops-load.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 clang/test/CodeGen/atomic-ops-load.c

diff --git a/clang/test/CodeGen/atomic-ops-load.c b/clang/test/CodeGen/atomic-ops-load.c
new file mode 100644
index 0000000000000..adcaf9a2112fa
--- /dev/null
+++ b/clang/test/CodeGen/atomic-ops-load.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple riscv64 -O1 -emit-llvm %s -o - | FileCheck %s
+#include <stdbool.h>
+
+extern bool t1;
+bool test1(void) {
+// CHECK-LABEL: define{{.*}} i1 @test1
+// CHECK: load atomic i8, ptr @t1 monotonic, align 1
+// CHECK-NEXT: trunc i8 %{{.*}} to i1
+// CHECK-NEXT: ret i1 %{{.*}}
+  return __atomic_load_n(&t1, __ATOMIC_RELAXED);
+}

>From 852b691fac487b3cef7b0df8875c26573bc58daa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20G=C3=B3rski?= <jan.a.gorski at wp.pl>
Date: Sat, 29 Mar 2025 00:53:23 +0100
Subject: [PATCH 2/9] [clang][CodeGen] Added `!range` metadata to atomic load
 for `bool`.

---
 clang/lib/CodeGen/CGAtomic.cpp       | 23 +++++++++++++++++++++++
 clang/test/CodeGen/atomic-ops-load.c |  4 ++--
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index 3adb2a7ad207f..70ae7180a9adc 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -590,6 +590,29 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
     llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
     Load->setAtomic(Order, Scope);
     Load->setVolatile(E->isVolatile());
+
+    if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
+      CGF.Builder.CreateStore(Load, Dest);
+      return;
+    }
+
+    QualType Ty = E->getValueType();
+    if (!Ty->isBooleanType()) {
+      CGF.Builder.CreateStore(Load, Dest);
+      return;
+    }
+
+    llvm::MDBuilder MDHelper(CGF.getLLVMContext());
+    llvm::APInt BooleanMin = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
+    llvm::APInt BooleanEnd = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
+
+    if (llvm::MDNode *RangeInfo =
+        MDHelper.createRange(BooleanMin, BooleanEnd)) {
+      Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
+      Load->setMetadata(llvm::LLVMContext::MD_noundef,
+          llvm::MDNode::get(CGF.getLLVMContext(), {}));
+    }
+
     CGF.Builder.CreateStore(Load, Dest);
     return;
   }
diff --git a/clang/test/CodeGen/atomic-ops-load.c b/clang/test/CodeGen/atomic-ops-load.c
index adcaf9a2112fa..778a7ebdc2618 100644
--- a/clang/test/CodeGen/atomic-ops-load.c
+++ b/clang/test/CodeGen/atomic-ops-load.c
@@ -4,8 +4,8 @@
 extern bool t1;
 bool test1(void) {
 // CHECK-LABEL: define{{.*}} i1 @test1
-// CHECK: load atomic i8, ptr @t1 monotonic, align 1
-// CHECK-NEXT: trunc i8 %{{.*}} to i1
+// CHECK: load atomic i8, ptr @t1 monotonic, align 1, !range ![[$WS_RANGE:[0-9]*]], !noundef !{{[0-9]+}}
+// CHECK-NEXT: trunc nuw i8 %{{.*}} to i1
 // CHECK-NEXT: ret i1 %{{.*}}
   return __atomic_load_n(&t1, __ATOMIC_RELAXED);
 }

>From e42772bbc0851696d73ded4abc3edf651f4e8b41 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20G=C3=B3rski?= <jan.a.gorski at wp.pl>
Date: Sat, 29 Mar 2025 01:12:18 +0100
Subject: [PATCH 3/9] Updated codestyle.

---
 clang/lib/CodeGen/CGAtomic.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index 70ae7180a9adc..2c9613deef744 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -607,10 +607,10 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
     llvm::APInt BooleanEnd = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
 
     if (llvm::MDNode *RangeInfo =
-        MDHelper.createRange(BooleanMin, BooleanEnd)) {
+            MDHelper.createRange(BooleanMin, BooleanEnd)) {
       Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
       Load->setMetadata(llvm::LLVMContext::MD_noundef,
-          llvm::MDNode::get(CGF.getLLVMContext(), {}));
+                        llvm::MDNode::get(CGF.getLLVMContext(), {}));
     }
 
     CGF.Builder.CreateStore(Load, Dest);

>From c95f16cf2df51e8f7a1d4952918c977104271072 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20G=C3=B3rski?= <jan.a.gorski at wp.pl>
Date: Fri, 4 Apr 2025 11:20:30 +0200
Subject: [PATCH 4/9] Refactored early returns into normal if statement.

---
 clang/lib/CodeGen/CGAtomic.cpp | 29 ++++++++++-------------------
 1 file changed, 10 insertions(+), 19 deletions(-)

diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index 2c9613deef744..c40bf3cd77d86 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -591,26 +591,17 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
     Load->setAtomic(Order, Scope);
     Load->setVolatile(E->isVolatile());
 
-    if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
-      CGF.Builder.CreateStore(Load, Dest);
-      return;
-    }
-
     QualType Ty = E->getValueType();
-    if (!Ty->isBooleanType()) {
-      CGF.Builder.CreateStore(Load, Dest);
-      return;
-    }
-
-    llvm::MDBuilder MDHelper(CGF.getLLVMContext());
-    llvm::APInt BooleanMin = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
-    llvm::APInt BooleanEnd = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
-
-    if (llvm::MDNode *RangeInfo =
-            MDHelper.createRange(BooleanMin, BooleanEnd)) {
-      Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
-      Load->setMetadata(llvm::LLVMContext::MD_noundef,
-                        llvm::MDNode::get(CGF.getLLVMContext(), {}));
+    if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 && Ty->isBooleanType()) {
+      llvm::MDBuilder MDHelper(CGF.getLLVMContext());
+      llvm::APInt BooleanMin = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
+      llvm::APInt BooleanEnd = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
+      if (llvm::MDNode *RangeInfo =
+              MDHelper.createRange(BooleanMin, BooleanEnd)) {
+        Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
+        Load->setMetadata(llvm::LLVMContext::MD_noundef,
+                          llvm::MDNode::get(CGF.getLLVMContext(), {}));
+      }
     }
 
     CGF.Builder.CreateStore(Load, Dest);

>From ecc0f4060b9192128837539ddab9797922cc5955 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20G=C3=B3rski?= <jan.a.gorski at wp.pl>
Date: Thu, 10 Apr 2025 11:51:38 +0200
Subject: [PATCH 5/9] Reverted adding `range!` metadata from 852b691fac48.
 Added `isSafeNUWTrunc` helper to `EmitFromMemory` to allow adding `nuw` to
 `load` when safe.

---
 clang/lib/CodeGen/CGAtomic.cpp                | 14 -----
 clang/lib/CodeGen/CGExpr.cpp                  | 58 ++++++++++++++++++-
 clang/test/C/drs/dr335.c                      |  2 +-
 clang/test/CodeGen/PowerPC/bool_test.c        |  2 +-
 clang/test/CodeGen/atomic-ops-load.c          |  2 +-
 .../attr-likelihood-if-branch-weights.cpp     | 32 +++++-----
 clang/test/CodeGenObjC/arc-ternary-op.m       |  2 +-
 7 files changed, 76 insertions(+), 36 deletions(-)

diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index c40bf3cd77d86..3adb2a7ad207f 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -590,20 +590,6 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
     llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
     Load->setAtomic(Order, Scope);
     Load->setVolatile(E->isVolatile());
-
-    QualType Ty = E->getValueType();
-    if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 && Ty->isBooleanType()) {
-      llvm::MDBuilder MDHelper(CGF.getLLVMContext());
-      llvm::APInt BooleanMin = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
-      llvm::APInt BooleanEnd = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
-      if (llvm::MDNode *RangeInfo =
-              MDHelper.createRange(BooleanMin, BooleanEnd)) {
-        Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
-        Load->setMetadata(llvm::LLVMContext::MD_noundef,
-                          llvm::MDNode::get(CGF.getLLVMContext(), {}));
-      }
-    }
-
     CGF.Builder.CreateStore(Load, Dest);
     return;
   }
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3d3a111f0514a..f6d0442261eb7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2093,6 +2093,57 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
   return Value;
 }
 
+static bool isSafeNUWTrunc(llvm::Value *V, llvm::Type *DestTy) {
+  if (!V || !DestTy || !DestTy->isIntegerTy())
+    return false;
+
+  unsigned SrcBits = V->getType()->getIntegerBitWidth();
+  unsigned DestBits = DestTy->getIntegerBitWidth();
+
+  if (DestBits >= SrcBits)
+    return false;
+  if (V->getType()->isIntegerTy(1))
+    return true;
+  if (llvm::ZExtInst *Zext = dyn_cast<llvm::ZExtInst>(V)) {
+    if (Zext->getSrcTy()->isIntegerTy(1) && DestBits == 1)
+      return true;
+  }
+  if (llvm::LoadInst *I = dyn_cast<llvm::LoadInst>(V)) {
+    if (llvm::MDNode *RangeMD = I->getMetadata(llvm::LLVMContext::MD_range)) {
+      if (RangeMD->getNumOperands() == 2) {
+        llvm::ConstantAsMetadata *LowMD =
+            cast<llvm::ConstantAsMetadata>(RangeMD->getOperand(0));
+        llvm::ConstantAsMetadata *HighMD =
+            cast<llvm::ConstantAsMetadata>(RangeMD->getOperand(1));
+
+        if (LowMD && HighMD) {
+          llvm::ConstantInt *LowConst =
+              dyn_cast<llvm::ConstantInt>(LowMD->getValue());
+          llvm::ConstantInt *HighConst =
+              dyn_cast<llvm::ConstantInt>(HighMD->getValue());
+
+          if (LowConst && HighConst) {
+            llvm::APInt HighVal = HighConst->getValue();
+            llvm::APInt MaxVal =
+                llvm::APInt(HighVal.getBitWidth(), 1ULL << DestBits);
+
+            if (HighVal.ule(MaxVal)) {
+              return true;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  if (llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(V)) {
+    llvm::APInt Val = CI->getValue();
+    return Val.ule(llvm::APInt::getMaxValue(DestBits));
+  }
+
+  return false;
+}
+
 /// Converts a scalar value from its load/store type (as returned
 /// by convertTypeForLoadStore) to its primary IR type (as returned
 /// by ConvertType).
@@ -2111,9 +2162,12 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
   }
 
   llvm::Type *ResTy = ConvertType(Ty);
+  bool IsSafe = isSafeNUWTrunc(Value, ResTy);
+
   if (hasBooleanRepresentation(Ty) || Ty->isBitIntType() ||
-      Ty->isExtVectorBoolType())
-    return Builder.CreateTrunc(Value, ResTy, "loadedv");
+      Ty->isExtVectorBoolType()) {
+    return Builder.CreateTrunc(Value, ResTy, "loadedv", /*IsNUW*/ IsSafe);
+  }
 
   return Value;
 }
diff --git a/clang/test/C/drs/dr335.c b/clang/test/C/drs/dr335.c
index 3ce6ce5bd53ca..8bbd119b88c20 100644
--- a/clang/test/C/drs/dr335.c
+++ b/clang/test/C/drs/dr335.c
@@ -45,6 +45,6 @@ void dr335(void) {
   // CHECK-NEXT: %[[CLEAR2:.+]] = and i8 %[[LOAD2]], -2
   // CHECK-NEXT: %[[SET:.+]] = or i8 %[[CLEAR2]], %[[ZERO]]
   // CHECK-NEXT: store i8 %[[SET]], ptr {{.+}}, align 1
-  // CHECK-NEXT: {{.+}} = trunc i8 %[[ZERO]] to i1
+  // CHECK-NEXT: {{.+}} = trunc nuw i8 %[[ZERO]] to i1
 }
 
diff --git a/clang/test/CodeGen/PowerPC/bool_test.c b/clang/test/CodeGen/PowerPC/bool_test.c
index d3e7db3c66dad..6b5b4fe5dc202 100644
--- a/clang/test/CodeGen/PowerPC/bool_test.c
+++ b/clang/test/CodeGen/PowerPC/bool_test.c
@@ -10,7 +10,7 @@ void f(_Bool *x, _Bool *y) {
 
 // CHECK-LABEL: define{{.*}} void @f(
 // CHECK: [[FROMMEM:%.*]] = load i8, ptr %
-// CHECK: [[BOOLVAL:%.*]] = trunc i8 [[FROMMEM]] to i1
+// CHECK: [[BOOLVAL:%.*]] = trunc nuw i8 [[FROMMEM]] to i1
 // CHECK: [[TOMEM:%.*]] = zext i1 [[BOOLVAL]] to i8
 // CHECK: store i8 [[TOMEM]]
 // CHECK: ret void
diff --git a/clang/test/CodeGen/atomic-ops-load.c b/clang/test/CodeGen/atomic-ops-load.c
index 778a7ebdc2618..f737f23ad6aea 100644
--- a/clang/test/CodeGen/atomic-ops-load.c
+++ b/clang/test/CodeGen/atomic-ops-load.c
@@ -4,7 +4,7 @@
 extern bool t1;
 bool test1(void) {
 // CHECK-LABEL: define{{.*}} i1 @test1
-// CHECK: load atomic i8, ptr @t1 monotonic, align 1, !range ![[$WS_RANGE:[0-9]*]], !noundef !{{[0-9]+}}
+// CHECK: load atomic i8, ptr @t1 monotonic, align 1
 // CHECK-NEXT: trunc nuw i8 %{{.*}} to i1
 // CHECK-NEXT: ret i1 %{{.*}}
   return __atomic_load_n(&t1, __ATOMIC_RELAXED);
diff --git a/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp b/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
index a77593f5df738..e502d6582054e 100644
--- a/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
+++ b/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
@@ -10,7 +10,7 @@ extern bool B();
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2:![0-9]+]], !range [[RNG6:![0-9]+]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 true)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -37,7 +37,7 @@ bool f() {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -65,7 +65,7 @@ bool g() {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -90,7 +90,7 @@ bool h() {
 // CHECK-LABEL: @_Z8NullStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 // CHECK:       if.then:
@@ -113,7 +113,7 @@ void NullStmt() {
 // CHECK-LABEL: @_Z6IfStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
 // CHECK:       if.then:
@@ -125,7 +125,7 @@ void NullStmt() {
 // CHECK-NEXT:    br label [[IF_END2]]
 // CHECK:       if.end2:
 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL3:%.*]] = trunc i8 [[TMP1]] to i1
+// CHECK-NEXT:    [[TOBOOL3:%.*]] = trunc nuw i8 [[TMP1]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_END8:%.*]]
 // CHECK:       if.then4:
 // CHECK-NEXT:    [[CALL5:%.*]] = call noundef zeroext i1 @_Z1Bv()
@@ -152,7 +152,7 @@ void IfStmt() {
 // CHECK-LABEL: @_Z9WhileStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -166,7 +166,7 @@ void IfStmt() {
 // CHECK-NEXT:    br label [[IF_END]]
 // CHECK:       if.end:
 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
+// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc nuw i8 [[TMP1]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
 // CHECK:       if.then2:
 // CHECK-NEXT:    br label [[WHILE_COND3:%.*]]
@@ -194,7 +194,7 @@ void WhileStmt() {
 // CHECK-LABEL: @_Z6DoStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -208,7 +208,7 @@ void WhileStmt() {
 // CHECK-NEXT:    br label [[IF_END]]
 // CHECK:       if.end:
 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
+// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc nuw i8 [[TMP1]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
 // CHECK:       if.then2:
 // CHECK-NEXT:    br label [[DO_BODY3:%.*]]
@@ -237,7 +237,7 @@ void DoStmt() {
 // CHECK-LABEL: @_Z7ForStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -251,7 +251,7 @@ void DoStmt() {
 // CHECK-NEXT:    br label [[IF_END]]
 // CHECK:       if.end:
 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
+// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc nuw i8 [[TMP1]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
 // CHECK:       if.then2:
 // CHECK-NEXT:    br label [[FOR_COND3:%.*]]
@@ -278,7 +278,7 @@ void ForStmt() {
 // CHECK-LABEL: @_Z8GotoStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 // CHECK:       if.then:
@@ -304,7 +304,7 @@ end:;
 // CHECK-LABEL: @_Z10ReturnStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 // CHECK:       if.then:
@@ -327,7 +327,7 @@ void ReturnStmt() {
 // CHECK-LABEL: @_Z10SwitchStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 // CHECK:       if.then:
@@ -341,7 +341,7 @@ void ReturnStmt() {
 // CHECK-NEXT:    br label [[IF_END]]
 // CHECK:       if.end:
 // CHECK-NEXT:    [[TMP2:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP2]] to i1
+// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc nuw i8 [[TMP2]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE4:%.*]]
 // CHECK:       if.then2:
 // CHECK-NEXT:    [[TMP3:%.*]] = load volatile i32, ptr @i, align 4, !tbaa [[TBAA15]]
diff --git a/clang/test/CodeGenObjC/arc-ternary-op.m b/clang/test/CodeGenObjC/arc-ternary-op.m
index 4a3c00c9807a9..51fc33ec29966 100644
--- a/clang/test/CodeGenObjC/arc-ternary-op.m
+++ b/clang/test/CodeGenObjC/arc-ternary-op.m
@@ -14,7 +14,7 @@ void test0(_Bool cond) {
   // CHECK-NEXT: store
   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[X]])
   // CHECK-NEXT: [[T0:%.*]] = load i8, ptr [[COND]]
-  // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
+  // CHECK-NEXT: [[T1:%.*]] = trunc nuw i8 [[T0]] to i1
   // CHECK-NEXT: store i1 false, ptr [[RELCOND]]
   // CHECK-NEXT: br i1 [[T1]],
   // CHECK:      br label

>From 7e60e8fed3ff186d1aa85f1292d491eafcc5afbb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20G=C3=B3rski?= <jan.a.gorski at wp.pl>
Date: Thu, 10 Apr 2025 15:50:05 +0200
Subject: [PATCH 6/9] fixup! Merge branch 'main' into add_range_metadata

---
 clang/lib/CodeGen/CGExpr.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index aadf6a34f8c55..6ae1db749633d 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2147,7 +2147,7 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
 
   llvm::Type *ResTy = ConvertType(Ty);
   bool IsSafe = isSafeNUWTrunc(Value, ResTy);
-  if (hasBooleanRepresentation(Ty) || Ty->isBitIntType() ||
+  if (Ty->hasBooleanRepresentation() || Ty->isBitIntType() ||
       Ty->isExtVectorBoolType()) {
     return Builder.CreateTrunc(Value, ResTy, "loadedv", /*IsNUW*/ IsSafe);
   }

>From df9c2bc5e7263ab374757be90be86ef9d1375f4e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20G=C3=B3rski?= <jan.a.gorski at wp.pl>
Date: Fri, 11 Apr 2025 00:46:26 +0200
Subject: [PATCH 7/9] Reverted to state before ecc0f4060b91.

---
 clang/lib/CodeGen/CGAtomic.cpp                | 14 +++++
 clang/lib/CodeGen/CGExpr.cpp                  | 57 +------------------
 clang/test/C/drs/dr335.c                      |  2 +-
 clang/test/CodeGen/PowerPC/bool_test.c        |  2 +-
 clang/test/CodeGen/atomic-ops-load.c          |  2 +-
 .../attr-likelihood-if-branch-weights.cpp     | 32 +++++------
 clang/test/CodeGenObjC/arc-ternary-op.m       |  2 +-
 7 files changed, 36 insertions(+), 75 deletions(-)

diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index 672e82f8dcc3e..0ead62ab0fd7b 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -590,7 +590,21 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
     llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
     Load->setAtomic(Order, Scope);
     Load->setVolatile(E->isVolatile());
+
+    QualType Ty = E->getValueType();
+    if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 && Ty->isBooleanType()) {
+      llvm::MDBuilder MDHelper(CGF.getLLVMContext());
+      llvm::APInt BooleanMin = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
+      llvm::APInt BooleanEnd = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
+      if (llvm::MDNode *RangeInfo =
+              MDHelper.createRange(BooleanMin, BooleanEnd)) {
+        Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
+        Load->setMetadata(llvm::LLVMContext::MD_noundef,
+                          llvm::MDNode::get(CGF.getLLVMContext(), {}));
+      }
+    }
     CGF.Builder.CreateStore(Load, Dest);
+
     return;
   }
 
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 6ae1db749633d..62eaff4e6a978 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2077,57 +2077,6 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
   return Value;
 }
 
-static bool isSafeNUWTrunc(llvm::Value *V, llvm::Type *DestTy) {
-  if (!V || !DestTy || !DestTy->isIntegerTy())
-    return false;
-
-  unsigned SrcBits = V->getType()->getIntegerBitWidth();
-  unsigned DestBits = DestTy->getIntegerBitWidth();
-
-  if (DestBits >= SrcBits)
-    return false;
-  if (V->getType()->isIntegerTy(1))
-    return true;
-  if (llvm::ZExtInst *Zext = dyn_cast<llvm::ZExtInst>(V)) {
-    if (Zext->getSrcTy()->isIntegerTy(1) && DestBits == 1)
-      return true;
-  }
-  if (llvm::LoadInst *I = dyn_cast<llvm::LoadInst>(V)) {
-    if (llvm::MDNode *RangeMD = I->getMetadata(llvm::LLVMContext::MD_range)) {
-      if (RangeMD->getNumOperands() == 2) {
-        llvm::ConstantAsMetadata *LowMD =
-            cast<llvm::ConstantAsMetadata>(RangeMD->getOperand(0));
-        llvm::ConstantAsMetadata *HighMD =
-            cast<llvm::ConstantAsMetadata>(RangeMD->getOperand(1));
-
-        if (LowMD && HighMD) {
-          llvm::ConstantInt *LowConst =
-              dyn_cast<llvm::ConstantInt>(LowMD->getValue());
-          llvm::ConstantInt *HighConst =
-              dyn_cast<llvm::ConstantInt>(HighMD->getValue());
-
-          if (LowConst && HighConst) {
-            llvm::APInt HighVal = HighConst->getValue();
-            llvm::APInt MaxVal =
-                llvm::APInt(HighVal.getBitWidth(), 1ULL << DestBits);
-
-            if (HighVal.ule(MaxVal)) {
-              return true;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  if (llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(V)) {
-    llvm::APInt Val = CI->getValue();
-    return Val.ule(llvm::APInt::getMaxValue(DestBits));
-  }
-
-  return false;
-}
-
 /// Converts a scalar value from its load/store type (as returned
 /// by convertTypeForLoadStore) to its primary IR type (as returned
 /// by ConvertType).
@@ -2146,11 +2095,9 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
   }
 
   llvm::Type *ResTy = ConvertType(Ty);
-  bool IsSafe = isSafeNUWTrunc(Value, ResTy);
   if (Ty->hasBooleanRepresentation() || Ty->isBitIntType() ||
-      Ty->isExtVectorBoolType()) {
-    return Builder.CreateTrunc(Value, ResTy, "loadedv", /*IsNUW*/ IsSafe);
-  }
+      Ty->isExtVectorBoolType())
+    return Builder.CreateTrunc(Value, ResTy, "loadedv");
 
   return Value;
 }
diff --git a/clang/test/C/drs/dr335.c b/clang/test/C/drs/dr335.c
index 8bbd119b88c20..3ce6ce5bd53ca 100644
--- a/clang/test/C/drs/dr335.c
+++ b/clang/test/C/drs/dr335.c
@@ -45,6 +45,6 @@ void dr335(void) {
   // CHECK-NEXT: %[[CLEAR2:.+]] = and i8 %[[LOAD2]], -2
   // CHECK-NEXT: %[[SET:.+]] = or i8 %[[CLEAR2]], %[[ZERO]]
   // CHECK-NEXT: store i8 %[[SET]], ptr {{.+}}, align 1
-  // CHECK-NEXT: {{.+}} = trunc nuw i8 %[[ZERO]] to i1
+  // CHECK-NEXT: {{.+}} = trunc i8 %[[ZERO]] to i1
 }
 
diff --git a/clang/test/CodeGen/PowerPC/bool_test.c b/clang/test/CodeGen/PowerPC/bool_test.c
index 6b5b4fe5dc202..d3e7db3c66dad 100644
--- a/clang/test/CodeGen/PowerPC/bool_test.c
+++ b/clang/test/CodeGen/PowerPC/bool_test.c
@@ -10,7 +10,7 @@ void f(_Bool *x, _Bool *y) {
 
 // CHECK-LABEL: define{{.*}} void @f(
 // CHECK: [[FROMMEM:%.*]] = load i8, ptr %
-// CHECK: [[BOOLVAL:%.*]] = trunc nuw i8 [[FROMMEM]] to i1
+// CHECK: [[BOOLVAL:%.*]] = trunc i8 [[FROMMEM]] to i1
 // CHECK: [[TOMEM:%.*]] = zext i1 [[BOOLVAL]] to i8
 // CHECK: store i8 [[TOMEM]]
 // CHECK: ret void
diff --git a/clang/test/CodeGen/atomic-ops-load.c b/clang/test/CodeGen/atomic-ops-load.c
index f737f23ad6aea..778a7ebdc2618 100644
--- a/clang/test/CodeGen/atomic-ops-load.c
+++ b/clang/test/CodeGen/atomic-ops-load.c
@@ -4,7 +4,7 @@
 extern bool t1;
 bool test1(void) {
 // CHECK-LABEL: define{{.*}} i1 @test1
-// CHECK: load atomic i8, ptr @t1 monotonic, align 1
+// CHECK: load atomic i8, ptr @t1 monotonic, align 1, !range ![[$WS_RANGE:[0-9]*]], !noundef !{{[0-9]+}}
 // CHECK-NEXT: trunc nuw i8 %{{.*}} to i1
 // CHECK-NEXT: ret i1 %{{.*}}
   return __atomic_load_n(&t1, __ATOMIC_RELAXED);
diff --git a/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp b/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
index e502d6582054e..a77593f5df738 100644
--- a/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
+++ b/clang/test/CodeGenCXX/attr-likelihood-if-branch-weights.cpp
@@ -10,7 +10,7 @@ extern bool B();
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2:![0-9]+]], !range [[RNG6:![0-9]+]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 true)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -37,7 +37,7 @@ bool f() {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -65,7 +65,7 @@ bool g() {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i1, align 1
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -90,7 +90,7 @@ bool h() {
 // CHECK-LABEL: @_Z8NullStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 // CHECK:       if.then:
@@ -113,7 +113,7 @@ void NullStmt() {
 // CHECK-LABEL: @_Z6IfStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
 // CHECK:       if.then:
@@ -125,7 +125,7 @@ void NullStmt() {
 // CHECK-NEXT:    br label [[IF_END2]]
 // CHECK:       if.end2:
 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL3:%.*]] = trunc nuw i8 [[TMP1]] to i1
+// CHECK-NEXT:    [[TOBOOL3:%.*]] = trunc i8 [[TMP1]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_END8:%.*]]
 // CHECK:       if.then4:
 // CHECK-NEXT:    [[CALL5:%.*]] = call noundef zeroext i1 @_Z1Bv()
@@ -152,7 +152,7 @@ void IfStmt() {
 // CHECK-LABEL: @_Z9WhileStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -166,7 +166,7 @@ void IfStmt() {
 // CHECK-NEXT:    br label [[IF_END]]
 // CHECK:       if.end:
 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc nuw i8 [[TMP1]] to i1
+// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
 // CHECK:       if.then2:
 // CHECK-NEXT:    br label [[WHILE_COND3:%.*]]
@@ -194,7 +194,7 @@ void WhileStmt() {
 // CHECK-LABEL: @_Z6DoStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -208,7 +208,7 @@ void WhileStmt() {
 // CHECK-NEXT:    br label [[IF_END]]
 // CHECK:       if.end:
 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc nuw i8 [[TMP1]] to i1
+// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
 // CHECK:       if.then2:
 // CHECK-NEXT:    br label [[DO_BODY3:%.*]]
@@ -237,7 +237,7 @@ void DoStmt() {
 // CHECK-LABEL: @_Z7ForStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 // CHECK:       if.then:
@@ -251,7 +251,7 @@ void DoStmt() {
 // CHECK-NEXT:    br label [[IF_END]]
 // CHECK:       if.end:
 // CHECK-NEXT:    [[TMP1:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc nuw i8 [[TMP1]] to i1
+// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP1]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END7:%.*]]
 // CHECK:       if.then2:
 // CHECK-NEXT:    br label [[FOR_COND3:%.*]]
@@ -278,7 +278,7 @@ void ForStmt() {
 // CHECK-LABEL: @_Z8GotoStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 // CHECK:       if.then:
@@ -304,7 +304,7 @@ end:;
 // CHECK-LABEL: @_Z10ReturnStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 // CHECK:       if.then:
@@ -327,7 +327,7 @@ void ReturnStmt() {
 // CHECK-LABEL: @_Z10SwitchStmtv(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc nuw i8 [[TMP0]] to i1
+// CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
 // CHECK-NEXT:    [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
 // CHECK-NEXT:    br i1 [[TOBOOL_EXPVAL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 // CHECK:       if.then:
@@ -341,7 +341,7 @@ void ReturnStmt() {
 // CHECK-NEXT:    br label [[IF_END]]
 // CHECK:       if.end:
 // CHECK-NEXT:    [[TMP2:%.*]] = load volatile i8, ptr @b, align 1, !tbaa [[TBAA2]], !range [[RNG6]]
-// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc nuw i8 [[TMP2]] to i1
+// CHECK-NEXT:    [[TOBOOL1:%.*]] = trunc i8 [[TMP2]] to i1
 // CHECK-NEXT:    br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE4:%.*]]
 // CHECK:       if.then2:
 // CHECK-NEXT:    [[TMP3:%.*]] = load volatile i32, ptr @i, align 4, !tbaa [[TBAA15]]
diff --git a/clang/test/CodeGenObjC/arc-ternary-op.m b/clang/test/CodeGenObjC/arc-ternary-op.m
index 51fc33ec29966..4a3c00c9807a9 100644
--- a/clang/test/CodeGenObjC/arc-ternary-op.m
+++ b/clang/test/CodeGenObjC/arc-ternary-op.m
@@ -14,7 +14,7 @@ void test0(_Bool cond) {
   // CHECK-NEXT: store
   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[X]])
   // CHECK-NEXT: [[T0:%.*]] = load i8, ptr [[COND]]
-  // CHECK-NEXT: [[T1:%.*]] = trunc nuw i8 [[T0]] to i1
+  // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
   // CHECK-NEXT: store i1 false, ptr [[RELCOND]]
   // CHECK-NEXT: br i1 [[T1]],
   // CHECK:      br label

>From f25e68736d12231b3483ec3eea8d4ce8da6f70f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20G=C3=B3rski?= <jan.a.gorski at wp.pl>
Date: Fri, 11 Apr 2025 00:55:18 +0200
Subject: [PATCH 8/9] Exposed `getRangeForLoadFromType` as a public method to
 support adding `range!` metadata for atomic loads.

---
 clang/lib/CodeGen/CGAtomic.cpp      | 12 ++++--------
 clang/lib/CodeGen/CodeGenFunction.h |  3 ++-
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index 0ead62ab0fd7b..e8346e4fb0e9c 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -590,21 +590,17 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
     llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
     Load->setAtomic(Order, Scope);
     Load->setVolatile(E->isVolatile());
-
     QualType Ty = E->getValueType();
-    if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 && Ty->isBooleanType()) {
-      llvm::MDBuilder MDHelper(CGF.getLLVMContext());
-      llvm::APInt BooleanMin = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
-      llvm::APInt BooleanEnd = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
-      if (llvm::MDNode *RangeInfo =
-              MDHelper.createRange(BooleanMin, BooleanEnd)) {
+    if (CGF.EmitScalarRangeCheck(Load, Ty, E->getExprLoc())) {
+    } else if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0) {
+      CGF.getRangeForLoadFromType(Ty);
+      if (llvm::MDNode *RangeInfo = CGF.getRangeForLoadFromType(Ty)) {
         Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
         Load->setMetadata(llvm::LLVMContext::MD_noundef,
                           llvm::MDNode::get(CGF.getLLVMContext(), {}));
       }
     }
     CGF.Builder.CreateStore(Load, Dest);
-
     return;
   }
 
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index a398ba55dcdc7..4667a629832ca 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -5306,6 +5306,8 @@ class CodeGenFunction : public CodeGenTypeCache {
                                      unsigned NumElementsDst,
                                      const llvm::Twine &Name = "");
 
+  llvm::MDNode *getRangeForLoadFromType(QualType Ty);
+
 private:
   // Emits a convergence_loop instruction for the given |BB|, with |ParentToken|
   // as it's parent convergence instr.
@@ -5321,7 +5323,6 @@ class CodeGenFunction : public CodeGenTypeCache {
   getOrEmitConvergenceEntryToken(llvm::Function *F);
 
 private:
-  llvm::MDNode *getRangeForLoadFromType(QualType Ty);
   void EmitReturnOfRValue(RValue RV, QualType Ty);
 
   void deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New);

>From a348252f3ab23548d76fe37a174d133b3583ff8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20G=C3=B3rski?= <jan.a.gorski at wp.pl>
Date: Fri, 11 Apr 2025 14:11:13 +0200
Subject: [PATCH 9/9] Created helper function for calling
 `EmitScalarRangeCheck()` and adding range metadata. Made
 `getRangeForLoadFromType` private function as it was before f25e68736d12.

---
 clang/lib/CodeGen/CGAtomic.cpp      | 11 +----------
 clang/lib/CodeGen/CGExpr.cpp        | 24 +++++++++++++++---------
 clang/lib/CodeGen/CodeGenFunction.h |  4 +++-
 3 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index e8346e4fb0e9c..0af3cd07b13a0 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -590,16 +590,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
     llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
     Load->setAtomic(Order, Scope);
     Load->setVolatile(E->isVolatile());
-    QualType Ty = E->getValueType();
-    if (CGF.EmitScalarRangeCheck(Load, Ty, E->getExprLoc())) {
-    } else if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0) {
-      CGF.getRangeForLoadFromType(Ty);
-      if (llvm::MDNode *RangeInfo = CGF.getRangeForLoadFromType(Ty)) {
-        Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
-        Load->setMetadata(llvm::LLVMContext::MD_noundef,
-                          llvm::MDNode::get(CGF.getLLVMContext(), {}));
-      }
-    }
+    CGF.maybeAttachRangeForLoad(Load, E->getValueType(), E->getExprLoc());
     CGF.Builder.CreateStore(Load, Dest);
     return;
   }
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 62eaff4e6a978..52960a976152a 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1919,6 +1919,20 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
   return MDHelper.createRange(Min, End);
 }
 
+void CodeGenFunction::maybeAttachRangeForLoad(llvm::LoadInst *Load, QualType Ty,
+                                              SourceLocation Loc) {
+  if (EmitScalarRangeCheck(Load, Ty, Loc)) {
+    // In order to prevent the optimizer from throwing away the check, don't
+    // attach range metadata to the load.
+  } else if (CGM.getCodeGenOpts().OptimizationLevel > 0) {
+    if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty)) {
+      Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
+      Load->setMetadata(llvm::LLVMContext::MD_noundef,
+                        llvm::MDNode::get(CGM.getLLVMContext(), {}));
+    }
+  }
+}
+
 bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
                                            SourceLocation Loc) {
   bool HasBoolCheck = SanOpts.has(SanitizerKind::Bool);
@@ -2037,15 +2051,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
 
   CGM.DecorateInstructionWithTBAA(Load, TBAAInfo);
 
-  if (EmitScalarRangeCheck(Load, Ty, Loc)) {
-    // In order to prevent the optimizer from throwing away the check, don't
-    // attach range metadata to the load.
-  } else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
-    if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty)) {
-      Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
-      Load->setMetadata(llvm::LLVMContext::MD_noundef,
-                        llvm::MDNode::get(getLLVMContext(), {}));
-    }
+  maybeAttachRangeForLoad(Load, Ty, Loc);
 
   return EmitFromMemory(Load, Ty);
 }
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 4667a629832ca..1da54888a3e78 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -5306,7 +5306,8 @@ class CodeGenFunction : public CodeGenTypeCache {
                                      unsigned NumElementsDst,
                                      const llvm::Twine &Name = "");
 
-  llvm::MDNode *getRangeForLoadFromType(QualType Ty);
+  void maybeAttachRangeForLoad(llvm::LoadInst *Load, QualType Ty,
+                               SourceLocation Loc);
 
 private:
   // Emits a convergence_loop instruction for the given |BB|, with |ParentToken|
@@ -5323,6 +5324,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   getOrEmitConvergenceEntryToken(llvm::Function *F);
 
 private:
+  llvm::MDNode *getRangeForLoadFromType(QualType Ty);
   void EmitReturnOfRValue(RValue RV, QualType Ty);
 
   void deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New);



More information about the cfe-commits mailing list