From 6f330cc39b84c4c9773c712e729b0d5ba38b6db7 Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Sat, 23 May 2026 22:25:05 +0200 Subject: [PATCH] [cir] Implement __builtin_astype for vec4 to vec3 --- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 20 ++++++++++---- clang/test/CIR/CodeGenOpenCL/as_type.cl | 32 ++++++++++++++-------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 5609bd848f230..911ff14e5ef84 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1430,6 +1430,13 @@ class ScalarExprEmitter : public StmtVisitor { return {}; } + mlir::Value convertVec3AndVec4(CIRGenBuilderTy &builder, mlir::Location loc, + mlir::Value src, unsigned numElementsDst) { + static constexpr int64_t mask[] = {0, 1, 2, -1}; + return builder.createVecShuffle( + loc, src, llvm::ArrayRef(mask, numElementsDst)); + } + // 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 @@ -1516,10 +1523,12 @@ class ScalarExprEmitter : public StmtVisitor { // 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 {}; + mlir::Location loc = cgf.getLoc(e->getExprLoc()); + auto dstElemTy = cast(dstTy).getElementType(); + auto dstVec4Ty = cir::VectorType::get(dstElemTy, 4); + src = createCastsForTypeOfSameSize(src, dstVec4Ty); + src = convertVec3AndVec4(builder, loc, src, 3); + return src; } return createCastsForTypeOfSameSize(src, dstTy); @@ -1987,7 +1996,8 @@ mlir::Value ScalarExprEmitter::emitRem(const BinOpInfo &ops) { mlir::Value ScalarExprEmitter::emitAdd(const BinOpInfo &ops) { if (mlir::isa(ops.lhs.getType()) || mlir::isa(ops.rhs.getType())) - return emitPointerArithmetic(cgf, ops, /*isSubtraction=*/false); + return emitPointerArithmetic(cgf, ops, /*isSubtraction=*/ + false); const mlir::Location loc = cgf.getLoc(ops.loc); if (ops.compType->isSignedIntegerOrEnumerationType()) { diff --git a/clang/test/CIR/CodeGenOpenCL/as_type.cl b/clang/test/CIR/CodeGenOpenCL/as_type.cl index 05afd65665e7c..fc5c3bd5a04b6 100644 --- a/clang/test/CIR/CodeGenOpenCL/as_type.cl +++ b/clang/test/CIR/CodeGenOpenCL/as_type.cl @@ -5,8 +5,9 @@ // 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 +// RUN: FileCheck %s --input-file=%t.ll --check-prefix=LLVM +typedef __attribute__(( ext_vector_type(3) )) char char3; typedef __attribute__(( ext_vector_type(4) )) char char4; char4 f4(int x) { @@ -27,10 +28,6 @@ char4 f4(int x) { // 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); } @@ -49,10 +46,6 @@ int f6(char4 x) { // 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]] - int* int_to_ptr(int x) { return __builtin_astype(x, int*); } @@ -71,6 +64,21 @@ int* int_to_ptr(int x) { // LLVM: %[[INT_TO_PTR:.*]] = inttoptr i32 %{{.*}} to ptr // LLVM: ret ptr %[[INT_TO_PTR]] -// OGCG: define {{.*}} ptr @int_to_ptr -// OGCG: %[[INT_TO_PTR:.*]] = inttoptr i32 %{{.*}} to ptr -// OGCG: ret ptr %[[INT_TO_PTR]] +char3 vec4_to_vec_3(char4 x) { + return __builtin_astype(x, char3); +} + +// CIR: cir.func {{.*}} @vec4_to_vec_3 +// CIR: %[[X_ADDR:.*]] = cir.alloca !cir.vector<4 x !s8i>, !cir.ptr>, ["x", init] +// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.vector<3 x !s8i>, !cir.ptr>, ["__retval"] +// CIR: cir.store %{{.*}}, %[[X_ADDR]] : !cir.vector<4 x !s8i>, !cir.ptr> +// CIR: %[[TMP_X:.*]] = cir.load {{.*}} %[[X_ADDR]] : !cir.ptr>, !cir.vector<4 x !s8i> +// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !s8i> +// CIR: %[[RESULT:.*]] = cir.vec.shuffle(%[[TMP_X]], %[[POISON]] : !cir.vector<4 x !s8i>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i] : !cir.vector<3 x !s8i> +// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !cir.vector<3 x !s8i>, !cir.ptr> +// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr>, !cir.vector<3 x !s8i> +// CIR: cir.return %[[TMP_RET]] : !cir.vector<3 x !s8i> + +// LLVM: define {{.*}} <3 x i8> @vec4_to_vec_3 +// LLVM: %[[RESULT:.*]] = shufflevector <4 x i8> %{{.*}}, <4 x i8> poison, <3 x i32> +// LLVM: ret <3 x i8> %[[RESULT]]