Skip to content

Conversation

@andykaylor
Copy link
Contributor

This updates the LLVM IR ConstantInt creation from mlir::IntegerAttr so that unsigned integers and 1-bit integers are zero-extended rather than sign-extended.

…VM IR

This updates the LLVM IR ConstantInt creation from mlir::IntegerAttr so
that unsigned integers and 1-bit integers are zero-extended rather than
sign-extended.
@llvmbot llvmbot added mlir:llvm mlir ClangIR Anything related to the ClangIR project labels Nov 27, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 27, 2025

@llvm/pr-subscribers-mlir-llvm

Author: Andy Kaylor (andykaylor)

Changes

This updates the LLVM IR ConstantInt creation from mlir::IntegerAttr so that unsigned integers and 1-bit integers are zero-extended rather than sign-extended.


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

3 Files Affected:

  • (modified) clang/test/CIR/CodeGen/globals.cpp (+6)
  • (modified) mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (+11-4)
  • (modified) mlir/test/Target/LLVMIR/llvmir.mlir (+3)
diff --git a/clang/test/CIR/CodeGen/globals.cpp b/clang/test/CIR/CodeGen/globals.cpp
index a3e16139a41a9..848cac8a46299 100644
--- a/clang/test/CIR/CodeGen/globals.cpp
+++ b/clang/test/CIR/CodeGen/globals.cpp
@@ -35,3 +35,9 @@ int *constArrAddr = &arr[2][1];
 // LLVM: @constArrAddr = global ptr getelementptr inbounds nuw (i8, ptr @arr, i64 132), align 8
 
 // OGCG: @constArrAddr = global ptr getelementptr (i8, ptr @arr, i64 132), align 8
+
+bool bool_global = true;
+
+// CIR: cir.global external @bool_global = #true {alignment = 1 : i64}
+// LLVM: @bool_global = global i8 1, align 1
+// OGCG: @bool_global = global i8 1, align 1
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 412a5f76d5753..0d36dcef56123 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -588,10 +588,17 @@ llvm::Constant *mlir::LLVM::detail::getLLVMConstant(
   }
   // For integer types, we allow a mismatch in sizes as the index type in
   // MLIR might have a different size than the index type in the LLVM module.
