From 81778322300abd0bbad923185b2da8b3572e3597 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 18 Jun 2008 08:30:37 +0000 Subject: [PATCH] Reapply r52397 (make IPConstProp promote returned arguments), but fixed this time. Sorry for the trouble! This time, also add a testcase, which I should have done in the first place... llvm-svn: 52455 --- lib/Transforms/IPO/IPConstantPropagation.cpp | 21 +++++++-- .../IPConstantProp/return-argument.ll | 46 +++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 test/Transforms/IPConstantProp/return-argument.ll diff --git a/lib/Transforms/IPO/IPConstantPropagation.cpp b/lib/Transforms/IPO/IPConstantPropagation.cpp index 0e654a50eef..f528b88983b 100644 --- a/lib/Transforms/IPO/IPConstantPropagation.cpp +++ b/lib/Transforms/IPO/IPConstantPropagation.cpp @@ -145,6 +145,10 @@ bool IPCP::PropagateConstantsIntoArguments(Function &F) { // all callers that use those return values with the constant value. This will // leave in the actual return values and instructions, but deadargelim will // clean that up. +// +// Additionally if a function always returns one of its arguments directly, +// callers will be updated to use the value they pass in directly instead of +// using the return value. bool IPCP::PropagateConstantReturn(Function &F) { if (F.getReturnType() == Type::VoidTy) return false; // No return value. @@ -188,8 +192,8 @@ bool IPCP::PropagateConstantReturn(Function &F) { if (isa(V)) continue; - // Try to see if all the rets return the same constant. - if (isa(V)) { + // Try to see if all the rets return the same constant or argument. + if (isa(V) || isa(V)) { if (isa(RV)) { // No value found yet? Try the current one. RetVals[i] = V; @@ -227,7 +231,13 @@ bool IPCP::PropagateConstantReturn(Function &F) { MadeChange = true; if (STy == 0) { - Call->replaceAllUsesWith(RetVals[0]); + Value* New = RetVals[0]; + if (Argument *A = dyn_cast(New)) + // Was an argument returned? Then find the corresponding argument in + // the call instruction and use that. Add 1 to the argument number + // to skip the first argument (the function itself). + New = Call->getOperand(A->getArgNo() + 1); + Call->replaceAllUsesWith(New); continue; } @@ -255,6 +265,11 @@ bool IPCP::PropagateConstantReturn(Function &F) { if (index != -1) { Value *New = RetVals[index]; if (New) { + if (Argument *A = dyn_cast(New)) + // Was an argument returned? Then find the corresponding argument in + // the call instruction and use that. Add 1 to the argument number + // to skip the first argument (the function itself). + New = Call->getOperand(A->getArgNo() + 1); Ins->replaceAllUsesWith(New); Ins->eraseFromParent(); } diff --git a/test/Transforms/IPConstantProp/return-argument.ll b/test/Transforms/IPConstantProp/return-argument.ll new file mode 100644 index 00000000000..53288ee1086 --- /dev/null +++ b/test/Transforms/IPConstantProp/return-argument.ll @@ -0,0 +1,46 @@ +; RUN: llvm-as < %s | opt -ipconstprop | llvm-dis > %t +; RUN: cat %t | grep {store i32 %Z, i32\\* %Q} +; RUN: cat %t | grep {add i32 1, 3} + +;; This function returns its second argument on all return statements +define internal i32* @incdec(i1 %C, i32* %V) { + %X = load i32* %V + br i1 %C, label %T, label %F + +T: ; preds = %0 + %X1 = add i32 %X, 1 + store i32 %X1, i32* %V + ret i32* %V + +F: ; preds = %0 + %X2 = sub i32 %X, 1 + store i32 %X2, i32* %V + ret i32* %V +} + +;; This function returns its first argument as a part of a multiple return +;; value +define internal { i32, i32 } @foo(i32 %A, i32 %B) { + %X = add i32 %A, %B + %Y = insertvalue { i32, i32 } undef, i32 %A, 0 + %Z = insertvalue { i32, i32 } %Y, i32 %X, 1 + ret { i32, i32 } %Z +} + +define void @caller(i1 %C) { + %Q = alloca i32 + ;; Call incdec to see if %W is properly replaced by %Q + %W = call i32* @incdec(i1 %C, i32* %Q ) ; [#uses=1] + ;; Call @foo twice, to prevent the arguments from propagating into the + ;; function (so we can check the returned argument is properly + ;; propagated per-caller). + %S1 = call { i32, i32 } @foo(i32 1, i32 2); + %X1 = extractvalue { i32, i32 } %S1, 0 + %S2 = call { i32, i32 } @foo(i32 3, i32 4); + %X2 = extractvalue { i32, i32 } %S2, 0 + ;; Do some stuff with the returned values which we can grep for + %Z = add i32 %X1, %X2 + store i32 %Z, i32* %W + ret void +} +