Index: llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h =================================================================== --- llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -210,6 +210,9 @@ Value *optimizeToAscii(CallInst *CI, IRBuilderBase &B); Value *optimizeAtoi(CallInst *CI, IRBuilderBase &B); Value *optimizeStrtol(CallInst *CI, IRBuilderBase &B); + // Wrapper for all integer library call optimizations + Value *optimizeIntegerLibCall(CallInst *CI, LibFunc Func, + IRBuilderBase &B); // Formatting and IO Library Call Optimizations Value *optimizeErrorReporting(CallInst *CI, IRBuilderBase &B, @@ -221,6 +224,9 @@ Value *optimizeFWrite(CallInst *CI, IRBuilderBase &B); Value *optimizeFPuts(CallInst *CI, IRBuilderBase &B); Value *optimizePuts(CallInst *CI, IRBuilderBase &B); + // Wrapper for all formatting and IO library call optimizations + Value *optimizeIOLibCall(CallInst *CI, LibFunc Func, + IRBuilderBase &B); // Helper methods Value *emitStrLenMemCpy(Value *Src, Value *Dst, uint64_t Len, Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -3019,6 +3019,81 @@ } } +Value *LibCallSimplifier::optimizeIntegerLibCall(CallInst *CI, + LibFunc Func, + IRBuilderBase &Builder) { + switch (Func) { + case LibFunc_ffs: + case LibFunc_ffsl: + case LibFunc_ffsll: + return optimizeFFS(CI, Builder); + case LibFunc_fls: + case LibFunc_flsl: + case LibFunc_flsll: + return optimizeFls(CI, Builder); + case LibFunc_abs: + case LibFunc_labs: + case LibFunc_llabs: + return optimizeAbs(CI, Builder); + case LibFunc_isdigit: + return optimizeIsDigit(CI, Builder); + case LibFunc_isascii: + return optimizeIsAscii(CI, Builder); + case LibFunc_toascii: + return optimizeToAscii(CI, Builder); + case LibFunc_atoi: + case LibFunc_atol: + case LibFunc_atoll: + return optimizeAtoi(CI, Builder); + case LibFunc_strtol: + case LibFunc_strtoll: + return optimizeStrtol(CI, Builder); + default: + return nullptr; + } +} + +Value *LibCallSimplifier::optimizeIOLibCall(CallInst *CI, + LibFunc Func, + IRBuilderBase &Builder) { + switch (Func) { + case LibFunc_printf: + return optimizePrintF(CI, Builder); + case LibFunc_sprintf: + return optimizeSPrintF(CI, Builder); + case LibFunc_snprintf: + return optimizeSnPrintF(CI, Builder); + case LibFunc_fprintf: + return optimizeFPrintF(CI, Builder); + case LibFunc_fwrite: + return optimizeFWrite(CI, Builder); + case LibFunc_fputs: + return optimizeFPuts(CI, Builder); + case LibFunc_puts: + return optimizePuts(CI, Builder); + case LibFunc_perror: + return optimizeErrorReporting(CI, Builder); + case LibFunc_vfprintf: + case LibFunc_fiprintf: + return optimizeErrorReporting(CI, Builder, 0); + default: + return nullptr; + } +} + +// Copy the calling convention from CI to NewVal if it's a function call. +// Used when replacing one function call with another. +static void copyCallingConv(Value *NewVal, CallInst *CI) { + if (!NewVal) + return; + if (CallInst *NewCI = dyn_cast(NewVal)) { + if (Function *F = NewCI->getCalledFunction()) { + F->setCallingConv(CI->getCallingConv()); + NewCI->setCallingConv(CI->getCallingConv()); + } + } +} + Value *LibCallSimplifier::optimizeCall(CallInst *CI, IRBuilderBase &Builder) { // TODO: Split out the code below that operates on FP calls so that // we can all non-FP calls with the StrictFP attribute to be @@ -3050,27 +3125,37 @@ return nullptr; // The FP intrinsics have corresponding constrained versions so we don't // need to check for the StrictFP attribute here. + Value *NewVal = nullptr; switch (II->getIntrinsicID()) { case Intrinsic::pow: - return optimizePow(CI, Builder); + NewVal = optimizePow(CI, Builder); + break; case Intrinsic::exp2: - return optimizeExp2(CI, Builder); + NewVal = optimizeExp2(CI, Builder); + break; case Intrinsic::log: case Intrinsic::log2: case Intrinsic::log10: - return optimizeLog(CI, Builder); + NewVal = optimizeLog(CI, Builder); + break; case Intrinsic::sqrt: - return optimizeSqrt(CI, Builder); + NewVal = optimizeSqrt(CI, Builder); + break; // TODO: Use foldMallocMemset() with memset intrinsic. case Intrinsic::memset: - return optimizeMemSet(CI, Builder); + NewVal = optimizeMemSet(CI, Builder); + break; case Intrinsic::memcpy: - return optimizeMemCpy(CI, Builder); + NewVal = optimizeMemCpy(CI, Builder); + break; case Intrinsic::memmove: - return optimizeMemMove(CI, Builder); + NewVal = optimizeMemMove(CI, Builder); + break; default: return nullptr; } + copyCallingConv(NewVal, CI); + return NewVal; } // Also try to simplify calls to fortified library functions. @@ -3089,6 +3174,7 @@ Builder.SetInsertPoint(SimplifiedCI); if (Value *V = optimizeStringMemoryLibCall(SimplifiedCI, Builder)) { // If we were able to further simplify, remove the now redundant call. + copyCallingConv(V, SimplifiedCI); substituteInParent(SimplifiedCI, V); return V; } @@ -3101,57 +3187,13 @@ // We never change the calling convention. if (!ignoreCallingConv(Func) && !isCallingConvC) return nullptr; - if (Value *V = optimizeStringMemoryLibCall(CI, Builder)) - return V; - if (Value *V = optimizeFloatingPointLibCall(CI, Func, Builder)) - return V; - switch (Func) { - case LibFunc_ffs: - case LibFunc_ffsl: - case LibFunc_ffsll: - return optimizeFFS(CI, Builder); - case LibFunc_fls: - case LibFunc_flsl: - case LibFunc_flsll: - return optimizeFls(CI, Builder); - case LibFunc_abs: - case LibFunc_labs: - case LibFunc_llabs: - return optimizeAbs(CI, Builder); - case LibFunc_isdigit: - return optimizeIsDigit(CI, Builder); - case LibFunc_isascii: - return optimizeIsAscii(CI, Builder); - case LibFunc_toascii: - return optimizeToAscii(CI, Builder); - case LibFunc_atoi: - case LibFunc_atol: - case LibFunc_atoll: - return optimizeAtoi(CI, Builder); - case LibFunc_strtol: - case LibFunc_strtoll: - return optimizeStrtol(CI, Builder); - case LibFunc_printf: - return optimizePrintF(CI, Builder); - case LibFunc_sprintf: - return optimizeSPrintF(CI, Builder); - case LibFunc_snprintf: - return optimizeSnPrintF(CI, Builder); - case LibFunc_fprintf: - return optimizeFPrintF(CI, Builder); - case LibFunc_fwrite: - return optimizeFWrite(CI, Builder); - case LibFunc_fputs: - return optimizeFPuts(CI, Builder); - case LibFunc_puts: - return optimizePuts(CI, Builder); - case LibFunc_perror: - return optimizeErrorReporting(CI, Builder); - case LibFunc_vfprintf: - case LibFunc_fiprintf: - return optimizeErrorReporting(CI, Builder, 0); - default: - return nullptr; + Value *NewVal = nullptr; + if ((NewVal = optimizeStringMemoryLibCall(CI, Builder)) || + (NewVal = optimizeFloatingPointLibCall(CI, Func, Builder)) || + (NewVal = optimizeIntegerLibCall(CI, Func, Builder)) || + (NewVal = optimizeIOLibCall(CI, Func, Builder))) { + copyCallingConv(NewVal, CI); + return NewVal; } } return nullptr; @@ -3491,45 +3533,63 @@ if (!ignoreCallingConv(Func) && !isCallingConvC) return nullptr; + Value *NewVal = nullptr; switch (Func) { case LibFunc_memcpy_chk: - return optimizeMemCpyChk(CI, Builder); + NewVal = optimizeMemCpyChk(CI, Builder); + break; case LibFunc_mempcpy_chk: - return optimizeMemPCpyChk(CI, Builder); + NewVal = optimizeMemPCpyChk(CI, Builder); + break; case LibFunc_memmove_chk: - return optimizeMemMoveChk(CI, Builder); + NewVal = optimizeMemMoveChk(CI, Builder); + break; case LibFunc_memset_chk: - return optimizeMemSetChk(CI, Builder); + NewVal = optimizeMemSetChk(CI, Builder); + break; case LibFunc_stpcpy_chk: case LibFunc_strcpy_chk: - return optimizeStrpCpyChk(CI, Builder, Func); + NewVal = optimizeStrpCpyChk(CI, Builder, Func); + break; case LibFunc_strlen_chk: - return optimizeStrLenChk(CI, Builder); + NewVal = optimizeStrLenChk(CI, Builder); + break; case LibFunc_stpncpy_chk: case LibFunc_strncpy_chk: - return optimizeStrpNCpyChk(CI, Builder, Func); + NewVal = optimizeStrpNCpyChk(CI, Builder, Func); + break; case LibFunc_memccpy_chk: - return optimizeMemCCpyChk(CI, Builder); + NewVal = optimizeMemCCpyChk(CI, Builder); + break; case LibFunc_snprintf_chk: - return optimizeSNPrintfChk(CI, Builder); + NewVal = optimizeSNPrintfChk(CI, Builder); + break; case LibFunc_sprintf_chk: - return optimizeSPrintfChk(CI, Builder); + NewVal = optimizeSPrintfChk(CI, Builder); + break; case LibFunc_strcat_chk: - return optimizeStrCatChk(CI, Builder); + NewVal = optimizeStrCatChk(CI, Builder); + break; case LibFunc_strlcat_chk: - return optimizeStrLCat(CI, Builder); + NewVal = optimizeStrLCat(CI, Builder); + break; case LibFunc_strncat_chk: - return optimizeStrNCatChk(CI, Builder); + NewVal = optimizeStrNCatChk(CI, Builder); + break; case LibFunc_strlcpy_chk: - return optimizeStrLCpyChk(CI, Builder); + NewVal = optimizeStrLCpyChk(CI, Builder); + break; case LibFunc_vsnprintf_chk: - return optimizeVSNPrintfChk(CI, Builder); + NewVal = optimizeVSNPrintfChk(CI, Builder); + break; case LibFunc_vsprintf_chk: - return optimizeVSPrintfChk(CI, Builder); + NewVal = optimizeVSPrintfChk(CI, Builder); + break; default: break; } - return nullptr; + copyCallingConv(NewVal, CI); + return NewVal; } FortifiedLibCallSimplifier::FortifiedLibCallSimplifier( Index: llvm/test/Transforms/InstCombine/ARM/strcmp.ll =================================================================== --- llvm/test/Transforms/InstCombine/ARM/strcmp.ll +++ llvm/test/Transforms/InstCombine/ARM/strcmp.ll @@ -67,7 +67,7 @@ define arm_aapcscc i32 @test5(i1 %b) { ; CHECK-LABEL: @test5( ; CHECK-NEXT: [[STR2:%.*]] = select i1 [[B:%.*]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @bell, i32 0, i32 0) -; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull dereferenceable(5) getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i8* nonnull dereferenceable(5) [[STR2]], i32 5) +; CHECK-NEXT: [[MEMCMP:%.*]] = call arm_aapcscc i32 @memcmp(i8* nonnull dereferenceable(5) getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i8* nonnull dereferenceable(5) [[STR2]], i32 5) ; CHECK-NEXT: ret i32 [[MEMCMP]] ; @@ -145,7 +145,7 @@ define arm_aapcs_vfpcc i32 @test5_vfp(i1 %b) { ; CHECK-LABEL: @test5_vfp( ; CHECK-NEXT: [[STR2:%.*]] = select i1 [[B:%.*]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @bell, i32 0, i32 0) -; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(i8* nonnull dereferenceable(5) getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i8* nonnull dereferenceable(5) [[STR2]], i32 5) +; CHECK-NEXT: [[MEMCMP:%.*]] = call arm_aapcs_vfpcc i32 @memcmp(i8* nonnull dereferenceable(5) getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i8* nonnull dereferenceable(5) [[STR2]], i32 5) ; CHECK-NEXT: ret i32 [[MEMCMP]] ; Index: llvm/test/Transforms/InstCombine/call-callconv.ll =================================================================== --- llvm/test/Transforms/InstCombine/call-callconv.ll +++ llvm/test/Transforms/InstCombine/call-callconv.ll @@ -2,6 +2,8 @@ ; RUN: opt < %s -instcombine -S | FileCheck %s ; Verify that the non-default calling conv doesn't prevent the libcall simplification +target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + @.str = private unnamed_addr constant [4 x i8] c"abc\00", align 1 define arm_aapcscc i32 @_abs(i32 %i) nounwind readnone { @@ -51,3 +53,46 @@ ret i1 %cmp } +%struct.FILE = type opaque +declare arm_aapcscc i32 @fprintf(%struct.FILE*, i8*, ...) + +define arm_aapcscc void @_fprintf(%struct.FILE* %file) { +; CHECK-LABEL: @_fprintf( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = call arm_aapcscc i32 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 3, i32 1, %struct.FILE* [[FILE:%.*]]) +; CHECK-NEXT: ret void +; +entry: + %call = tail call arm_aapcscc i32 (%struct.FILE*, i8*, ...) @fprintf(%struct.FILE* %file, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0)) + ret void +} + +declare arm_aapcscc i32 @printf(i8*, ...) +@.str2 = private unnamed_addr constant [2 x i8] c"a\00", align 1 + +define arm_aapcscc void @_printf(%struct.FILE* %file) { +; CHECK-LABEL: @_printf( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[PUTCHAR:%.*]] = call arm_aapcscc i32 @putchar(i32 97) +; CHECK-NEXT: ret void +; +entry: + %call = tail call arm_aapcscc i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str2, i32 0, i32 0)) + ret void +} + +@a = common global [60 x i8] zeroinitializer, align 1 +@b = common global [60 x i8] zeroinitializer, align 1 +declare arm_aapcscc i8* @__strcpy_chk(i8*, i8*, i32) + +define arm_aapcscc i8* @_strcpy_chk() { +; CHECK-LABEL: @_strcpy_chk( +; CHECK-NEXT: [[STRCPY:%.*]] = call arm_aapcscc i8* @strcpy(i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0)) +; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0) +; + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + + %ret = call arm_aapcscc i8* @__strcpy_chk(i8* %dst, i8* %src, i32 -1) + ret i8* %ret +}