From 36c120365980de11c71dae76730d4ff18f273de6 Mon Sep 17 00:00:00 2001 From: Thibault-Monnier Date: Thu, 13 Nov 2025 20:57:19 +0100 Subject: [PATCH 1/2] Upstream CIR codegen for vec_ext x86 builtins --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 6 ++++ clang/lib/CIR/CodeGen/CIRGenBuilder.h | 6 ++-- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 16 +++++++++ clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 33 ++++++++++++++++-- clang/lib/CIR/CodeGen/CIRGenFunction.h | 3 ++ clang/test/CIR/CodeGen/X86/sse2-builtins.c | 36 ++++++++++++++++++++ 6 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 clang/test/CIR/CodeGen/X86/sse2-builtins.c diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 16258513239d9..9646e55ab9ea8 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -413,6 +413,12 @@ def CIR_ConstantOp : CIR_Op<"const", [ template T getValueAttr() { return mlir::dyn_cast(getValue()); } + + llvm::APInt getIntValue() { + if (const auto intAttr = getValueAttr()) + return intAttr.getValue(); + llvm_unreachable("Expected an IntAttr in ConstantOp"); + } }]; let hasFolder = 1; diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index e5066fac19185..a0af38ceab74c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -315,8 +315,10 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return getConstantInt(loc, getUInt32Ty(), c); } cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc) { - cir::IntType sInt64Ty = getSInt64Ty(); - return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(sInt64Ty, c)); + return getConstantInt(loc, getSInt64Ty(), c); + } + cir::ConstantOp getUInt64(uint64_t c, mlir::Location loc) { + return getConstantInt(loc, getUInt64Ty(), c); } mlir::Value createNeg(mlir::Value value) { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 4e6a5ee7ee210..b54256715be96 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -625,6 +625,22 @@ CIRGenFunction::emitTargetBuiltinExpr(unsigned builtinID, const CallExpr *e, getTarget().getTriple().getArch()); } +mlir::Value CIRGenFunction::emitScalarOrConstFoldImmArg( + const unsigned iceArguments, const unsigned idx, const Expr *argExpr) { + mlir::Value arg = {}; + if ((iceArguments & (1 << idx)) == 0) { + arg = emitScalarExpr(argExpr); + } else { + // If this is required to be a constant, constant fold it so that we + // know that the generated intrinsic gets a ConstantInt. + const std::optional result = + argExpr->getIntegerConstantExpr(getContext()); + assert(result && "Expected argument to be a constant"); + arg = builder.getConstInt(getLoc(argExpr->getSourceRange()), *result); + } + return arg; +} + /// Given a builtin id for a function like "__builtin_fabsf", return a Function* /// for "fabsf". cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *fd, diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 0198a9d4eb192..ca00b12eb9623 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -16,7 +16,6 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/CIR/MissingFeatures.h" -#include "llvm/IR/IntrinsicsX86.h" using namespace clang; using namespace clang::CIRGen; @@ -43,6 +42,17 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, // Find out if any arguments are required to be integer constant expressions. assert(!cir::MissingFeatures::handleBuiltinICEArguments()); + llvm::SmallVector ops; + + // Find out if any arguments are required to be integer constant expressions. + unsigned iceArguments = 0; + ASTContext::GetBuiltinTypeError error; + getContext().GetBuiltinType(builtinID, error, &iceArguments); + assert(error == ASTContext::GE_None && "Should not codegen an error"); + + for (auto [idx, arg] : llvm::enumerate(e->arguments())) + ops.push_back(emitScalarOrConstFoldImmArg(iceArguments, idx, arg)); + switch (builtinID) { default: return {}; @@ -63,6 +73,10 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, case X86::BI__builtin_ia32_undef128: case X86::BI__builtin_ia32_undef256: case X86::BI__builtin_ia32_undef512: + cgm.errorNYI(e->getSourceRange(), + std::string("unimplemented X86 builtin call: ") + + getContext().BuiltinInfo.getName(builtinID)); + return {}; case X86::BI__builtin_ia32_vec_ext_v4hi: case X86::BI__builtin_ia32_vec_ext_v16qi: case X86::BI__builtin_ia32_vec_ext_v8hi: @@ -72,7 +86,22 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, case X86::BI__builtin_ia32_vec_ext_v32qi: case X86::BI__builtin_ia32_vec_ext_v16hi: case X86::BI__builtin_ia32_vec_ext_v8si: - case X86::BI__builtin_ia32_vec_ext_v4di: + case X86::BI__builtin_ia32_vec_ext_v4di: { + unsigned numElts = cast(ops[0].getType()).getSize(); + + uint64_t index = + ops[1].getDefiningOp().getIntValue().getZExtValue(); + + index &= numElts - 1; + + cir::ConstantOp indexVal = + builder.getUInt64(index, getLoc(e->getExprLoc())); + + // These builtins exist so we can ensure the index is an ICE and in range. + // Otherwise we could just do this in the header file. + return cir::VecExtractOp::create(builder, getLoc(e->getExprLoc()), ops[0], + indexVal); + } case X86::BI__builtin_ia32_vec_set_v4hi: case X86::BI__builtin_ia32_vec_set_v16qi: case X86::BI__builtin_ia32_vec_set_v8hi: diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index f879e580989f7..c2ef98d2b25d6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1699,6 +1699,9 @@ class CIRGenFunction : public CIRGenTypeCache { void emitScalarInit(const clang::Expr *init, mlir::Location loc, LValue lvalue, bool capturedByInit = false); + mlir::Value emitScalarOrConstFoldImmArg(unsigned iceArguments, unsigned idx, + const Expr *argExpr); + void emitStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage); void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, diff --git a/clang/test/CIR/CodeGen/X86/sse2-builtins.c b/clang/test/CIR/CodeGen/X86/sse2-builtins.c new file mode 100644 index 0000000000000..9154cae4ea12e --- /dev/null +++ b/clang/test/CIR/CodeGen/X86/sse2-builtins.c @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse2 -fclangir -emit-cir -o %t.cir -Wall -Werror +// RUN: FileCheck --check-prefixes=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse2 -fno-signed-char -fclangir -emit-cir -o %t.cir -Wall -Werror +// RUN: FileCheck --check-prefixes=CIR --input-file=%t.cir %s + +// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse2 -fclangir -emit-llvm -o %t.ll -Wall -Werror +// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s +// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse2 -fno-signed-char -fclangir -emit-llvm -o %t.ll -Wall -Werror +// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s + +// RUN: FileCheck --check-prefixes=OGCG --input-file=%t.ll %s +// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse2 -fno-signed-char -emit-llvm -o %t.ll -Wall -Werror +// RUN: FileCheck --check-prefixes=OGCG --input-file=%t.ll %s + +// This test mimics clang/test/CodeGen/X86/sse2-builtins.c, which eventually +// CIR shall be able to support fully. + +#include + +// Lowering to pextrw requires optimization. +int test_mm_extract_epi16(__m128i A) { + + // CIR-LABEL: test_mm_extract_epi16 + // CIR %{{.*}} = cir.vec.extract %{{.*}}[%{{.*}} : {{!u32i|!u64i}}] : !cir.vector + // CIR %{{.*}} = cir.cast integral %{{.*}} : !u16i -> !s32i + + // LLVM-LABEL: test_mm_extract_epi16 + // LLVM: extractelement <8 x i16> %{{.*}}, {{i32|i64}} 1 + // LLVM: zext i16 %{{.*}} to i32 + + // OGCG-LABEL: test_mm_extract_epi16 + // OGCG: extractelement <8 x i16> %{{.*}}, {{i32|i64}} 1 + // OGCG: zext i16 %{{.*}} to i32 + + return _mm_extract_epi16(A, 1); +} From 0227a8d8956d00416f10cb26f467f7d689c08e6f Mon Sep 17 00:00:00 2001 From: Thibault-Monnier Date: Fri, 14 Nov 2025 23:32:23 +0100 Subject: [PATCH 2/2] Remove duplicate definition --- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 22 ---------------------- clang/lib/CIR/CodeGen/CIRGenFunction.h | 3 --- 2 files changed, 25 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 15d96c0a340ff..5d9188777741d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1442,28 +1442,6 @@ mlir::Value CIRGenFunction::emitPromotedScalarExpr(const Expr *e, return ScalarExprEmitter(*this, builder).Visit(const_cast(e)); } -mlir::Value CIRGenFunction::emitScalarOrConstFoldImmArg(unsigned iceArguments, - unsigned index, - const Expr *arg) { - mlir::Value result{}; - - // The bit at the specified index indicates whether the argument is required - // to be a constant integer expression. - bool isArgRequiredToBeConstant = (iceArguments & (1 << index)); - - if (!isArgRequiredToBeConstant) { - result = emitScalarExpr(arg); - } else { - // If this is required to be a constant, constant fold it so that we - // know that the generated intrinsic gets a ConstantInt. - std::optional iceOpt = - arg->getIntegerConstantExpr(getContext()); - assert(iceOpt && "Expected argument to be a constant"); - result = builder.getConstInt(getLoc(arg->getSourceRange()), *iceOpt); - } - return result; -} - [[maybe_unused]] static bool mustVisitNullValue(const Expr *e) { // If a null pointer expression's type is the C++0x nullptr_t and // the expression is not a simple literal, it must be evaluated diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 8afec753aae14..00f289bcd1bb2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1546,9 +1546,6 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign = false); - mlir::Value emitScalarOrConstFoldImmArg(unsigned iceArguments, unsigned index, - const Expr *arg); - mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv, cir::UnaryOpKind kind, bool isPre);