[clang] [Clang][AArch64][ARM]: Fix Inefficient loads/stores of _BitInt(N) (PR #93495)

via cfe-commits cfe-commits at lists.llvm.org
Mon May 27 18:27:44 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Hassnaa Hamdi (hassnaaHamdi)

<details>
<summary>Changes</summary>

- Update clang codegen for loads/stores to read/write the legal in-memory representation for _BitInt(N <= 128) and _BitInt(N <= 64).
- AArch64: for _BitInt(N <= 128) the machine type is the smallest (un)signed fundamental integral data types.
- ARM: for _BitInt(N <= 64) the machine type is the smallest (un)signed fundamental integral data types.
- So, Loads and Stores will be as following:
N - bit-precise integer size as declared
M - number of bits in the representation, M >= N
```
Loads
%u = load iM, ptr %p
%v = trunc iM %u to iN
```
```
Stores
%u = Xext iN %v to iM
store iM %u, ptr %p
where Xext is zext or sext on ARM, depending on C type, and zext for AArch64.
```

These changes are according to the ABI documentation for: 
ARM: https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst 
AArch64: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst 

---
Full diff: https://github.com/llvm/llvm-project/pull/93495.diff


11 Files Affected:

- (modified) clang/include/clang/Basic/TargetInfo.h (+9) 
- (modified) clang/lib/Basic/Targets/AArch64.cpp (+10) 
- (modified) clang/lib/Basic/Targets/AArch64.h (+2) 
- (modified) clang/lib/Basic/Targets/ARM.cpp (+16) 
- (modified) clang/lib/Basic/Targets/ARM.h (+4) 
- (modified) clang/lib/CodeGen/CGExpr.cpp (+16-1) 
- (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+3) 
- (added) clang/test/CodeGen/AArch64/BitInt.c (+35) 
- (added) clang/test/CodeGen/Arm/BitInt.c (+36) 
- (modified) clang/test/CodeGen/attr-noundef.cpp (+3-3) 
- (modified) clang/test/CodeGen/builtins-bitint.c (+30-24) 


``````````diff
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 8a6511b9ced83..92b03e8d6bdbc 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -667,6 +667,15 @@ class TargetInfo : public TransferrableTargetInfo,
     return false;
   }
 
+  // Different targets may support different machine type width for the _BitInt
+  virtual unsigned getBitIntLegalWidth(unsigned Width) const {
+    return Width;
+  }
+
+  virtual bool isBitIntSignExtended(bool IsSigned) const {
+    return false;
+  }
+
   // Different targets may support a different maximum width for the _BitInt
   // type, depending on what operations are supported.
   virtual size_t getMaxBitIntWidth() const {
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 5db1ce78c657f..a5d66cb44b566 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -221,6 +221,16 @@ bool AArch64TargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
   return true;
 }
 
+unsigned AArch64TargetInfo::getBitIntLegalWidth(unsigned Width) const {
+  unsigned IntegralSizes[] = {32, 64, 128};
+  const unsigned ARR_SZ = sizeof(IntegralSizes) / sizeof(unsigned);
+  for (unsigned I = 0; I < ARR_SZ; I ++) {
+    if (IntegralSizes[I] > Width)
+      return IntegralSizes[I];
+  }
+  return Width;
+}
+
 bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,
                                                  BranchProtectionInfo &BPI,
                                                  StringRef &Err) const {
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index 12fb50286f751..89c6af00e628c 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -202,6 +202,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
   bool hasBitIntType() const override { return true; }
 
   bool validateTarget(DiagnosticsEngine &Diags) const override;
+
+  unsigned getBitIntLegalWidth(unsigned Width) const override;
 };
 
 class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo {
diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp
index 7423626d7c3cb..a074bafacc25f 100644
--- a/clang/lib/Basic/Targets/ARM.cpp
+++ b/clang/lib/Basic/Targets/ARM.cpp
@@ -1344,6 +1344,22 @@ int ARMTargetInfo::getEHDataRegisterNumber(unsigned RegNo) const {
 
 bool ARMTargetInfo::hasSjLjLowering() const { return true; }
 
+unsigned ARMTargetInfo::getBitIntLegalWidth(unsigned Width) const {
+  unsigned IntegralSizes[] = {32, 64};
+  const unsigned ARR_SZ = sizeof(IntegralSizes) / sizeof(unsigned);
+  for (unsigned I = 0; I < ARR_SZ; I ++) {
+    if (IntegralSizes[I] > Width)
+      return IntegralSizes[I];
+  }
+  return Width;
+}
+
+bool ARMTargetInfo::isBitIntSignExtended(bool IsSigned) const {
+    if (IsSigned)
+      return true;
+    return false;
+}
+
 ARMleTargetInfo::ARMleTargetInfo(const llvm::Triple &Triple,
                                  const TargetOptions &Opts)
     : ARMTargetInfo(Triple, Opts) {}
diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h
index df9855a52e61c..679c29e786cc9 100644
--- a/clang/lib/Basic/Targets/ARM.h
+++ b/clang/lib/Basic/Targets/ARM.h
@@ -229,6 +229,10 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
   std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
     return std::make_pair(getTriple().isArch64Bit() ? 256 : 64, 64);
   }
+
+  unsigned getBitIntLegalWidth(unsigned Width) const override;
+
+  bool isBitIntSignExtended(bool IsSigned) const override;
 };
 
 class LLVM_LIBRARY_VISIBILITY ARMleTargetInfo : public ARMTargetInfo {
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index d6478cc6835d8..4030f0024df4d 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1989,7 +1989,14 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
     return EmitAtomicLoad(AtomicLValue, Loc).getScalarVal();
   }
 
