Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CIR][CIRGen] Support __builtin_memset_inline #1114

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
31 changes: 31 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -4147,6 +4147,37 @@ def MemSetOp : CIR_Op<"libc.memset"> {
let hasVerifier = 0;
}

//===----------------------------------------------------------------------===//
// MemSetInlineOp
//===----------------------------------------------------------------------===//

def MemSetInlineOp : CIR_Op<"memset_inline"> {
let arguments = (ins Arg<VoidPtr, "", [MemWrite]>:$dst,
SInt32:$val,
I64Attr:$len);
let summary = "Fill a block of memory with constant length without calling"
"any external function";
let description = [{
Given the CIR pointer, `dst`, `cir.memset_inline` will set the first `len`
bytes of the memory pointed by `dst` to the specified `val`.

The `len` argument must be a constant integer argument specifying the number
of bytes to fill.

Examples:

```mlir
// Set 2 bytes from a struct to 0
cir.memset_inline 2 bytes from %struct set to %zero : !cir.ptr<!void>, !s32i
```
}];

let assemblyFormat = [{
$len `bytes` `from` $dst `set` `to` $val attr-dict
`:` qualified(type($dst)) `,` type($val)
}];
let hasVerifier = 0;
}
//===----------------------------------------------------------------------===//
// MemChrOp
//===----------------------------------------------------------------------===//
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,13 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return create<cir::MemSetOp>(loc, dst, val, len);
}

cir::MemSetInlineOp createMemSetInline(mlir::Location loc, mlir::Value dst,
mlir::Value val,
mlir::IntegerAttr len) {
val = createIntCast(val, cir::IntType::get(getContext(), 32, true));
return create<cir::MemSetInlineOp>(loc, dst, val, len);
}

mlir::Value createNeg(mlir::Value value) {

if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1554,8 +1554,20 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Dest.getPointer());
}

case Builtin::BI__builtin_memset_inline:
llvm_unreachable("BI__builtin_memset_inline NYI");
case Builtin::BI__builtin_memset_inline: {
Address Dest = emitPointerWithAlignment(E->getArg(0));
mlir::Value ByteVal = emitScalarExpr(E->getArg(1));
uint64_t size =
E->getArg(2)->EvaluateKnownConstInt(getContext()).getZExtValue();
emitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(),
E->getArg(0)->getExprLoc(), FD, 0);
builder.createMemSetInline(
getLoc(E->getSourceRange()), Dest.getPointer(), ByteVal,
mlir::IntegerAttr::get(mlir::IntegerType::get(builder.getContext(), 64),
size));
// __builtin_memset_inline has no return value
return RValue::get(nullptr);
}
case Builtin::BI__builtin___memset_chk: {
// fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
llvm::APSInt size;
Expand Down
29 changes: 21 additions & 8 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,18 @@ mlir::LogicalResult CIRToLLVMMemSetOpLowering::matchAndRewrite(
return mlir::success();
}

mlir::LogicalResult CIRToLLVMMemSetInlineOpLowering::matchAndRewrite(
cir::MemSetInlineOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
auto converted = rewriter.create<mlir::LLVM::TruncOp>(
op.getLoc(), mlir::IntegerType::get(op.getContext(), 8),
adaptor.getVal());
rewriter.replaceOpWithNewOp<mlir::LLVM::MemsetInlineOp>(
op, adaptor.getDst(), converted, adaptor.getLenAttr(),
/*isVolatile=*/false);
return mlir::success();
}

static mlir::Value getLLVMIntCast(mlir::ConversionPatternRewriter &rewriter,
mlir::Value llvmSrc, mlir::Type llvmDstIntTy,
bool isUnsigned, uint64_t cirSrcWidth,
Expand Down Expand Up @@ -1851,8 +1863,8 @@ mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite(
return op.emitError("cir.vaarg lowering is NYI");
}

/// Returns the name used for the linkage attribute. This *must* correspond
/// to the name of the attribute in ODS.
/// Returns the name used for the linkage attribute. This *must* correspond
/// to the name of the attribute in ODS.
StringRef CIRToLLVMFuncOpLowering::getLinkageAttrNameString() {
return "linkage";
}
Expand Down Expand Up @@ -1886,8 +1898,8 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
}
}

