diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 3d135e59e6ba..fc485c38f453 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4147,6 +4147,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 55619a8d935a..e7a07f1523c3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -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; diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index e0a87dd78413..035be9cca2da 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -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( + 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, @@ -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"; } @@ -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(); @@ -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()); @@ -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 diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index d1488ec8f6f5..a88c30d3dd15 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -125,6 +125,16 @@ class CIRToLLVMMemSetOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMMemSetInlineOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::MemSetInlineOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override; +}; + class CIRToLLVMPtrStrideOpLowering : public mlir::OpConversionPattern { public: diff --git a/clang/test/CIR/CodeGen/builtins-memory.c b/clang/test/CIR/CodeGen/builtins-memory.c index 472d2103a960..9c7a74301aaa 100644 --- a/clang/test/CIR/CodeGen/builtins-memory.c +++ b/clang/test/CIR/CodeGen/builtins-memory.c @@ -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) { + + // 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); +}