-  llvm::LoadInst *Load = Builder.CreateLoad(Addr, Volatile);
+  llvm::LoadInst *Load = nullptr;
+  if (const auto *BitintTy = Ty->getAs<BitIntType>()) {
+    Address TempAddr(Addr.getBasePointer(), ConvertTypeForMem(Ty), Addr.getAlignment());
+    Load = Builder.CreateLoad(TempAddr, Volatile);
+  }
+  else
+    Load = Builder.CreateLoad(Addr, Volatile);
+
   if (isNontemporal) {
     llvm::MDNode *Node = llvm::MDNode::get(
         Load->getContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
@@ -2021,6 +2028,12 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
     assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
            "wrong value rep of bool");
   }
+  if(auto *BitIntTy = Ty->getAs<BitIntType>()) {
+    if (CGM.getTarget().isBitIntSignExtended(BitIntTy->isSigned()))
+      return Builder.CreateSExt(Value, ConvertTypeForMem(Ty), "sext_bitint");
+    else
+      return Builder.CreateZExt(Value, ConvertTypeForMem(Ty), "zext_bitint");
+  }
 
   return Value;
 }
@@ -2043,6 +2056,8 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
     unsigned ValNumElems = cast<llvm::FixedVectorType>(ValTy)->getNumElements();
     return emitBoolVecConversion(V, ValNumElems, "extractvec");
   }
+  if(Ty->getAs<BitIntType>())
+    return Builder.CreateTrunc(Value, ConvertType(Ty), "to_bitint");
 
   return Value;
 }
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 0a926e4ac27fe..743c95e5d2a2f 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -114,6 +114,9 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T, bool ForBitField) {
     return llvm::IntegerType::get(getLLVMContext(),
                                   (unsigned)Context.getTypeSize(T));
 
+  if (T->isBitIntType())
+    return llvm::IntegerType::get(getLLVMContext(),
+      CGM.getTarget().getBitIntLegalWidth(T->getAs<BitIntType>()->getNumBits()));
   // Else, don't map it.
   return R;
 }
