llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clangir Author: Ayokunle Amodu (ayokunle321) <details> <summary>Changes</summary> This adds CIR support for the bcopy builtin. --- Full diff: https://github.com/llvm/llvm-project/pull/185038.diff 7 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+29-1) - (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (+5) - (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+12-2) - (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+9) - (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+7) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+9) - (added) clang/test/CIR/CodeGenBuiltins/builtin-bcopy.cpp (+80) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index a5a5197cd3ea6..ac35bf53206d3 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3725,7 +3725,35 @@ def CIR_MemCpyOp : CIR_MemOp<"libc.memcpy"> { }]; } -// TODO: MemMoveOp +def CIR_MemMoveOp : CIR_MemOp<"libc.memmove"> { + let summary = "Equivalent to libc's `memmove`"; + let description = [{ + Given two CIR pointers, `src` and `dst`, `cir.libc.memmove` will copy `len` + bytes from the memory pointed by `src` to the memory pointed by `dst`. + + similiar to `cir.libc.memcpy` but accounts for overlapping memory. + + Examples: + + ```mlir + // Copying 2 bytes from one array to a record: + %2 = cir.const #cir.int<2> : !u32i + cir.libc.memmove %2 bytes from %arr to %record : !cir.ptr<!void>, !u64i + ``` + }]; + + let arguments = !con(commonArgs, (ins CIR_AnyFundamentalUIntType:$len)); + + let assemblyFormat = [{ + $len `bytes` `from` $src `to` $dst attr-dict + `:` qualified(type($dst)) `,` type($len) + }]; + + let extraClassDeclaration = [{ + /// Returns the byte length type. + cir::IntType getLenTy() { return getLen().getType(); } + }]; +} //===----------------------------------------------------------------------===// // MemSetOp diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index cd13c9578adf7..2f6ece84c6c0b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -240,6 +240,11 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return cir::MemCpyOp::create(*this, loc, dst, src, len); } + cir::MemMoveOp createMemMove(mlir::Location loc, mlir::Value dst, + mlir::Value src, mlir::Value len) { + return cir::MemMoveOp::create(*this, loc, dst, src, len); + } + cir::MemSetOp createMemSet(mlir::Location loc, mlir::Value dst, mlir::Value val, mlir::Value len) { assert(val.getType() == getUInt8Ty()); diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index a27e66e0989fa..ca8764821e48c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1557,8 +1557,18 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIbzero: case Builtin::BI__builtin_bzero: case Builtin::BIbcopy: - case Builtin::BI__builtin_bcopy: - return errorBuiltinNYI(*this, e, builtinID); + case Builtin::BI__builtin_bcopy: { + Address src = emitPointerWithAlignment(e->getArg(0)); + Address dest = emitPointerWithAlignment(e->getArg(1)); + mlir::Value sizeVal = emitScalarExpr(e->getArg(2)); + emitNonNullArgCheck(RValue::get(src.getPointer()), e->getArg(0)->getType(), + e->getArg(0)->getExprLoc(), fd, 0); + emitNonNullArgCheck(RValue::get(dest.getPointer()), e->getArg(1)->getType(), + e->getArg(1)->getExprLoc(), fd, 0); + builder.createMemMove(getLoc(e->getSourceRange()), dest.getPointer(), + src.getPointer(), sizeVal); + return RValue::get(nullptr); + } case Builtin::BI__builtin_char_memchr: case Builtin::BI__builtin_memchr: { Address srcPtr = emitPointerWithAlignment(e->getArg(0)); diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index c92296352db4e..c32a1c7a8f780 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -1021,6 +1021,15 @@ CIRGenTypes::arrangeFunctionDeclaration(const FunctionDecl *fd) { return arrangeFreeFunctionType(funcTy.castAs<FunctionProtoType>()); } +void CIRGenFunction::emitNonNullArgCheck(RValue rv, QualType argType, + SourceLocation argLoc, + AbstractCallee ac, unsigned paramNum) { + if (!ac.getDecl() || !(sanOpts.has(SanitizerKind::NonnullAttribute) || + sanOpts.has(SanitizerKind::NullabilityArg))) + return; + cgm.errorNYI("non-null arg check is NYI"); +} + static cir::CIRCallOpInterface emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc, cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal, diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index bb29d47dbb0e5..9145a16ad6822 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -513,6 +513,8 @@ class CIRGenFunction : public CIRGenTypeCache { return llvm::isa_and_nonnull<clang::FunctionDecl>(calleeDecl); } + const clang::Decl *getDecl() const { return calleeDecl; } + unsigned getNumParams() const { if (const auto *fd = llvm::dyn_cast<clang::FunctionDecl>(calleeDecl)) return fd->getNumParams(); @@ -1585,6 +1587,11 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value numElements, mlir::Value allocSizeWithoutCookie); + /// Create a check for a function parameter that may potentially be + /// declared as non-null. + void emitNonNullArgCheck(RValue rv, QualType argType, SourceLocation argLoc, + AbstractCallee ac, unsigned paramNum); + RValue emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e, const CXXMethodDecl *md, ReturnValueSlot returnValue); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 3318638b8a03d..a2a8ceca987e2 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -199,6 +199,15 @@ mlir::LogicalResult CIRToLLVMMemCpyOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMMemMoveOpLowering::matchAndRewrite( + cir::MemMoveOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + rewriter.replaceOpWithNewOp<mlir::LLVM::MemmoveOp>( + op, adaptor.getDst(), adaptor.getSrc(), adaptor.getLen(), + /*isVolatile=*/false); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMMemSetOpLowering::matchAndRewrite( cir::MemSetOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-bcopy.cpp b/clang/test/CIR/CodeGenBuiltins/builtin-bcopy.cpp new file mode 100644 index 0000000000000..71c0ffcfb4941 --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/builtin-bcopy.cpp @@ -0,0 +1,80 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +void foo(void) { + // CIR-LABEL: cir.func no_inline dso_local @_Z3foov() + // CIR: %[[V0:.*]] = cir.alloca !cir.array<!cir.float x 4>, !cir.ptr<!cir.array<!cir.float x 4>>, ["f4"] {alignment = 16 : i64} + // CIR: %[[V1:.*]] = cir.alloca !cir.array<!cir.float x 8>, !cir.ptr<!cir.array<!cir.float x 8>>, ["f8"] {alignment = 16 : i64} + // CIR: %[[V2:.*]] = cir.cast array_to_ptrdecay %[[V0]] : !cir.ptr<!cir.array<!cir.float x 4>> -> !cir.ptr<!cir.float> + // CIR: %[[V3:.*]] = cir.cast bitcast %[[V2]] : !cir.ptr<!cir.float> -> !cir.ptr<!void> + // CIR: %[[V4:.*]] = cir.cast array_to_ptrdecay %[[V1]] : !cir.ptr<!cir.array<!cir.float x 8>> -> !cir.ptr<!cir.float> + // CIR: %[[V5:.*]] = cir.cast bitcast %[[V4]] : !cir.ptr<!cir.float> -> !cir.ptr<!void> + // CIR: %[[V6:.*]] = cir.const #cir.int<4> : !u64i + // CIR: %[[V7:.*]] = cir.const #cir.int<4> : !u64i + // CIR: %[[V8:.*]] = cir.binop(mul, %[[V6]], %[[V7]]) : !u64i + // CIR: cir.libc.memmove %[[V8]] bytes from %[[V3]] to %[[V5]] : !cir.ptr<!void>, !u64i + // CIR: cir.return + + // LLVM-LABEL: define dso_local void @_Z3foov() + // LLVM: %[[V1:.*]] = alloca [4 x float], i64 1, align 16 + // LLVM: %[[V2:.*]] = alloca [8 x float], i64 1, align 16 + // LLVM: %[[V3:.*]] = getelementptr float, ptr %[[V1]], i32 0 + // LLVM: %[[V4:.*]] = getelementptr float, ptr %[[V2]], i32 0 + // LLVM: call void @llvm.memmove.p0.p0.i64(ptr %[[V4]], ptr %[[V3]], i64 16, i1 false) + // LLVM: ret void + + // OGCG-LABEL: define dso_local void @_Z3foov() + // OGCG: %[[V1:.*]] = alloca [4 x float], align 16 + // OGCG: %[[V2:.*]] = alloca [8 x float], align 16 + // OGCG: %[[V3:.*]] = getelementptr inbounds [4 x float], ptr %[[V1]], i64 0, i64 0 + // OGCG: %[[V4:.*]] = getelementptr inbounds [8 x float], ptr %[[V2]], i64 0, i64 0 + // OGCG: call void @llvm.memmove.p0.p0.i64(ptr align 16 %[[V4]], ptr align 16 %[[V3]], i64 16, i1 false) + // OGCG: ret void + + float f4[4]; + float f8[8]; + __builtin_bcopy(f4, f8, sizeof(float) * 4); +} + +void another_conditional_bcopy(char *dst, char *src, int sz, int len) { + // CIR-LABEL: cir.func no_inline dso_local @_Z25another_conditional_bcopyPcS_ii + // CIR: cir.libc.memmove {{.*}} bytes from {{.*}} to {{.*}} : !cir.ptr<!void>, !u64i + // CIR: cir.libc.memmove {{.*}} bytes from {{.*}} to {{.*}} : !cir.ptr<!void>, !u64i + + // LLVM-LABEL: define{{.*}} void @_Z25another_conditional_bcopyPcS_ii + // LLVM: call void @llvm.memmove + // LLVM: call void @llvm.memmove + // LLVM-NOT: phi + + // OGCG-LABEL: define{{.*}} void @_Z25another_conditional_bcopyPcS_ii + // OGCG: call void @llvm.memmove + // OGCG: call void @llvm.memmove + // OGCG-NOT: phi + + if (sz >= len) + __builtin_bcopy(src, dst, len); + else + __builtin_bcopy(src, dst, len * 2); +} + +#define size_t __SIZE_TYPE__ + +extern "C" void bcopy(const void *__src, void *__dest, size_t __n); +// CIR: @_Z9testbcopyPKvPvm( +// CIR: cir.libc.memmove {{.*}} bytes from {{.*}} to {{.*}} : !cir.ptr<!void>, !u64i +// CIR: cir.return + +// LLVM: @_Z9testbcopyPKvPvm( +// LLVM: call void @llvm.memmove.p0.p0.i64(ptr {{.*}}, ptr {{.*}}, i64 {{.*}}, i1 false) +// LLVM: ret void + +// OGCG: @_Z9testbcopyPKvPvm( +// OGCG: call void @llvm.memmove.p0.p0.i64(ptr {{.*}}, ptr {{.*}}, i64 {{.*}}, i1 false) +// OGCG: ret void +void testbcopy(const void *src, void *dest, size_t n) { + bcopy(src, dest, n); +} `````````` </details> https://github.com/llvm/llvm-project/pull/185038 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
