diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index 3b68afe8700dd..80d354ccaa826 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -3378,6 +3378,8 @@ Value *LibCallSimplifier::optimizePrintFString(CallInst *CI, IRBuilderBase &B) { } // printf("%s", str"\n") --> puts(str) if (OperandStr.back() == '\n') { + if (!isLibFuncEmittable(CI->getModule(), TLI, LibFunc_puts)) + return nullptr; OperandStr = OperandStr.drop_back(); Value *GV = B.CreateGlobalString(OperandStr, "str"); return copyFlags(*CI, emitPutS(GV, B, TLI)); @@ -3388,6 +3390,8 @@ Value *LibCallSimplifier::optimizePrintFString(CallInst *CI, IRBuilderBase &B) { // printf("foo\n") --> puts("foo") if (FormatStr.back() == '\n' && !FormatStr.contains('%')) { // No format characters. + if (!isLibFuncEmittable(CI->getModule(), TLI, LibFunc_puts)) + return nullptr; // Create a string literal with no \n on it. We expect the constant merge // pass to be run after this pass, to merge duplicate strings. FormatStr = FormatStr.drop_back(); diff --git a/llvm/test/Transforms/InstCombine/printf-puts-not-emittable.ll b/llvm/test/Transforms/InstCombine/printf-puts-not-emittable.ll new file mode 100644 index 0000000000000..563d671533ffa --- /dev/null +++ b/llvm/test/Transforms/InstCombine/printf-puts-not-emittable.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +@str = constant [5 x i8] c"foo\0A\00" +@fmt = constant [3 x i8] c"%s\00" + +; Make puts un-emittable by redefining it as a global variable. +@puts = global i32 0 + + +;. +; CHECK: @str = constant [5 x i8] c"foo\0A\00" +; CHECK: @fmt = constant [3 x i8] c"%s\00" +; CHECK: @puts = global i32 0 +;. +define i32 @test() { +; CHECK-LABEL: define i32 @test() { +; CHECK-NEXT: [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @str) +; CHECK-NEXT: ret i32 0 +; + %call = call i32 (ptr, ...) @printf(ptr @str) + ret i32 0 +} + +define i32 @test2() { +; CHECK-LABEL: define i32 @test2() { +; CHECK-NEXT: [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @fmt, ptr nonnull @str) +; CHECK-NEXT: ret i32 0 +; + %call = call i32 (ptr, ...) @printf(ptr @fmt, ptr @str) + ret i32 0 +} + +declare i32 @printf(ptr, ...)