https://github.com/FantasqueX updated https://github.com/llvm/llvm-project/pull/222396
>From 36cd407ce87d271d3636c3dc9f10371b18ba9356 Mon Sep 17 00:00:00 2001 From: Letu Ren <[email protected]> Date: Thu, 10 Sep 2026 01:22:42 +0800 Subject: [PATCH] [CIR] Add cir.fshl and cir.fshr for elementwise funnel shifts Emit dedicated CIR ops from __builtin_elementwise_fshl/fshr instead of cir.call_llvm_intrinsic. Assisted-by: grok-4.6 Assisted-by: gpt-5.6-sol Signed-off-by: Letu Ren <[email protected]> --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 62 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 34 +++++----- .../X86/avx512vbmi2-builtins.c | 6 +- .../CodeGenBuiltins/builtins-elementwise.c | 24 +++---- clang/test/CIR/IR/funnel-shift.cir | 34 ++++++++++ clang/test/CIR/IR/invalid-funnel-shift.cir | 32 ++++++++++ clang/test/CIR/Lowering/funnel-shift.cir | 26 ++++++++ 7 files changed, 187 insertions(+), 31 deletions(-) create mode 100644 clang/test/CIR/IR/funnel-shift.cir create mode 100644 clang/test/CIR/IR/invalid-funnel-shift.cir create mode 100644 clang/test/CIR/Lowering/funnel-shift.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index f03c591fe9597..a4336ac20a6ac 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -6956,6 +6956,68 @@ def CIR_RotateOp : CIR_Op<"rotate", [Pure, SameOperandsAndResultType]> { let hasFolder = 1; } +//===----------------------------------------------------------------------===// +// Funnel Shift Operations +//===----------------------------------------------------------------------===// + +// Concatenate `a` and `b`, shift by `c`, and return one half of the doubled +// width. All operands and the result share an integer or vector-of-integer +// type. +class CIR_FunnelShiftOp<string mnemonic, string llvmOpName> + : CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]> { + let arguments = (ins + CIR_AnyIntOrVecOfIntType:$a, + CIR_AnyIntOrVecOfIntType:$b, + CIR_AnyIntOrVecOfIntType:$c + ); + + let results = (outs CIR_AnyIntOrVecOfIntType:$result); + + let assemblyFormat = "$a `,` $b `,` $c `:` type($a) attr-dict"; + + let llvmOp = llvmOpName; +} + +def CIR_FshlOp : CIR_FunnelShiftOp<"fshl", "FshlOp"> { + let summary = "Funnel shift left"; + let description = [{ + The `cir.fshl` operation concatenates `a` and `b` (with `a` in the high + half), shifts the concatenation left by `c` bit positions, and returns the + high half of the result. The shift amount is treated modulo the bitwidth + of the operands. + + All operands and the result must have the same integer type or + vector-of-integer type. + + Example: + + ``` + %r = cir.fshl %a, %b, %c : !u32i + %v = cir.fshl %va, %vb, %vc : !cir.vector<4 x !s32i> + ``` + }]; +} + +def CIR_FshrOp : CIR_FunnelShiftOp<"fshr", "FshrOp"> { + let summary = "Funnel shift right"; + let description = [{ + The `cir.fshr` operation concatenates `a` and `b` (with `a` in the high + half), shifts the concatenation right by `c` bit positions, and returns + the low half of the result. The shift amount is treated modulo the bitwidth + of the operands. + + All operands and the result must have the same integer type or + vector-of-integer type. + + Example: + + ``` + %r = cir.fshr %a, %b, %c : !u32i + %v = cir.fshr %va, %vb, %vc : !cir.vector<4 x !s32i> + ``` + }]; +} + //===----------------------------------------------------------------------===// // FPClass Test Flags //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index c7ce147b68d61..cdaf6c0daeded 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -595,6 +595,20 @@ static RValue emitBinaryFPBuiltin(CIRGenFunction &cgf, const CallExpr &e) { return RValue::get(call->getResult(0)); } +template <typename Op> +static RValue emitTernarySameTypeBuiltin(CIRGenFunction &cgf, + const CallExpr &e) { + mlir::Value arg0 = cgf.emitScalarExpr(e.getArg(0)); + mlir::Value arg1 = cgf.emitScalarExpr(e.getArg(1)); + mlir::Value arg2 = cgf.emitScalarExpr(e.getArg(2)); + + mlir::Location loc = cgf.getLoc(e.getExprLoc()); + mlir::Type ty = cgf.convertType(e.getType()); + auto call = Op::create(cgf.getBuilder(), loc, ty, arg0, arg1, arg2); + + return RValue::get(call->getResult(0)); +} + template <typename Op> static RValue emitTernaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf, const CallExpr &e) { @@ -2044,22 +2058,10 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BI__builtin_elementwise_canonicalize: case Builtin::BI__builtin_elementwise_copysign: return errorBuiltinNYI(*this, e, builtinID); - case Builtin::BI__builtin_elementwise_fshl: { - mlir::Location loc = getLoc(e->getExprLoc()); - mlir::Value a = emitScalarExpr(e->getArg(0)); - mlir::Value b = emitScalarExpr(e->getArg(1)); - mlir::Value c = emitScalarExpr(e->getArg(2)); - return RValue::get(builder.emitIntrinsicCallOp(loc, "fshl", a.getType(), - mlir::ValueRange{a, b, c})); - } - case Builtin::BI__builtin_elementwise_fshr: { - mlir::Location loc = getLoc(e->getExprLoc()); - mlir::Value a = emitScalarExpr(e->getArg(0)); - mlir::Value b = emitScalarExpr(e->getArg(1)); - mlir::Value c = emitScalarExpr(e->getArg(2)); - return RValue::get(builder.emitIntrinsicCallOp(loc, "fshr", a.getType(), - mlir::ValueRange{a, b, c})); - } + case Builtin::BI__builtin_elementwise_fshl: + return emitTernarySameTypeBuiltin<cir::FshlOp>(*this, *e); + case Builtin::BI__builtin_elementwise_fshr: + return emitTernarySameTypeBuiltin<cir::FshrOp>(*this, *e); case Builtin::BI__builtin_elementwise_clmul: case Builtin::BI__builtin_elementwise_pext: case Builtin::BI__builtin_elementwise_pdep: diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512vbmi2-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/avx512vbmi2-builtins.c index d8cd6a2c089b1..c56a1b5ab06b6 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx512vbmi2-builtins.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512vbmi2-builtins.c @@ -13,7 +13,7 @@ __m512i test_mm512_shldv_epi64(__m512i s, __m512i a, __m512i b) { // CIR: %{{.*}} = cir.call @_mm512_shldv_epi64 // CIR-LABEL: cir.func{{.*}} @_mm512_shldv_epi64( // CIR: %{{.*}} = cir.cast bitcast %{{.*}} : !cir.vector<8 x !s64i> -> !cir.vector<8 x !u64i> - // CIR: %{{.*}} = cir.call_llvm_intrinsic "fshl" %{{.*}}, %{{.*}}, %{{.*}} : (!cir.vector<8 x !u64i>{{.*}}, !cir.vector<8 x !u64i>{{.*}}, !cir.vector<8 x !u64i>{{.*}}) -> !cir.vector<8 x !u64i> + // CIR: %{{.*}} = cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<8 x !u64i> // CIR: %{{.*}} = cir.cast bitcast %{{.*}} : !cir.vector<8 x !u64i> -> !cir.vector<8 x !s64i> // LLVM-LABEL: @test_mm512_shldv_epi64 // LLVM: call <8 x i64> @llvm.fshl.v8i64(<8 x i64> {{.*}}, <8 x i64> {{.*}}, <8 x i64> @@ -151,7 +151,7 @@ __m512i test_mm512_shldv_epi32(__m512i s, __m512i a, __m512i b) { // CIR-LABEL: test_mm512_shldv_epi32 // CIR: cir.call @_mm512_shldv_epi32 // CIR-LABEL: cir.func{{.*}} @_mm512_shldv_epi32( - // CIR: cir.call_llvm_intrinsic "fshl" %{{.*}}, %{{.*}}, %{{.*}} : (!cir.vector<16 x !u32i>, !cir.vector<16 x !u32i>, !cir.vector<16 x !u32i>) -> !cir.vector<16 x !u32i> + // CIR: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<16 x !u32i> // CIR: cir.cast bitcast %{{.*}} : !cir.vector<16 x !u32i> -> !cir.vector<8 x !s64i> // LLVM-LABEL: @test_mm512_shldv_epi32 // LLVM: call <16 x i32> @llvm.fshl.v16i32(<16 x i32> {{.*}}, <16 x i32> {{.*}}, <16 x i32> @@ -194,7 +194,7 @@ __m512i test_mm512_shldv_epi16(__m512i s, __m512i a, __m512i b) { // CIR-LABEL: @test_mm512_shldv_epi16 // CIR: cir.call @_mm512_shldv_epi16 // CIR-LABEL: cir.func{{.*}} @_mm512_shldv_epi16( - // CIR: cir.call_llvm_intrinsic "fshl" %{{.*}}, %{{.*}}, %{{.*}}{{.*}} : (!cir.vector<32 x !u16i>, !cir.vector<32 x !u16i>, !cir.vector<32 x !u16i>) -> !cir.vector<32 x !u16i> + // CIR: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<32 x !u16i> // CIR: cir.cast bitcast %{{.*}} : !cir.vector<32 x !u16i> -> !cir.vector<8 x !s64i> // LLVM-LABEL: @test_mm512_shldv_epi16 // LLVM: call <32 x i16> @llvm.fshl.v32i16(<32 x i16> {{.*}}, <32 x i16> {{.*}}, <32 x i16> diff --git a/clang/test/CIR/CodeGenBuiltins/builtins-elementwise.c b/clang/test/CIR/CodeGenBuiltins/builtins-elementwise.c index f89c9278c082d..2825c7df1684c 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtins-elementwise.c +++ b/clang/test/CIR/CodeGenBuiltins/builtins-elementwise.c @@ -604,27 +604,27 @@ void test_builtin_elementwise_fshl(long long int i1, long long int i2, // CIR-LABEL: test_builtin_elementwise_fshl // LLVM-LABEL: test_builtin_elementwise_fshl - // CIR: cir.call_llvm_intrinsic "fshl" %{{.*}}, %{{.*}}, %{{.*}} : (!s64i, !s64i, !s64i) -> !s64i + // CIR: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !s64i // LLVM: call i64 @llvm.fshl.i64(i64 %{{.*}}, i64 %{{.*}}, i64 %{{.*}}) i1 = __builtin_elementwise_fshl(i1, i2, i3); - // CIR: cir.call_llvm_intrinsic "fshl" %{{.*}}, %{{.*}}, %{{.*}} : (!u16i, !u16i, !u16i) -> !u16i + // CIR: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !u16i // LLVM: call i16 @llvm.fshl.i16(i16 %{{.*}}, i16 %{{.*}}, i16 %{{.*}}) us1 = __builtin_elementwise_fshl(us1, us2, us3); - // CIR: cir.call_llvm_intrinsic "fshl" %{{.*}}, %{{.*}}, %{{.*}} : (!s8i, !s8i, !s8i) -> !s8i + // CIR: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !s8i // LLVM: call i8 @llvm.fshl.i8(i8 %{{.*}}, i8 %{{.*}}, i8 %{{.*}}) c1 = __builtin_elementwise_fshl(c1, c2, c3); - // CIR: cir.call_llvm_intrinsic "fshl" %{{.*}}, %{{.*}}, %{{.*}} : (!u8i, !u8i, !u8i) -> !u8i + // CIR: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !u8i // LLVM: call i8 @llvm.fshl.i8(i8 %{{.*}}, i8 %{{.*}}, i8 %{{.*}}) uc1 = __builtin_elementwise_fshl(uc1, uc2, uc3); - // CIR: cir.call_llvm_intrinsic "fshl" %{{.*}}, %{{.*}}, %{{.*}} : (!cir.vector<8 x !s16i>, !cir.vector<8 x !s16i>, !cir.vector<8 x !s16i>) -> !cir.vector<8 x !s16i> + // CIR: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<8 x !s16i> // LLVM: call <8 x i16> @llvm.fshl.v8i16(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}}) vi1 = __builtin_elementwise_fshl(vi1, vi2, vi3); - // CIR: cir.call_llvm_intrinsic "fshl" %{{.*}}, %{{.*}}, %{{.*}} : (!cir.vector<4 x !s32i>, !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> + // CIR: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x !s32i> // LLVM: call <4 x i32> @llvm.fshl.v4i32(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}}) vu1 = __builtin_elementwise_fshl(vu1, vu2, vu3); } @@ -640,27 +640,27 @@ void test_builtin_elementwise_fshr(long long int i1, long long int i2, // CIR-LABEL: test_builtin_elementwise_fshr // LLVM-LABEL: test_builtin_elementwise_fshr - // CIR: cir.call_llvm_intrinsic "fshr" %{{.*}}, %{{.*}}, %{{.*}} : (!s64i, !s64i, !s64i) -> !s64i + // CIR: cir.fshr %{{.*}}, %{{.*}}, %{{.*}} : !s64i // LLVM: call i64 @llvm.fshr.i64(i64 %{{.*}}, i64 %{{.*}}, i64 %{{.*}}) i1 = __builtin_elementwise_fshr(i1, i2, i3); - // CIR: cir.call_llvm_intrinsic "fshr" %{{.*}}, %{{.*}}, %{{.*}} : (!u16i, !u16i, !u16i) -> !u16i + // CIR: cir.fshr %{{.*}}, %{{.*}}, %{{.*}} : !u16i // LLVM: call i16 @llvm.fshr.i16(i16 %{{.*}}, i16 %{{.*}}, i16 %{{.*}}) us1 = __builtin_elementwise_fshr(us1, us2, us3); - // CIR: cir.call_llvm_intrinsic "fshr" %{{.*}}, %{{.*}}, %{{.*}} : (!s8i, !s8i, !s8i) -> !s8i + // CIR: cir.fshr %{{.*}}, %{{.*}}, %{{.*}} : !s8i // LLVM: call i8 @llvm.fshr.i8(i8 %{{.*}}, i8 %{{.*}}, i8 %{{.*}}) c1 = __builtin_elementwise_fshr(c1, c2, c3); - // CIR: cir.call_llvm_intrinsic "fshr" %{{.*}}, %{{.*}}, %{{.*}} : (!u8i, !u8i, !u8i) -> !u8i + // CIR: cir.fshr %{{.*}}, %{{.*}}, %{{.*}} : !u8i // LLVM: call i8 @llvm.fshr.i8(i8 %{{.*}}, i8 %{{.*}}, i8 %{{.*}}) uc1 = __builtin_elementwise_fshr(uc1, uc2, uc3); - // CIR: cir.call_llvm_intrinsic "fshr" %{{.*}}, %{{.*}}, %{{.*}} : (!cir.vector<8 x !s16i>, !cir.vector<8 x !s16i>, !cir.vector<8 x !s16i>) -> !cir.vector<8 x !s16i> + // CIR: cir.fshr %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<8 x !s16i> // LLVM: call <8 x i16> @llvm.fshr.v8i16(<8 x i16> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}}) vi1 = __builtin_elementwise_fshr(vi1, vi2, vi3); - // CIR: cir.call_llvm_intrinsic "fshr" %{{.*}}, %{{.*}}, %{{.*}} : (!cir.vector<4 x !s32i>, !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> + // CIR: cir.fshr %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x !s32i> // LLVM: call <4 x i32> @llvm.fshr.v4i32(<4 x i32> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}}) vu1 = __builtin_elementwise_fshr(vu1, vu2, vu3); } diff --git a/clang/test/CIR/IR/funnel-shift.cir b/clang/test/CIR/IR/funnel-shift.cir new file mode 100644 index 0000000000000..1bf1f04738db3 --- /dev/null +++ b/clang/test/CIR/IR/funnel-shift.cir @@ -0,0 +1,34 @@ +// RUN: cir-opt %s --verify-roundtrip | FileCheck %s + +!s32i = !cir.int<s, 32> +!u16i = !cir.int<u, 16> + +module { + cir.func @fshl_scalar(%a : !s32i, %b : !s32i, %c : !s32i) -> !s32i { + // CHECK: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !s32i + %0 = cir.fshl %a, %b, %c : !s32i + cir.return %0 : !s32i + } + + cir.func @fshr_scalar(%a : !u16i, %b : !u16i, %c : !u16i) -> !u16i { + // CHECK: cir.fshr %{{.*}}, %{{.*}}, %{{.*}} : !u16i + %0 = cir.fshr %a, %b, %c : !u16i + cir.return %0 : !u16i + } + + cir.func @fshl_vector(%a : !cir.vector<4 x !s32i>, + %b : !cir.vector<4 x !s32i>, + %c : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> { + // CHECK: cir.fshl %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x !s32i> + %0 = cir.fshl %a, %b, %c : !cir.vector<4 x !s32i> + cir.return %0 : !cir.vector<4 x !s32i> + } + + cir.func @fshr_vector(%a : !cir.vector<4 x !s32i>, + %b : !cir.vector<4 x !s32i>, + %c : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> { + // CHECK: cir.fshr %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x !s32i> + %0 = cir.fshr %a, %b, %c : !cir.vector<4 x !s32i> + cir.return %0 : !cir.vector<4 x !s32i> + } +} diff --git a/clang/test/CIR/IR/invalid-funnel-shift.cir b/clang/test/CIR/IR/invalid-funnel-shift.cir new file mode 100644 index 0000000000000..e0f7631c349cb --- /dev/null +++ b/clang/test/CIR/IR/invalid-funnel-shift.cir @@ -0,0 +1,32 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +module { + cir.func @fshl_float(%a : !cir.float, %b : !cir.float, %c : !cir.float) { + // expected-error@+1 {{'cir.fshl' op operand #0 must be integer or vector of integer type, but got '!cir.float'}} + %0 = cir.fshl %a, %b, %c : !cir.float + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!u32i = !cir.int<u, 32> + +module { + cir.func @fshl_mixed_signedness(%a : !s32i, %b : !s32i, %c : !u32i) { + // expected-error@+1 {{'cir.fshl' op requires the same type for all operands and results}} + %0 = "cir.fshl"(%a, %b, %c) : (!s32i, !s32i, !u32i) -> !s32i + cir.return + } +} + +// ----- + +module { + cir.func @fshr_float(%a : !cir.float, %b : !cir.float, %c : !cir.float) { + // expected-error@+1 {{'cir.fshr' op operand #0 must be integer or vector of integer type, but got '!cir.float'}} + %0 = cir.fshr %a, %b, %c : !cir.float + cir.return + } +} diff --git a/clang/test/CIR/Lowering/funnel-shift.cir b/clang/test/CIR/Lowering/funnel-shift.cir new file mode 100644 index 0000000000000..a59f6ae6843a7 --- /dev/null +++ b/clang/test/CIR/Lowering/funnel-shift.cir @@ -0,0 +1,26 @@ +// RUN: cir-opt %s -cir-to-llvm -o - | FileCheck %s + +!s32i = !cir.int<s, 32> +!u16i = !cir.int<u, 16> + +module { + cir.func @fshl_scalar(%a : !s32i, %b : !s32i, %c : !s32i) -> !s32i { + %0 = cir.fshl %a, %b, %c : !s32i + // CHECK: llvm.intr.fshl(%{{.*}}, %{{.*}}, %{{.*}}) : (i32, i32, i32) -> i32 + cir.return %0 : !s32i + } + + cir.func @fshr_scalar(%a : !u16i, %b : !u16i, %c : !u16i) -> !u16i { + %0 = cir.fshr %a, %b, %c : !u16i + // CHECK: llvm.intr.fshr(%{{.*}}, %{{.*}}, %{{.*}}) : (i16, i16, i16) -> i16 + cir.return %0 : !u16i + } + + cir.func @fshl_vector(%a : !cir.vector<4 x !s32i>, + %b : !cir.vector<4 x !s32i>, + %c : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> { + %0 = cir.fshl %a, %b, %c : !cir.vector<4 x !s32i> + // CHECK: llvm.intr.fshl(%{{.*}}, %{{.*}}, %{{.*}}) : (vector<4xi32>, vector<4xi32>, vector<4xi32>) -> vector<4xi32> + cir.return %0 : !cir.vector<4 x !s32i> + } +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