-  if (auto intAttr = dyn_cast<IntegerAttr>(attr))
-    return llvm::ConstantInt::get(
-        llvmType,
-        intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth()));
+  if (auto intAttr = dyn_cast<IntegerAttr>(attr)) {
+    // If the attribute is an unsigned integer or a 1-bit integer, zero-extend
+    // the value to the bit width of the LLVM type. Otherwise, sign-extend.
+    auto intTy = mlir::dyn_cast<IntegerType>(intAttr.getType());
+    APInt value;
+    if (intTy && (intTy.isUnsigned() || intTy.getWidth() == 1))
+      value = intAttr.getValue().zextOrTrunc(llvmType->getIntegerBitWidth());
+    else
+      value = intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth());
+    return llvm::ConstantInt::get(llvmType, value);
+  }
   if (auto floatAttr = dyn_cast<FloatAttr>(attr)) {
     const llvm::fltSemantics &sem = floatAttr.getValue().getSemantics();
     // Special case for 8-bit floats, which are represented by integers due to
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index d1ed1b4bfa064..819a514bc8b7e 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -78,6 +78,9 @@ llvm.mlir.global internal @f8E8M0FNU_global_as_i8(1.0 : f8E8M0FNU) : i8
 // CHECK: @bf16_global_as_i16 = internal global i16 16320
 llvm.mlir.global internal @bf16_global_as_i16(1.5 : bf16) : i16
 
+// CHECK: @bool_global_as_i8 = internal global i8 1
+llvm.mlir.global internal @bool_global_as_i8(true) : i8
+
 // CHECK: @explicit_undef = global i32 undef
 llvm.mlir.global external @explicit_undef() : i32 {
   %0 = llvm.mlir.undef : i32

@llvmbot
Copy link
Member

llvmbot commented Nov 27, 2025

@llvm/pr-subscribers-mlir

Author: Andy Kaylor (andykaylor)

Changes

This updates the LLVM IR ConstantInt creation from mlir::IntegerAttr so that unsigned integers and 1-bit integers are zero-extended rather than sign-extended.


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

3 Files Affected:

  • (modified) clang/test/CIR/CodeGen/globals.cpp (+6)
  • (modified) mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (+11-4)
  • (modified) mlir/test/Target/LLVMIR/llvmir.mlir (+3)
diff --git a/clang/test/CIR/CodeGen/globals.cpp b/clang/test/CIR/CodeGen/globals.cpp
index a3e16139a41a9..848cac8a46299 100644
--- a/clang/test/CIR/CodeGen/globals.cpp
+++ b/clang/test/CIR/CodeGen/globals.cpp
@@ -35,3 +35,9 @@ int *constArrAddr = &arr[2][1];
 // LLVM: @constArrAddr = global ptr getelementptr inbounds nuw (i8, ptr @arr, i64 132), align 8
 
 // OGCG: @constArrAddr = global ptr getelementptr (i8, ptr @arr, i64 132), align 8
+
+bool bool_global = true;
+
+// CIR: cir.global external @bool_global = #true {alignment = 1 : i64}
+// LLVM: @bool_global = global i8 1, align 1
+// OGCG: @bool_global = global i8 1, align 1
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 412a5f76d5753..0d36dcef56123 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -588,10 +588,17 @@ llvm::Constant *mlir::LLVM::detail::getLLVMConstant(
   }
   // For integer types, we allow a mismatch in sizes as the index type in
   // MLIR might have a different size than the index type in the LLVM module.
-  if (auto intAttr = dyn_cast<IntegerAttr>(attr))
-    return llvm::ConstantInt::get(
-        llvmType,
-        intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth()));
+  if (auto intAttr = dyn_cast<IntegerAttr>(attr)) {
+    // If the attribute is an unsigned integer or a 1-bit integer, zero-extend
+    // the value to the bit width of the LLVM type. Otherwise, sign-extend.
+    auto intTy = mlir::dyn_cast<IntegerType>(intAttr.getType());
+    APInt value;
+    if (intTy && (intTy.isUnsigned() || intTy.getWidth() == 1))
+      value = intAttr.getValue().zextOrTrunc(llvmType->getIntegerBitWidth());
+    else
+      value = intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth());
+    return llvm::ConstantInt::get(llvmType, value);
+  }
   if (auto floatAttr = dyn_cast<FloatAttr>(attr)) {
     const llvm::fltSemantics &sem = floatAttr.getValue().getSemantics();
     // Special case for 8-bit floats, which are represented by integers due to
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index d1ed1b4bfa064..819a514bc8b7e 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -78,6 +78,9 @@ llvm.mlir.global internal @f8E8M0FNU_global_as_i8(1.0 : f8E8M0FNU) : i8
 // CHECK: @bf16_global_as_i16 = internal global i16 16320
 llvm.mlir.global internal @bf16_global_as_i16(1.5 : bf16) : i16
 
+// CHECK: @bool_global_as_i8 = internal global i8 1
+llvm.mlir.global internal @bool_global_as_i8(true) : i8
+
 // CHECK: @explicit_undef = global i32 undef
 llvm.mlir.global external @explicit_undef() : i32 {
   %0 = llvm.mlir.undef : i32

@llvmbot
Copy link
Member

llvmbot commented Nov 27, 2025

@llvm/pr-subscribers-clangir

Author: Andy Kaylor (andykaylor)

Changes

This updates the LLVM IR ConstantInt creation from mlir::IntegerAttr so that unsigned integers and 1-bit integers are zero-extended rather than sign-extended.


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

3 Files Affected:

  • (modified) clang/test/CIR/CodeGen/globals.cpp (+6)
  • (modified) mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (+11-4)
  • (modified) mlir/test/Target/LLVMIR/llvmir.mlir (+3)
diff --git a/clang/test/CIR/CodeGen/globals.cpp b/clang/test/CIR/CodeGen/globals.cpp
index a3e16139a41a9..848cac8a46299 100644
--- a/clang/test/CIR/CodeGen/globals.cpp
+++ b/clang/test/CIR/CodeGen/globals.cpp
@@ -35,3 +35,9 @@ int *constArrAddr = &arr[2][1];
 // LLVM: @constArrAddr = global ptr getelementptr inbounds nuw (i8, ptr @arr, i64 132), align 8
 
 // OGCG: @constArrAddr = global ptr getelementptr (i8, ptr @arr, i64 132), align 8
+
+bool bool_global = true;
+
+// CIR: cir.global external @bool_global = #true {alignment = 1 : i64}
+// LLVM: @bool_global = global i8 1, align 1
+// OGCG: @bool_global = global i8 1, align 1
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 412a5f76d5753..0d36dcef56123 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -588,10 +588,17 @@ llvm::Constant *mlir::LLVM::detail::getLLVMConstant(
   }
   // For integer types, we allow a mismatch in sizes as the index type in
   // MLIR might have a different size than the index type in the LLVM module.
-  if (auto intAttr = dyn_cast<IntegerAttr>(attr))
-    return llvm::ConstantInt::get(
-        llvmType,
-        intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth()));
+  if (auto intAttr = dyn_cast<IntegerAttr>(attr)) {
+    // If the attribute is an unsigned integer or a 1-bit integer, zero-extend
+    // the value to the bit width of the LLVM type. Otherwise, sign-extend.
+    auto intTy = mlir::dyn_cast<IntegerType>(intAttr.getType());
+    APInt value;
+    if (intTy && (intTy.isUnsigned() || intTy.getWidth() == 1))
+      value = intAttr.getValue().zextOrTrunc(llvmType->getIntegerBitWidth());
+    else
+      value = intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth());
+    return llvm::ConstantInt::get(llvmType, value);
+  }
   if (auto floatAttr = dyn_cast<FloatAttr>(attr)) {
     const llvm::fltSemantics &sem = floatAttr.getValue().getSemantics();
     // Special case for 8-bit floats, which are represented by integers due to
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index d1ed1b4bfa064..819a514bc8b7e 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -78,6 +78,9 @@ llvm.mlir.global internal @f8E8M0FNU_global_as_i8(1.0 : f8E8M0FNU) : i8
 // CHECK: @bf16_global_as_i16 = internal global i16 16320
 llvm.mlir.global internal @bf16_global_as_i16(1.5 : bf16) : i16
 
+// CHECK: @bool_global_as_i8 = internal global i8 1
+llvm.mlir.global internal @bool_global_as_i8(true) : i8
+
 // CHECK: @explicit_undef = global i32 undef
 llvm.mlir.global external @explicit_undef() : i32 {
   %0 = llvm.mlir.undef : i32

@llvmbot llvmbot added the flang Flang issues not falling into any other category label Dec 1, 2025
// the value to the bit width of the LLVM type. Otherwise, sign-extend.
auto intTy = mlir::dyn_cast<IntegerType>(intAttr.getType());
APInt value;
if (intTy && (intTy.isUnsigned() || intTy.getWidth() == 1))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't entirely sure what the condition should be here. Sign-extending a signless value feels a bit arbitrary, but I think that's the behavior that's expected for index types, so I guess it makes sense for signless integers also. My motivation in making this change is that in global initializers true was being translated to i8 -1 whereas in local initializers it was i8 1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ClangIR Anything related to the ClangIR project flang Flang issues not falling into any other category mlir:llvm mlir

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants