diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index ee6900141647f..3e5f956f1ba80 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -68,6 +68,28 @@ static mlir::Value emitVectorFCmp(CIRGenBuilderTy &builder, return bitCast; } +static mlir::Value getMaskVecValue(CIRGenFunction &cgf, const CallExpr *expr, + mlir::Value mask, unsigned numElems) { + + CIRGenBuilderTy &builder = cgf.getBuilder(); + auto maskTy = cir::VectorType::get( + builder.getBoolTy(), cast(mask.getType()).getWidth()); + mlir::Value maskVec = builder.createBitcast(mask, maskTy); + + // If we have less than 8 elements, then the starting mask was an i8 and + // we need to extract down to the right number of elements. + if (numElems < 8) { + SmallVector indices; + mlir::Type i32Ty = builder.getSInt32Ty(); + for (auto i : llvm::seq(0, numElems)) + indices.push_back(cir::IntAttr::get(i32Ty, i)); + + maskVec = builder.createVecShuffle(cgf.getLoc(expr->getExprLoc()), maskVec, + maskVec, indices); + } + return maskVec; +} + mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { if (builtinID == Builtin::BI__builtin_cpu_is) { @@ -546,11 +568,53 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, case X86::BI__builtin_ia32_kshiftliqi: case X86::BI__builtin_ia32_kshiftlihi: case X86::BI__builtin_ia32_kshiftlisi: - case X86::BI__builtin_ia32_kshiftlidi: + case X86::BI__builtin_ia32_kshiftlidi: { + unsigned shiftVal = + ops[1].getDefiningOp().getIntValue().getZExtValue() & + 0xff; + unsigned numElems = cast(ops[0].getType()).getWidth(); + + if (shiftVal >= numElems) + return builder.getNullValue(ops[0].getType(), getLoc(expr->getExprLoc())); + + mlir::Value in = getMaskVecValue(*this, expr, ops[0], numElems); + + SmallVector indices; + mlir::Type i32Ty = builder.getSInt32Ty(); + for (auto i : llvm::seq(0, numElems)) + indices.push_back(cir::IntAttr::get(i32Ty, numElems + i - shiftVal)); + + mlir::Value zero = + builder.getNullValue(in.getType(), getLoc(expr->getExprLoc())); + mlir::Value sv = + builder.createVecShuffle(getLoc(expr->getExprLoc()), zero, in, indices); + return builder.createBitcast(sv, ops[0].getType()); + } case X86::BI__builtin_ia32_kshiftriqi: case X86::BI__builtin_ia32_kshiftrihi: case X86::BI__builtin_ia32_kshiftrisi: - case X86::BI__builtin_ia32_kshiftridi: + case X86::BI__builtin_ia32_kshiftridi: { + unsigned shiftVal = + ops[1].getDefiningOp().getIntValue().getZExtValue() & + 0xff; + unsigned numElems = cast(ops[0].getType()).getWidth(); + + if (shiftVal >= numElems) + return builder.getNullValue(ops[0].getType(), getLoc(expr->getExprLoc())); + + mlir::Value in = getMaskVecValue(*this, expr, ops[0], numElems); + + SmallVector indices; + mlir::Type i32Ty = builder.getSInt32Ty(); + for (auto i : llvm::seq(0, numElems)) + indices.push_back(cir::IntAttr::get(i32Ty, i + shiftVal)); + + mlir::Value zero = + builder.getNullValue(in.getType(), getLoc(expr->getExprLoc())); + mlir::Value sv = + builder.createVecShuffle(getLoc(expr->getExprLoc()), in, zero, indices); + return builder.createBitcast(sv, ops[0].getType()); + } case X86::BI__builtin_ia32_vprotbi: case X86::BI__builtin_ia32_vprotwi: case X86::BI__builtin_ia32_vprotdi: diff --git a/clang/test/CIR/CodeGen/X86/avx512bw-builtins.c b/clang/test/CIR/CodeGen/X86/avx512bw-builtins.c new file mode 100644 index 0000000000000..57fb7af2dd685 --- /dev/null +++ b/clang/test/CIR/CodeGen/X86/avx512bw-builtins.c @@ -0,0 +1,117 @@ +// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -fclangir -emit-cir -o %t.cir -Wall -Werror +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -fclangir -emit-llvm -o %t.ll -Wall -Werror +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -fno-signed-char -fclangir -emit-cir -o %t.cir -Wall -Werror +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -fno-signed-char -fclangir -emit-llvm -o %t.ll -Wall -Werror +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=OGCG +// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=OGCG + +// This test mimics clang/test/CodeGen/X86/avx512bw-builtins.c, which eventually +// CIR shall be able to support fully. + +#include + +__mmask32 test_kshiftli_mask32(__mmask32 A) { + // CIR-LABEL: test_kshiftli_mask32 + // CIR: [[VAL:%.*]] = cir.cast bitcast %{{.*}} : !u32i -> !cir.vector<32 x !cir.bool> + // CIR: [[SHIFT:%.*]] = cir.const #cir.zero : !cir.vector<32 x !cir.bool> + // CIR: %{{.*}} = cir.vec.shuffle([[SHIFT]], [[VAL]] : !cir.vector<32 x !cir.bool>) [#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<6> : !s32i, #cir.int<7> : !s32i, #cir.int<8> : !s32i, #cir.int<9> : !s32i, #cir.int<10> : !s32i, #cir.int<11> : !s32i, #cir.int<12> : !s32i, #cir.int<13> : !s32i, #cir.int<14> : !s32i, #cir.int<15> : !s32i, #cir.int<16> : !s32i, #cir.int<17> : !s32i, #cir.int<18> : !s32i, #cir.int<19> : !s32i, #cir.int<20> : !s32i, #cir.int<21> : !s32i, #cir.int<22> : !s32i, #cir.int<23> : !s32i, #cir.int<24> : !s32i, #cir.int<25> : !s32i, #cir.int<26> : !s32i, #cir.int<27> : !s32i, #cir.int<28> : !s32i, #cir.int<29> : !s32i, #cir.int<30> : !s32i, #cir.int<31> : !s32i, #cir.int<32> : !s32i] : !cir.vector<32 x !cir.bool> + + // LLVM-LABEL: test_kshiftli_mask32 + // LLVM: [[VAL:%.*]] = bitcast i32 %{{.*}} to <32 x i1> + // LLVM: [[RES:%.*]] = shufflevector <32 x i1> zeroinitializer, <32 x i1> [[VAL]], <32 x i32> + + // OGCG-LABEL: test_kshiftli_mask32 + // OGCG: [[VAL:%.*]] = bitcast i32 %{{.*}} to <32 x i1> + // OGCG: [[RES:%.*]] = shufflevector <32 x i1> zeroinitializer, <32 x i1> [[VAL]], <32 x i32> + return _kshiftli_mask32(A, 31); +} + +__mmask32 test_kshiftri_mask32(__mmask32 A) { + // CIR-LABEL: test_kshiftri_mask32 + // CIR: [[VAL:%.*]] = cir.cast bitcast %{{.*}} : !u32i -> !cir.vector<32 x !cir.bool> + // CIR: [[SHIFT:%.*]] = cir.const #cir.zero : !cir.vector<32 x !cir.bool> + // CIR: %{{.*}} = cir.vec.shuffle([[VAL]], [[SHIFT]] : !cir.vector<32 x !cir.bool>) [#cir.int<31> : !s32i, #cir.int<32> : !s32i, #cir.int<33> : !s32i, #cir.int<34> : !s32i, #cir.int<35> : !s32i, #cir.int<36> : !s32i, #cir.int<37> : !s32i, #cir.int<38> : !s32i, #cir.int<39> : !s32i, #cir.int<40> : !s32i, #cir.int<41> : !s32i, #cir.int<42> : !s32i, #cir.int<43> : !s32i, #cir.int<44> : !s32i, #cir.int<45> : !s32i, #cir.int<46> : !s32i, #cir.int<47> : !s32i, #cir.int<48> : !s32i, #cir.int<49> : !s32i, #cir.int<50> : !s32i, #cir.int<51> : !s32i, #cir.int<52> : !s32i, #cir.int<53> : !s32i, #cir.int<54> : !s32i, #cir.int<55> : !s32i, #cir.int<56> : !s32i, #cir.int<57> : !s32i, #cir.int<58> : !s32i, #cir.int<59> : !s32i, #cir.int<60> : !s32i, #cir.int<61> : !s32i, #cir.int<62> : !s32i] : !cir.vector<32 x !cir.bool> + + // LLVM-LABEL: test_kshiftri_mask32 + // LLVM: [[VAL:%.*]] = bitcast i32 %{{.*}} to <32 x i1> + // LLVM: [[RES:%.*]] = shufflevector <32 x i1> [[VAL]], <32 x i1> zeroinitializer, <32 x i32> + + // OGCG-LABEL: test_kshiftri_mask32 + // OGCG: [[VAL:%.*]] = bitcast i32 %{{.*}} to <32 x i1> + // OGCG: [[RES:%.*]] = shufflevector <32 x i1> [[VAL]], <32 x i1> zeroinitializer, <32 x i32> + return _kshiftri_mask32(A, 31); +} + +__mmask64 test_kshiftli_mask64(__mmask64 A) { + // CIR-LABEL: test_kshiftli_mask64 + // CIR: [[VAL:%.*]] = cir.cast bitcast %{{.*}} : !u64i -> !cir.vector<64 x !cir.bool> + // CIR: [[SHIFT:%.*]] = cir.const #cir.zero : !cir.vector<64 x !cir.bool> + // CIR: %{{.*}} = cir.vec.shuffle([[SHIFT]], [[VAL]] : !cir.vector<64 x !cir.bool>) [#cir.int<32> : !s32i, #cir.int<33> : !s32i, #cir.int<34> : !s32i, #cir.int<35> : !s32i, #cir.int<36> : !s32i, #cir.int<37> : !s32i, #cir.int<38> : !s32i, #cir.int<39> : !s32i, #cir.int<40> : !s32i, #cir.int<41> : !s32i, #cir.int<42> : !s32i, #cir.int<43> : !s32i, #cir.int<44> : !s32i, #cir.int<45> : !s32i, #cir.int<46> : !s32i, #cir.int<47> : !s32i, #cir.int<48> : !s32i, #cir.int<49> : !s32i, #cir.int<50> : !s32i, #cir.int<51> : !s32i, #cir.int<52> : !s32i, #cir.int<53> : !s32i, #cir.int<54> : !s32i, #cir.int<55> : !s32i, #cir.int<56> : !s32i, #cir.int<57> : !s32i, #cir.int<58> : !s32i, #cir.int<59> : !s32i, #cir.int<60> : !s32i, #cir.int<61> : !s32i, #cir.int<62> : !s32i, #cir.int<63> : !s32i, #cir.int<64> : !s32i, #cir.int<65> : !s32i, #cir.int<66> : !s32i, #cir.int<67> : !s32i, #cir.int<68> : !s32i, #cir.int<69> : !s32i, #cir.int<70> : !s32i, #cir.int<71> : !s32i, #cir.int<72> : !s32i, #cir.int<73> : !s32i, #cir.int<74> : !s32i, #cir.int<75> : !s32i, #cir.int<76> : !s32i, #cir.int<77> : !s32i, #cir.int<78> : !s32i, #cir.int<79> : !s32i, #cir.int<80> : !s32i, #cir.int<81> : !s32i, #cir.int<82> : !s32i, #cir.int<83> : !s32i, #cir.int<84> : !s32i, #cir.int<85> : !s32i, #cir.int<86> : !s32i, #cir.int<87> : !s32i, #cir.int<88> : !s32i, #cir.int<89> : !s32i, #cir.int<90> : !s32i, #cir.int<91> : !s32i, #cir.int<92> : !s32i, #cir.int<93> : !s32i, #cir.int<94> : !s32i, #cir.int<95> : !s32i] : !cir.vector<64 x !cir.bool> + + // LLVM-LABEL: test_kshiftli_mask64 + // LLVM: [[VAL:%.*]] = bitcast i64 %{{.*}} to <64 x i1> + // LLVM: [[RES:%.*]] = shufflevector <64 x i1> zeroinitializer, <64 x i1> [[VAL]], <64 x i32> + + // OGCG-LABEL: test_kshiftli_mask64 + // OGCG: [[VAL:%.*]] = bitcast i64 %{{.*}} to <64 x i1> + // OGCG: [[RES:%.*]] = shufflevector <64 x i1> zeroinitializer, <64 x i1> [[VAL]], <64 x i32> + return _kshiftli_mask64(A, 32); +} + +__mmask64 test_kshiftri_mask64(__mmask64 A) { + // CIR-LABEL: test_kshiftri_mask64 + // CIR: [[VAL:%.*]] = cir.cast bitcast %{{.*}} : !u64i -> !cir.vector<64 x !cir.bool> + // CIR: [[SHIFT:%.*]] = cir.const #cir.zero : !cir.vector<64 x !cir.bool> + // CIR: %{{.*}} = cir.vec.shuffle([[VAL]], [[SHIFT]] : !cir.vector<64 x !cir.bool>) [#cir.int<32> : !s32i, #cir.int<33> : !s32i, #cir.int<34> : !s32i, #cir.int<35> : !s32i, #cir.int<36> : !s32i, #cir.int<37> : !s32i, #cir.int<38> : !s32i, #cir.int<39> : !s32i, #cir.int<40> : !s32i, #cir.int<41> : !s32i, #cir.int<42> : !s32i, #cir.int<43> : !s32i, #cir.int<44> : !s32i, #cir.int<45> : !s32i, #cir.int<46> : !s32i, #cir.int<47> : !s32i, #cir.int<48> : !s32i, #cir.int<49> : !s32i, #cir.int<50> : !s32i, #cir.int<51> : !s32i, #cir.int<52> : !s32i, #cir.int<53> : !s32i, #cir.int<54> : !s32i, #cir.int<55> : !s32i, #cir.int<56> : !s32i, #cir.int<57> : !s32i, #cir.int<58> : !s32i, #cir.int<59> : !s32i, #cir.int<60> : !s32i, #cir.int<61> : !s32i, #cir.int<62> : !s32i, #cir.int<63> : !s32i, #cir.int<64> : !s32i, #cir.int<65> : !s32i, #cir.int<66> : !s32i, #cir.int<67> : !s32i, #cir.int<68> : !s32i, #cir.int<69> : !s32i, #cir.int<70> : !s32i, #cir.int<71> : !s32i, #cir.int<72> : !s32i, #cir.int<73> : !s32i, #cir.int<74> : !s32i, #cir.int<75> : !s32i, #cir.int<76> : !s32i, #cir.int<77> : !s32i, #cir.int<78> : !s32i, #cir.int<79> : !s32i, #cir.int<80> : !s32i, #cir.int<81> : !s32i, #cir.int<82> : !s32i, #cir.int<83> : !s32i, #cir.int<84> : !s32i, #cir.int<85> : !s32i, #cir.int<86> : !s32i, #cir.int<87> : !s32i, #cir.int<88> : !s32i, #cir.int<89> : !s32i, #cir.int<90> : !s32i, #cir.int<91> : !s32i, #cir.int<92> : !s32i, #cir.int<93> : !s32i, #cir.int<94> : !s32i, #cir.int<95> : !s32i] : !cir.vector<64 x !cir.bool> + + // LLVM-LABEL: test_kshiftri_mask64 + // LLVM: [[VAL:%.*]] = bitcast i64 %{{.*}} to <64 x i1> + // LLVM: [[RES:%.*]] = shufflevector <64 x i1> [[VAL]], <64 x i1> zeroinitializer, <64 x i32> + + // OGCG-LABEL: test_kshiftri_mask64 + // OGCG: [[VAL:%.*]] = bitcast i64 %{{.*}} to <64 x i1> + // OGCG: [[RES:%.*]] = shufflevector <64 x i1> [[VAL]], <64 x i1> zeroinitializer, <64 x i32> + return _kshiftri_mask64(A, 32); +} + +__mmask32 test_kshiftli_mask32_out_of_range(__mmask32 A) { + // CIR-LABEL: test_kshiftli_mask32_out_of_range + // CIR: [[VAL:%.*]] = cir.const #cir.int<0> : !u32i + // CIR: cir.store [[VAL]], {{%.*}} : !u32i, !cir.ptr + // CIR: [[RES:%.*]] = cir.load {{%.*}} : !cir.ptr, !u32i + // CIR: cir.return [[RES]] : !u32i + + // LLVM-LABEL: test_kshiftli_mask32_out_of_range + // LLVM: store i32 0, ptr [[VAL:%.*]], align 4 + // LLVM: [[RES:%.*]] = load i32, ptr [[VAL]], align 4 + // LLVM: ret i32 [[RES]] + + // OGCG-LABEL: test_kshiftli_mask32_out_of_range + // OGCG: ret i32 0 + + return _kshiftli_mask32(A, 33); +} + +__mmask32 test_kshiftri_mask32_out_of_range(__mmask32 A) { + // CIR-LABEL: test_kshiftri_mask32_out_of_range + // CIR: [[VAL:%.*]] = cir.const #cir.int<0> : !u32i + // CIR: cir.store [[VAL]], {{%.*}} : !u32i, !cir.ptr + // CIR: [[RES:%.*]] = cir.load {{%.*}} : !cir.ptr, !u32i + // CIR: cir.return [[RES]] : !u32i + + // LLVM-LABEL: test_kshiftri_mask32_out_of_range + // LLVM: store i32 0, ptr [[VAL:%.*]], align 4 + // LLVM: [[RES:%.*]] = load i32, ptr [[VAL]], align 4 + // LLVM: ret i32 [[RES]] + + // OGCG-LABEL: test_kshiftri_mask32_out_of_range + // OGCG: ret i32 0 + + return _kshiftri_mask32(A, 33); +}