Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -2579,6 +2579,40 @@ def CIR_FuncOp : CIR_Op<"func", [
}];
}

//===----------------------------------------------------------------------===//
// LLVMIntrinsicCallOp
//===----------------------------------------------------------------------===//

def CIR_LLVMIntrinsicCallOp : CIR_Op<"call_llvm_intrinsic"> {
let summary = "Call to llvm intrinsic functions that is not defined in CIR";
let description = [{
`cir.llvm.intrinsic` operation represents a call-like expression which has
return type and arguments that maps directly to a llvm intrinsic.
It only records intrinsic `intrinsic_name`.
}];

let results = (outs Optional<CIR_AnyType>:$result);
let arguments = (ins
StrAttr:$intrinsic_name, Variadic<CIR_AnyType>:$arg_ops);

let skipDefaultBuilders = 1;

let assemblyFormat = [{
$intrinsic_name $arg_ops `:` functional-type($arg_ops, $result) attr-dict
}];

let builders = [
OpBuilder<(ins "mlir::StringAttr":$intrinsic_name, "mlir::Type":$resType,
CArg<"mlir::ValueRange", "{}">:$operands), [{
$_state.addAttribute("intrinsic_name", intrinsic_name);
$_state.addOperands(operands);
if (resType)
$_state.addTypes(resType);
}]>,
];

}

//===----------------------------------------------------------------------===//
// CallOp
//===----------------------------------------------------------------------===//
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<llvm::APSInt> 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,
Expand Down
37 changes: 34 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -43,6 +42,18 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
// Find out if any arguments are required to be integer constant expressions.
assert(!cir::MissingFeatures::handleBuiltinICEArguments());

llvm::SmallVector<mlir::Value> 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 {};
Expand Down Expand Up @@ -82,10 +93,30 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
case X86::BI__builtin_ia32_vec_set_v16hi:
case X86::BI__builtin_ia32_vec_set_v8si:
case X86::BI__builtin_ia32_vec_set_v4di:
cgm.errorNYI(e->getSourceRange(),
std::string("unimplemented X86 builtin call: ") +
getContext().BuiltinInfo.getName(builtinID));
return {};
case X86::BI_mm_setcsr:
case X86::BI__builtin_ia32_ldmxcsr:
case X86::BI__builtin_ia32_ldmxcsr: {
Address tmp =
createMemTemp(e->getArg(0)->getType(), getLoc(e->getExprLoc()));
builder.createStore(getLoc(e->getExprLoc()), ops[0], tmp);
return cir::LLVMIntrinsicCallOp::create(
builder, getLoc(e->getExprLoc()),
builder.getStringAttr("x86.sse.ldmxcsr"), builder.getVoidTy(),
tmp.getPointer())
.getResult();
}
case X86::BI_mm_getcsr:
case X86::BI__builtin_ia32_stmxcsr:
case X86::BI__builtin_ia32_stmxcsr: {
Address tmp = createMemTemp(e->getType(), getLoc(e->getExprLoc()));
cir::LLVMIntrinsicCallOp::create(builder, getLoc(e->getExprLoc()),
builder.getStringAttr("x86.sse.stmxcsr"),
builder.getVoidTy(), tmp.getPointer())
.getResult();
return builder.createLoad(getLoc(e->getExprLoc()), tmp);
}
case X86::BI__builtin_ia32_xsave:
case X86::BI__builtin_ia32_xsave64:
case X86::BI__builtin_ia32_xrstor:
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,29 @@ mlir::LogicalResult CIRToLLVMASinOpLowering::matchAndRewrite(
return mlir::success();
}

mlir::LogicalResult CIRToLLVMLLVMIntrinsicCallOpLowering::matchAndRewrite(
cir::LLVMIntrinsicCallOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
mlir::Type llvmResTy =
getTypeConverter()->convertType(op->getResultTypes()[0]);
if (!llvmResTy)
return op.emitError("expected LLVM result type");
StringRef name = op.getIntrinsicName();
// Some llvm intrinsics require ElementType attribute to be attached to
// the argument of pointer type. That prevents us from generating LLVM IR
// because from LLVM dialect, we have LLVM IR like the below which fails
// LLVM IR verification.
// %3 = call i64 @llvm.aarch64.ldxr.p0(ptr %2)
// The expected LLVM IR should be like
// %3 = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i32) %2)
// TODO(cir): MLIR LLVM dialect should handle this part as CIR has no way
// to set LLVM IR attribute.
assert(!cir::MissingFeatures::llvmIntrinsicElementTypeSupport());
replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm." + name, llvmResTy,
adaptor.getOperands());
return mlir::success();
}

mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(
cir::AssumeOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
Expand Down
36 changes: 36 additions & 0 deletions clang/test/CIR/CodeGen/X86/sse-builtins.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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
// 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 +sse -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 +sse -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 +sse -fclangir -emit-llvm -o %t.ll -Wall -Werror
// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s

// This test mimics clang/test/CodeGen/X86/sse-builtins.c, which eventually
// CIR shall be able to support fully.

#include <immintrin.h>

void test_mm_setcsr(unsigned int A) {
// CIR-LABEL: test_mm_setcsr
// CIR: cir.store {{.*}}, {{.*}} : !u32i
// CIR: cir.call_llvm_intrinsic "x86.sse.ldmxcsr" {{.*}} : (!cir.ptr<!u32i>) -> !void

// LLVM-LABEL: test_mm_setcsr
// LLVM: store i32
// LLVM: call void @llvm.x86.sse.ldmxcsr(ptr {{.*}})
_mm_setcsr(A);
}

unsigned int test_mm_getcsr(void) {
// CIR-LABEL: test_mm_getcsr
// CIR: cir.call_llvm_intrinsic "x86.sse.stmxcsr" %{{.*}} : (!cir.ptr<!u32i>) -> !void
// CIR: cir.load {{.*}} : !cir.ptr<!u32i>, !u32i

// LLVM-LABEL: test_mm_getcsr
// LLVM: call void @llvm.x86.sse.stmxcsr(ptr %{{.*}})
// LLVM: load i32
return _mm_getcsr();
}
Loading