diff --git a/clang/test/CodeGen/AArch64/BitInt.c b/clang/test/CodeGen/AArch64/BitInt.c
new file mode 100644
index 0000000000000..1784bb461ff86
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/BitInt.c
@@ -0,0 +1,35 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64 -S -o /dev/null %s
+
+_BitInt(18) signed_src;
+_BitInt(18) signed_dst;
+
+// CHECK-LABEL: define dso_local void @test_signed(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @signed_dst, align 4
+// CHECK-NEXT:    [[TOBITINT:%.*]] = trunc i32 [[TMP0]] to i18
+// CHECK-NEXT:    [[ZEXTBITINT:%.*]] = zext i18 [[TOBITINT]] to i32
+// CHECK-NEXT:    store i32 [[ZEXTBITINT]], ptr @signed_src, align 4
+// CHECK-NEXT:    ret void
+//
+void test_signed() {
+  signed_src = signed_dst;
+}
+
+unsigned _BitInt(18) src;
+unsigned _BitInt(18) dst;
+
+// CHECK-LABEL: define dso_local void @test_unsigned(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @dst, align 4
+// CHECK-NEXT:    [[TOBITINT:%.*]] = trunc i32 [[TMP0]] to i18
+// CHECK-NEXT:    [[ZEXTBITINT:%.*]] = zext i18 [[TOBITINT]] to i32
+// CHECK-NEXT:    store i32 [[ZEXTBITINT]], ptr @src, align 4
+// CHECK-NEXT:    ret void
+//
+void test_unsigned() {
+  src = dst;
+}
diff --git a/clang/test/CodeGen/Arm/BitInt.c b/clang/test/CodeGen/Arm/BitInt.c
new file mode 100644
index 0000000000000..a8fe5029383ea
--- /dev/null
+++ b/clang/test/CodeGen/Arm/BitInt.c
@@ -0,0 +1,36 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4
+// RUN: %clang_cc1 -triple arm -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm -S -o /dev/null %s
+
+_BitInt(18) signed_src;
+_BitInt(18) signed_dst;
+
+// CHECK-LABEL: define dso_local arm_aapcscc void @test_signed(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @signed_dst, align 4
+// CHECK-NEXT:    [[TOBITINT:%.*]] = trunc i32 [[TMP0]] to i18
+// CHECK-NEXT:    [[SEXTBITINT:%.*]] = sext i18 [[TOBITINT]] to i32
+// CHECK-NEXT:    store i32 [[SEXTBITINT]], ptr @signed_src, align 4
+// CHECK-NEXT:    ret void
+//
+void test_signed() {
+  signed_src = signed_dst;
+}
+
+unsigned _BitInt(18) src;
+unsigned _BitInt(18) dst;
+
+// CHECK-LABEL: define dso_local arm_aapcscc void @test_unsigned(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @dst, align 4
+// CHECK-NEXT:    [[TOBITINT:%.*]] = trunc i32 [[TMP0]] to i18
+// CHECK-NEXT:    [[ZEXTBITINT:%.*]] = zext i18 [[TOBITINT]] to i32
+// CHECK-NEXT:    store i32 [[ZEXTBITINT]], ptr @src, align 4
+// CHECK-NEXT:    ret void
+//
+void test_unsigned() {
+  src = dst;
+}
+
diff --git a/clang/test/CodeGen/attr-noundef.cpp b/clang/test/CodeGen/attr-noundef.cpp
index e1cab091bfcbf..16fc03bd6d0be 100644
--- a/clang/test/CodeGen/attr-noundef.cpp
+++ b/clang/test/CodeGen/attr-noundef.cpp
@@ -159,9 +159,9 @@ void pass_large_BitInt(_BitInt(127) e) {
 
 // TODO: for now, ExtInt is only noundef if it is sign/zero-extended
 // CHECK-INTEL: [[DEF]] noundef signext i3 @{{.*}}ret_BitInt{{.*}}()
-// CHECK-AARCH: [[DEF]] i3 @{{.*}}ret_BitInt{{.*}}()
+// CHECK-AARCH: [[DEF]] noundef i3 @{{.*}}ret_BitInt{{.*}}()
 // CHECK-INTEL: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef signext %
-// CHECK-AARCH: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 %
+// CHECK-AARCH: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef %
 // CHECK-INTEL: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i64 %{{.*}}, i64 %
-// CHECK-AARCH: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i127 %
+// CHECK-AARCH: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i127 noundef %
 } // namespace check_exotic
diff --git a/clang/test/CodeGen/builtins-bitint.c b/clang/test/CodeGen/builtins-bitint.c
index 804e497128773..3d103de5542ec 100644
--- a/clang/test/CodeGen/builtins-bitint.c
+++ b/clang/test/CodeGen/builtins-bitint.c
@@ -8,10 +8,11 @@
 // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_popcountg_ubi1(
 // CHECK-O0-SAME: ) #[[ATTR0:[0-9]+]] {
 // CHECK-O0-NEXT:  entry:
-// CHECK-O0-NEXT:    [[A:%.*]] = alloca i1, align 1
-// CHECK-O0-NEXT:    store i1 true, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i1, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i1 @llvm.ctpop.i1(i1 [[TMP0]])
+// CHECK-O0-NEXT:    [[A:%.*]] = alloca i32, align 1
+// CHECK-O0-NEXT:    store i32 1, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i1
+// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i1 @llvm.ctpop.i1(i1 [[TO_BITINT]])
 // CHECK-O0-NEXT:    [[CAST:%.*]] = zext i1 [[TMP1]] to i32
 // CHECK-O0-NEXT:    ret i32 [[CAST]]
 //
