Author: Chaitanya
Date: 2026-10-09T11:03:36+05:30
New Revision: 09b471a37a186472699272ed3bce43d3cb20271b

URL: 
https://github.com/llvm/llvm-project/commit/09b471a37a186472699272ed3bce43d3cb20271b
DIFF: 
https://github.com/llvm/llvm-project/commit/09b471a37a186472699272ed3bce43d3cb20271b.diff

LOG: [CIR] Lower non-power-of-two vectors in CallConvLowering (#230087)

Summary:

- The x86_64 classifier now sizes a vector at its ABI size (#227889), so
the bridge no longer needs to reject vectors whose width is not a power
of two.
- The SSEUP walk rounds vector widths the same way, so a union holding
such a vector is still refused at sizes with no coerce type.
- This issue came up while enabling `CallConvLowering` for AMDGPU in
#220197: the gfx950/gfx1250 `transpose-load` builtins return
three-element vectors, and
`CIR/CodeGenHIP/builtins-amdgcn-gfx950-read-tr.hip` and
`builtins-amdgcn-gfx1250-load-tr.hip` fail on the gate.

Related to issue: #220471 

Assisted by : claude opus 5.5

Added: 
    clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vec3.c

Modified: 
    clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
    clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir

Removed: 
    


################################################################################
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..9200abc50ff3ad
--- /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() -> !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(){{.*}} : () -> !u32i
+// CIR: cir.call @sink_c3(%{{.+}}){{.*}} : (!u32i{{.*}}) -> ()
+// 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
   // 
diff erently.  Classic passes this one in an xmm register from its 128-bit


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to