Skip to content

Conversation

kimsh02
Copy link
Contributor

@kimsh02 kimsh02 commented Oct 2, 2025

Fix #153658

Handle integral to pointer casts and port the relevant cast.cpp test cases from incubator.

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Oct 2, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 2, 2025

@llvm/pr-subscribers-clangir

@llvm/pr-subscribers-clang

Author: Shawn K (kimsh02)

Changes

Fix #153658

Handle integral to pointer casts and port the relevant cast.cpp test cases from incubator.


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

3 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h (+18)
  • (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+19)
  • (modified) clang/test/CIR/CodeGen/cast.cpp (+22)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h b/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
index 417a226e44cbf..c7450d8770714 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
@@ -14,6 +14,11 @@
 
 #include "mlir/Dialect/DLTI/DLTI.h"
 #include "mlir/IR/BuiltinOps.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/TypeSize.h"
 
 namespace cir {
 
@@ -81,6 +86,19 @@ class CIRDataLayout {
   }
 
   llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const;
+
+    llvm::TypeSize getPointerTypeSizeInBits(mlir::Type Ty) const {
+    assert(mlir::isa<cir::PointerType>(Ty) &&
+           "This should only be called with a pointer type");
+    return layout.getTypeSizeInBits(Ty);
+  }
+
+  mlir::Type getIntPtrType(mlir::Type Ty) const {
+    assert(mlir::isa<cir::PointerType>(Ty) && "Expected pointer type");
+    auto IntTy =
+        cir::IntType::get(Ty.getContext(), getPointerTypeSizeInBits(Ty), false);
+    return IntTy;
+  }
 };
 
 } // namespace cir
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 500007f6f241b..c64c5f7d7a9c8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1889,6 +1889,25 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
     }
     return v;
   }
+  case CK_IntegralToPointer: {
+    auto DestCIRTy = cgf.convertType(destTy);
+    mlir::Value Src = Visit(const_cast<Expr *>(subExpr));
+
+    // Properly resize by casting to an int of the same size as the pointer.
+    // Clang's IntegralToPointer includes 'bool' as the source, but in CIR
+    // 'bool' is not an integral type.  So check the source type to get the
+    // correct CIR conversion.
+    auto MiddleTy = cgf.cgm.getDataLayout().getIntPtrType(DestCIRTy);
+    auto MiddleVal = builder.createCast(subExpr->getType()->isBooleanType()
+                                            ? cir::CastKind::bool_to_int
+                                            : cir::CastKind::integral,
+                                        Src, MiddleTy);
+
+    if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
+      llvm_unreachable("NYI");
+
+    return builder.createIntToPtr(MiddleVal, DestCIRTy);
+  }  
 
   case CK_ArrayToPointerDecay:
     return cgf.emitArrayToPointerDecay(subExpr).getPointer();
diff --git a/clang/test/CIR/CodeGen/cast.cpp b/clang/test/CIR/CodeGen/cast.cpp
index 7afa955cf3bcf..a1fd92612fe37 100644
--- a/clang/test/CIR/CodeGen/cast.cpp
+++ b/clang/test/CIR/CodeGen/cast.cpp
@@ -131,3 +131,25 @@ void bitcast() {
 
 // LLVM: %[[D_VEC:.*]] = load <2 x double>, ptr {{.*}}, align 16
 // LLVM: %[[I_VEC:.*]] = bitcast <2 x double> %[[D_VEC]] to <4 x i32>
+
+void f(long int start) {
+  void *p = (void*)start;
+}
+// CIR: %[[L:.*]] = cir.load {{.*}} : !cir.ptr<!s64i>, !s64i
+// CIR: %[[MID:.*]] = cir.cast integral %[[L]] : !s64i -> !u64i
+// CIR:          cir.cast int_to_ptr %[[MID]] : !u64i -> !cir.ptr<!void>
+
+struct A { int x; };
+
+void int_cast(long ptr) {
+  ((A *)ptr)->x = 0;
+}
+// CIR: cir.cast int_to_ptr {{.*}} : !u64i -> !cir.ptr<!rec_A>
+// LLVM: inttoptr {{.*}} to ptr
+
+void null_cast(long) {
+  *(int *)0 = 0;
+  ((A *)0)->x = 0;
+}
+// CIR: #cir.ptr<null> : !cir.ptr<!s32i>
+// CIR: #cir.ptr<null> : !cir.ptr<!rec_A>

Copy link

github-actions bot commented Oct 2, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions h,cpp -- clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp clang/test/CIR/CodeGen/cast.cpp

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h b/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
index 4eeb27d15..0ada74c69 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
@@ -95,7 +95,8 @@ public:
 
   mlir::Type getIntPtrType(mlir::Type Ty) const {
     assert(mlir::isa<cir::PointerType>(Ty) && "Expected pointer type");
-    return cir::IntType::get(ty.getContext(), getPointerTypeSizeInBits(ty), false);
+    return cir::IntType::get(ty.getContext(), getPointerTypeSizeInBits(ty),
+                             false);
   }
 };
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 7ee8c3b08..05ed0c4ee 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1890,7 +1890,8 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
     return v;
   }
   case CK_IntegralToPointer: {
-    mlir:Type destCIRTy = cgf.convertType(destTy);
+  mlir:
+    Type destCIRTy = cgf.convertType(destTy);
     mlir::Value src = Visit(const_cast<Expr *>(subExpr));
 
     // Properly resize by casting to an int of the same size as the pointer.
@@ -1898,13 +1899,14 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
     // 'bool' is not an integral type.  So check the source type to get the
     // correct CIR conversion.
     mlirType middleTy = cgf.cgm.getDataLayout().getIntPtrType(destCIRTy);
-    cir::CastOp middleVal = builder.createCast(subExpr->getType()->isBooleanType()
-                                            ? cir::CastKind::bool_to_int
+    cir::CastOp middleVal = builder.createCast(
+        subExpr->getType()->isBooleanType() ? cir::CastKind::bool_to_int
                                             : cir::CastKind::integral,
-                                        src, middleTy);
+        src, middleTy);
 
     if (cgf.cgm.getCodeGenOpts().StrictVTablePointers) {
-      cgf.cgm.errorNYI(subExpr->getSourceRange(), "IntegralToPointer: strict vtable pointers");
+      cgf.cgm.errorNYI(subExpr->getSourceRange(),
+                       "IntegralToPointer: strict vtable pointers");
       return {};
     }
 

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

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

Thanks for the PR!

What you've done here is basically correct. I have a lot of comments, but they're all just a matter of adapting to the expectations for upstreaming CIR code. I hope you won't be discouraged.

Comment on lines +17 to +21
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/TypeSize.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

Are all of these headers needed for your change?

https://llvm.org/docs/CodingStandards.html#include-as-little-as-possible

}
// CIR: %[[L:.*]] = cir.load {{.*}} : !cir.ptr<!s64i>, !s64i
// CIR: %[[MID:.*]] = cir.cast integral %[[L]] : !s64i -> !u64i
// CIR: cir.cast int_to_ptr %[[MID]] : !u64i -> !cir.ptr<!void>
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add LLVM checks here?

