Skip to content

Commit e76ff90

Browse files
Upstream CIR codegen for mxcsr x86 builtins
1 parent 938f521 commit e76ff90

File tree

6 files changed

+146
-3
lines changed

6 files changed

+146
-3
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2579,6 +2579,40 @@ def CIR_FuncOp : CIR_Op<"func", [
25792579
}];
25802580
}
25812581

2582+
//===----------------------------------------------------------------------===//
2583+
// LLVMIntrinsicCallOp
2584+
//===----------------------------------------------------------------------===//
2585+
2586+
def CIR_LLVMIntrinsicCallOp : CIR_Op<"call_llvm_intrinsic"> {
2587+
let summary = "Call to llvm intrinsic functions that is not defined in CIR";
2588+
let description = [{
2589+
`cir.llvm.intrinsic` operation represents a call-like expression which has
2590+
return type and arguments that maps directly to a llvm intrinsic.
2591+
It only records intrinsic `intrinsic_name`.
2592+
}];
2593+
2594+
let results = (outs Optional<CIR_AnyType>:$result);
2595+
let arguments = (ins
2596+
StrAttr:$intrinsic_name, Variadic<CIR_AnyType>:$arg_ops);
2597+
2598+
let skipDefaultBuilders = 1;
2599+
2600+
let assemblyFormat = [{
2601+
$intrinsic_name $arg_ops `:` functional-type($arg_ops, $result) attr-dict
2602+
}];
2603+
2604+
let builders = [
2605+
OpBuilder<(ins "mlir::StringAttr":$intrinsic_name, "mlir::Type":$resType,
2606+
CArg<"mlir::ValueRange", "{}">:$operands), [{
2607+
$_state.addAttribute("intrinsic_name", intrinsic_name);
2608+
$_state.addOperands(operands);
2609+
if (resType)
2610+
$_state.addTypes(resType);
2611+
}]>,
2612+
];
2613+
2614+
}
2615+
25822616
//===----------------------------------------------------------------------===//
25832617
// CallOp
25842618
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,22 @@ CIRGenFunction::emitTargetBuiltinExpr(unsigned builtinID, const CallExpr *e,
625625
getTarget().getTriple().getArch());
626626
}
627627

628+
mlir::Value CIRGenFunction::emitScalarOrConstFoldImmArg(
629+
const unsigned iceArguments, const unsigned idx, const Expr *argExpr) {
630+
mlir::Value arg = {};
631+
if ((iceArguments & (1 << idx)) == 0) {
632+
arg = emitScalarExpr(argExpr);
633+
} else {
634+
// If this is required to be a constant, constant fold it so that we
635+
// know that the generated intrinsic gets a ConstantInt.
636+
const std::optional<llvm::APSInt> result =
637+
argExpr->getIntegerConstantExpr(getContext());
638+
assert(result && "Expected argument to be a constant");
639+
arg = builder.getConstInt(getLoc(argExpr->getSourceRange()), *result);
640+
}
641+
return arg;
642+
}
643+
628644
/// Given a builtin id for a function like "__builtin_fabsf", return a Function*
629645
/// for "fabsf".
630646
cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *fd,

clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include "clang/Basic/Builtins.h"
1717
#include "clang/Basic/TargetBuiltins.h"
1818
#include "clang/CIR/MissingFeatures.h"
19-
#include "llvm/IR/IntrinsicsX86.h"
2019

2120
using namespace clang;
2221
using namespace clang::CIRGen;
@@ -43,6 +42,18 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
4342
// Find out if any arguments are required to be integer constant expressions.
4443
assert(!cir::MissingFeatures::handleBuiltinICEArguments());
4544

