From 59d6e814ce0e7b40b7cc3ab136b9af2ffab9c6f8 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 30 Jul 2020 13:06:15 +0100 Subject: [PATCH] Revert "[IPConstProp] Remove and move tests to SCCP." This reverts commit e77624a3be942c7abba48942b3a8da3462070a3f. Looks like some clang tests manually invoke -ipconstprop via opt..... --- llvm/bindings/go/llvm/transforms_ipo.go | 1 + .../bindings/ocaml/transforms/ipo/ipo_ocaml.c | 6 + .../ocaml/transforms/ipo/llvm_ipo.mli | 5 + llvm/docs/Passes.rst | 9 + llvm/include/llvm-c/Transforms/IPO.h | 3 + llvm/include/llvm/InitializePasses.h | 1 + llvm/include/llvm/LinkAllPasses.h | 1 + llvm/include/llvm/Transforms/IPO.h | 6 + llvm/lib/Transforms/IPO/CMakeLists.txt | 1 + .../Transforms/IPO/IPConstantPropagation.cpp | 308 ++++++++++++++++++ llvm/lib/Transforms/IPO/IPO.cpp | 5 + .../2008-06-09-WeakProp.ll | 2 +- .../{SCCP => IPConstantProp}/PR43857.ll | 4 +- .../arg-count-mismatch.ll | 4 +- .../arg-type-mismatch.ll | 2 +- .../Transforms/IPConstantProp/comdat-ipo.ll | 34 ++ .../{SCCP => IPConstantProp}/deadarg.ll | 2 +- .../multiple_callbacks.ll | 7 +- .../{SCCP => IPConstantProp}/naked-return.ll | 1 + .../openmp_parallel_for.ll | 4 +- .../{SCCP => IPConstantProp}/pthreads.ll | 6 +- .../{SCCP => IPConstantProp}/recursion.ll | 2 +- .../return-argument.ll | 8 +- .../return-constant.ll | 6 +- .../return-constants.ll | 18 +- .../thread_local_acs.ll | 4 +- llvm/test/Transforms/SCCP/comdat-ipo.ll | 14 +- llvm/utils/findoptdiff | 2 +- .../llvm/lib/Transforms/IPO/BUILD.gn | 1 + 29 files changed, 424 insertions(+), 43 deletions(-) create mode 100644 llvm/lib/Transforms/IPO/IPConstantPropagation.cpp rename llvm/test/Transforms/{SCCP => IPConstantProp}/2008-06-09-WeakProp.ll (91%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/PR43857.ll (86%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/arg-count-mismatch.ll (96%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/arg-type-mismatch.ll (92%) create mode 100644 llvm/test/Transforms/IPConstantProp/comdat-ipo.ll rename llvm/test/Transforms/{SCCP => IPConstantProp}/deadarg.ll (77%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/multiple_callbacks.ll (96%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/naked-return.ll (97%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/openmp_parallel_for.ll (98%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/pthreads.ll (93%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/recursion.ll (90%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/return-argument.ll (91%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/return-constant.ll (91%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/return-constants.ll (70%) rename llvm/test/Transforms/{SCCP => IPConstantProp}/thread_local_acs.ll (92%) diff --git a/llvm/bindings/go/llvm/transforms_ipo.go b/llvm/bindings/go/llvm/transforms_ipo.go index 8a158f208bef..1dcb2af8bf24 100644 --- a/llvm/bindings/go/llvm/transforms_ipo.go +++ b/llvm/bindings/go/llvm/transforms_ipo.go @@ -32,6 +32,7 @@ func (pm PassManager) AddFunctionAttrsPass() { C.LLVMAddFunctionAttrsPas func (pm PassManager) AddFunctionInliningPass() { C.LLVMAddFunctionInliningPass(pm.C) } func (pm PassManager) AddGlobalDCEPass() { C.LLVMAddGlobalDCEPass(pm.C) } func (pm PassManager) AddGlobalOptimizerPass() { C.LLVMAddGlobalOptimizerPass(pm.C) } +func (pm PassManager) AddIPConstantPropagationPass() { C.LLVMAddIPConstantPropagationPass(pm.C) } func (pm PassManager) AddPruneEHPass() { C.LLVMAddPruneEHPass(pm.C) } func (pm PassManager) AddIPSCCPPass() { C.LLVMAddIPSCCPPass(pm.C) } func (pm PassManager) AddInternalizePass(allButMain bool) { diff --git a/llvm/bindings/ocaml/transforms/ipo/ipo_ocaml.c b/llvm/bindings/ocaml/transforms/ipo/ipo_ocaml.c index c0e213714ed0..9fcaa10534f6 100644 --- a/llvm/bindings/ocaml/transforms/ipo/ipo_ocaml.c +++ b/llvm/bindings/ocaml/transforms/ipo/ipo_ocaml.c @@ -73,6 +73,12 @@ CAMLprim value llvm_add_global_optimizer(LLVMPassManagerRef PM) { return Val_unit; } +/* [`Module] Llvm.PassManager.t -> unit */ +CAMLprim value llvm_add_ip_constant_propagation(LLVMPassManagerRef PM) { + LLVMAddIPConstantPropagationPass(PM); + return Val_unit; +} + /* [`Module] Llvm.PassManager.t -> unit */ CAMLprim value llvm_add_prune_eh(LLVMPassManagerRef PM) { LLVMAddPruneEHPass(PM); diff --git a/llvm/bindings/ocaml/transforms/ipo/llvm_ipo.mli b/llvm/bindings/ocaml/transforms/ipo/llvm_ipo.mli index a581924c6d54..6507c5d92c2b 100644 --- a/llvm/bindings/ocaml/transforms/ipo/llvm_ipo.mli +++ b/llvm/bindings/ocaml/transforms/ipo/llvm_ipo.mli @@ -56,6 +56,11 @@ external add_global_optimizer : [ `Module ] Llvm.PassManager.t -> unit = "llvm_add_global_optimizer" +(** See the [llvm::createIPConstantPropagationPass] function. *) +external add_ipc_propagation + : [ `Module ] Llvm.PassManager.t -> unit + = "llvm_add_ip_constant_propagation" + (** See the [llvm::createPruneEHPass] function. *) external add_prune_eh : [ `Module ] Llvm.PassManager.t -> unit diff --git a/llvm/docs/Passes.rst b/llvm/docs/Passes.rst index 13317ecc966e..e45adad98c15 100644 --- a/llvm/docs/Passes.rst +++ b/llvm/docs/Passes.rst @@ -676,6 +676,15 @@ This pass loops over all of the functions in the input module, looking for a main function. If a main function is found, all other functions and all global variables with initializers are marked as internal. +``-ipconstprop``: Interprocedural constant propagation +------------------------------------------------------ + +This pass implements an *extremely* simple interprocedural constant propagation +pass. It could certainly be improved in many different ways, like using a +worklist. This pass makes arguments dead, but does not remove them. The +existing dead argument elimination pass should be run after this to clean up +the mess. + ``-ipsccp``: Interprocedural Sparse Conditional Constant Propagation -------------------------------------------------------------------- diff --git a/llvm/include/llvm-c/Transforms/IPO.h b/llvm/include/llvm-c/Transforms/IPO.h index 3f2cadf32366..cde3d2460920 100644 --- a/llvm/include/llvm-c/Transforms/IPO.h +++ b/llvm/include/llvm-c/Transforms/IPO.h @@ -57,6 +57,9 @@ void LLVMAddGlobalDCEPass(LLVMPassManagerRef PM); /** See llvm::createGlobalOptimizerPass function. */ void LLVMAddGlobalOptimizerPass(LLVMPassManagerRef PM); +/** See llvm::createIPConstantPropagationPass function. */ +void LLVMAddIPConstantPropagationPass(LLVMPassManagerRef PM); + /** See llvm::createPruneEHPass function. */ void LLVMAddPruneEHPass(LLVMPassManagerRef PM); diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index d23ecfb98ce9..cce6a4350402 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -179,6 +179,7 @@ void initializeGuardWideningLegacyPassPass(PassRegistry&); void initializeHardwareLoopsPass(PassRegistry&); void initializeHotColdSplittingLegacyPassPass(PassRegistry&); void initializeHWAddressSanitizerLegacyPassPass(PassRegistry &); +void initializeIPCPPass(PassRegistry&); void initializeIPSCCPLegacyPassPass(PassRegistry&); void initializeIRCELegacyPassPass(PassRegistry&); void initializeIRTranslatorPass(PassRegistry&); diff --git a/llvm/include/llvm/LinkAllPasses.h b/llvm/include/llvm/LinkAllPasses.h index 9d7ac2b3f3b9..90e2e24294d4 100644 --- a/llvm/include/llvm/LinkAllPasses.h +++ b/llvm/include/llvm/LinkAllPasses.h @@ -116,6 +116,7 @@ namespace { (void) llvm::createGlobalsAAWrapperPass(); (void) llvm::createGuardWideningPass(); (void) llvm::createLoopGuardWideningPass(); + (void) llvm::createIPConstantPropagationPass(); (void) llvm::createIPSCCPPass(); (void) llvm::createInductiveRangeCheckEliminationPass(); (void) llvm::createIndVarSimplifyPass(); diff --git a/llvm/include/llvm/Transforms/IPO.h b/llvm/include/llvm/Transforms/IPO.h index 7b73eeaf8e45..28e454d3b0fc 100644 --- a/llvm/include/llvm/Transforms/IPO.h +++ b/llvm/include/llvm/Transforms/IPO.h @@ -155,6 +155,12 @@ Pass *createArgumentPromotionPass(unsigned maxElements = 3); /// createOpenMPOptLegacyPass - OpenMP specific optimizations. Pass *createOpenMPOptLegacyPass(); +//===----------------------------------------------------------------------===// +/// createIPConstantPropagationPass - This pass propagates constants from call +/// sites into the bodies of functions. +/// +ModulePass *createIPConstantPropagationPass(); + //===----------------------------------------------------------------------===// /// createIPSCCPPass - This pass propagates constants from call sites into the /// bodies of functions, and keeps track of whether basic blocks are executable diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt index a17ef6337106..3f30c0289e8c 100644 --- a/llvm/lib/Transforms/IPO/CMakeLists.txt +++ b/llvm/lib/Transforms/IPO/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_component_library(LLVMipo GlobalOpt.cpp GlobalSplit.cpp HotColdSplitting.cpp + IPConstantPropagation.cpp IPO.cpp InferFunctionAttrs.cpp InlineSimple.cpp diff --git a/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp b/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp new file mode 100644 index 000000000000..8d05a72d68da --- /dev/null +++ b/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp @@ -0,0 +1,308 @@ +//===-- IPConstantPropagation.cpp - Propagate constants through calls -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This pass implements an _extremely_ simple interprocedural constant +// propagation pass. It could certainly be improved in many different ways, +// like using a worklist. This pass makes arguments dead, but does not remove +// them. The existing dead argument elimination pass should be run after this +// to clean up the mess. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/AbstractCallSite.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/IPO.h" +using namespace llvm; + +#define DEBUG_TYPE "ipconstprop" + +STATISTIC(NumArgumentsProped, "Number of args turned into constants"); +STATISTIC(NumReturnValProped, "Number of return values turned into constants"); + +namespace { + /// IPCP - The interprocedural constant propagation pass + /// + struct IPCP : public ModulePass { + static char ID; // Pass identification, replacement for typeid + IPCP() : ModulePass(ID) { + initializeIPCPPass(*PassRegistry::getPassRegistry()); + } + + bool runOnModule(Module &M) override; + }; +} + +/// PropagateConstantsIntoArguments - Look at all uses of the specified +/// function. If all uses are direct call sites, and all pass a particular +/// constant in for an argument, propagate that constant in as the argument. +/// +static bool PropagateConstantsIntoArguments(Function &F) { + if (F.arg_empty() || F.use_empty()) return false; // No arguments? Early exit. + + // For each argument, keep track of its constant value and whether it is a + // constant or not. The bool is driven to true when found to be non-constant. + SmallVector, 16> ArgumentConstants; + ArgumentConstants.resize(F.arg_size()); + + unsigned NumNonconstant = 0; + for (Use &U : F.uses()) { + User *UR = U.getUser(); + // Ignore blockaddress uses. + if (isa(UR)) continue; + + // If no abstract call site was created we did not understand the use, bail. + AbstractCallSite ACS(&U); + if (!ACS) + return false; + + // Mismatched argument count is undefined behavior. Simply bail out to avoid + // handling of such situations below (avoiding asserts/crashes). + unsigned NumActualArgs = ACS.getNumArgOperands(); + if (F.isVarArg() ? ArgumentConstants.size() > NumActualArgs + : ArgumentConstants.size() != NumActualArgs) + return false; + + // Check out all of the potentially constant arguments. Note that we don't + // inspect varargs here. + Function::arg_iterator Arg = F.arg_begin(); + for (unsigned i = 0, e = ArgumentConstants.size(); i != e; ++i, ++Arg) { + + // If this argument is known non-constant, ignore it. + if (ArgumentConstants[i].getInt()) + continue; + + Value *V = ACS.getCallArgOperand(i); + Constant *C = dyn_cast_or_null(V); + + // Mismatched argument type is undefined behavior. Simply bail out to avoid + // handling of such situations below (avoiding asserts/crashes). + if (C && Arg->getType() != C->getType()) + return false; + + // We can only propagate thread independent values through callbacks. + // This is different to direct/indirect call sites because for them we + // know the thread executing the caller and callee is the same. For + // callbacks this is not guaranteed, thus a thread dependent value could + // be different for the caller and callee, making it invalid to propagate. + if (C && ACS.isCallbackCall() && C->isThreadDependent()) { + // Argument became non-constant. If all arguments are non-constant now, + // give up on this function. + if (++NumNonconstant == ArgumentConstants.size()) + return false; + + ArgumentConstants[i].setInt(true); + continue; + } + + if (C && ArgumentConstants[i].getPointer() == nullptr) { + ArgumentConstants[i].setPointer(C); // First constant seen. + } else if (C && ArgumentConstants[i].getPointer() == C) { + // Still the constant value we think it is. + } else if (V == &*Arg) { + // Ignore recursive calls passing argument down. + } else { + // Argument became non-constant. If all arguments are non-constant now, + // give up on this function. + if (++NumNonconstant == ArgumentConstants.size()) + return false; + ArgumentConstants[i].setInt(true); + } + } + } + + // If we got to this point, there is a constant argument! + assert(NumNonconstant != ArgumentConstants.size()); + bool MadeChange = false; + Function::arg_iterator AI = F.arg_begin(); + for (unsigned i = 0, e = ArgumentConstants.size(); i != e; ++i, ++AI) { + // Do we have a constant argument? + if (ArgumentConstants[i].getInt() || AI->use_empty() || + (AI->hasByValAttr() && !F.onlyReadsMemory())) + continue; + + Value *V = ArgumentConstants[i].getPointer(); + if (!V) V = UndefValue::get(AI->getType()); + AI->replaceAllUsesWith(V); + ++NumArgumentsProped; + MadeChange = true; + } + return MadeChange; +} + + +// Check to see if this function returns one or more constants. If so, replace +// 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. +static bool PropagateConstantReturn(Function &F) { + if (F.getReturnType()->isVoidTy()) + return false; // No return value. + + // We can infer and propagate the return value only when we know that the + // definition we'll get at link time is *exactly* the definition we see now. + // For more details, see GlobalValue::mayBeDerefined. + if (!F.isDefinitionExact()) + return false; + + // Don't touch naked functions. The may contain asm returning + // value we don't see, so we may end up interprocedurally propagating + // the return value incorrectly. + if (F.hasFnAttribute(Attribute::Naked)) + return false; + + // Check to see if this function returns a constant. + SmallVector RetVals; + StructType *STy = dyn_cast(F.getReturnType()); + if (STy) + for (unsigned i = 0, e = STy->getNumElements(); i < e; ++i) + RetVals.push_back(UndefValue::get(STy->getElementType(i))); + else + RetVals.push_back(UndefValue::get(F.getReturnType())); + + unsigned NumNonConstant = 0; + for (BasicBlock &BB : F) + if (ReturnInst *RI = dyn_cast(BB.getTerminator())) { + for (unsigned i = 0, e = RetVals.size(); i != e; ++i) { + // Already found conflicting return values? + Value *RV = RetVals[i]; + if (!RV) + continue; + + // Find the returned value + Value *V; + if (!STy) + V = RI->getOperand(0); + else + V = FindInsertedValue(RI->getOperand(0), i); + + if (V) { + // Ignore undefs, we can change them into anything + if (isa(V)) + continue; + + // 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; + continue; + } + // Returning the same value? Good. + if (RV == V) + continue; + } + } + // Different or no known return value? Don't propagate this return + // value. + RetVals[i] = nullptr; + // All values non-constant? Stop looking. + if (++NumNonConstant == RetVals.size()) + return false; + } + } + + // If we got here, the function returns at least one constant value. Loop + // over all users, replacing any uses of the return value with the returned + // constant. + bool MadeChange = false; + for (Use &U : F.uses()) { + CallBase *CB = dyn_cast(U.getUser()); + + // Not a call instruction or a call instruction that's not calling F + // directly? + if (!CB || !CB->isCallee(&U)) + continue; + + // Call result not used? + if (CB->use_empty()) + continue; + + MadeChange = true; + + if (!STy) { + 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. + New = CB->getArgOperand(A->getArgNo()); + CB->replaceAllUsesWith(New); + continue; + } + + for (auto I = CB->user_begin(), E = CB->user_end(); I != E;) { + Instruction *Ins = cast(*I); + + // Increment now, so we can remove the use + ++I; + + // Find the index of the retval to replace with + int index = -1; + if (ExtractValueInst *EV = dyn_cast(Ins)) + if (EV->getNumIndices() == 1) + index = *EV->idx_begin(); + + // If this use uses a specific return value, and we have a replacement, + // replace it. + 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. + New = CB->getArgOperand(A->getArgNo()); + Ins->replaceAllUsesWith(New); + Ins->eraseFromParent(); + } + } + } + } + + if (MadeChange) ++NumReturnValProped; + return MadeChange; +} + +char IPCP::ID = 0; +INITIALIZE_PASS(IPCP, "ipconstprop", + "Interprocedural constant propagation", false, false) + +ModulePass *llvm::createIPConstantPropagationPass() { return new IPCP(); } + +bool IPCP::runOnModule(Module &M) { + if (skipModule(M)) + return false; + + bool Changed = false; + bool LocalChange = true; + + // FIXME: instead of using smart algorithms, we just iterate until we stop + // making changes. + while (LocalChange) { + LocalChange = false; + for (Function &F : M) + if (!F.isDeclaration()) { + // Delete any klingons. + F.removeDeadConstantUsers(); + if (F.hasLocalLinkage()) + LocalChange |= PropagateConstantsIntoArguments(F); + Changed |= PropagateConstantReturn(F); + } + Changed |= LocalChange; + } + return Changed; +} diff --git a/llvm/lib/Transforms/IPO/IPO.cpp b/llvm/lib/Transforms/IPO/IPO.cpp index 45aca100086d..d37b9236380d 100644 --- a/llvm/lib/Transforms/IPO/IPO.cpp +++ b/llvm/lib/Transforms/IPO/IPO.cpp @@ -35,6 +35,7 @@ void llvm::initializeIPO(PassRegistry &Registry) { initializeGlobalOptLegacyPassPass(Registry); initializeGlobalSplitPass(Registry); initializeHotColdSplittingLegacyPassPass(Registry); + initializeIPCPPass(Registry); initializeAlwaysInlinerLegacyPassPass(Registry); initializeSimpleInlinerPass(Registry); initializeInferFunctionAttrsLegacyPassPass(Registry); @@ -103,6 +104,10 @@ void LLVMAddGlobalOptimizerPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createGlobalOptimizerPass()); } +void LLVMAddIPConstantPropagationPass(LLVMPassManagerRef PM) { + unwrap(PM)->add(createIPConstantPropagationPass()); +} + void LLVMAddPruneEHPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createPruneEHPass()); } diff --git a/llvm/test/Transforms/SCCP/2008-06-09-WeakProp.ll b/llvm/test/Transforms/IPConstantProp/2008-06-09-WeakProp.ll similarity index 91% rename from llvm/test/Transforms/SCCP/2008-06-09-WeakProp.ll rename to llvm/test/Transforms/IPConstantProp/2008-06-09-WeakProp.ll index b6c5299ae7dc..270115cf5ddd 100644 --- a/llvm/test/Transforms/SCCP/2008-06-09-WeakProp.ll +++ b/llvm/test/Transforms/IPConstantProp/2008-06-09-WeakProp.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -ipsccp -S | FileCheck %s +; RUN: opt < %s -ipconstprop -S | FileCheck %s ; Should not propagate the result of a weak function. ; PR2411 diff --git a/llvm/test/Transforms/SCCP/PR43857.ll b/llvm/test/Transforms/IPConstantProp/PR43857.ll similarity index 86% rename from llvm/test/Transforms/SCCP/PR43857.ll rename to llvm/test/Transforms/IPConstantProp/PR43857.ll index efe4bca4f514..0d0d14d398de 100644 --- a/llvm/test/Transforms/SCCP/PR43857.ll +++ b/llvm/test/Transforms/IPConstantProp/PR43857.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -S -ipsccp | FileCheck %s +; RUN: opt < %s -S -ipconstprop | FileCheck %s %struct.wobble = type { i32 } %struct.zot = type { %struct.wobble, %struct.wobble, %struct.wobble } @@ -19,7 +19,7 @@ define void @baz(<8 x i32> %arg) local_unnamed_addr { ; CHECK-LABEL: @baz( ; CHECK-NEXT: bb: ; CHECK-NEXT: [[TMP:%.*]] = call [[STRUCT_ZOT:%.*]] @widget(<8 x i32> [[ARG:%.*]]) -; CHECK-NEXT: [[TMP1:%.*]] = extractvalue [[STRUCT_ZOT]] undef, 0, 0 +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue [[STRUCT_ZOT]] %tmp, 0, 0 ; CHECK-NEXT: ret void ; bb: diff --git a/llvm/test/Transforms/SCCP/arg-count-mismatch.ll b/llvm/test/Transforms/IPConstantProp/arg-count-mismatch.ll similarity index 96% rename from llvm/test/Transforms/SCCP/arg-count-mismatch.ll rename to llvm/test/Transforms/IPConstantProp/arg-count-mismatch.ll index ba5f1a6d83f7..7afe858e52d1 100644 --- a/llvm/test/Transforms/SCCP/arg-count-mismatch.ll +++ b/llvm/test/Transforms/IPConstantProp/arg-count-mismatch.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -ipsccp -S -o - | FileCheck %s +; RUN: opt < %s -ipconstprop -S -o - | FileCheck %s ; The original C source looked like this: ; @@ -53,7 +53,7 @@ define internal i16 @bar(i16 %p1, i16 %p2) { define internal i16 @vararg_prop(i16 %p1, ...) { ; CHECK-LABEL: @vararg_prop( -; CHECK-NEXT: ret i16 undef +; CHECK-NEXT: ret i16 7 ; ret i16 %p1 } diff --git a/llvm/test/Transforms/SCCP/arg-type-mismatch.ll b/llvm/test/Transforms/IPConstantProp/arg-type-mismatch.ll similarity index 92% rename from llvm/test/Transforms/SCCP/arg-type-mismatch.ll rename to llvm/test/Transforms/IPConstantProp/arg-type-mismatch.ll index 9a9da52174c2..ff924d73390b 100644 --- a/llvm/test/Transforms/SCCP/arg-type-mismatch.ll +++ b/llvm/test/Transforms/IPConstantProp/arg-type-mismatch.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -ipsccp -S -o - | FileCheck %s +; RUN: opt < %s -ipconstprop -S -o - | FileCheck %s ; This test is just to verify that we do not crash/assert due to mismatch in ; argument type between the caller and callee. diff --git a/llvm/test/Transforms/IPConstantProp/comdat-ipo.ll b/llvm/test/Transforms/IPConstantProp/comdat-ipo.ll new file mode 100644 index 000000000000..a19c89cb9bcf --- /dev/null +++ b/llvm/test/Transforms/IPConstantProp/comdat-ipo.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -ipconstprop -S | FileCheck %s + +; See PR26774 + +define i32 @baz() { +; CHECK-LABEL: @baz( +; CHECK-NEXT: ret i32 10 +; + ret i32 10 +} + +; We can const-prop @baz's return value *into* @foo, but cannot +; constprop @foo's return value into bar. + +define linkonce_odr i32 @foo() { +; CHECK-LABEL: @foo( +; CHECK-NEXT: [[VAL:%.*]] = call i32 @baz() +; CHECK-NEXT: ret i32 10 +; + + %val = call i32 @baz() + ret i32 %val +} + +define i32 @bar() { +; CHECK-LABEL: @bar( +; CHECK-NEXT: [[VAL:%.*]] = call i32 @foo() +; CHECK-NEXT: ret i32 [[VAL]] +; + + %val = call i32 @foo() + ret i32 %val +} diff --git a/llvm/test/Transforms/SCCP/deadarg.ll b/llvm/test/Transforms/IPConstantProp/deadarg.ll similarity index 77% rename from llvm/test/Transforms/SCCP/deadarg.ll rename to llvm/test/Transforms/IPConstantProp/deadarg.ll index 1117acc7d013..25b9749b5079 100644 --- a/llvm/test/Transforms/SCCP/deadarg.ll +++ b/llvm/test/Transforms/IPConstantProp/deadarg.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -ipsccp -disable-output +; RUN: opt < %s -ipconstprop -disable-output define internal void @foo(i32 %X) { call void @foo( i32 %X ) ret void diff --git a/llvm/test/Transforms/SCCP/multiple_callbacks.ll b/llvm/test/Transforms/IPConstantProp/multiple_callbacks.ll similarity index 96% rename from llvm/test/Transforms/SCCP/multiple_callbacks.ll rename to llvm/test/Transforms/IPConstantProp/multiple_callbacks.ll index 3d196f86e4a1..6684044e24ce 100644 --- a/llvm/test/Transforms/SCCP/multiple_callbacks.ll +++ b/llvm/test/Transforms/IPConstantProp/multiple_callbacks.ll @@ -1,6 +1,5 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes -; RUN: opt -ipsccp -S %s | FileCheck %s -; +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -ipconstprop -S < %s | FileCheck %s ; ; /---------------------------------------| ; | /----------------------|----| @@ -39,7 +38,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" define internal i32 @cb0(i32 %zero) { ; CHECK-LABEL: @cb0( ; CHECK-NEXT: entry: -; CHECK-NEXT: ret i32 [[ZERO:%.*]] +; CHECK-NEXT: ret i32 0 ; entry: ret i32 %zero diff --git a/llvm/test/Transforms/SCCP/naked-return.ll b/llvm/test/Transforms/IPConstantProp/naked-return.ll similarity index 97% rename from llvm/test/Transforms/SCCP/naked-return.ll rename to llvm/test/Transforms/IPConstantProp/naked-return.ll index daeb176b0997..133662a211b4 100644 --- a/llvm/test/Transforms/SCCP/naked-return.ll +++ b/llvm/test/Transforms/IPConstantProp/naked-return.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -ipsccp -S %s | FileCheck %s +; RUN: opt -ipconstprop -S %s | FileCheck %s target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" target triple = "i686-pc-windows-msvc19.0.24215" diff --git a/llvm/test/Transforms/SCCP/openmp_parallel_for.ll b/llvm/test/Transforms/IPConstantProp/openmp_parallel_for.ll similarity index 98% rename from llvm/test/Transforms/SCCP/openmp_parallel_for.ll rename to llvm/test/Transforms/IPConstantProp/openmp_parallel_for.ll index 27831c6e6619..338cc8886e29 100644 --- a/llvm/test/Transforms/SCCP/openmp_parallel_for.ll +++ b/llvm/test/Transforms/IPConstantProp/openmp_parallel_for.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -ipsccp < %s | FileCheck %s +; RUN: opt -S -ipconstprop < %s | FileCheck %s ; ; void bar(int, float, double); ; @@ -53,7 +53,7 @@ define internal void @.omp_outlined.(i32* noalias %.global_tid., i32* noalias %. ; CHECK-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4 ; CHECK-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4 ; CHECK-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i64 [[Q:%.*]], i64* [[Q_ADDR]], align 8 +; CHECK-NEXT: store i64 4617315517961601024, i64* [[Q_ADDR]], align 8 ; CHECK-NEXT: [[CONV:%.*]] = bitcast i64* [[Q_ADDR]] to double* ; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[N:%.*]], align 4 ; CHECK-NEXT: [[SUB3:%.*]] = add nsw i32 [[TMP]], -3 diff --git a/llvm/test/Transforms/SCCP/pthreads.ll b/llvm/test/Transforms/IPConstantProp/pthreads.ll similarity index 93% rename from llvm/test/Transforms/SCCP/pthreads.ll rename to llvm/test/Transforms/IPConstantProp/pthreads.ll index a9d2b942c1a5..dcad3858da13 100644 --- a/llvm/test/Transforms/SCCP/pthreads.ll +++ b/llvm/test/Transforms/IPConstantProp/pthreads.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -ipsccp -S < %s | FileCheck %s +; RUN: opt -ipconstprop -S < %s | FileCheck %s ; ; #include ; @@ -44,7 +44,7 @@ declare !callback !0 dso_local i32 @pthread_create(i64*, %union.pthread_attr_t*, define internal i8* @foo(i8* %arg) { ; CHECK-LABEL: @foo( ; CHECK-NEXT: entry: -; CHECK-NEXT: ret i8* [[ARG:%.*]] +; CHECK-NEXT: ret i8* null ; entry: ret i8* %arg @@ -53,7 +53,7 @@ entry: define internal i8* @bar(i8* %arg) { ; CHECK-LABEL: @bar( ; CHECK-NEXT: entry: -; CHECK-NEXT: ret i8* [[ARG:%.*]] +; CHECK-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*) ; entry: ret i8* %arg diff --git a/llvm/test/Transforms/SCCP/recursion.ll b/llvm/test/Transforms/IPConstantProp/recursion.ll similarity index 90% rename from llvm/test/Transforms/SCCP/recursion.ll rename to llvm/test/Transforms/IPConstantProp/recursion.ll index e4f5f1d240e7..ac8ff9ca00e3 100644 --- a/llvm/test/Transforms/SCCP/recursion.ll +++ b/llvm/test/Transforms/IPConstantProp/recursion.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -ipsccp -deadargelim -S | FileCheck %s +; RUN: opt < %s -ipconstprop -deadargelim -S | FileCheck %s ; CHECK-NOT: %X diff --git a/llvm/test/Transforms/SCCP/return-argument.ll b/llvm/test/Transforms/IPConstantProp/return-argument.ll similarity index 91% rename from llvm/test/Transforms/SCCP/return-argument.ll rename to llvm/test/Transforms/IPConstantProp/return-argument.ll index 764b4898c961..6a3eac0c120d 100644 --- a/llvm/test/Transforms/SCCP/return-argument.ll +++ b/llvm/test/Transforms/IPConstantProp/return-argument.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -ipsccp -S | FileCheck %s +; RUN: opt < %s -ipconstprop -S | FileCheck %s ;; This function returns its second argument on all return statements define internal i32* @incdec(i1 %C, i32* %V) { @@ -49,13 +49,11 @@ define void @caller(i1 %C) personality i32 (...)* @__gxx_personality_v0 { ; CHECK-NEXT: [[Q:%.*]] = alloca i32, align 4 ; CHECK-NEXT: [[W:%.*]] = call i32* @incdec(i1 [[C:%.*]], i32* [[Q]]) ; CHECK-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 1, i32 2) -; CHECK-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 ; CHECK-NEXT: [[S2:%.*]] = invoke { i32, i32 } @foo(i32 3, i32 4) ; CHECK-NEXT: to label [[OK:%.*]] unwind label [[LPAD:%.*]] ; CHECK: OK: -; CHECK-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 -; CHECK-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]] -; CHECK-NEXT: store i32 [[Z]], i32* [[W]], align 4 +; CHECK-NEXT: [[Z:%.*]] = add i32 1, 3 +; CHECK-NEXT: store i32 [[Z]], i32* [[Q]], align 4 ; CHECK-NEXT: br label [[RET:%.*]] ; CHECK: LPAD: ; CHECK-NEXT: [[EXN:%.*]] = landingpad { i8*, i32 } diff --git a/llvm/test/Transforms/SCCP/return-constant.ll b/llvm/test/Transforms/IPConstantProp/return-constant.ll similarity index 91% rename from llvm/test/Transforms/SCCP/return-constant.ll rename to llvm/test/Transforms/IPConstantProp/return-constant.ll index 5cf53eea12b7..d75aa9b96931 100644 --- a/llvm/test/Transforms/SCCP/return-constant.ll +++ b/llvm/test/Transforms/IPConstantProp/return-constant.ll @@ -1,13 +1,13 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -ipsccp -instcombine -S | FileCheck %s +; RUN: opt < %s -ipconstprop -instcombine -S | FileCheck %s define internal i32 @foo(i1 %C) { ; CHECK-LABEL: @foo( ; CHECK-NEXT: br i1 [[C:%.*]], label [[T:%.*]], label [[F:%.*]] ; CHECK: T: -; CHECK-NEXT: ret i32 undef +; CHECK-NEXT: ret i32 52 ; CHECK: F: -; CHECK-NEXT: ret i32 undef +; CHECK-NEXT: ret i32 52 ; br i1 %C, label %T, label %F diff --git a/llvm/test/Transforms/SCCP/return-constants.ll b/llvm/test/Transforms/IPConstantProp/return-constants.ll similarity index 70% rename from llvm/test/Transforms/SCCP/return-constants.ll rename to llvm/test/Transforms/IPConstantProp/return-constants.ll index cbf178d2efca..461106731614 100644 --- a/llvm/test/Transforms/SCCP/return-constants.ll +++ b/llvm/test/Transforms/IPConstantProp/return-constants.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -ipsccp -S | FileCheck %s +; RUN: opt < %s -ipconstprop -S | FileCheck %s %0 = type { i32, i32 } @@ -7,9 +7,13 @@ define internal %0 @foo(i1 %Q) { ; CHECK-LABEL: @foo( ; CHECK-NEXT: br i1 [[Q:%.*]], label [[T:%.*]], label [[F:%.*]] ; CHECK: T: -; CHECK-NEXT: ret [[TMP0:%.*]] { i32 21, i32 22 } +; CHECK-NEXT: [[MRV:%.*]] = insertvalue [[TMP0:%.*]] undef, i32 21, 0 +; CHECK-NEXT: [[MRV1:%.*]] = insertvalue [[TMP0]] %mrv, i32 22, 1 +; CHECK-NEXT: ret [[TMP0]] %mrv1 ; CHECK: F: -; CHECK-NEXT: ret [[TMP0]] { i32 21, i32 23 } +; CHECK-NEXT: [[MRV2:%.*]] = insertvalue [[TMP0]] undef, i32 21, 0 +; CHECK-NEXT: [[MRV3:%.*]] = insertvalue [[TMP0]] %mrv2, i32 23, 1 +; CHECK-NEXT: ret [[TMP0]] %mrv3 ; br i1 %Q, label %T, label %F @@ -26,11 +30,14 @@ F: ; preds = %0 define internal %0 @bar(i1 %Q) { ; CHECK-LABEL: @bar( +; CHECK-NEXT: [[A:%.*]] = insertvalue [[TMP0:%.*]] undef, i32 21, 0 ; CHECK-NEXT: br i1 [[Q:%.*]], label [[T:%.*]], label [[F:%.*]] ; CHECK: T: -; CHECK-NEXT: ret [[TMP0:%.*]] { i32 21, i32 22 } +; CHECK-NEXT: [[B:%.*]] = insertvalue [[TMP0]] %A, i32 22, 1 +; CHECK-NEXT: ret [[TMP0]] %B ; CHECK: F: -; CHECK-NEXT: ret [[TMP0]] { i32 21, i32 23 } +; CHECK-NEXT: [[C:%.*]] = insertvalue [[TMP0]] %A, i32 23, 1 +; CHECK-NEXT: ret [[TMP0]] %C ; %A = insertvalue %0 undef, i32 21, 0 br i1 %Q, label %T, label %F @@ -50,6 +57,7 @@ define %0 @caller(i1 %Q) { ; CHECK-NEXT: [[B:%.*]] = extractvalue [[TMP0]] %X, 1 ; CHECK-NEXT: [[Y:%.*]] = call [[TMP0]] @bar(i1 [[Q]]) ; CHECK-NEXT: [[D:%.*]] = extractvalue [[TMP0]] %Y, 1 +; CHECK-NEXT: [[M:%.*]] = add i32 21, 21 ; CHECK-NEXT: [[N:%.*]] = add i32 [[B]], [[D]] ; CHECK-NEXT: ret [[TMP0]] %X ; diff --git a/llvm/test/Transforms/SCCP/thread_local_acs.ll b/llvm/test/Transforms/IPConstantProp/thread_local_acs.ll similarity index 92% rename from llvm/test/Transforms/SCCP/thread_local_acs.ll rename to llvm/test/Transforms/IPConstantProp/thread_local_acs.ll index 69c0cfeec163..3f843d26077a 100644 --- a/llvm/test/Transforms/SCCP/thread_local_acs.ll +++ b/llvm/test/Transforms/IPConstantProp/thread_local_acs.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -ipsccp -S < %s | FileCheck %s +; RUN: opt -ipconstprop -S < %s | FileCheck %s ; ; #include ; thread_local int gtl = 0; @@ -24,7 +24,7 @@ define internal i32 @callee(i32* %thread_local_ptr, i32* %shared_ptr) { ; CHECK-LABEL: @callee( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[THREAD_LOCAL_PTR:%.*]], align 4 -; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[SHARED_PTR:%.*]], align 4 +; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @gsh, align 4 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP]], [[TMP1]] ; CHECK-NEXT: ret i32 [[ADD]] ; diff --git a/llvm/test/Transforms/SCCP/comdat-ipo.ll b/llvm/test/Transforms/SCCP/comdat-ipo.ll index fc715f45406f..618075fd5e3f 100644 --- a/llvm/test/Transforms/SCCP/comdat-ipo.ll +++ b/llvm/test/Transforms/SCCP/comdat-ipo.ll @@ -1,12 +1,8 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -ipsccp -S | FileCheck %s ; See PR26774 define i32 @baz() { -; CHECK-LABEL: @baz( -; CHECK-NEXT: ret i32 10 -; ret i32 10 } @@ -15,9 +11,8 @@ define i32 @baz() { define linkonce_odr i32 @foo() { ; CHECK-LABEL: @foo( -; CHECK-NEXT: [[VAL:%.*]] = call i32 @baz() -; CHECK-NEXT: ret i32 10 -; +; CHECK-NEXT: %val = call i32 @baz() +; CHECK-NEXT: ret i32 10 %val = call i32 @baz() ret i32 %val @@ -25,9 +20,8 @@ define linkonce_odr i32 @foo() { define i32 @bar() { ; CHECK-LABEL: @bar( -; CHECK-NEXT: [[VAL:%.*]] = call i32 @foo() -; CHECK-NEXT: ret i32 [[VAL]] -; +; CHECK-NEXT: %val = call i32 @foo() +; CHECK-NEXT: ret i32 %val %val = call i32 @foo() ret i32 %val diff --git a/llvm/utils/findoptdiff b/llvm/utils/findoptdiff index 925e2dce4bf3..9a8803184384 100755 --- a/llvm/utils/findoptdiff +++ b/llvm/utils/findoptdiff @@ -70,7 +70,7 @@ dis2="$llvm2/Debug/bin/llvm-dis" opt1="$llvm1/Debug/bin/opt" opt2="$llvm2/Debug/bin/opt" -all_switches="-verify -lowersetjmp -simplifycfg -mem2reg -globalopt -globaldce -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -tailduplicate -simplifycfg -sroa -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -sroa -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify" +all_switches="-verify -lowersetjmp -simplifycfg -mem2reg -globalopt -globaldce -ipconstprop -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -tailduplicate -simplifycfg -sroa -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -sroa -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify" #counter=0 function tryit { diff --git a/llvm/utils/gn/secondary/llvm/lib/Transforms/IPO/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Transforms/IPO/BUILD.gn index 168bb499dcff..7d48256b6cfa 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Transforms/IPO/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Transforms/IPO/BUILD.gn @@ -38,6 +38,7 @@ static_library("IPO") { "GlobalOpt.cpp", "GlobalSplit.cpp", "HotColdSplitting.cpp", + "IPConstantPropagation.cpp", "IPO.cpp", "InferFunctionAttrs.cpp", "InlineSimple.cpp",