Comment on lines +154 to +155
// CIR: #cir.ptr<null> : !cir.ptr<!s32i>
// CIR: #cir.ptr<null> : !cir.ptr<!rec_A>
Copy link
Contributor

Choose a reason for hiding this comment

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

These checks need to be expanded. The CIR generated should look like this:

    %1 = cir.const #cir.int<0> : !s32i
    %2 = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
    cir.store align(4) %1, %2 : !s32i, !cir.ptr<!s32i>
    %3 = cir.const #cir.int<0> : !s32i
    %4 = cir.const #cir.ptr<null> : !cir.ptr<!rec_A>
    %5 = cir.get_member %4[0] {name = "x"} : !cir.ptr<!rec_A> -> !cir.ptr<!s32i>
    cir.store align(4) %3, %5 : !s32i, !cir.ptr<!s32i>

The point of the test is to verify that we're using a null pointer in the expected instructions, so I'd check at least that (and always use regex substitutions for SSA values):

// CIR:    %[[NULLPTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
// CIR:    cir.store{{.*}} %{{.*}}, %[[NULLPTR]] : !s32i, !cir.ptr<!s32i>
// CIR:    %[[NULLPTR_A:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_A>
// CIR:    %[[A_X:.*]] = cir.get_member %[[NULLPTR_A]][0] {name = "x"} : !cir.ptr<!rec_A> -> !cir.ptr<!s32i>

Note that I've used %{{.*}} for the value being stored in the second line, because we don't need to test that here. Also note, I used {{.*}} following cir.store so that this test will pass with or without an alignment specifier, because that's not relevant to this test and we wouldn't want to have to update this test if alignment behavior is changed in the future.

Nothing specific to casts is being lowered to LLVM IR, so I don't think LLVM checks are needed here.

kimsh02 and others added 5 commits October 2, 2025 10:10
Co-authored-by: Andy Kaylor <akaylor@nvidia.com>
Co-authored-by: Andy Kaylor <akaylor@nvidia.com>
Co-authored-by: Andy Kaylor <akaylor@nvidia.com>
Co-authored-by: Andy Kaylor <akaylor@nvidia.com>
Co-authored-by: Andy Kaylor <akaylor@nvidia.com>
@kimsh02
Copy link
Contributor Author

kimsh02 commented Oct 2, 2025

Thanks for all the helpful feedback! I've applied the suggested commits, and I'll revisit the headers and IR checks.

@andykaylor
Copy link
Contributor

Thanks for all the helpful feedback! I've applied the suggested commits, and I'll revisit the headers and IR checks.

My suggested changes didn't include all uses of the variables that were renamed, so you'll need to do that manually, as well as fixing formatting issues.

Copy link
Member

@AmrDeveloper AmrDeveloper left a comment

Choose a reason for hiding this comment

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

Thank you @kimsh02 for the PR!

I added some small suggestions

kimsh02 and others added 5 commits October 3, 2025 04:16
Co-authored-by: Amr Hesham <amr96@programmer.net>
Co-authored-by: Amr Hesham <amr96@programmer.net>
Co-authored-by: Amr Hesham <amr96@programmer.net>
Co-authored-by: Amr Hesham <amr96@programmer.net>
Co-authored-by: Amr Hesham <amr96@programmer.net>
@kimsh02
Copy link
Contributor Author

kimsh02 commented Oct 3, 2025

Thanks, @AmrDeveloper ! I've applied the suggested commits.

@kimsh02
Copy link
Contributor Author

kimsh02 commented Oct 3, 2025

@andykaylor Yes, thanks for heads up. I will be properly revisiting everything.

@AmrDeveloper
Copy link
Member

@kimsh02 For code formatting, you can check it locally using git clang-format HEAD~1 (Change 1 for the number of commits you want to check)

https://llvm.org/docs/Contributing.html#how-to-submit-a-patch

Note: For the "Build and Test Linux" the current issue is not related to your PR

@kimsh02
Copy link
Contributor Author

kimsh02 commented Oct 4, 2025

@AmrDeveloper Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[CIR] Upstream handling of integral-to-pointer casts
4 participants