45+
llvm::SmallVector<mlir::Value> ops;
46+
47+
// Find out if any arguments are required to be integer constant expressions.
48+
unsigned iceArguments = 0;
49+
ASTContext::GetBuiltinTypeError error;
50+
getContext().GetBuiltinType(builtinID, error, &iceArguments);
51+
assert(error == ASTContext::GE_None && "Should not codegen an error");
52+
53+
for (auto [idx, arg] : llvm::enumerate(e->arguments())) {
54+
ops.push_back(emitScalarOrConstFoldImmArg(iceArguments, idx, arg));
55+
}
56+
4657
switch (builtinID) {
4758
default:
4859
return {};
@@ -82,10 +93,30 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
8293
case X86::BI__builtin_ia32_vec_set_v16hi:
8394
case X86::BI__builtin_ia32_vec_set_v8si:
8495
case X86::BI__builtin_ia32_vec_set_v4di:
96+
cgm.errorNYI(e->getSourceRange(),
97+
std::string("unimplemented X86 builtin call: ") +
98+
getContext().BuiltinInfo.getName(builtinID));
99+
return {};
85100
case X86::BI_mm_setcsr:
86-
case X86::BI__builtin_ia32_ldmxcsr:
101+
case X86::BI__builtin_ia32_ldmxcsr: {
102+
Address tmp =
103+
createMemTemp(e->getArg(0)->getType(), getLoc(e->getExprLoc()));
104+
builder.createStore(getLoc(e->getExprLoc()), ops[0], tmp);
105+
return cir::LLVMIntrinsicCallOp::create(
106+
builder, getLoc(e->getExprLoc()),
107+
builder.getStringAttr("x86.sse.ldmxcsr"), builder.getVoidTy(),
108+
tmp.getPointer())
109+
.getResult();
110+
}
87111
case X86::BI_mm_getcsr:
88-
case X86::BI__builtin_ia32_stmxcsr:
112+
case X86::BI__builtin_ia32_stmxcsr: {
113+
Address tmp = createMemTemp(e->getType(), getLoc(e->getExprLoc()));
114+
cir::LLVMIntrinsicCallOp::create(builder, getLoc(e->getExprLoc()),
115+
builder.getStringAttr("x86.sse.stmxcsr"),
116+
builder.getVoidTy(), tmp.getPointer())
117+
.getResult();
118+
return builder.createLoad(getLoc(e->getExprLoc()), tmp);
119+
}
89120
case X86::BI__builtin_ia32_xsave:
90121
case X86::BI__builtin_ia32_xsave64:
91122
case X86::BI__builtin_ia32_xrstor:

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,9 @@ class CIRGenFunction : public CIRGenTypeCache {
16991699
void emitScalarInit(const clang::Expr *init, mlir::Location loc,
17001700
LValue lvalue, bool capturedByInit = false);
17011701

1702+
mlir::Value emitScalarOrConstFoldImmArg(unsigned iceArguments, unsigned idx,
1703+
const Expr *argExpr);
1704+
17021705
void emitStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage);
17031706

17041707
void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest,

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,29 @@ mlir::LogicalResult CIRToLLVMASinOpLowering::matchAndRewrite(
646646
return mlir::success();
647647
}
648648

649+
mlir::LogicalResult CIRToLLVMLLVMIntrinsicCallOpLowering::matchAndRewrite(
650+
cir::LLVMIntrinsicCallOp op, OpAdaptor adaptor,
651+
mlir::ConversionPatternRewriter &rewriter) const {
652+
mlir::Type llvmResTy =
653+
getTypeConverter()->convertType(op->getResultTypes()[0]);
654+
if (!llvmResTy)
655+
return op.emitError("expected LLVM result type");
656+
StringRef name = op.getIntrinsicName();
657+
// Some llvm intrinsics require ElementType attribute to be attached to
658+
// the argument of pointer type. That prevents us from generating LLVM IR
659+
// because from LLVM dialect, we have LLVM IR like the below which fails
660+
// LLVM IR verification.
661+
// %3 = call i64 @llvm.aarch64.ldxr.p0(ptr %2)
662+
// The expected LLVM IR should be like
663+
// %3 = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i32) %2)
664+
// TODO(cir): MLIR LLVM dialect should handle this part as CIR has no way
665+
// to set LLVM IR attribute.
666+
assert(!cir::MissingFeatures::llvmIntrinsicElementTypeSupport());
667+
replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm." + name, llvmResTy,
668+
adaptor.getOperands());
669+
return mlir::success();
670+
}
671+
649672
mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(
650673
cir::AssumeOp op, OpAdaptor adaptor,
651674
mlir::ConversionPatternRewriter &rewriter) const {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fclangir -emit-cir -o %t.cir -Wall -Werror
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fclangir -emit-llvm -o %t.ll -Wall -Werror
4+
// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s
5+
6+
// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fno-signed-char -fclangir -emit-cir -o %t.cir -Wall -Werror
7+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
8+
// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fclangir -emit-llvm -o %t.ll -Wall -Werror
9+
// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s
10+
11+
// This test mimics clang/test/CodeGen/X86/sse-builtins.c, which eventually
12+
// CIR shall be able to support fully.
13+
14+
#include <immintrin.h>
15+
16+
void test_mm_setcsr(unsigned int A) {
17+
// CIR-LABEL: test_mm_setcsr
18+
// CIR: cir.store {{.*}}, {{.*}} : !u32i
19+
// CIR: cir.call_llvm_intrinsic "x86.sse.ldmxcsr" {{.*}} : (!cir.ptr<!u32i>) -> !void
20+
21+
// LLVM-LABEL: test_mm_setcsr
22+
// LLVM: store i32
23+
// LLVM: call void @llvm.x86.sse.ldmxcsr(ptr {{.*}})
24+
_mm_setcsr(A);
25+
}
26+
27+
unsigned int test_mm_getcsr(void) {
28+
// CIR-LABEL: test_mm_getcsr
29+
// CIR: cir.call_llvm_intrinsic "x86.sse.stmxcsr" %{{.*}} : (!cir.ptr<!u32i>) -> !void
30+
// CIR: cir.load {{.*}} : !cir.ptr<!u32i>, !u32i
31+
32+
// LLVM-LABEL: test_mm_getcsr
33+
// LLVM: call void @llvm.x86.sse.stmxcsr(ptr %{{.*}})
34+
// LLVM: load i32
35+
return _mm_getcsr();
36+
}

0 commit comments

Comments
 (0)