[clang] [CIR] Upstream VectorType __builtin_astype (PR #192859)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 19 10:18:33 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Amr Hesham (AmrDeveloper)
<details>
<summary>Changes</summary>
Upstream support for VectorType __builtin_astype
Issue #<!-- -->192311
---
Full diff: https://github.com/llvm/llvm-project/pull/192859.diff
2 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+90-2)
- (added) clang/test/CIR/CodeGenOpenCL/as_type.cl (+54)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 298baaba8d3e2..d2866d5db10ee 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1422,11 +1422,99 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
return {};
}
- mlir::Value VisitAsTypeExpr(AsTypeExpr *e) {
- cgf.cgm.errorNYI(e->getSourceRange(), "ScalarExprEmitter: as type");
+ // Create cast instructions for converting MLIR value \p Src to MLIR type \p
+ // DstTy. \p Src has the same size as \p DstTy. Both are single value types
+ // but could be scalar or vectors of different lengths, and either can be
+ // pointer.
+ //
+ // There are 4 cases:
+ // 1. non-pointer -> non-pointer : needs 1 bitcast
+ // 2. pointer -> pointer : needs 1 bitcast or addrspacecast
+ // 3. pointer -> non-pointer
+ // a) pointer -> intptr_t : needs 1 ptrtoint
+ // b) pointer -> non-intptr_t : needs 1 ptrtoint then 1 bitcast
+ // 4. non-pointer -> pointer
+ // a) intptr_t -> pointer : needs 1 inttoptr
+ // b) non-intptr_t -> pointer : needs 1 bitcast then 1 inttoptr
+ //
+ // Note: for cases 3b and 4b two casts are required since LLVM casts do not
+ // allow casting directly between pointer types and non-integer non-pointer
+ // types.
+ mlir::Value createCastsForTypeOfSameSize(mlir::Value src, mlir::Type dstTy) {
+ mlir::Type srcTy = src.getType();
+
+ // Case 1.
+ if (!isa<cir::PointerType>(srcTy) && !isa<cir::PointerType>(dstTy))
+ return builder.createBitcast(src, dstTy);
+
+ // Case 2.
+ if (isa<cir::PointerType>(srcTy) && isa<cir::PointerType>(dstTy)) {
+ cgf.cgm.errorNYI(
+ "ScalarExprEmitter: createCastsForTypeOfSameSize Case 2");
+ return {};
+ }
+
+ // Case 3.
+ if (isa<cir::PointerType>(srcTy) && !isa<cir::PointerType>(dstTy)) {
+ cgf.cgm.errorNYI(
+ "ScalarExprEmitter: createCastsForTypeOfSameSize Case 3");
+ return {};
+ }
+
+ // Case 4b.
+ if (srcTy.isInteger()) {
+ cgf.cgm.errorNYI(
+ "ScalarExprEmitter: createCastsForTypeOfSameSize Case 4b");
+ return {};
+ }
+
+ // Cases 4a and 4b.
+ cgf.cgm.errorNYI(
+ "ScalarExprEmitter: createCastsForTypeOfSameSize Cases 4a and 4b");
return {};
}
+ mlir::Value VisitAsTypeExpr(AsTypeExpr *e) {
+ mlir::Value src = cgf.emitScalarExpr(e->getSrcExpr());
+ mlir::Type srcTy = src.getType();
+ mlir::Type dstTy = cgf.convertType(e->getType());
+
+ unsigned numElementsSrc = isa<cir::VectorType>(srcTy)
+ ? cast<cir::VectorType>(srcTy).getSize()
+ : 0;
+ unsigned numElementsDst = isa<cir::VectorType>(dstTy)
+ ? cast<cir::VectorType>(dstTy).getSize()
+ : 0;
+
+ // Use bit vector expansion for ext_vector_type boolean vectors.
+ if (e->getType()->isExtVectorBoolType()) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "ScalarExprEmitter: VisitAsTypeExpr ExtVectorBoolType");
+ return {};
+ }
+
+ // Going from vec3 to non-vec3 is a special case and requires a shuffle
+ // vector to get a vec4, then a bitcast if the target type is different.
+ if (numElementsSrc == 3 && numElementsDst != 3) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "ScalarExprEmitter: VisitAsTypeExpr numElemsSrc = 3, "
+ "numElemsDst = 3");
+ return {};
+ }
+
+ // Going from non-vec3 to vec3 is a special case and requires a bitcast
+ // to vec4 if the original type is not vec4, then a shuffle vector to
+ // get a vec3.
+ if (numElementsSrc != 3 && numElementsDst == 3) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "ScalarExprEmitter: VisitAsTypeExpr numElemsSrc != 3, "
+ "numElemsDst = 3");
+ return {};
+ }
+
+ return createCastsForTypeOfSameSize(src, dstTy);
+ }
+
mlir::Value VisitAtomicExpr(AtomicExpr *e) {
return cgf.emitAtomicExpr(e).getValue();
}
diff --git a/clang/test/CIR/CodeGenOpenCL/as_type.cl b/clang/test/CIR/CodeGenOpenCL/as_type.cl
new file mode 100644
index 0000000000000..f314b1dced5b5
--- /dev/null
+++ b/clang/test/CIR/CodeGenOpenCL/as_type.cl
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 %s -fclangir -emit-cir -triple spir-unknown-unknown -o %t.cir
+// RUN: FileCheck %s --input-file=%t.cir --check-prefix=CIR
+
+// RUN: %clang_cc1 %s -fclangir -emit-llvm -triple spir-unknown-unknown -o %t.ll
+// RUN: FileCheck %s --input-file=%t.ll --check-prefix=LLVM
+
+// RUN: %clang_cc1 %s -emit-llvm -triple spir-unknown-unknown -o %t.ll
+// RUN: FileCheck %s --input-file=%t.ll --check-prefix=OGCG
+
+typedef __attribute__(( ext_vector_type(4) )) char char4;
+
+char4 f4(int x) {
+ return __builtin_astype(x, char4);
+}
+
+// CIR: cir.func {{.*}} @f4
+// CIR: %[[X_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
+// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.vector<4 x !s8i>, !cir.ptr<!cir.vector<4 x !s8i>>, ["__retval"]
+// CIR: cir.store %{{.*}}, %[[X_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[TMP_X:.*]] = cir.load {{.*}} %[[X_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[X_V4_I8:.*]] = cir.cast bitcast %[[TMP_X]] : !s32i -> !cir.vector<4 x !s8i>
+// CIR: cir.store %[[X_V4_I8]], %[[RET_ADDR]] : !cir.vector<4 x !s8i>, !cir.ptr<!cir.vector<4 x !s8i>>
+// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!cir.vector<4 x !s8i>>, !cir.vector<4 x !s8i>
+// CIR: cir.return %[[TMP_RET]] : !cir.vector<4 x !s8i>
+
+// LLVM: define {{.*}} <4 x i8> @f4
+// LLVM: %[[RET:.*]] = bitcast i32 %{{.*}} to <4 x i8>
+// LLVM: ret <4 x i8> %[[RET]]
+
+// OGCG: define {{.*}} <4 x i8> @f4
+// OGCG: %[[RET:.*]] = bitcast i32 %{{.*}} to <4 x i8>
+// OGCG: ret <4 x i8> %[[RET]]
+
+int f6(char4 x) {
+ return __builtin_astype(x, int);
+}
+
+// CIR: cir.func {{.*}} @f6
+// CIR: %[[X_ADDR:.*]] = cir.alloca !cir.vector<4 x !s8i>, !cir.ptr<!cir.vector<4 x !s8i>>, ["x", init]
+// CIR: %[[RET_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR: cir.store %{{.*}}, %[[X_ADDR]] : !cir.vector<4 x !s8i>, !cir.ptr<!cir.vector<4 x !s8i>>
+// CIR: %[[TMP_X:.*]] = cir.load {{.*}} %[[X_ADDR]] : !cir.ptr<!cir.vector<4 x !s8i>>, !cir.vector<4 x !s8i>
+// CIR: %[[X_S32I:.*]] = cir.cast bitcast %[[TMP_X]] : !cir.vector<4 x !s8i> -> !s32i
+// CIR: cir.store %[[X_S32I]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.return %[[TMP_RET]] : !s32i
+
+// LLVM: define {{.*}} i32 @f6
+// LLVM: %[[RET:.*]] = bitcast <4 x i8> %{{.*}} to i32
+// LLVM: ret i32 %[[RET]]
+
+// OGCG: define {{.*}} i32 @f6
+// OGCG: %[[RET:.*]] = bitcast <4 x i8> %{{.*}} to i32
+// OGCG: ret i32 %[[RET]]
``````````
</details>
https://github.com/llvm/llvm-project/pull/192859
More information about the cfe-commits
mailing list