https://github.com/lucaslive974 updated https://github.com/llvm/llvm-project/pull/208851
>From 19dc8973140ace79b77832e312a897163c0d7d44 Mon Sep 17 00:00:00 2001 From: Lucas-Ribeiro-Lima <[email protected]> Date: Thu, 9 Jul 2026 16:56:33 -0300 Subject: [PATCH 1/2] [clang][clangIR]: X86 vperm2f128 builtin implementation --- clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 49 +++++ .../CIR/CodeGenBuiltins/X86/avx-vperm2f128 | 171 ++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128 diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 2b5b27fa7cfb2..51d3c6916a1ac 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -811,6 +811,53 @@ static mlir::Value emitX86MaskedLoad(CIRGenBuilderTy &builder, return builder.createMaskedLoad(loc, ty, ptr, alignment, maskVec, ops[1]); } +static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder, + mlir::Location loc, mlir::Type resType, + llvm::SmallVector<mlir::Value> ops) { + auto inputType = cast<cir::VectorType>(ops[0].getType()); + const unsigned imm = CIRGenFunction::getZExtIntValueFromConstOp(ops[2]); + const uint8_t zeroMask = 0x08, controlMask = 0x0F; + + // Mirror hardware and OGCG behaviour returning a zero vector + if ((imm & zeroMask) && (imm & zeroMask << 4)) + return builder.getZero(loc, resType); + + mlir::Value lanes[2]; + llvm::SmallVector<int64_t, 64> mask; + const unsigned numElts = inputType.getSize(); + + // We must evaluated each lane(128 bits) separetely + for (auto lane : llvm::seq(0, 2)) { + uint8_t controlBits = (imm >> (lane * 4)) & controlMask; + + llvm::Boolean isZeroBit = controlBits & zeroMask; + llvm::Boolean isSourceA = controlBits <= 1; + llvm::Boolean isLowerHalf = controlBits % 2 == 0; + + // Determine the source for this lane + if (isZeroBit) + lanes[lane] = builder.getZero(loc, resType); + else + lanes[lane] = isSourceA ? ops[0] : ops[1]; + + // We need to built the shuffle mask selecting the right half + for (auto elt : llvm::seq(0u, numElts / 2u)) { + unsigned idx = (lane * numElts) + elt; + if (!isLowerHalf) + idx += numElts / 2; + mask.push_back(idx); + } + } + + mlir::Value shuffleResult = + builder.createVecShuffle(loc, lanes[0], lanes[1], mask); + + if (inputType != resType) + builder.createBitcast(shuffleResult, resType); + + return shuffleResult; +} + std::optional<mlir::Value> CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { if (builtinID == Builtin::BI__builtin_cpu_is) { @@ -1801,6 +1848,8 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_vperm2f128_ps256: case X86::BI__builtin_ia32_vperm2f128_si256: case X86::BI__builtin_ia32_permti256: + return emitX86VPerm2f128(builder, getLoc(expr->getExprLoc()), + this->convertType(expr->getType()), ops); case X86::BI__builtin_ia32_pslldqi128_byteshift: case X86::BI__builtin_ia32_pslldqi256_byteshift: case X86::BI__builtin_ia32_pslldqi512_byteshift: diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128 b/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128 new file mode 100644 index 0000000000000..e46e4d342df98 --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128 @@ -0,0 +1,171 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -target-feature +avx +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -target-feature +avx +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.og.ll -target-feature +avx +// RUN: FileCheck --input-file=%t.og.ll %s -check-prefix=OGCG + +// Tests perm2f128 byte permutation intrinsics implementation in ClangIR +// Compares CIR emission, LLVM lowering, and original CodeGen output + +typedef float __m256 __attribute__((__vector_size__(32))); +typedef int __m256i __attribute__((__vector_size__(32))); +typedef double __m256d __attribute__((__vector_size__(32))); + +//First operand sources half lane(64 bits) +#define A_LOW 0x00 +#define A_HIGH 0x01 + +//Second operand sources half lane(64 bits) +#define B_LOW 0x02 +#define B_HIGH 0x03 + +//Zero overwritte bit +#define ZERO_BIT 0x08 + +//Macro helpers to set control bits +#define LANES(low, high) (((low) | ((high) << 4))) + +//The test will be named following this convention for selected lanes +// test_perm2f128pd_a_{{lane/zero}}_b_{{lane/zero}} + +__m256d test_perm2f128pd_a_low_b_low(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_low_b_low + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(A_LOW, B_LOW)); +} + +__m256d test_perm2f128pd_a_low_b_high(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_low_b_high + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<6> : !s32i, #cir.int<7> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 6, i32 7> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 6, i32 7> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(A_LOW, B_HIGH)); +} + +__m256d test_perm2f128pd_a_high_b_low(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_high_b_low + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 2, i32 3, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 2, i32 3, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(A_HIGH, B_LOW)); +} + +__m256d test_perm2f128pd_a_high_b_high(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_high_b_high + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<6> : !s32i, #cir.int<7> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 2, i32 3, i32 6, i32 7> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 2, i32 3, i32 6, i32 7> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(A_HIGH, B_HIGH)); +} + +__m256d test_perm2f128pd_b_high_b_low(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_b_high_b_low + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 2, i32 3, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 2, i32 3, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(B_HIGH, B_LOW)); +} + +__m256d test_perm2f128pd_a_high_a_low(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_high_a_low + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 2, i32 3, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 2, i32 3, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(A_HIGH, A_LOW)); +} + + +__m256d test_perm2f128pd_a_low_a_low(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_low_a_low + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(A_LOW, A_LOW)); +} + +__m256d test_perm2f128pd_a_high_a_high(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_high_a_high + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(A_LOW, A_LOW)); +} + +//Zero bit tests +__m256d test_perm2f128pd_a_zero_b_low(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_zero_b_low + //CIR: {{.*}} = cir.const #cir.zero : !cir.vector<4 x !cir.double> + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> zeroinitializer, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> zeroinitializer, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(ZERO_BIT, B_LOW)); +} + +//Zero bit tests +__m256d test_perm2f128pd_a_low_b_zero(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_low_b_zero + //CIR: {{.*}} = cir.const #cir.zero : !cir.vector<4 x !cir.double> + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(A_LOW, ZERO_BIT)); +} + +//Zero bit overwrittes control bits +__m256d test_perm2f128pd_a_zero_overwritte(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_zero_overwritte + //CIR: {{.*}} = cir.const #cir.zero : !cir.vector<4 x !cir.double> + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> zeroinitializer, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> zeroinitializer, <4 x double> {{.*}}, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(ZERO_BIT | A_LOW, B_LOW)); +} + +__m256d test_perm2f128pd_b_zero_overwritte(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_b_zero_overwritte + //CIR: {{.*}} = cir.const #cir.zero : !cir.vector<4 x !cir.double> + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<4 x !cir.double>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i] : !cir.vector<4 x !cir.double> + //LLVM: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + //OGCG: {{.*}} = shufflevector <4 x double> {{.*}}, <4 x double> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 4, i32 5> + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(A_LOW, ZERO_BIT | B_LOW)); +} + +__m256d test_perm2f128pd_ab_zero_overwritte(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_ab_zero_overwritte + //CIR: {{.*}} = cir.const #cir.zero : !cir.vector<4 x !cir.double> + //CIR: cir.return {{.*}} : !cir.vector<4 x !cir.double> + //LLVM: store <4 x double> zeroinitializer + //OGCG: ret <4 x double> zeroinitializer + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(ZERO_BIT | A_LOW, ZERO_BIT | B_LOW)); +} + +__m256d test_perm2f128pd_a_zero_b_zero(__m256d a, __m256d b) { + //CIR-LABEL: test_perm2f128pd_a_zero_b_zero + //CIR: {{.*}} = cir.const #cir.zero : !cir.vector<4 x !cir.double> + //CIR: cir.return {{.*}} : !cir.vector<4 x !cir.double> + //LLVM: store <4 x double> zeroinitializer + //OGCG: ret <4 x double> zeroinitializer + return __builtin_ia32_vperm2f128_pd256(a, b, LANES(ZERO_BIT, ZERO_BIT)); +} + +__m256 test_perm2f128ps_bitcast(__m256 a, __m256 b) { + //CIR-LABEL: test_perm2f128ps_bitcast + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<8 x !cir.float>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<12> : !s32i, #cir.int<13> : !s32i, #cir.int<14> : !s32i, #cir.int<15> : !s32i] : !cir.vector<8 x !cir.float> + //LLVM: {{.*}} = shufflevector <8 x float> {{.*}}, <8 x float> {{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15> + //OGCG: {{.*}} = shufflevector <8 x float> {{.*}}, <8 x float> {{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15> + return __builtin_ia32_vperm2f128_ps256(a, b, LANES(A_LOW, B_HIGH)); +} + +__m256 test_perm2f128si_bitcast(__m256 a, __m256 b) { + //CIR-LABEL: test_perm2f128si_bitcast + //CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<8 x !s32i>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<12> : !s32i, #cir.int<13> : !s32i, #cir.int<14> : !s32i, #cir.int<15> : !s32i] : !cir.vector<8 x !s32i> + //CIR: {{.*}} = cir.cast bitcast {{.*}} : !cir.vector<8 x !s32i> -> !cir.vector<8 x !cir.float> + //LLVM: {{.*}} = shufflevector <8 x i32> {{.*}} <8 x i32> {{.*}} <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15> + //LLVM: {{.*}} = bitcast <8 x i32> {{.*}} to <8 x float> + //OGCG: {{.*}} = shufflevector <8 x i32> {{.*}} <8 x i32> {{.*}} <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15> + //OGCG: {{.*}} = bitcast <8 x i32> {{.*}} to <8 x float> + return __builtin_ia32_vperm2f128_si256(a, b, LANES(A_LOW, B_HIGH)); +} >From 05ae30b9d216af8be5dd960e110e1ce83fab5c3b Mon Sep 17 00:00:00 2001 From: Lucas-Ribeiro-Lima <[email protected]> Date: Sun, 12 Jul 2026 21:23:37 -0300 Subject: [PATCH 2/2] [clang][ClangIR][style]: modernize-macro-to-enum clang-tidy --- .../X86/{avx-vperm2f128 => avx-vperm2f128.c} | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) rename clang/test/CIR/CodeGenBuiltins/X86/{avx-vperm2f128 => avx-vperm2f128.c} (98%) diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128 b/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128.c similarity index 98% rename from clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128 rename to clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128.c index e46e4d342df98..a2c546885f3d6 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128 +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128.c @@ -12,16 +12,16 @@ typedef float __m256 __attribute__((__vector_size__(32))); typedef int __m256i __attribute__((__vector_size__(32))); typedef double __m256d __attribute__((__vector_size__(32))); -//First operand sources half lane(64 bits) -#define A_LOW 0x00 -#define A_HIGH 0x01 - -//Second operand sources half lane(64 bits) -#define B_LOW 0x02 -#define B_HIGH 0x03 - -//Zero overwritte bit -#define ZERO_BIT 0x08 +enum VPerm2F128LaneControl { + //First operand 128 bits lane + A_LOW= 0x00, + A_HIGH = 0x01, + //Second operand 128 bits lane + B_LOW = 0x02, + B_HIGH = 0x03, + //Zero overwritte bit + ZERO_BIT = 0x08, +}; //Macro helpers to set control bits #define LANES(low, high) (((low) | ((high) << 4))) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