@@ -28,10 +29,11 @@ int test_popcountg_ubi1() {
 // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_popcountg_ubi2(
 // CHECK-O0-SAME: ) #[[ATTR0]] {
 // CHECK-O0-NEXT:  entry:
-// CHECK-O0-NEXT:    [[A:%.*]] = alloca i2, align 1
-// CHECK-O0-NEXT:    store i2 -1, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i2, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i2 @llvm.ctpop.i2(i2 [[TMP0]])
+// CHECK-O0-NEXT:    [[A:%.*]] = alloca i32, align 1
+// CHECK-O0-NEXT:    store i32 3, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i2
+// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i2 @llvm.ctpop.i2(i2 [[TO_BITINT]])
 // CHECK-O0-NEXT:    [[CAST:%.*]] = zext i2 [[TMP1]] to i32
 // CHECK-O0-NEXT:    ret i32 [[CAST]]
 //
@@ -48,10 +50,11 @@ int test_popcountg_ubi2() {
 // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_ctzg_ubi1(
 // CHECK-O0-SAME: ) #[[ATTR0]] {
 // CHECK-O0-NEXT:  entry:
-// CHECK-O0-NEXT:    [[A:%.*]] = alloca i1, align 1
-// CHECK-O0-NEXT:    store i1 false, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i1, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i1 @llvm.cttz.i1(i1 [[TMP0]], i1 false)
+// CHECK-O0-NEXT:    [[A:%.*]] = alloca i32, align 1
+// CHECK-O0-NEXT:    store i32 0, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i1
+// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i1 @llvm.cttz.i1(i1 [[TO_BITINT]], i1 false)
 // CHECK-O0-NEXT:    [[CAST:%.*]] = zext i1 [[TMP1]] to i32
 // CHECK-O0-NEXT:    ret i32 [[CAST]]
 //
@@ -68,10 +71,11 @@ int test_ctzg_ubi1() {
 // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_ctzg_ubi2(
 // CHECK-O0-SAME: ) #[[ATTR0]] {
 // CHECK-O0-NEXT:  entry:
-// CHECK-O0-NEXT:    [[A:%.*]] = alloca i2, align 1
-// CHECK-O0-NEXT:    store i2 0, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i2, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i2 @llvm.cttz.i2(i2 [[TMP0]], i1 false)
+// CHECK-O0-NEXT:    [[A:%.*]] = alloca i32, align 1
+// CHECK-O0-NEXT:    store i32 0, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i2
+// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i2 @llvm.cttz.i2(i2 [[TO_BITINT]], i1 false)
 // CHECK-O0-NEXT:    [[CAST:%.*]] = zext i2 [[TMP1]] to i32
 // CHECK-O0-NEXT:    ret i32 [[CAST]]
 //
@@ -88,10 +92,11 @@ int test_ctzg_ubi2() {
 // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_clzg_ubi1(
 // CHECK-O0-SAME: ) #[[ATTR0]] {
 // CHECK-O0-NEXT:  entry:
-// CHECK-O0-NEXT:    [[A:%.*]] = alloca i1, align 1
-// CHECK-O0-NEXT:    store i1 false, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i1, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i1 @llvm.ctlz.i1(i1 [[TMP0]], i1 false)
+// CHECK-O0-NEXT:    [[A:%.*]] = alloca i32, align 1
+// CHECK-O0-NEXT:    store i32 0, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i1
+// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i1 @llvm.ctlz.i1(i1 [[TO_BITINT]], i1 false)
 // CHECK-O0-NEXT:    [[CAST:%.*]] = zext i1 [[TMP1]] to i32
 // CHECK-O0-NEXT:    ret i32 [[CAST]]
 //
@@ -108,10 +113,11 @@ int test_clzg_ubi1() {
 // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_clzg_ubi2(
 // CHECK-O0-SAME: ) #[[ATTR0]] {
 // CHECK-O0-NEXT:  entry:
-// CHECK-O0-NEXT:    [[A:%.*]] = alloca i2, align 1
-// CHECK-O0-NEXT:    store i2 0, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i2, ptr [[A]], align 1
-// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i2 @llvm.ctlz.i2(i2 [[TMP0]], i1 false)
+// CHECK-O0-NEXT:    [[A:%.*]] = alloca i32, align 1
+// CHECK-O0-NEXT:    store i32 0, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A]], align 1
+// CHECK-O0-NEXT:    [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i2
+// CHECK-O0-NEXT:    [[TMP1:%.*]] = call i2 @llvm.ctlz.i2(i2 [[TO_BITINT]], i1 false)
 // CHECK-O0-NEXT:    [[CAST:%.*]] = zext i2 [[TMP1]] to i32
 // CHECK-O0-NEXT:    ret i32 [[CAST]]
 //

``````````

</details>


https://github.com/llvm/llvm-project/pull/93495


More information about the cfe-commits mailing list