/// When do module translation, we can only translate LLVM-compatible types.
/// Here we lower possible OpenCLKernelMetadataAttr to use the converted type.
/// When do module translation, we can only translate LLVM-compatible types.
/// Here we lower possible OpenCLKernelMetadataAttr to use the converted type.
void CIRToLLVMFuncOpLowering::lowerFuncOpenCLKernelMetadata(
mlir::NamedAttribute &extraAttrsEntry) const {
const auto attrKey = cir::OpenCLKernelMetadataAttr::getMnemonic();
Expand Down Expand Up @@ -2100,8 +2112,8 @@ mlir::LogicalResult CIRToLLVMSwitchFlatOpLowering::matchAndRewrite(
return mlir::success();
}

/// Replace CIR global with a region initialized LLVM global and update
/// insertion point to the end of the initializer block.
/// Replace CIR global with a region initialized LLVM global and update
/// insertion point to the end of the initializer block.
void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const {
const auto llvmType = getTypeConverter()->convertType(op.getSymType());
Expand Down Expand Up @@ -3890,8 +3902,9 @@ void populateCIRToLLVMConversionPatterns(
CIRToLLVMBaseClassAddrOpLowering, CIRToLLVMDerivedClassAddrOpLowering,
CIRToLLVMVTTAddrPointOpLowering, CIRToLLVMIsFPClassOpLowering,
CIRToLLVMAbsOpLowering, CIRToLLVMMemMoveOpLowering,
CIRToLLVMMemSetOpLowering, CIRToLLVMMemCpyInlineOpLowering,
CIRToLLVMSignBitOpLowering, CIRToLLVMPtrMaskOpLowering
CIRToLLVMMemSetOpLowering, CIRToLLVMMemSetInlineOpLowering,
CIRToLLVMMemCpyInlineOpLowering, CIRToLLVMSignBitOpLowering,
CIRToLLVMPtrMaskOpLowering
#define GET_BUILTIN_LOWERING_LIST
#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
#undef GET_BUILTIN_LOWERING_LIST
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ class CIRToLLVMMemSetOpLowering
mlir::ConversionPatternRewriter &) const override;
};

class CIRToLLVMMemSetInlineOpLowering
: public mlir::OpConversionPattern<cir::MemSetInlineOp> {
public:
using mlir::OpConversionPattern<cir::MemSetInlineOp>::OpConversionPattern;

mlir::LogicalResult
matchAndRewrite(cir::MemSetInlineOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override;
};

class CIRToLLVMPtrStrideOpLowering
: public mlir::OpConversionPattern<cir::PtrStrideOp> {
public:
Expand Down
20 changes: 20 additions & 0 deletions clang/test/CIR/CodeGen/builtins-memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,23 @@ void test_memcpy_inline_aligned_buffers(unsigned long long *dst, const unsigned
// COM: LLVM: call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 {{%.*}}, ptr align 8 {{%.*}}, i64 4, i1 false)
__builtin_memcpy_inline(dst, src, 4);
}

void test_memset_inline(void *dst, int val) {
PikachuHyA marked this conversation as resolved.
Show resolved Hide resolved

// CIR-LABEL: test_memset_inline
// CIR: cir.memset_inline 0 bytes from {{%.*}} set to {{%.*}} : !cir.ptr<!void>, !s32i

// LLVM-LABEL: test_memset_inline
// LLVM: call void @llvm.memset.inline.p0.i64(ptr {{%.*}}, i8 {{%.*}}, i64 0, i1 false)
__builtin_memset_inline(dst, val, 0);

// CIR: cir.memset_inline 1 bytes from {{%.*}} set to {{%.*}} : !cir.ptr<!void>, !s32i

// LLVM: call void @llvm.memset.inline.p0.i64(ptr {{%.*}}, i8 {{%.*}}, i64 1, i1 false)
__builtin_memset_inline(dst, val, 1);

// CIR: cir.memset_inline 4 bytes from {{%.*}} set to {{%.*}} : !cir.ptr<!void>, !s32i

// LLVM: call void @llvm.memset.inline.p0.i64(ptr {{%.*}}, i8 {{%.*}}, i64 4, i1 false)
__builtin_memset_inline(dst, val, 4);
}