https://github.com/lucaslive974 updated https://github.com/llvm/llvm-project/pull/208851
>From c6c41770f079ee6c7736c8d0264563d1ebc34f3a 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/5] [clang][clangIR]: X86 vperm2f128 builtin implementation --- clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 53 +++++- .../CIR/CodeGenBuiltins/X86/avx-vperm2f128 | 171 ++++++++++++++++++ 2 files changed, 220 insertions(+), 4 deletions(-) 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 1b9a07ba10b04..02ad9c5eb6edd 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; +} + static mlir::Value emitX86PackedByteShift(CIRGenBuilderTy &builder, unsigned builtinID, mlir::Location loc, @@ -1855,10 +1902,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: - cgm.errorNYI(expr->getSourceRange(), - std::string("unimplemented X86 builtin call: ") + - getContext().BuiltinInfo.getName(builtinID)); - return mlir::Value{}; + 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 24d0a5fdbd7e3d3e1dab2d555b09b6a601e11e12 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/5] [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))) >From 1cd4242b4bad0d398e54eb07573c80792f0932fe Mon Sep 17 00:00:00 2001 From: lucaslive974 <[email protected]> Date: Fri, 17 Jul 2026 09:23:13 -0300 Subject: [PATCH 3/5] [clang][ClangIR]: Refactor x86 permutate2f128 builtin to mirror original codegen. --- clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 38 ++-- .../CIR/CodeGenBuiltins/X86/avx-builtins.c | 36 ++++ .../X86/avx-shuffle-builtins.c | 181 ++++++++++++++++++ .../CIR/CodeGenBuiltins/X86/avx-vperm2f128.c | 171 ----------------- 4 files changed, 233 insertions(+), 193 deletions(-) delete mode 100644 clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128.c diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 02ad9c5eb6edd..3e23c5e21b209 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -812,15 +812,18 @@ static mlir::Value emitX86MaskedLoad(CIRGenBuilderTy &builder, } static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder, - mlir::Location loc, mlir::Type resType, + mlir::Location loc, 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; + assert(!inputType.getIsScalable() && + "This is only intended for fixed-width vectors"); + + const uint8_t imm = CIRGenFunction::getZExtIntValueFromConstOp(ops[2]) & 0xFF; + mlir::Value zeroVec = builder.getZero(loc, inputType); // Mirror hardware and OGCG behaviour returning a zero vector - if ((imm & zeroMask) && (imm & zeroMask << 4)) - return builder.getZero(loc, resType); + if ((imm & 0x80) && (imm & 0x08)) + return zeroVec; mlir::Value lanes[2]; llvm::SmallVector<int64_t, 64> mask; @@ -828,34 +831,26 @@ static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder, // 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; + llvm::Boolean isZeroBit = imm & (1 << ((lane * 4) + 3)), + isSourceB = imm & (1 << ((lane * 4) + 1)), + isUpperHalf = imm & (1 << (lane * 4)); // Determine the source for this lane if (isZeroBit) - lanes[lane] = builder.getZero(loc, resType); + lanes[lane] = zeroVec; else - lanes[lane] = isSourceA ? ops[0] : ops[1]; + lanes[lane] = isSourceB ? ops[1] : ops[0]; // 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) + if (isUpperHalf) 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; + return builder.createVecShuffle(loc, lanes[0], lanes[1], mask); } static mlir::Value emitX86PackedByteShift(CIRGenBuilderTy &builder, @@ -1902,8 +1897,7 @@ 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); + return emitX86VPerm2f128(builder, getLoc(expr->getExprLoc()), 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-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/avx-builtins.c index 01ca55994ce50..ff3a3f46f6807 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx-builtins.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx-builtins.c @@ -215,3 +215,39 @@ __m256d test_mm256_permute_pd(__m256d A) { // OGCG: shufflevector <4 x double> %{{.*}}, <4 x double> poison, <4 x i32> <i32 1, i32 0, i32 3, i32 2> return _mm256_permute_pd(A, 0x5); } + +__m256d test_mm256_permute2f128_pd(__m256d A, __m256d B) { + // CIR-LABEL: test_mm256_permute2f128_pd + // 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-LABEL: test_mm256_permute2f128_pd + // LLVM: shufflevector <4 x double> %{{.*}}, <4 x double> %{{.*}}, <4 x i32> <i32 2, i32 3, i32 6, i32 7> + + // OGCG-LABEL: test_mm256_permute2f128_pd + // OGCG: shufflevector <4 x double> %{{.*}}, <4 x double> %{{.*}}, <4 x i32> <i32 2, i32 3, i32 6, i32 7> + return _mm256_permute2f128_pd(A, B, 0x31); +} + +__m256 test_mm256_permute2f128_ps(__m256 A, __m256 B) { + // CIR-LABEL: test_mm256_permute2f128_ps + // CIR: {{.*}} = cir.vec.shuffle({{.*}}, {{.*}} : !cir.vector<8 x !cir.float>) [#cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<6> : !s32i, #cir.int<7> : !s32i, #cir.int<12> : !s32i, #cir.int<13> : !s32i, #cir.int<14> : !s32i, #cir.int<15> : !s32i] : !cir.vector<8 x !cir.float> + + // LLVM-LABEL: test_mm256_permute2f128_ps + // LLVM: shufflevector <8 x float> %{{.*}}, <8 x float> %{{.*}}, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 12, i32 13, i32 14, i32 15> + + // OGCG-LABEL: test_mm256_permute2f128_ps + // OGCG: shufflevector <8 x float> %{{.*}}, <8 x float> %{{.*}}, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 12, i32 13, i32 14, i32 15> + return _mm256_permute2f128_ps(A, B, 0x13); +} + +__m256i test_mm256_permute2f128_si256(__m256i A, __m256i B) { + // CIR-LABEL: test_mm256_permute2f128_si256 + // 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<8> : !s32i, #cir.int<9> : !s32i, #cir.int<10> : !s32i, #cir.int<11> : !s32i] : !cir.vector<8 x !s32i> + + // LLVM-LABEL: test_mm256_permute2f128_si256 + // LLVM: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11> + + // OGCG-LABEL: test_mm256_permute2f128_si256 + // OGCG: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11> + return _mm256_permute2f128_si256(A, B, 0x20); +} \ No newline at end of file diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx-shuffle-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/avx-shuffle-builtins.c index 8e30ca93ef6cd..1e12a95e0f408 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx-shuffle-builtins.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx-shuffle-builtins.c @@ -160,3 +160,184 @@ __m256i test1_mm256_insertf128_si256(__m256i a, __m128i b) { // OGCG-NEXT: ret <4 x i64> [[TMP2]] return _mm256_insertf128_si256(a, b, 1); } + +__m256d test_mm256_permute2f128_pd(__m256d a, __m256d b) { + // CIR-LABEL: test_mm256_permute2f128_pd + // CIR: [[VPERM:%.*]] = 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> + // CIR: cir.return {{.*}} : !cir.vector<4 x !cir.double> + + // LLVM-LABEL: define dso_local <4 x double> @test_mm256_permute2f128_pd( + // LLVM: [[VPERM:%.*]] = shufflevector <4 x double> {{.*}}, <4 x double> {{.*}}, <4 x i32> <i32 2, i32 3, i32 6, i32 7> + // LLVM: ret <4 x double> {{.*}} + + // OGCG-LABEL: define dso_local <4 x double> @test_mm256_permute2f128_pd( + // OGCG-SAME: <4 x double> noundef [[A:%.*]], <4 x double> noundef [[B:%.*]]) #[[ATTR0]] { + // OGCG-NEXT: [[ENTRY:.*:]] + // OGCG-NEXT: [[VPERM:%.*]] = shufflevector <4 x double> [[A]], <4 x double> [[B]], <4 x i32> <i32 2, i32 3, i32 6, i32 7> + // OGCG-NEXT: ret <4 x double> [[VPERM]] + return _mm256_permute2f128_pd(a, b, 0x31); +} + +__m256 test_mm256_permute2f128_ps(__m256 a, __m256 b) { + // CIR-LABEL: test_mm256_permute2f128_ps + // CIR: [[VPERM:%.*]] = cir.vec.shuffle({{.*}}, {{.*}}: !cir.vector<8 x !cir.float>) [#cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<6> : !s32i, #cir.int<7> : !s32i, #cir.int<12> : !s32i, #cir.int<13> : !s32i, #cir.int<14> : !s32i, #cir.int<15> : !s32i] : !cir.vector<8 x !cir.float> + // CIR: cir.return {{.*}} : !cir.vector<8 x !cir.float> + + // LLVM-LABEL: define dso_local <8 x float> @test_mm256_permute2f128_ps( + // LLVM: [[VPERM:%.*]] = shufflevector <8 x float> {{.*}}, <8 x float> {{.*}}, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 12, i32 13, i32 14, i32 15> + // LLVM: ret <8 x float> {{.*}} + + // OGCG-LABEL: define dso_local <8 x float> @test_mm256_permute2f128_ps( + // OGCG-SAME: <8 x float> noundef [[A:%.*]], <8 x float> noundef [[B:%.*]]) #[[ATTR0]] { + // OGCG-NEXT: [[ENTRY:.*:]] + // OGCG-NEXT: [[VPERM:%.*]] = shufflevector <8 x float> [[B]], <8 x float> [[A]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 12, i32 13, i32 14, i32 15> + // OGCG-NEXT: ret <8 x float> [[VPERM]] + return _mm256_permute2f128_ps(a, b, 0x13); +} + +__m256i test_mm256_permute2f128_si256(__m256i a, __m256i b) { + // CIR-LABEL: test_mm256_permute2f128_si256 + // CIR: [[TMP0:%.*]] = cir.cast bitcast {{.*}} : !cir.vector<4 x !s64i> -> !cir.vector<8 x !s32i> + // CIR: [[TMP1:%.*]] = cir.cast bitcast {{.*}} : !cir.vector<4 x !s64i> -> !cir.vector<8 x !s32i> + // CIR: [[VPERM:%.*]] = cir.vec.shuffle([[TMP0]], [[TMP1]] : !cir.vector<8 x !s32i>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<8> : !s32i, #cir.int<9> : !s32i, #cir.int<10> : !s32i, #cir.int<11> : !s32i] : !cir.vector<8 x !s32i> + // CIR: [[TMP2:%.*]] = cir.cast bitcast [[VPERM]] : !cir.vector<8 x !s32i> -> !cir.vector<4 x !s64i> + // CIR: cir.return {{.*}} : !cir.vector<4 x !s64i> + + // LLVM-LABEL: define dso_local <4 x i64> @test_mm256_permute2f128_si256( + // LLVM: [[TMP0:%.*]] = bitcast <4 x i64> {{.*}} to <8 x i32> + // LLVM: [[TMP1:%.*]] = bitcast <4 x i64> {{.*}} to <8 x i32> + // LLVM: [[VPERM:%.*]] = shufflevector <8 x i32> [[TMP0]], <8 x i32> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11> + // LLVM: [[TMP2:%.*]] = bitcast <8 x i32> [[VPERM]] to <4 x i64> + // LLVM: ret <4 x i64> {{.*}} + + // OGCG-LABEL: define dso_local <4 x i64> @test_mm256_permute2f128_si256( + // OGCG-SAME: <4 x i64> noundef [[A:%.*]], <4 x i64> noundef [[B:%.*]]) #[[ATTR0]] { + // OGCG-NEXT: [[ENTRY:.*:]] + // OGCG-NEXT: [[TMP0:%.*]] = bitcast <4 x i64> [[A]] to <8 x i32> + // OGCG-NEXT: [[TMP1:%.*]] = bitcast <4 x i64> [[B]] to <8 x i32> + // OGCG-NEXT: [[VPERM:%.*]] = shufflevector <8 x i32> [[TMP0]], <8 x i32> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11> + // OGCG-NEXT: [[TMP2:%.*]] = bitcast <8 x i32> [[VPERM]] to <4 x i64> + // OGCG-NEXT: ret <4 x i64> [[TMP2]] + return _mm256_permute2f128_si256(a, b, 0x20); +} + +// The test will be named following this convention for selected lanes +// test_mm_permute2f128_pd_[[low_half]]_{{lane/zero}}_[[high_half]]_{{lane/zero}} + +__m256d test_mm256_permute2f128_pd_a_low_b_high(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0x30); +} + +__m256d test_mm256_permute2f128_pd_a_high_b_low(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0x21); +} + +__m256d test_mm256_permute2f128_pd_b_high_b_low(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0x23); +} + +__m256d test_mm256_permute2f128_pd_a_high_a_low(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0x01); +} + + +__m256d test_mm256_permute2f128_pd_a_low_a_low(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0x00); +} + +__m256d test_mm256_permute2f128_pd_a_high_a_high(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_a_high_a_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 _mm256_permute2f128_pd(a, b, 0x11); +} + +//zero bit tests +__m256d test_mm256_permute2f128_pd_a_zero_b_low(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0x28); +} + +//zero bit tests +__m256d test_mm256_permute2f128_pd_a_low_b_zero(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0x80); +} + +__m256d test_mm256_permute2f128_pd_b_zero_overwritte(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0xA0); +} + +__m256d test_mm256_permute2f128_pd_ab_zero_overwritte(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0xA8); +} + +__m256d test_mm256_permute2f128_pd_a_zero_b_zero(__m256d a, __m256d b) { + //CIR-LABEL: test_mm256_permute2f128_pd_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 _mm256_permute2f128_pd(a, b, 0x88); +} diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128.c b/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128.c deleted file mode 100644 index a2c546885f3d6..0000000000000 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx-vperm2f128.c +++ /dev/null @@ -1,171 +0,0 @@ -// 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))); - -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))) - -//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 abef45d38b0ddd0ab27dcc84b5745fc047a5d922 Mon Sep 17 00:00:00 2001 From: lucaslive974 <[email protected]> Date: Fri, 17 Jul 2026 09:24:15 -0300 Subject: [PATCH 4/5] fix missing line-feed --- clang/test/CIR/CodeGenBuiltins/X86/avx-builtins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/avx-builtins.c index ff3a3f46f6807..a833970fff421 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx-builtins.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx-builtins.c @@ -250,4 +250,4 @@ __m256i test_mm256_permute2f128_si256(__m256i A, __m256i B) { // OGCG-LABEL: test_mm256_permute2f128_si256 // OGCG: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11> return _mm256_permute2f128_si256(A, B, 0x20); -} \ No newline at end of file +} >From a38f9f78f8d49fe60b9e21b281b322419646f755 Mon Sep 17 00:00:00 2001 From: lucaslive974 <[email protected]> Date: Sat, 18 Jul 2026 20:01:02 -0300 Subject: [PATCH 5/5] [clang][ClangIR]: Optimize createVecShuffle signature. --- clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 3e23c5e21b209..52312e907bf21 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -818,7 +818,7 @@ static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder, assert(!inputType.getIsScalable() && "This is only intended for fixed-width vectors"); - const uint8_t imm = CIRGenFunction::getZExtIntValueFromConstOp(ops[2]) & 0xFF; + const uint8_t imm = CIRGenFunction::getZExtIntValueFromConstOp(ops[2]); mlir::Value zeroVec = builder.getZero(loc, inputType); // Mirror hardware and OGCG behaviour returning a zero vector @@ -826,14 +826,15 @@ static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder, return zeroVec; mlir::Value lanes[2]; - llvm::SmallVector<int64_t, 64> mask; - const unsigned numElts = inputType.getSize(); + llvm::SmallVector<mlir::Attribute, 64> mask; + cir::IntType i32Ty = builder.getSInt32Ty(); + const unsigned numElts = inputType.getSize(); // We must evaluated each lane(128 bits) separetely for (auto lane : llvm::seq(0, 2)) { - llvm::Boolean isZeroBit = imm & (1 << ((lane * 4) + 3)), - isSourceB = imm & (1 << ((lane * 4) + 1)), - isUpperHalf = imm & (1 << (lane * 4)); + bool isZeroBit = imm & (1 << ((lane * 4) + 3)), + isSourceB = imm & (1 << ((lane * 4) + 1)), + isUpperHalf = imm & (1 << (lane * 4)); // Determine the source for this lane if (isZeroBit) @@ -846,7 +847,7 @@ static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder, unsigned idx = (lane * numElts) + elt; if (isUpperHalf) idx += numElts / 2; - mask.push_back(idx); + mask.push_back(cir::IntAttr::get(i32Ty, idx)); } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
