Skip to content

Commit 2813bac

Browse files
authored
[CIR][CIRGen] Add support for memmove (#1019)
due to the issue described in #1018, the MLIR lowering for `memmove` has been excluded in this patch.
1 parent 7e7be0e commit 2813bac

File tree

7 files changed

+97
-37
lines changed

7 files changed

+97
-37
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

+34-13
Original file line numberDiff line numberDiff line change
@@ -3927,13 +3927,22 @@ def CopyOp : CIR_Op<"copy",
39273927
}
39283928

39293929
//===----------------------------------------------------------------------===//
3930-
// MemCpyOp
3930+
// MemCpyOp && MemMoveOp
39313931
//===----------------------------------------------------------------------===//
39323932

3933-
def MemCpyOp : CIR_Op<"libc.memcpy"> {
3934-
let arguments = (ins Arg<CIR_PointerType, "", [MemWrite]>:$dst,
3935-
Arg<CIR_PointerType, "", [MemRead]>:$src,
3936-
PrimitiveInt:$len);
3933+
class CIR_MemCpyOp<string mnemonic>: CIR_Op<mnemonic, [AllTypesMatch<["dst", "src"]>]> {
3934+
let arguments = (ins Arg<VoidPtr, "", [MemWrite]>:$dst,
3935+
Arg<VoidPtr, "", [MemRead]>:$src,
3936+
PrimitiveUInt:$len);
3937+
let hasVerifier = 0;
3938+
3939+
let extraClassDeclaration = [{
3940+
/// Returns the byte length type.
3941+
mlir::cir::IntType getLenTy() { return getLen().getType(); }
3942+
}];
3943+
}
3944+
3945+
def MemCpyOp : CIR_MemCpyOp<"libc.memcpy"> {
39373946
let summary = "Equivalent to libc's `memcpy`";
39383947
let description = [{
39393948
Given two CIR pointers, `src` and `dst`, `cir.libc.memcpy` will copy `len`
@@ -3956,17 +3965,29 @@ def MemCpyOp : CIR_Op<"libc.memcpy"> {
39563965
$len `bytes` `from` $src `to` $dst attr-dict
39573966
`:` type($len) `` `,` qualified(type($src)) `->` qualified(type($dst))
39583967
}];
3959-
let hasVerifier = 1;
3968+
}
39603969

3961-
let extraClassDeclaration = [{
3962-
/// Returns the data source pointer type.
3963-
mlir::cir::PointerType getSrcTy() { return getSrc().getType(); }
3970+
def MemMoveOp : CIR_MemCpyOp<"libc.memmove"> {
3971+
let summary = "Equivalent to libc's `memmove`";
3972+
let description = [{
3973+
Given two CIR pointers, `src` and `dst`, `cir.libc.memmove` will copy `len`
3974+
bytes from the memory pointed by `src` to the memory pointed by `dst`.
39643975

3965-
/// Returns the data destination pointer type.
3966-
mlir::cir::PointerType getDstTy() { return getDst().getType(); }
3976+
similiar to `cir.libc.memcpy` but accounts for overlapping memory.
39673977

3968-
/// Returns the byte length type.
3969-
mlir::cir::IntType getLenTy() { return getLen().getType(); }
3978+
Examples:
3979+
3980+
```mlir
3981+
// Copying 2 bytes from one array to a struct:
3982+
%2 = cir.const #cir.int<2> : !u32i
3983+
cir.libc.memmove %2 bytes from %arr to %struct : !cir.ptr<!void>, !u64i
3984+
```
3985+
}];
3986+
3987+
3988+
let assemblyFormat = [{
3989+
$len `bytes` `from` $src `to` $dst attr-dict
3990+
`:` qualified(type($dst)) `,` type($len)
39703991
}];
39713992
}
39723993

clang/lib/CIR/CodeGen/CIRGenBuilder.h

+10
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,16 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
624624
return create<mlir::cir::ContinueOp>(loc);
625625
}
626626

627+
mlir::cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst,
628+
mlir::Value src, mlir::Value len) {
629+
return create<mlir::cir::MemCpyOp>(loc, dst, src, len);
630+
}
631+
632+
mlir::cir::MemMoveOp createMemMove(mlir::Location loc, mlir::Value dst,
633+
mlir::Value src, mlir::Value len) {
634+
return create<mlir::cir::MemMoveOp>(loc, dst, src, len);
635+
}
636+
627637
mlir::Value createNeg(mlir::Value value) {
628638

629639
if (auto intTy = mlir::dyn_cast<mlir::cir::IntType>(value.getType())) {

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

+13-3
Original file line numberDiff line numberDiff line change
@@ -1435,9 +1435,19 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
14351435
llvm_unreachable("BI__builtin___memmove_chk NYI");
14361436

14371437
case Builtin::BImemmove:
1438-
case Builtin::BI__builtin_memmove:
1439-
llvm_unreachable("BImemmove like NYI");
1440-
1438+
case Builtin::BI__builtin_memmove: {
1439+
Address Dest = buildPointerWithAlignment(E->getArg(0));
1440+
Address Src = buildPointerWithAlignment(E->getArg(1));
1441+
mlir::Value SizeVal = buildScalarExpr(E->getArg(2));
1442+
buildNonNullArgCheck(RValue::get(Dest.getPointer()),
1443+
E->getArg(0)->getType(), E->getArg(0)->getExprLoc(),
1444+
FD, 0);
1445+
buildNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(),
1446+
E->getArg(1)->getExprLoc(), FD, 1);
1447+
builder.createMemMove(getLoc(E->getSourceRange()), Dest.getPointer(),
1448+
Src.getPointer(), SizeVal);
1449+
return RValue::get(Dest.getPointer());
1450+
}
14411451
case Builtin::BImemset:
14421452
case Builtin::BI__builtin_memset:
14431453
llvm_unreachable("BImemset like NYI");

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

-17
Original file line numberDiff line numberDiff line change
@@ -3489,23 +3489,6 @@ LogicalResult mlir::cir::CopyOp::verify() {
34893489
return mlir::success();
34903490
}
34913491

3492-
//===----------------------------------------------------------------------===//
3493-
// MemCpyOp Definitions
3494-
//===----------------------------------------------------------------------===//
3495-
3496-
LogicalResult mlir::cir::MemCpyOp::verify() {
3497-
auto voidPtr =
3498-
cir::PointerType::get(getContext(), cir::VoidType::get(getContext()));
3499-
3500-
if (!getLenTy().isUnsigned())
3501-
return emitError() << "memcpy length must be an unsigned integer";
3502-
3503-
if (getSrcTy() != voidPtr || getDstTy() != voidPtr)
3504-
return emitError() << "memcpy src and dst must be void pointers";
3505-
3506-
return mlir::success();
3507-
}
3508-
35093492
//===----------------------------------------------------------------------===//
35103493
// GetMemberOp Definitions
35113494
//===----------------------------------------------------------------------===//

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

+16-1
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,20 @@ class CIRMemCpyOpLowering
713713
return mlir::success();
714714
}
715715
};
716+
class CIRMemMoveOpLowering
717+
: public mlir::OpConversionPattern<mlir::cir::MemMoveOp> {
718+
public:
719+
using mlir::OpConversionPattern<mlir::cir::MemMoveOp>::OpConversionPattern;
720+
721+
mlir::LogicalResult
722+
matchAndRewrite(mlir::cir::MemMoveOp op, OpAdaptor adaptor,
723+
mlir::ConversionPatternRewriter &rewriter) const override {
724+
rewriter.replaceOpWithNewOp<mlir::LLVM::MemmoveOp>(
725+
op, adaptor.getDst(), adaptor.getSrc(), adaptor.getLen(),
726+
/*isVolatile=*/false);
727+
return mlir::success();
728+
}
729+
};
716730

717731
static mlir::Value getLLVMIntCast(mlir::ConversionPatternRewriter &rewriter,
718732
mlir::Value llvmSrc, mlir::Type llvmDstIntTy,
@@ -4208,7 +4222,8 @@ void populateCIRToLLVMConversionPatterns(
42084222
CIREhTypeIdOpLowering, CIRCatchParamOpLowering, CIRResumeOpLowering,
42094223
CIRAllocExceptionOpLowering, CIRFreeExceptionOpLowering,
42104224
CIRThrowOpLowering, CIRIntrinsicCallLowering, CIRBaseClassAddrOpLowering,
4211-
CIRVTTAddrPointOpLowering, CIRIsFPClassOpLowering, CIRAbsOpLowering
4225+
CIRVTTAddrPointOpLowering, CIRIsFPClassOpLowering, CIRAbsOpLowering,
4226+
CIRMemMoveOpLowering
42124227
#define GET_BUILTIN_LOWERING_LIST
42134228
#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
42144229
#undef GET_BUILTIN_LOWERING_LIST

clang/test/CIR/CodeGen/libc.c

+8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ void testMemcpy(void *dst, const void *src, unsigned long size) {
1515
// CHECK: cir.libc.memcpy %{{.+}} bytes from %{{.+}} to %{{.+}} : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
1616
}
1717

18+
// Should generate CIR's builtin memmove op.
19+
void *memmove(void *, const void *, unsigned long);
20+
void testMemmove(void *src, const void *dst, unsigned long size) {
21+
memmove(dst, src, size);
22+
// CHECK: cir.libc.memmove %{{.+}} bytes from %{{.+}} to %{{.+}} : !cir.ptr<!void>, !u64i
23+
// LLVM: call void @llvm.memmove.{{.+}}.i64(ptr %{{.+}}, ptr %{{.+}}, i64 %{{.+}}, i1 false),
24+
}
25+
1826
double fabs(double);
1927
double testFabs(double x) {
2028
return fabs(x);

clang/test/CIR/IR/invalid.cir

+16-3
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ module {
715715
module {
716716
// Should not memcpy with invalid length type.
717717
cir.func @invalid_memcpy_len(%arg0 : !cir.ptr<!cir.void>, %arg1 : !s8i) {
718-
// expected-error@+1 {{memcpy length must be an unsigned integer}}
718+
// expected-error@+1 {{'cir.libc.memcpy' op operand #2 must be primitive unsigned int, but got '!cir.int<s, 8>'}}
719719
cir.libc.memcpy %arg1 bytes from %arg0 to %arg0 : !s8i, !cir.ptr<!cir.void> -> !cir.ptr<!cir.void>
720720
cir.return
721721
}
@@ -727,13 +727,26 @@ module {
727727
!u32i = !cir.int<u, 32>
728728
module {
729729
// Should not memcpy non-void pointers.
730-
cir.func @invalid_memcpy_len(%arg0 : !cir.ptr<!s8i>, %arg1 : !u32i) {
731-
// expected-error@+1 {{memcpy src and dst must be void pointers}}
730+
cir.func @invalid_memcpy_pointer_0(%arg0 : !cir.ptr<!s8i>, %arg1 : !u32i) {
731+
// expected-error@+1 {{'cir.libc.memcpy' op operand #0 must be void*, but got '!cir.ptr<!cir.int<s, 8>>'}}
732732
cir.libc.memcpy %arg1 bytes from %arg0 to %arg0 : !u32i, !cir.ptr<!s8i> -> !cir.ptr<!s8i>
733733
cir.return
734734
}
735735
}
736736

737+
// -----
738+
739+
!s8i = !cir.int<s, 8>
740+
!u32i = !cir.int<u, 32>
741+
module {
742+
// Should not memcpy non-void pointers.
743+
cir.func @invalid_memcpy_pointer_1(%arg0 : !cir.ptr<!cir.void>, %arg1 : !cir.ptr<!s8i>, %arg2 : !u32i) {
744+
// expected-error@+1 {{'cir.libc.memcpy' op operand #1 must be void*, but got '!cir.ptr<!cir.int<s, 8>>'}}
745+
cir.libc.memcpy %arg2 bytes from %arg1 to %arg0 : !u32i, !cir.ptr<!s8i> -> !cir.ptr<!cir.void>
746+
cir.return
747+
}
748+
}
749+
737750
// -----
738751
!s8i = !cir.int<s, 8>
739752
!ty_Init = !cir.struct<class "Init" {!s8i} #cir.record.decl.ast>

0 commit comments

Comments
 (0)