llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-backend-powerpc Author: Stefan Pintilie (stefanp-ibm) <details> <summary>Changes</summary> In the backend we want to provide special handling for the function memcmp. This patch adds an intrinsic so that the backend will recognize it as more than just a regular function call. This patch also adds special handling for PowerPC on AIX. --- Full diff: https://github.com/llvm/llvm-project/pull/118178.diff 10 Files Affected: - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+13) - (modified) clang/test/CodeGen/builtin-memfns.c (+35-18) - (modified) clang/test/CodeGen/debug-info-extern-call.c (+5-5) - (modified) llvm/include/llvm/CodeGen/SelectionDAG.h (+6) - (modified) llvm/include/llvm/IR/Intrinsics.td (+6) - (modified) llvm/include/llvm/IR/RuntimeLibcalls.def (+1) - (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (+51) - (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (+19-1) - (modified) llvm/lib/Target/PowerPC/PPCISelLowering.cpp (+1) - (added) llvm/test/CodeGen/PowerPC/memintr.ll (+151) ``````````diff diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index cb9c23b8e0a0d0..0688f4064d788b 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4483,6 +4483,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } + case Builtin::BImemcmp: { + Address Src = EmitPointerWithAlignment(E->getArg(0)); + Address Dst = EmitPointerWithAlignment(E->getArg(1)); + Value *SizeVal = EmitScalarExpr(E->getArg(2)); + llvm::Type *Tys[] = {Dst.getBasePointer()->getType(), + Src.getBasePointer()->getType(), SizeVal->getType()}; + + Function *F = CGM.getIntrinsic(Intrinsic::memcmp, Tys); + Value *Mem1Value = EmitScalarExpr(E->getArg(0)); + Value *Mem2Value = EmitScalarExpr(E->getArg(1)); + Value *Args[] = {Mem1Value, Mem2Value, SizeVal}; + return RValue::get(Builder.CreateCall(F, Args)); + } case Builtin::BImemcpy: case Builtin::BI__builtin_memcpy: case Builtin::BImempcpy: diff --git a/clang/test/CodeGen/builtin-memfns.c b/clang/test/CodeGen/builtin-memfns.c index 23c3c60b779b37..51c5ad43cc7ef2 100644 --- a/clang/test/CodeGen/builtin-memfns.c +++ b/clang/test/CodeGen/builtin-memfns.c @@ -1,16 +1,23 @@ -// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm < %s| FileCheck %s +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm < %s| FileCheck %s --check-prefixes=CHECK,CHECK32 +// RUN: %clang_cc1 -triple ppc -emit-llvm < %s| FileCheck %s --check-prefixes=CHECK,CHECK32 +// RUN: %clang_cc1 -triple ppc64 -emit-llvm < %s| FileCheck %s --check-prefixes=CHECK,CHECK64 typedef __WCHAR_TYPE__ wchar_t; typedef __SIZE_TYPE__ size_t; void *memcpy(void *, void const *, size_t); void *memccpy(void *, void const *, int, size_t); - -// CHECK: @test1 -// CHECK: call void @llvm.memset.p0.i32 -// CHECK: call void @llvm.memset.p0.i32 -// CHECK: call void @llvm.memcpy.p0.p0.i32 -// CHECK: call void @llvm.memmove.p0.p0.i32 +int memcmp(const void *, const void *, size_t); + +// CHECK-LABEL: @test1 +// CHECK32: call void @llvm.memset.p0.i32 +// CHECK64: call void @llvm.memset.p0.i64 +// CHECK32: call void @llvm.memset.p0.i32 +// CHECK64: call void @llvm.memset.p0.i64 +// CHECK32: call void @llvm.memcpy.p0.p0.i32 +// CHECK64: call void @llvm.memcpy.p0.p0.i64 +// CHECK32: call void @llvm.memmove.p0.p0.i32 +// CHECK64: call void @llvm.memmove.p0.p0.i64 // CHECK-NOT: __builtin // CHECK: ret int test1(int argc, char **argv) { @@ -23,37 +30,38 @@ int test1(int argc, char **argv) { return 0; } -// CHECK: @test2 -// CHECK: call void @llvm.memcpy.p0.p0.i32 +// CHECK-LABEL: @test2 +// CHECK32: call void @llvm.memcpy.p0.p0.i32 +// CHECK64: call void @llvm.memcpy.p0.p0.i64 char* test2(char* a, char* b) { return __builtin_memcpy(a, b, 4); } -// CHECK: @test3 +// CHECK-LABEL: @test3 // CHECK: call void @llvm.memset void test3(char *P) { __builtin___memset_chk(P, 42, 128, 128); } -// CHECK: @test4 +// CHECK-LABEL: @test4 // CHECK: call void @llvm.memcpy void test4(char *P, char *Q) { __builtin___memcpy_chk(P, Q, 128, 128); } -// CHECK: @test5 +// CHECK-LABEL: @test5 // CHECK: call void @llvm.memmove void test5(char *P, char *Q) { __builtin___memmove_chk(P, Q, 128, 128); } -// CHECK: @test6 +// CHECK-LABEL: @test6 // CHECK: call void @llvm.memcpy int test6(char *X) { return __builtin___memcpy_chk(X, X, 42, 42) != 0; } -// CHECK: @test7 +// CHECK-LABEL: @test7 // PR12094 int test7(int *p) { struct snd_pcm_hw_params_t* hwparams; // incomplete type. @@ -75,14 +83,14 @@ struct PS { } __attribute__((packed)); struct PS ps; void test8(int *arg) { - // CHECK: @test8 + // CHECK-LABEL: @test8 // CHECK: call void @llvm.memcpy{{.*}} align 4 {{.*}} align 1 {{.*}} 16, i1 false) __builtin_memcpy(arg, ps.modes, sizeof(struct PS)); } __attribute((aligned(16))) int x[4], y[4]; void test9(void) { - // CHECK: @test9 + // CHECK-LABEL: @test9 // CHECK: call void @llvm.memcpy{{.*}} align 16 {{.*}} align 16 {{.*}} 16, i1 false) __builtin_memcpy(x, y, sizeof(y)); } @@ -93,10 +101,12 @@ wchar_t src; // CHECK-LABEL: @test10 // FIXME: Consider lowering these to llvm.memcpy / llvm.memmove. void test10(void) { - // CHECK: call ptr @wmemcpy(ptr noundef @dest, ptr noundef @src, i32 noundef 4) + // CHECK32: call ptr @wmemcpy(ptr noundef @dest, ptr noundef @src, i32 noundef 4) + // CHECK64: call ptr @wmemcpy(ptr noundef @dest, ptr noundef @src, i64 noundef 4) __builtin_wmemcpy(&dest, &src, 4); - // CHECK: call ptr @wmemmove(ptr noundef @dest, ptr noundef @src, i32 noundef 4) + // CHECK32: call ptr @wmemmove(ptr noundef @dest, ptr noundef @src, i32 noundef 4) + // CHECK64: call ptr @wmemmove(ptr noundef @dest, ptr noundef @src, i64 noundef 4) __builtin_wmemmove(&dest, &src, 4); } @@ -122,3 +132,10 @@ void test13(char *d, char *s, int c, size_t n) { // CHECK: call ptr @memccpy memccpy(d, s, c, n); } + +// CHECK-LABEL: @test14 +int test14(const void * ptr1, const void * ptr2, size_t num) { + // CHECK32: call i32 @llvm.memcmp.p0.p0.i32 + // CHECK64: call i32 @llvm.memcmp.p0.p0.i64 + return memcmp(ptr1, ptr2, num); +} diff --git a/clang/test/CodeGen/debug-info-extern-call.c b/clang/test/CodeGen/debug-info-extern-call.c index 0d18dc436040fa..10bd64baebb377 100644 --- a/clang/test/CodeGen/debug-info-extern-call.c +++ b/clang/test/CodeGen/debug-info-extern-call.c @@ -29,22 +29,22 @@ // DECLS-FOR-EXTERN: [[FN1_TYPES]] = !{[[X_TYPE:![0-9]+]], // DECLS-FOR-EXTERN: [[X_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "x", // DECLS-FOR-EXTERN-SAME: baseType: [[INT_TYPE]]) -// DECLS-FOR-EXTERN: !DISubprogram(name: "memcmp" +// DECLS-FOR-EXTERN: !DISubprogram(name: "strcmp" // DECLS-FOR-EXTERN: !DISubprogram(name: "__some_reserved_name" // NO-DECLS-FOR-EXTERN-NOT: !DISubprogram(name: "fn1" -// NO-DECLS-FOR-EXTERN-NOT: !DISubprogram(name: "memcmp" +// NO-DECLS-FOR-EXTERN-NOT: !DISubprogram(name: "strcmp" // NO-DECLS-FOR-EXTERN-NOT: !DISubprogram(name: "__some_reserved_name" typedef int x; extern x fn1(int a, int b); -extern int memcmp(const void *s1, const void *s2, unsigned long n); +extern int strcmp(const char *s1, const char *s2); extern void __some_reserved_name(void); -int fn2 (int *src, int *dst) { +int fn2 (char *src, char *dst) { int x = 4, y = 5; int res = fn1(x, y); - int res2 = memcmp(dst, src, res); + int res2 = strcmp(dst, src); __some_reserved_name(); return res + res2; } diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h index 2e3507386df309..c5c68edaa28ea0 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAG.h +++ b/llvm/include/llvm/CodeGen/SelectionDAG.h @@ -1190,6 +1190,12 @@ class SelectionDAG { /// stack arguments from being clobbered. SDValue getStackArgumentTokenFactor(SDValue Chain); + std::pair<SDValue, SDValue> getMemcmp(SDValue Chain, const SDLoc &dl, + SDValue Dst, SDValue Src, SDValue Size, + Align Alignment, bool isVol, + bool AlwaysInline, const CallInst *CI, + std::optional<bool> OverrideTailCall); + /* \p CI if not null is the memset call being lowered. * \p OverrideTailCall is an optional parameter that can be used to override * the tail call optimization decision. */ diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 1ca8c2565ab0b6..62c9071ddf0e59 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -967,6 +967,12 @@ def int_memcpy : Intrinsic<[], WriteOnly<ArgIndex<0>>, ReadOnly<ArgIndex<1>>, ImmArg<ArgIndex<3>>]>; +def int_memcmp + : Intrinsic<[llvm_i32_ty], [llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty], + [IntrArgMemOnly, IntrWillReturn, IntrNoFree, IntrNoCallback, + NoCapture<ArgIndex<0>>, NoCapture<ArgIndex<1>>, + ReadOnly<ArgIndex<0>>, ReadOnly<ArgIndex<1>>]>; + // Memcpy semantic that is guaranteed to be inlined. // In particular this means that the generated code is not allowed to call any // external function. diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.def b/llvm/include/llvm/IR/RuntimeLibcalls.def index 13a27b58b9cd78..fa6dad96e59a68 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.def +++ b/llvm/include/llvm/IR/RuntimeLibcalls.def @@ -498,6 +498,7 @@ HANDLE_LIBCALL(UO_F128, "__unordtf2") HANDLE_LIBCALL(UO_PPCF128, "__gcc_qunord") // Memory +HANDLE_LIBCALL(MEMCMP, "memcmp") HANDLE_LIBCALL(MEMCPY, "memcpy") HANDLE_LIBCALL(MEMMOVE, "memmove") HANDLE_LIBCALL(MEMSET, "memset") diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 182529123ec6d8..b2e69586f62087 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -8497,6 +8497,57 @@ static void checkAddrSpaceIsValidForLibcall(const TargetLowering *TLI, } } +std::pair<SDValue, SDValue> +SelectionDAG::getMemcmp(SDValue Chain, const SDLoc &dl, SDValue Mem0, + SDValue Mem1, SDValue Size, Align Alignment, bool isVol, + bool AlwaysInline, const CallInst *CI, + std::optional<bool> OverrideTailCall) { + + // TODO: Add special case for situation where size is known. + // TODO: Add hooks for Target Specifc Code. + // TODO: Always inline not yet supported. + assert(!AlwaysInline && "Always inline for memcmp is not yet supported."); + + // Emit a library call. + TargetLowering::ArgListTy Args; + TargetLowering::ArgListEntry Entry; + Entry.Ty = PointerType::getUnqual(*getContext()); + Entry.Node = Mem0; + Args.push_back(Entry); + Entry.Node = Mem1; + Args.push_back(Entry); + + Entry.Ty = getDataLayout().getIntPtrType(*getContext()); + Entry.Node = Size; + Args.push_back(Entry); + + // FIXME: pass in SDLoc + TargetLowering::CallLoweringInfo CLI(*this); + bool IsTailCall = false; + if (OverrideTailCall.has_value()) { + IsTailCall = *OverrideTailCall; + } else { + bool LowersToMemcmp = + TLI->getLibcallName(RTLIB::MEMCMP) == StringRef("memcmp"); + bool ReturnsFirstArg = CI && funcReturnsFirstArgOfCall(*CI); + IsTailCall = CI && CI->isTailCall() && + isInTailCallPosition(*CI, getTarget(), + ReturnsFirstArg && LowersToMemcmp); + } + + CLI.setDebugLoc(dl) + .setChain(Chain) + .setLibCallee(TLI->getLibcallCallingConv(RTLIB::MEMCMP), + Type::getInt32Ty(*getContext()), + getExternalSymbol(TLI->getLibcallName(RTLIB::MEMCMP), + TLI->getPointerTy(getDataLayout())), + std::move(Args)) + .setTailCall(IsTailCall); + + std::pair<SDValue, SDValue> CallResult = TLI->LowerCallTo(CLI); + return CallResult; +} + SDValue SelectionDAG::getMemcpy( SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align Alignment, bool isVol, bool AlwaysInline, const CallInst *CI, diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index a38a3e9b91052d..f0b2d610892120 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6527,6 +6527,25 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, RegName, getValue(RegValue))); return; } + case Intrinsic::memcmp: { + const auto &CallI = cast<CallInst>(I); + SDValue Op1 = getValue(I.getArgOperand(0)); + SDValue Op2 = getValue(I.getArgOperand(1)); + SDValue Op3 = getValue(I.getArgOperand(2)); + + Align Mem0Align = CallI.getParamAlign(0).valueOrOne(); + Align Mem1Align = CallI.getParamAlign(1).valueOrOne(); + Align Alignment = std::min(Mem0Align, Mem1Align); + bool isVol = CallI.isVolatile(); + SDValue Root = isVol ? getRoot() : getMemoryRoot(); + + std::pair<SDValue, SDValue> MC = + DAG.getMemcmp(Root, sdl, Op1, Op2, Op3, Alignment, isVol, + /* AlwaysInline */ false, &I, std::nullopt); + setValue(&I, MC.first); + updateDAGForMaybeTailCall(MC.second); + return; + } case Intrinsic::memcpy: { const auto &MCI = cast<MemCpyInst>(I); SDValue Op1 = getValue(I.getArgOperand(0)); @@ -9351,7 +9370,6 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) { visitInlineAsm(I); return; } - diagnoseDontCall(I); if (Function *F = I.getCalledFunction()) { diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index e917ef3f5e8c9a..500582c124eb27 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -1442,6 +1442,7 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM, setLibcallName(RTLIB::FREXP_F128, "frexpf128"); if (Subtarget.isAIXABI()) { + setLibcallName(RTLIB::MEMCMP, isPPC64 ? "___memcmp64" : "___memcmp"); setLibcallName(RTLIB::MEMCPY, isPPC64 ? "___memmove64" : "___memmove"); setLibcallName(RTLIB::MEMMOVE, isPPC64 ? "___memmove64" : "___memmove"); setLibcallName(RTLIB::MEMSET, isPPC64 ? "___memset64" : "___memset"); diff --git a/llvm/test/CodeGen/PowerPC/memintr.ll b/llvm/test/CodeGen/PowerPC/memintr.ll new file mode 100644 index 00000000000000..5fbe7234b06221 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/memintr.ll @@ -0,0 +1,151 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -verify-machineinstrs -mcpu=pwr9 -ppc-asm-full-reg-names \ +; RUN: -ppc-vsr-nums-as-vr -mtriple=powerpc64le-unknown-linux-gnu < %s | \ +; RUN: FileCheck %s --check-prefix=CHECK-LE-P9 +; RUN: llc -verify-machineinstrs -mcpu=pwr9 -ppc-asm-full-reg-names \ +; RUN: -ppc-vsr-nums-as-vr -mtriple=powerpc64-unknown-linux-gnu < %s | \ +; RUN: FileCheck %s --check-prefix=CHECK-BE-P9 +; RUN: llc -verify-machineinstrs -mcpu=pwr9 -ppc-asm-full-reg-names \ +; RUN: -ppc-vsr-nums-as-vr -mtriple=powerpc64-ibm-aix < %s | \ +; RUN: FileCheck %s --check-prefix=CHECK-AIX-64-P9 +; RUN: llc -verify-machineinstrs -mcpu=pwr9 -ppc-asm-full-reg-names \ +; RUN: -ppc-vsr-nums-as-vr -mtriple=powerpc-ibm-aix < %s | \ +; RUN: FileCheck %s --check-prefix=CHECK-AIX-32-P9 + + +define noundef ptr @memcpy_test(ptr noundef returned writeonly %destination, ptr nocapture noundef readonly %source, i32 noundef %num) local_unnamed_addr { +; CHECK-LE-P9-LABEL: memcpy_test: +; CHECK-LE-P9: # %bb.0: # %entry +; CHECK-LE-P9-NEXT: mflr r0 +; CHECK-LE-P9-NEXT: .cfi_def_cfa_offset 48 +; CHECK-LE-P9-NEXT: .cfi_offset lr, 16 +; CHECK-LE-P9-NEXT: .cfi_offset r30, -16 +; CHECK-LE-P9-NEXT: std r30, -16(r1) # 8-byte Folded Spill +; CHECK-LE-P9-NEXT: stdu r1, -48(r1) +; CHECK-LE-P9-NEXT: std r0, 64(r1) +; CHECK-LE-P9-NEXT: mr r30, r3 +; CHECK-LE-P9-NEXT: bl memcpy +; CHECK-LE-P9-NEXT: nop +; CHECK-LE-P9-NEXT: mr r3, r30 +; CHECK-LE-P9-NEXT: addi r1, r1, 48 +; CHECK-LE-P9-NEXT: ld r0, 16(r1) +; CHECK-LE-P9-NEXT: ld r30, -16(r1) # 8-byte Folded Reload +; CHECK-LE-P9-NEXT: mtlr r0 +; CHECK-LE-P9-NEXT: blr +; +; CHECK-BE-P9-LABEL: memcpy_test: +; CHECK-BE-P9: # %bb.0: # %entry +; CHECK-BE-P9-NEXT: mflr r0 +; CHECK-BE-P9-NEXT: stdu r1, -128(r1) +; CHECK-BE-P9-NEXT: std r0, 144(r1) +; CHECK-BE-P9-NEXT: .cfi_def_cfa_offset 128 +; CHECK-BE-P9-NEXT: .cfi_offset lr, 16 +; CHECK-BE-P9-NEXT: .cfi_offset r30, -16 +; CHECK-BE-P9-NEXT: std r30, 112(r1) # 8-byte Folded Spill +; CHECK-BE-P9-NEXT: mr r30, r3 +; CHECK-BE-P9-NEXT: bl memcpy +; CHECK-BE-P9-NEXT: nop +; CHECK-BE-P9-NEXT: mr r3, r30 +; CHECK-BE-P9-NEXT: ld r30, 112(r1) # 8-byte Folded Reload +; CHECK-BE-P9-NEXT: addi r1, r1, 128 +; CHECK-BE-P9-NEXT: ld r0, 16(r1) +; CHECK-BE-P9-NEXT: mtlr r0 +; CHECK-BE-P9-NEXT: blr +; +; CHECK-AIX-64-P9-LABEL: memcpy_test: +; CHECK-AIX-64-P9: # %bb.0: # %entry +; CHECK-AIX-64-P9-NEXT: mflr r0 +; CHECK-AIX-64-P9-NEXT: stdu r1, -128(r1) +; CHECK-AIX-64-P9-NEXT: std r0, 144(r1) +; CHECK-AIX-64-P9-NEXT: std r31, 120(r1) # 8-byte Folded Spill +; CHECK-AIX-64-P9-NEXT: mr r31, r3 +; CHECK-AIX-64-P9-NEXT: bl .___memmove64[PR] +; CHECK-AIX-64-P9-NEXT: nop +; CHECK-AIX-64-P9-NEXT: mr r3, r31 +; CHECK-AIX-64-P9-NEXT: ld r31, 120(r1) # 8-byte Folded Reload +; CHECK-AIX-64-P9-NEXT: addi r1, r1, 128 +; CHECK-AIX-64-P9-NEXT: ld r0, 16(r1) +; CHECK-AIX-64-P9-NEXT: mtlr r0 +; CHECK-AIX-64-P9-NEXT: blr +; +; CHECK-AIX-32-P9-LABEL: memcpy_test: +; CHECK-AIX-32-P9: # %bb.0: # %entry +; CHECK-AIX-32-P9-NEXT: mflr r0 +; CHECK-AIX-32-P9-NEXT: stwu r1, -64(r1) +; CHECK-AIX-32-P9-NEXT: stw r0, 72(r1) +; CHECK-AIX-32-P9-NEXT: stw r31, 60(r1) # 4-byte Folded Spill +; CHECK-AIX-32-P9-NEXT: mr r31, r3 +; CHECK-AIX-32-P9-NEXT: bl .___memmove[PR] +; CHECK-AIX-32-P9-NEXT: nop +; CHECK-AIX-32-P9-NEXT: mr r3, r31 +; CHECK-AIX-32-P9-NEXT: lwz r31, 60(r1) # 4-byte Folded Reload +; CHECK-AIX-32-P9-NEXT: addi r1, r1, 64 +; CHECK-AIX-32-P9-NEXT: lwz r0, 8(r1) +; CHECK-AIX-32-P9-NEXT: mtlr r0 +; CHECK-AIX-32-P9-NEXT: blr +entry: + tail call void @llvm.memcpy.p0.p0.i32(ptr align 1 %destination, ptr align 1 %source, i32 %num, i1 false) + ret ptr %destination +} + +declare void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1 immarg) + +define i32 @memcmp_test(ptr nocapture noundef readonly %ptr1, ptr nocapture noundef readonly %ptr2, i32 noundef %num) local_unnamed_addr { +; CHECK-LE-P9-LABEL: memcmp_test: +; CHECK-LE-P9: # %bb.0: # %entry +; CHECK-LE-P9-NEXT: mflr r0 +; CHECK-LE-P9-NEXT: stdu r1, -32(r1) +; CHECK-LE-P9-NEXT: std r0, 48(r1) +; CHECK-LE-P9-NEXT: .cfi_def_cfa_offset 32 +; CHECK-LE-P9-NEXT: .cfi_offset lr, 16 +; CHECK-LE-P9-NEXT: bl memcmp +; CHECK-LE-P9-NEXT: nop +; CHECK-LE-P9-NEXT: addi r1, r1, 32 +; CHECK-LE-P9-NEXT: ld r0, 16(r1) +; CHECK-LE-P9-NEXT: mtlr r0 +; CHECK-LE-P9-NEXT: blr +; +; CHECK-BE-P9-LABEL: memcmp_test: +; CHECK-BE-P9: # %bb.0: # %entry +; CHECK-BE-P9-NEXT: mflr r0 +; CHECK-BE-P9-NEXT: stdu r1, -112(r1) +; CHECK-BE-P9-NEXT: std r0, 128(r1) +; CHECK-BE-P9-NEXT: .cfi_def_cfa_offset 112 +; CHECK-BE-P9-NEXT: .cfi_offset lr, 16 +; CHECK-BE-P9-NEXT: bl memcmp +; CHECK-BE-P9-NEXT: nop +; CHECK-BE-P9-NEXT: addi r1, r1, 112 +; CHECK-BE-P9-NEXT: ld r0, 16(r1) +; CHECK-BE-P9-NEXT: mtlr r0 +; CHECK-BE-P9-NEXT: blr +; +; CHECK-AIX-64-P9-LABEL: memcmp_test: +; CHECK-AIX-64-P9: # %bb.0: # %entry +; CHECK-AIX-64-P9-NEXT: mflr r0 +; CHECK-AIX-64-P9-NEXT: stdu r1, -112(r1) +; CHECK-AIX-64-P9-NEXT: std r0, 128(r1) +; CHECK-AIX-64-P9-NEXT: bl .___memcmp64[PR] +; CHECK-AIX-64-P9-NEXT: nop +; CHECK-AIX-64-P9-NEXT: addi r1, r1, 112 +; CHECK-AIX-64-P9-NEXT: ld r0, 16(r1) +; CHECK-AIX-64-P9-NEXT: mtlr r0 +; CHECK-AIX-64-P9-NEXT: blr +; +; CHECK-AIX-32-P9-LABEL: memcmp_test: +; CHECK-AIX-32-P9: # %bb.0: # %entry +; CHECK-AIX-32-P9-NEXT: mflr r0 +; CHECK-AIX-32-P9-NEXT: stwu r1, -64(r1) +; CHECK-AIX-32-P9-NEXT: stw r0, 72(r1) +; CHECK-AIX-32-P9-NEXT: bl .___memcmp[PR] +; CHECK-AIX-32-P9-NEXT: nop +; CHECK-AIX-32-P9-NEXT: addi r1, r1, 64 +; CHECK-AIX-32-P9-NEXT: lwz r0, 8(r1) +; CHECK-AIX-32-P9-NEXT: mtlr r0 +; CHECK-AIX-32-P9-NEXT: blr +entry: + %0 = tail call i32 @llvm.memcmp.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 %num) + ret i32 %0 +} + +declare i32 @llvm.memcmp.p0.p0.i32(ptr nocapture readonly, ptr nocapture readonly, i32) + `````````` </details> https://github.com/llvm/llvm-project/pull/118178 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits