Skip to content

Commit ec6c39a

Browse files
ghehglanza
authored andcommitted
[CIR][CIRGen][Builtin] Support __builtin___memmove_chk (llvm#1106)
1 parent 19dc789 commit ec6c39a

File tree

2 files changed

+98
-18
lines changed

2 files changed

+98
-18
lines changed

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,19 @@ RValue CIRGenFunction::emitRotate(const CallExpr *E, bool IsRotateRight) {
345345
return RValue::get(r);
346346
}
347347

348+
static bool isMemBuiltinOutOfBoundPossible(const clang::Expr *sizeArg,
349+
const clang::Expr *dstSizeArg,
350+
clang::ASTContext &astContext,
351+
llvm::APSInt &size) {
352+
clang::Expr::EvalResult sizeResult, dstSizeResult;
353+
if (!sizeArg->EvaluateAsInt(sizeResult, astContext) ||
354+
!dstSizeArg->EvaluateAsInt(dstSizeResult, astContext))
355+
return true;
356+
size = sizeResult.Val.getInt();
357+
llvm::APSInt dstSize = dstSizeResult.Val.getInt();
358+
return size.ugt(dstSize);
359+
}
360+
348361
RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
349362
const CallExpr *E,
350363
ReturnValueSlot ReturnValue) {
@@ -1488,13 +1501,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
14881501

14891502
case Builtin::BI__builtin___memcpy_chk: {
14901503
// fold __builtin_memcpy_chk(x, y, cst1, cst2) to memcpy iff cst1<=cst2.
1491-
Expr::EvalResult sizeResult, dstSizeResult;
1492-
if (!E->getArg(2)->EvaluateAsInt(sizeResult, CGM.getASTContext()) ||
1493-
!E->getArg(3)->EvaluateAsInt(dstSizeResult, CGM.getASTContext()))
1494-
break;
1495-
llvm::APSInt size = sizeResult.Val.getInt();
1496-
llvm::APSInt dstSize = dstSizeResult.Val.getInt();
1497-
if (size.ugt(dstSize))
1504+
llvm::APSInt size;
1505+
if (isMemBuiltinOutOfBoundPossible(E->getArg(2), E->getArg(3),
1506+
CGM.getASTContext(), size))
14981507
break;
14991508
Address dest = emitPointerWithAlignment(E->getArg(0));
15001509
Address src = emitPointerWithAlignment(E->getArg(1));
@@ -1507,9 +1516,19 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
15071516
case Builtin::BI__builtin_objc_memmove_collectable:
15081517
llvm_unreachable("BI__builtin_objc_memmove_collectable NYI");
15091518

1510-
case Builtin::BI__builtin___memmove_chk:
1511-
llvm_unreachable("BI__builtin___memmove_chk NYI");
1512-
1519+
case Builtin::BI__builtin___memmove_chk: {
1520+
// fold __builtin_memcpy_chk(x, y, cst1, cst2) to memcpy iff cst1<=cst2.
1521+
llvm::APSInt size;
1522+
if (isMemBuiltinOutOfBoundPossible(E->getArg(2), E->getArg(3),
1523+
CGM.getASTContext(), size))
1524+
break;
1525+
Address Dest = emitPointerWithAlignment(E->getArg(0));
1526+
Address Src = emitPointerWithAlignment(E->getArg(1));
1527+
auto loc = getLoc(E->getSourceRange());
1528+
ConstantOp sizeOp = builder.getConstInt(loc, size);
1529+
builder.createMemMove(loc, Dest.getPointer(), Src.getPointer(), sizeOp);
1530+
return RValue::get(Dest.getPointer());
1531+
}
15131532
case Builtin::BImemmove:
15141533
case Builtin::BI__builtin_memmove: {
15151534
Address Dest = emitPointerWithAlignment(E->getArg(0));
@@ -1539,13 +1558,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
15391558
llvm_unreachable("BI__builtin_memset_inline NYI");
15401559
case Builtin::BI__builtin___memset_chk: {
15411560
// fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
1542-
Expr::EvalResult sizeResult, dstSizeResult;
1543-
if (!E->getArg(2)->EvaluateAsInt(sizeResult, CGM.getASTContext()) ||
1544-
!E->getArg(3)->EvaluateAsInt(dstSizeResult, CGM.getASTContext()))
1545-
break;
1546-
llvm::APSInt size = sizeResult.Val.getInt();
1547-
llvm::APSInt dstSize = dstSizeResult.Val.getInt();
1548-
if (size.ugt(dstSize))
1561+
llvm::APSInt size;
1562+
if (isMemBuiltinOutOfBoundPossible(E->getArg(2), E->getArg(3),
1563+
CGM.getASTContext(), size))
15491564
break;
15501565
Address dest = emitPointerWithAlignment(E->getArg(0));
15511566
mlir::Value byteVal = emitScalarExpr(E->getArg(1));

clang/test/CIR/CodeGen/builtins-memory.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
22
// RUN: FileCheck %s --check-prefix=CIR --input-file=%t.cir
3-
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - \
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - \
44
// RUN: | opt -S -passes=instcombine,mem2reg,simplifycfg -o %t.ll
55
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
66
// XFAIL: *
@@ -59,6 +59,71 @@ void test_memcpy_chk(void *dest, const void *src, size_t n) {
5959
__builtin___memcpy_chk(dest, src, n, n);
6060
}
6161

62+
void test_memmove_chk(void *dest, const void *src, size_t n) {
63+
// CIR-LABEL: cir.func @test_memmove_chk
64+
// CIR: %[[#DEST:]] = cir.alloca {{.*}} ["dest", init]
65+
// CIR: %[[#SRC:]] = cir.alloca {{.*}} ["src", init]
66+
// CIR: %[[#N:]] = cir.alloca {{.*}} ["n", init]
67+
68+
// LLVM-LABEL: test_memmove_chk
69+
70+
// An unchecked memmove should be emitted when the count and buffer size are
71+
// constants and the count is less than or equal to the buffer size.
72+
73+
// CIR: %[[#DEST_LOAD:]] = cir.load %[[#DEST]]
74+
// CIR: %[[#SRC_LOAD:]] = cir.load %[[#SRC]]
75+
// CIR: %[[#COUNT:]] = cir.const #cir.int<8>
76+
// CIR: cir.libc.memmove %[[#COUNT]] bytes from %[[#SRC_LOAD]] to %[[#DEST_LOAD]]
77+
// LLVM: call void @llvm.memmove.p0.p0.i64(ptr {{%.*}}, ptr {{%.*}}, i64 8, i1 false)
78+
// COM: LLVM: call void @llvm.memmove.p0.p0.i64(ptr align 1 {{%.*}}, ptr align 1 {{%.*}}, i64 8, i1 false)
79+
__builtin___memmove_chk(dest, src, 8, 10);
80+
81+
// CIR: %[[#DEST_LOAD:]] = cir.load %[[#DEST]]
82+
// CIR: %[[#SRC_LOAD:]] = cir.load %[[#SRC]]
83+
// CIR: %[[#COUNT:]] = cir.const #cir.int<10>
84+
// CIR: cir.libc.memmove %[[#COUNT]] bytes from %[[#SRC_LOAD]] to %[[#DEST_LOAD]]
85+
// LLVM: call void @llvm.memmove.p0.p0.i64(ptr {{%.*}}, ptr {{%.*}}, i64 10, i1 false)
86+
// COM: LLVM: call void @llvm.memmove.p0.p0.i64(ptr align 1 {{%.*}}, ptr align 1 {{%.*}}, i64 10, i1 false)
87+
__builtin___memmove_chk(dest, src, 10, 10);
88+
89+
// CIR: %[[#DEST_LOAD:]] = cir.load %[[#DEST]]
90+
// CIR: %[[#SRC_LOAD:]] = cir.load %[[#SRC]]
91+
// CIR: %[[#COUNT:]] = cir.const #cir.int<10>
92+
// CIR: %[[#SIZE:]] = cir.const #cir.int<8>
93+
// CIR: cir.call @__memmove_chk(%[[#DEST_LOAD]], %[[#SRC_LOAD]], %[[#COUNT]], %[[#SIZE]])
94+
// LLVM: call ptr @__memmove_chk(ptr {{%.*}}, ptr {{%.*}}, i64 10, i64 8)
95+
// COM: LLVM: call ptr @__memmove_chk(ptr noundef %4, ptr noundef %5, i64 noundef 10, i64 noundef 8)
96+
__builtin___memmove_chk(dest, src, 10lu, 8lu);
97+
98+
// CIR: %[[#DEST_LOAD:]] = cir.load %[[#DEST]]
99+
// CIR: %[[#SRC_LOAD:]] = cir.load %[[#SRC]]
100+
// CIR: %[[#N_LOAD:]] = cir.load %[[#N]]
101+
// CIR: %[[#SIZE:]] = cir.const #cir.int<10>
102+
// CIR: cir.call @__memmove_chk(%[[#DEST_LOAD]], %[[#SRC_LOAD]], %[[#N_LOAD]], %[[#SIZE]])
103+
// LLVM: call ptr @__memmove_chk(ptr {{%.*}}, ptr {{%.*}}, i64 {{%.*}}, i64 10)
104+
// COM: LLVM: call ptr @__memmove_chk(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef {{%.*}}, i64 noundef 10)
105+
__builtin___memmove_chk(dest, src, n, 10lu);
106+
107+
// CIR: %[[#DEST_LOAD:]] = cir.load %[[#DEST]]
108+
// CIR: %[[#SRC_LOAD:]] = cir.load %[[#SRC]]
109+
// CIR: %[[#COUNT:]] = cir.const #cir.int<10>
110+
// CIR: %[[#N_LOAD:]] = cir.load %[[#N]]
111+
// CIR: cir.call @__memmove_chk(%[[#DEST_LOAD]], %[[#SRC_LOAD]], %[[#COUNT]], %[[#N_LOAD]])
112+
// LLVM: call ptr @__memmove_chk(ptr {{%.*}}, ptr {{%.*}}, i64 10, i64 {{%.*}})
113+
// COM: LLVM: call ptr @__memmove_chk(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef 10, i64 noundef {{%.*}})
114+
__builtin___memmove_chk(dest, src, 10lu, n);
115+
116+
// CIR: %[[#DEST_LOAD:]] = cir.load %[[#DEST]]
117+
// CIR: %[[#SRC_LOAD:]] = cir.load %[[#SRC]]
118+
// CIR: %[[#N_LOAD1:]] = cir.load %[[#N]]
119+
// CIR: %[[#N_LOAD2:]] = cir.load %[[#N]]
120+
// CIR: cir.call @__memmove_chk(%[[#DEST_LOAD]], %[[#SRC_LOAD]], %[[#N_LOAD1]], %[[#N_LOAD2]])
121+
// LLVM: call ptr @__memmove_chk(ptr {{%.*}}, ptr {{%.*}}, i64 {{%.*}}, i64 {{%.*}})
122+
// COM: LLVM: call ptr @__memmove_chk(ptr noundef {{%.*}}, ptr noundef {{%.*}}, i64 noundef {{%.*}}, i64 noundef {{%.*}})
123+
__builtin___memmove_chk(dest, src, n, n);
124+
}
125+
126+
62127
void test_memset_chk(void *dest, int ch, size_t n) {
63128
// CIR-LABEL: cir.func @test_memset_chk
64129
// CIR: %[[#DEST:]] = cir.alloca {{.*}} ["dest", init]

0 commit comments

Comments
 (0)