llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Andrzej Warzyński (banach-space) <details> <summary>Changes</summary> The operation is a 1:1 mapping to libc's memcpy. NOTE: This patch merely upstreams code from * https://github.com/llvm/clangir. This Op was originally implemented by Vinicius Couto Espindola. Further modification were made by other ClangIR contributors. co-authored-by: Vinicius Couto Espindola <vini.couto.e@<!-- -->gmail.com> --- Full diff: https://github.com/llvm/llvm-project/pull/176781.diff 6 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+47) - (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (+10) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+9) - (added) clang/test/CIR/IR/invalid-memcpy.cir (+37) - (added) clang/test/CIR/IR/libc-memcpy.cir (+10) - (added) clang/test/CIR/Lowering/libc.cir (+12) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index db1696d50848c..c7f4df200d909 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3439,6 +3439,53 @@ def CIR_CopyOp : CIR_Op<"copy",[ }]; } +//===----------------------------------------------------------------------===// +// MemCpyOp && MemMoveOp +//===----------------------------------------------------------------------===// + +class CIR_MemOp<string mnemonic> : CIR_Op<mnemonic, [ + AllTypesMatch<["dst", "src"]> +]> { + dag commonArgs = (ins + Arg<CIR_VoidPtrType, "", [MemWrite]>:$dst, + Arg<CIR_VoidPtrType, "", [MemRead]>:$src + ); +} + +def CIR_MemCpyOp : CIR_MemOp<"libc.memcpy"> { + let summary = "Equivalent to libc's `memcpy`"; + let description = [{ + Given two CIR pointers, `src` and `dst`, `cir.libc.memcpy` will copy `len` + bytes from the memory pointed by `src` to the memory pointed by `dst`. + + While `cir.copy` is meant to be used for implicit copies in the code where + the length of the copy is known, `cir.memcpy` copies only from and to void + pointers, requiring the copy length to be passed as an argument. + + Examples: + + ```mlir + // Copying 2 bytes from one array to a record: + %2 = cir.const #cir.int<2> : !u32i + cir.libc.memcpy %2 bytes from %arr to %record : !cir.ptr<!arr> -> !cir.ptr<!record> + ``` + }]; + + let arguments = !con(commonArgs, (ins CIR_AnyFundamentalUIntType:$len)); + + let assemblyFormat = [{ + $len `bytes` `from` $src `to` $dst attr-dict + `:` type($len) `` `,` qualified(type($src)) `->` qualified(type($dst)) + }]; + + let extraClassDeclaration = [{ + /// Returns the byte length type. + cir::IntType getLenTy() { return getLen().getType(); } + }]; +} + +// TODO: MemMoveOp + //===----------------------------------------------------------------------===// // ReturnAddrOp and FrameAddrOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index ff492edf0b04e..dc1ce9a901381 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -189,6 +189,16 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return getType<cir::RecordType>(nameAttr, kind); } + // + // Operation creation helpers + // -------------------------- + // + cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst, + mlir::Value src, mlir::Value len) { + return cir::MemCpyOp::create(*this, loc, dst, src, len); + } + // --------------------------- + cir::DataMemberAttr getDataMemberAttr(cir::DataMemberType ty, unsigned memberIndex) { return cir::DataMemberAttr::get(ty, memberIndex); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 7625bcccd520f..a774b0dcc6ba8 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -187,6 +187,15 @@ mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMMemCpyOpLowering::matchAndRewrite( + cir::MemCpyOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + rewriter.replaceOpWithNewOp<mlir::LLVM::MemcpyOp>( + op, adaptor.getDst(), adaptor.getSrc(), adaptor.getLen(), + /*isVolatile=*/false); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMSqrtOpLowering::matchAndRewrite( cir::SqrtOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/IR/invalid-memcpy.cir b/clang/test/CIR/IR/invalid-memcpy.cir new file mode 100644 index 0000000000000..805d03adcb95f --- /dev/null +++ b/clang/test/CIR/IR/invalid-memcpy.cir @@ -0,0 +1,37 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +!s8i = !cir.int<s, 8> +module { + // Should not memcpy with invalid length type. + cir.func @invalid_memcpy_len(%arg0 : !cir.ptr<!cir.void>, %arg1 : !s8i) { + // expected-error@+1 {{'cir.libc.memcpy' op operand #2 must be fundamental unsigned integer type, but got '!cir.int<s, 8>'}} + cir.libc.memcpy %arg1 bytes from %arg0 to %arg0 : !s8i, !cir.ptr<!cir.void> -> !cir.ptr<!cir.void> + cir.return + } +} + +// ----- + +!s8i = !cir.int<s, 8> +!u32i = !cir.int<u, 32> +module { + // Should not memcpy non-void pointers. + cir.func @invalid_memcpy_pointer_0(%arg0 : !cir.ptr<!s8i>, %arg1 : !u32i) { + // expected-error@+1 {{'cir.libc.memcpy' op operand #0 must be pointer to void type, but got '!cir.ptr<!cir.int<s, 8>>'}} + cir.libc.memcpy %arg1 bytes from %arg0 to %arg0 : !u32i, !cir.ptr<!s8i> -> !cir.ptr<!s8i> + cir.return + } +} + +// ----- + +!s8i = !cir.int<s, 8> +!u32i = !cir.int<u, 32> +module { + // Should not memcpy non-void pointers. + cir.func @invalid_memcpy_pointer_1(%arg0 : !cir.ptr<!cir.void>, %arg1 : !cir.ptr<!s8i>, %arg2 : !u32i) { + // expected-error@+1 {{'cir.libc.memcpy' op operand #1 must be pointer to void type, but got '!cir.ptr<!cir.int<s, 8>>'}} + cir.libc.memcpy %arg2 bytes from %arg1 to %arg0 : !u32i, !cir.ptr<!s8i> -> !cir.ptr<!cir.void> + cir.return + } +} diff --git a/clang/test/CIR/IR/libc-memcpy.cir b/clang/test/CIR/IR/libc-memcpy.cir new file mode 100644 index 0000000000000..6769092f3beb1 --- /dev/null +++ b/clang/test/CIR/IR/libc-memcpy.cir @@ -0,0 +1,10 @@ +// RUN: cir-opt %s --verify-roundtrip | FileCheck %s + +!u32i = !cir.int<u, 32> +module { + cir.func @shouldParseLibcMemcpyOp(%arg0 : !cir.ptr<!cir.void>, %arg1 : !u32i) { + // CHECK: cir.libc.memcpy + cir.libc.memcpy %arg1 bytes from %arg0 to %arg0 : !u32i, !cir.ptr<!cir.void> -> !cir.ptr<!cir.void> + cir.return + } +} diff --git a/clang/test/CIR/Lowering/libc.cir b/clang/test/CIR/Lowering/libc.cir new file mode 100644 index 0000000000000..74e384d08a74b --- /dev/null +++ b/clang/test/CIR/Lowering/libc.cir @@ -0,0 +1,12 @@ +// RUN: cir-opt %s -cir-to-llvm -o %t.mlir +// RUN: FileCheck --input-file=%t.mlir %s + +!void = !cir.void +!u64i = !cir.int<u, 64> +module { + cir.func @shouldLowerLibcMemcpyBuiltin(%arg0: !cir.ptr<!void>, %arg1: !cir.ptr<!void>, %arg2: !u64i) { + cir.libc.memcpy %arg2 bytes from %arg0 to %arg1 : !u64i, !cir.ptr<!void> -> !cir.ptr<!void> + // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %{{.+}}) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i64) -> () + cir.return + } +} `````````` </details> https://github.com/llvm/llvm-project/pull/176781 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
