https://github.com/skc7 updated https://github.com/llvm/llvm-project/pull/230087
>From 05e41e5273ec520a7579f2c35fba449665d45999 Mon Sep 17 00:00:00 2001 From: skc7 <[email protected]> Date: Thu, 8 Oct 2026 17:32:52 +0530 Subject: [PATCH 1/2] [CIR] Lower non-power-of-two vectors in CallConvLowering --- .../Transforms/CallConvLoweringPass.cpp | 8 +- .../CodeGen/call-conv-lowering-x86_64-vec3.c | 86 +++++++++++++++++++ .../abi-lowering/x86_64-aggregate-nyi.cir | 21 ++--- 3 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp index 402cd09afd6370..4c543191f036d8 100644 --- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp @@ -92,8 +92,9 @@ static bool recordCanPassInRegs(ModuleOp modOp, cir::RecordType recTy) { /// Whether the classifier could give this type the SSEUP class, looking /// through arrays and records at the types they hold. static bool mayReachSseUp(mlir::Type ty, const DataLayout &dl) { + // The classifier sizes a vector with its width rounded up to a power of two. if (isa<cir::VectorType>(ty)) - return dl.getTypeSizeInBits(ty).getFixedValue() >= 128; + return llvm::PowerOf2Ceil(dl.getTypeSizeInBits(ty).getFixedValue()) >= 128; if (auto fpTy = dyn_cast<cir::FPTypeInterface>(ty)) return &fpTy.getFloatSemantics() == &llvm::APFloat::IEEEquad(); if (auto arrTy = dyn_cast<cir::ArrayType>(ty)) @@ -220,11 +221,6 @@ static bool isSupportedType(mlir::Type ty, const DataLayout &dl) { } else { return false; } - // Clang also rounds the vector's own width up to a power of two, and the - // classifier branches on the exact width, so a three-char vector would be - // classified at 24 bits where clang uses 32. - if (!llvm::isPowerOf2_64(dl.getTypeSizeInBits(ty).getFixedValue())) - return false; return isSupportedType(elemTy, dl); } if (auto arrTy = dyn_cast<cir::ArrayType>(ty)) diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c new file mode 100644 index 00000000000000..eea4574c536ad0 --- /dev/null +++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +// A three-element vector is classified at its width rounded up to a power of +// two. + +// CIRGen cannot yet load or store a three-element vector, so plain vectors +// only flow from a call result into a return or another call. + +typedef char c3 __attribute__((ext_vector_type(3))); +typedef short s3 __attribute__((ext_vector_type(3))); +typedef float f3 __attribute__((ext_vector_type(3))); +typedef double d3 __attribute__((ext_vector_type(3))); + +c3 src_c3(void); +void sink_c3(c3); +s3 src_s3(void); +void sink_s3(s3); +f3 src_f3(void); +void sink_f3(f3); + +// Three chars take 4 bytes. +c3 fwd_c3(void) { return src_c3(); } + +// CIR: cir.func {{.*}}@fwd_c3() -> !{{[su]}}32i +// CIR: cir.call @src_c3(){{.*}} : () -> !{{[su]}}32i +// LLVM: define{{.*}} i32 @fwd_c3() +// LLVM: call i32 @src_c3() + +void pass_c3(void) { sink_c3(src_c3()); } + +// CIR: cir.func {{.*}}@pass_c3() +// CIR: cir.call @src_c3(){{.*}} : () -> !{{[su]}}32i +// CIR: cir.call @sink_c3(%{{.+}}){{.*}} : (!{{[su]}}32i{{.*}}) -> () +// LLVM: define{{.*}} void @pass_c3() +// LLVM: call i32 @src_c3() +// LLVM: call void @sink_c3(i32 {{.*}}%{{.+}}) + +// Three shorts take 8 bytes. +s3 fwd_s3(void) { return src_s3(); } + +// CIR: cir.func {{.*}}@fwd_s3() -> !cir.double +// CIR: cir.call @src_s3(){{.*}} : () -> !cir.double +// LLVM: define{{.*}} double @fwd_s3() +// LLVM: call double @src_s3() + +void pass_s3(void) { sink_s3(src_s3()); } + +// CIR: cir.func {{.*}}@pass_s3() +// CIR: cir.call @src_s3(){{.*}} : () -> !cir.double +// CIR: cir.call @sink_s3(%{{.+}}){{.*}} : (!cir.double{{.*}}) -> () +// LLVM: define{{.*}} void @pass_s3() +// LLVM: call double @src_s3() +// LLVM: call void @sink_s3(double {{.*}}%{{.+}}) + +// Three floats take 16 bytes and keep their vector type. +f3 fwd_f3(void) { return src_f3(); } + +// CIR: cir.func {{.*}}@fwd_f3() -> !cir.vector<3 x !cir.float> +// CIR: cir.call @src_f3(){{.*}} : () -> !cir.vector<3 x !cir.float> +// LLVM: define{{.*}} <3 x float> @fwd_f3() +// LLVM: call <3 x float> @src_f3() + +void pass_f3(void) { sink_f3(src_f3()); } + +// CIR: cir.func {{.*}}@pass_f3() +// CIR: cir.call @sink_f3(%{{.+}}){{.*}} : (!cir.vector<3 x !cir.float>{{.*}}) -> () +// LLVM: define{{.*}} void @pass_f3() +// LLVM: call void @sink_f3(<3 x float> {{.*}}%{{.+}}) + +struct SF3 { f3 v; }; +struct SF3 sf3(struct SF3 s) { return s; } + +// CIR: cir.func {{.*}}@sf3(%arg0: !cir.vector<3 x !cir.float>{{.*}}) -> !cir.vector<3 x !cir.float> +// LLVM: define{{.*}} <3 x float> @sf3(<3 x float> {{.*}}%{{.+}}) + +// Three doubles take 32 bytes, which goes to memory without AVX. +struct SD3 { d3 v; }; +struct SD3 sd3(struct SD3 s) { return s; } + +// CIR: cir.func {{.*}}@sd3(%arg0: !cir.ptr<!rec_SD3> {{.*}}llvm.sret = !rec_SD3{{.*}}, %arg1: !cir.ptr<!rec_SD3> {{.*}}llvm.byval = !rec_SD3 +// LLVM: define{{.*}} void @sd3(ptr dead_on_unwind noalias writable sret(%struct.SD3) align 32 %{{.+}}, ptr noundef byval(%struct.SD3) align 32 %{{.+}}) diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir index 59a2583b797e74..bd7547a9805551 100644 --- a/clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir +++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir @@ -15,6 +15,9 @@ !rec_UVec384 = !cir.union<"UVec384" {data !cir.vector<4 x !cir.float>, data !cir.array<!s8i x 33>}, padding = {!cir.array<!u8i x 32>}> +!rec_UVec3x384 = + !cir.union<"UVec3x384" {data !cir.vector<3 x !cir.float>, data !cir.array<!s8i x 33>}, + padding = {!cir.array<!u8i x 36>}> !rec_UVecInArr = !cir.union<"UVecInArr" {data !cir.array<!cir.vector<4 x !cir.float> x 2>, data !cir.array<!s8i x 33>}, @@ -93,6 +96,14 @@ module attributes { // CHECK: not yet implemented for type '!cir.union<"UVec384" + // A three-float vector is 96 bits in CIR but classifies at 128, so it + // reaches SSEUP too. + cir.func @take_vec3_384_union(%arg0: !rec_UVec3x384) { + cir.return + } + + // CHECK: not yet implemented for type '!cir.union<"UVec3x384" + // The same vector, an array away. cir.func @take_vec_in_arr_union(%arg0: !rec_UVecInArr) { cir.return @@ -148,16 +159,6 @@ module attributes { // CHECK: not yet implemented for type '!cir.vector<[4] x !cir.float> - // Clang pads a vector's type width up to a power of two and the classifier - // branches on the exact width, so a three-byte vector would be classified at - // 24 bits where clang uses 32. The ABI library's vector type cannot carry - // the padded width, so this is rejected rather than misclassified. - cir.func @take_odd_width(%arg0: !cir.vector<3 x !s8i>) { - cir.return - } - - // CHECK: not yet implemented for type '!cir.vector<3 x !cir.int<s, 8>> - // An element narrower than a byte is rounded up to its storage container by // clang but not by the classifier, so the two would size the vector // differently. Classic passes this one in an xmm register from its 128-bit >From e1df86a905f2e596d1472f46f68b652bd5208074 Mon Sep 17 00:00:00 2001 From: skc7 <[email protected]> Date: Fri, 9 Oct 2026 09:28:10 +0530 Subject: [PATCH 2/2] test update --- clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c index eea4574c536ad0..9200abc50ff3ad 100644 --- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c +++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c @@ -26,16 +26,16 @@ void sink_f3(f3); // Three chars take 4 bytes. c3 fwd_c3(void) { return src_c3(); } -// CIR: cir.func {{.*}}@fwd_c3() -> !{{[su]}}32i -// CIR: cir.call @src_c3(){{.*}} : () -> !{{[su]}}32i +// CIR: cir.func {{.*}}@fwd_c3() -> !u32i +// CIR: cir.call @src_c3(){{.*}} : () -> !u32i // LLVM: define{{.*}} i32 @fwd_c3() // LLVM: call i32 @src_c3() void pass_c3(void) { sink_c3(src_c3()); } // CIR: cir.func {{.*}}@pass_c3() -// CIR: cir.call @src_c3(){{.*}} : () -> !{{[su]}}32i -// CIR: cir.call @sink_c3(%{{.+}}){{.*}} : (!{{[su]}}32i{{.*}}) -> () +// CIR: cir.call @src_c3(){{.*}} : () -> !u32i +// CIR: cir.call @sink_c3(%{{.+}}){{.*}} : (!u32i{{.*}}) -> () // LLVM: define{{.*}} void @pass_c3() // LLVM: call i32 @src_c3() // LLVM: call void @sink_c3(i32 {{.*}}%{{.+}}) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
