From 74c2c64cb88df3bdde356956b915a85322f0b28d Mon Sep 17 00:00:00 2001 From: PikachuHy Date: Tue, 12 Nov 2024 11:50:58 +0800 Subject: [PATCH] [CIR][CIRGen] Support __builtin_memset_inline --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 31 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenBuilder.h | 7 +++++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 16 ++++++++-- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 21 ++++++++++++- clang/test/CIR/CodeGen/builtins-memory.c | 20 ++++++++++++ 5 files changed, 92 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index b01e9eb55517..5f82360b6b4d 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4148,6 +4148,37 @@ def MemSetOp : CIR_Op<"libc.memset"> { let hasVerifier = 0; } +//===----------------------------------------------------------------------===// +// MemSetInlineOp +//===----------------------------------------------------------------------===// + +def MemSetInlineOp : CIR_Op<"memset_inline"> { + let arguments = (ins Arg:$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, !s32i + ``` + }]; + + let assemblyFormat = [{ + $len `bytes` `from` $dst `set` `to` $val attr-dict + `:` qualified(type($dst)) `,` type($val) + }]; + let hasVerifier = 0; +} //===----------------------------------------------------------------------===// // MemChrOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index aedf2c390911..e66b40700875 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -623,6 +623,13 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return create(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(loc, dst, val, len); + } + mlir::Value createNeg(mlir::Value value) { if (auto intTy = mlir::dyn_cast(value.getType())) { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index ea726b0f07b9..63c31766a7e5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1522,8 +1522,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. Expr::EvalResult sizeResult, dstSizeResult; diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index a5d6a69693ae..3d527afbf89f 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -823,6 +823,24 @@ class CIRMemsetOpLowering : public mlir::OpConversionPattern { } }; +class CIRMemsetInlineOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::MemSetInlineOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + auto converted = rewriter.create( + op.getLoc(), mlir::IntegerType::get(op.getContext(), 8), + adaptor.getVal()); + rewriter.replaceOpWithNewOp( + 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, @@ -4398,7 +4416,8 @@ void populateCIRToLLVMConversionPatterns( CIRAssumeLowering, CIRAssumeAlignedLowering, CIRAssumeSepStorageLowering, CIRBaseClassAddrOpLowering, CIRDerivedClassAddrOpLowering, CIRVTTAddrPointOpLowering, CIRIsFPClassOpLowering, CIRAbsOpLowering, - CIRMemMoveOpLowering, CIRMemsetOpLowering, CIRSignBitOpLowering + CIRMemMoveOpLowering, CIRMemsetOpLowering, CIRMemsetInlineOpLowering, + CIRSignBitOpLowering #define GET_BUILTIN_LOWERING_LIST #include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc" #undef GET_BUILTIN_LOWERING_LIST diff --git a/clang/test/CIR/CodeGen/builtins-memory.c b/clang/test/CIR/CodeGen/builtins-memory.c index 940e09a8ed6d..f2d20fb13915 100644 --- a/clang/test/CIR/CodeGen/builtins-memory.c +++ b/clang/test/CIR/CodeGen/builtins-memory.c @@ -145,3 +145,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) { + + // CIR-LABEL: test_memset_inline + // CIR: cir.memset_inline 0 bytes from {{%.*}} set to {{%.*}} : !cir.ptr, !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, !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, !s32i + + // LLVM: call void @llvm.memset.inline.p0.i64(ptr {{%.*}}, i8 {{%.*}}, i64 4, i1 false) + __builtin_memset_inline(dst, val, 4); +}