[IPO] Remove IR Outliner (#211971)

The IR Outliner has major bugs and no active maintainer, and is disabled
by default. The new LLVM Policy states the pass should be removed.

This commit removes:
- The IROutliner pass
- The IRSimilarity analysis
- The `llvm-sim` executable, used for understanding the latter
- All tests of the above

Related discussion:
https://discourse.llvm.org/t/ir-outliner-status-interest/89672
This commit is contained in:
Sam Elliott 2026-07-31 15:03:31 -07:00 committed by GitHub
parent 5ca2b9313c
commit 1cf3b70dab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
129 changed files with 3 additions and 18737 deletions

View file

@ -64,6 +64,9 @@ Makes programs 10x faster by doing Special New Thing.
### Changes to Interprocedural Optimizations
- The IR Outliner has been removed, due to lack of a maintainer and the presence
of correctness issues.
### Changes to Vectorizers
### Changes to the AArch64 Backend

File diff suppressed because it is too large Load diff

View file

@ -134,7 +134,6 @@ LLVM_ABI void initializeGlobalsAAWrapperPassPass(PassRegistry &);
LLVM_ABI void initializeHardwareLoopsLegacyPass(PassRegistry &);
LLVM_ABI void initializeLibcallLoweringInfoWrapperPass(PassRegistry &);
LLVM_ABI void initializeMIRProfileLoaderPassPass(PassRegistry &);
LLVM_ABI void initializeIRSimilarityIdentifierWrapperPassPass(PassRegistry &);
LLVM_ABI void initializeIRTranslatorPass(PassRegistry &);
LLVM_ABI void initializeIVUsersWrapperPassPass(PassRegistry &);
LLVM_ABI void initializeIfConverterPass(PassRegistry &);

View file

@ -1,469 +0,0 @@
//===- IROutliner.h - Extract similar IR regions into functions --*- C++ -*-==//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// \file
// The interface file for the IROutliner which is used by the IROutliner Pass.
//
// The outliner uses the IRSimilarityIdentifier to identify the similar regions
// of code. It evaluates each set of IRSimilarityCandidates with an estimate of
// whether it will provide code size reduction. Each region is extracted using
// the code extractor. These extracted functions are consolidated into a single
// function and called from the extracted call site.
//
// For example:
// \code
// %1 = add i32 %a, %b
// %2 = add i32 %b, %a
// %3 = add i32 %b, %a
// %4 = add i32 %a, %b
// \endcode
// would become function
// \code
// define internal void outlined_ir_function(i32 %0, i32 %1) {
// %1 = add i32 %0, %1
// %2 = add i32 %1, %0
// ret void
// }
// \endcode
// with calls:
// \code
// call void outlined_ir_function(i32 %a, i32 %b)
// call void outlined_ir_function(i32 %b, i32 %a)
// \endcode
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_IPO_IROUTLINER_H
#define LLVM_TRANSFORMS_IPO_IROUTLINER_H
#include "llvm/Analysis/IRSimilarityIdentifier.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/InstructionCost.h"
#include "llvm/Transforms/Utils/CodeExtractor.h"
struct OutlinableGroup;
namespace llvm {
using namespace CallingConv;
using namespace IRSimilarity;
class Module;
class TargetTransformInfo;
class OptimizationRemarkEmitter;
/// The OutlinableRegion holds all the information for a specific region, or
/// sequence of instructions. This includes what values need to be hoisted to
/// arguments from the extracted function, inputs and outputs to the region, and
/// mapping from the extracted function arguments to overall function arguments.
struct OutlinableRegion {
/// Describes the region of code.
IRSimilarityCandidate *Candidate = nullptr;
/// If this region is outlined, the front and back IRInstructionData could
/// potentially become invalidated if the only new instruction is a call.
/// This ensures that we replace in the instruction in the IRInstructionData.
IRInstructionData *NewFront = nullptr;
IRInstructionData *NewBack = nullptr;
/// The number of extracted inputs from the CodeExtractor.
unsigned NumExtractedInputs = 0;
/// The corresponding BasicBlock with the appropriate stores for this
/// OutlinableRegion in the overall function.
unsigned OutputBlockNum = -1;
/// Mapping the extracted argument number to the argument number in the
/// overall function. Since there will be inputs, such as elevated constants
/// that are not the same in each region in a SimilarityGroup, or values that
/// cannot be sunk into the extracted section in every region, we must keep
/// track of which extracted argument maps to which overall argument.
DenseMap<unsigned, unsigned> ExtractedArgToAgg;
DenseMap<unsigned, unsigned> AggArgToExtracted;
/// Values in the outlined functions will often be replaced by arguments. When
/// finding corresponding values from one region to another, the found value
/// will be the value the argument previously replaced. This structure maps
/// any replaced values for the region to the aggregate aggregate argument
/// in the overall function.
DenseMap<Value *, Value *> RemappedArguments;
/// Marks whether we need to change the order of the arguments when mapping
/// the old extracted function call to the new aggregate outlined function
/// call.
bool ChangedArgOrder = false;
/// Marks whether this region ends in a branch, there is special handling
/// required for the following basic blocks in this case.
bool EndsInBranch = false;
/// The PHIBlocks with their corresponding return block based on the return
/// value as the key.
DenseMap<Value *, BasicBlock *> PHIBlocks;
/// Mapping of the argument number in the deduplicated function
/// to a given constant, which is used when creating the arguments to the call
/// to the newly created deduplicated function. This is handled separately
/// since the CodeExtractor does not recognize constants.
DenseMap<unsigned, Constant *> AggArgToConstant;
/// The global value numbers that are used as outputs for this section. Once
/// extracted, each output will be stored to an output register. This
/// documents the global value numbers that are used in this pattern.
SmallVector<unsigned, 4> GVNStores;
/// Used to create an outlined function.
CodeExtractor *CE = nullptr;
/// The call site of the extracted region.
CallInst *Call = nullptr;
/// The function for the extracted region.
Function *ExtractedFunction = nullptr;
/// Flag for whether we have split out the IRSimilarityCanidate. That is,
/// make the region contained the IRSimilarityCandidate its own BasicBlock.
bool CandidateSplit = false;
/// Flag for whether we should not consider this region for extraction.
bool IgnoreRegion = false;
/// The BasicBlock that is before the start of the region BasicBlock,
/// only defined when the region has been split.
BasicBlock *PrevBB = nullptr;
/// The BasicBlock that contains the starting instruction of the region.
BasicBlock *StartBB = nullptr;
/// The BasicBlock that contains the ending instruction of the region.
BasicBlock *EndBB = nullptr;
/// The BasicBlock that is after the start of the region BasicBlock,
/// only defined when the region has been split.
BasicBlock *FollowBB = nullptr;
/// The Outlinable Group that contains this region and structurally similar
/// regions to this region.
OutlinableGroup *Parent = nullptr;
OutlinableRegion(IRSimilarityCandidate &C, OutlinableGroup &Group)
: Candidate(&C), Parent(&Group) {
StartBB = C.getStartBB();
EndBB = C.getEndBB();
}
/// For the contained region, split the parent BasicBlock at the starting and
/// ending instructions of the contained IRSimilarityCandidate.
LLVM_ABI void splitCandidate();
/// For the contained region, reattach the BasicBlock at the starting and
/// ending instructions of the contained IRSimilarityCandidate, or if the
/// function has been extracted, the start and end of the BasicBlock
/// containing the called function.
LLVM_ABI void reattachCandidate();
/// Find a corresponding value for \p V in similar OutlinableRegion \p Other.
///
/// \param Other [in] - The OutlinableRegion to find the corresponding Value
/// in.
/// \param V [in] - The Value to look for in the other region.
/// \return The corresponding Value to \p V if it exists, otherwise nullptr.
LLVM_ABI Value *findCorrespondingValueIn(const OutlinableRegion &Other,
Value *V);
/// Find a corresponding BasicBlock for \p BB in similar OutlinableRegion \p Other.
///
/// \param Other [in] - The OutlinableRegion to find the corresponding
/// BasicBlock in.
/// \param BB [in] - The BasicBlock to look for in the other region.
/// \return The corresponding Value to \p V if it exists, otherwise nullptr.
LLVM_ABI BasicBlock *findCorrespondingBlockIn(const OutlinableRegion &Other,
BasicBlock *BB);
/// Get the size of the code removed from the region.
///
/// \param [in] TTI - The TargetTransformInfo for the parent function.
/// \returns the code size of the region
LLVM_ABI InstructionCost getBenefit(TargetTransformInfo &TTI);
};
/// This class is a pass that identifies similarity in a Module, extracts
/// instances of the similarity, and then consolidating the similar regions
/// in an effort to reduce code size. It uses the IRSimilarityIdentifier pass
/// to identify the similar regions of code, and then extracts the similar
/// sections into a single function. See the above for an example as to
/// how code is extracted and consolidated into a single function.
class IROutliner {
public:
IROutliner(function_ref<TargetTransformInfo &(Function &)> GTTI,
function_ref<IRSimilarityIdentifier &(Module &)> GIRSI,
function_ref<OptimizationRemarkEmitter &(Function &)> GORE)
: getTTI(GTTI), getIRSI(GIRSI), getORE(GORE) {}
LLVM_ABI bool run(Module &M);
private:
/// Find repeated similar code sequences in \p M and outline them into new
/// Functions.
///
/// \param [in] M - The module to outline from.
/// \returns The number of Functions created.
unsigned doOutline(Module &M);
/// Check whether an OutlinableRegion is incompatible with code already
/// outlined. OutlinableRegions are incomptaible when there are overlapping
/// instructions, or code that has not been recorded has been added to the
/// instructions.
///
/// \param [in] Region - The OutlinableRegion to check for conflicts with
/// already outlined code.
/// \returns whether the region can safely be outlined.
bool isCompatibleWithAlreadyOutlinedCode(const OutlinableRegion &Region);
/// Remove all the IRSimilarityCandidates from \p CandidateVec that have
/// instructions contained in a previously outlined region and put the
/// remaining regions in \p CurrentGroup.
///
/// \param [in] CandidateVec - List of similarity candidates for regions with
/// the same similarity structure.
/// \param [in,out] CurrentGroup - Contains the potential sections to
/// be outlined.
void
pruneIncompatibleRegions(std::vector<IRSimilarityCandidate> &CandidateVec,
OutlinableGroup &CurrentGroup);
/// Create the function based on the overall types found in the current
/// regions being outlined.
///
/// \param M - The module to outline from.
/// \param [in,out] CG - The OutlinableGroup for the regions to be outlined.
/// \param [in] FunctionNameSuffix - How many functions have we previously
/// created.
/// \returns the newly created function.
Function *createFunction(Module &M, OutlinableGroup &CG,
unsigned FunctionNameSuffix);
/// Identify the needed extracted inputs in a section, and add to the overall
/// function if needed.
///
/// \param [in] M - The module to outline from.
/// \param [in,out] Region - The region to be extracted.
/// \param [in] NotSame - The global value numbers of the Values in the region
/// that do not have the same Constant in each strucutrally similar region.
void findAddInputsOutputs(Module &M, OutlinableRegion &Region,
DenseSet<unsigned> &NotSame);
/// Find the number of instructions that will be removed by extracting the
/// OutlinableRegions in \p CurrentGroup.
///
/// \param [in] CurrentGroup - The collection of OutlinableRegions to be
/// analyzed.
/// \returns the number of outlined instructions across all regions.
InstructionCost findBenefitFromAllRegions(OutlinableGroup &CurrentGroup);
/// Find the number of instructions that will be added by reloading arguments.
///
/// \param [in] CurrentGroup - The collection of OutlinableRegions to be
/// analyzed.
/// \returns the number of added reload instructions across all regions.
InstructionCost findCostOutputReloads(OutlinableGroup &CurrentGroup);
/// Find the cost and the benefit of \p CurrentGroup and save it back to
/// \p CurrentGroup.
///
/// \param [in] M - The module being analyzed
/// \param [in,out] CurrentGroup - The overall outlined section
void findCostBenefit(Module &M, OutlinableGroup &CurrentGroup);
/// Update the output mapping based on the load instruction, and the outputs
/// of the extracted function.
///
/// \param Region - The region extracted
/// \param Outputs - The outputs from the extracted function.
/// \param LI - The load instruction used to update the mapping.
void updateOutputMapping(OutlinableRegion &Region,
ArrayRef<Value *> Outputs, LoadInst *LI);
/// Extract \p Region into its own function.
///
/// \param [in] Region - The region to be extracted into its own function.
/// \returns True if it was successfully outlined.
bool extractSection(OutlinableRegion &Region);
/// For the similarities found, and the extracted sections, create a single
/// outlined function with appropriate output blocks as necessary.
///
/// \param [in] M - The module to outline from
/// \param [in] CurrentGroup - The set of extracted sections to consolidate.
/// \param [in,out] FuncsToRemove - List of functions to remove from the
/// module after outlining is completed.
/// \param [in,out] OutlinedFunctionNum - the number of new outlined
/// functions.
void deduplicateExtractedSections(Module &M, OutlinableGroup &CurrentGroup,
std::vector<Function *> &FuncsToRemove,
unsigned &OutlinedFunctionNum);
/// Fill the new function that will serve as the replacement function for all
/// of the extracted regions of a certain structure from the first region in
/// the list of regions. Replace this first region's extracted function with
/// the new overall function.
///
/// \param [in] M - The module we are outlining from.
/// \param [in] CurrentGroup - The group of regions to be outlined.
/// \param [in,out] OutputStoreBBs - The output blocks for each different
/// set of stores needed for the different functions.
/// \param [in,out] FuncsToRemove - Extracted functions to erase from module
/// once outlining is complete.
void fillOverallFunction(
Module &M, OutlinableGroup &CurrentGroup,
std::vector<DenseMap<Value *, BasicBlock *>> &OutputStoreBBs,
std::vector<Function *> &FuncsToRemove);
/// If true, enables us to outline from functions that have LinkOnceFromODR
/// linkages.
bool OutlineFromLinkODRs = false;
/// If false, we do not worry if the cost is greater than the benefit. This
/// is for debugging and testing, so that we can test small cases to ensure
/// that the outlining is being done correctly.
bool CostModel = true;
/// The set of outlined Instructions, identified by their location in the
/// sequential ordering of instructions in a Module.
DenseSet<unsigned> Outlined;
/// TargetTransformInfo lambda for target specific information.
function_ref<TargetTransformInfo &(Function &)> getTTI;
/// A mapping from newly created reloaded output values to the original value.
/// If an value is replace by an output from an outlined region, this maps
/// that Value, back to its original Value.
DenseMap<Value *, Value *> OutputMappings;
/// IRSimilarityIdentifier lambda to retrieve IRSimilarityIdentifier.
function_ref<IRSimilarityIdentifier &(Module &)> getIRSI;
/// The optimization remark emitter for the pass.
function_ref<OptimizationRemarkEmitter &(Function &)> getORE;
/// The memory allocator used to allocate the CodeExtractors.
SpecificBumpPtrAllocator<CodeExtractor> ExtractorAllocator;
/// The memory allocator used to allocate the OutlinableRegions.
SpecificBumpPtrAllocator<OutlinableRegion> RegionAllocator;
/// The memory allocator used to allocate new IRInstructionData.
SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
/// Custom InstVisitor to classify different instructions for whether it can
/// be analyzed for similarity. This is needed as there may be instruction we
/// can identify as having similarity, but are more complicated to outline.
struct InstructionAllowed : public InstVisitor<InstructionAllowed, bool> {
InstructionAllowed() = default;
bool visitUncondBrInst(UncondBrInst &BI) { return EnableBranches; }
bool visitCondBrInst(CondBrInst &BI) { return EnableBranches; }
bool visitPHINode(PHINode &PN) { return EnableBranches; }
// TODO: Handle allocas.
bool visitAllocaInst(AllocaInst &AI) { return false; }
// VAArg instructions are not allowed since this could cause difficulty when
// differentiating between different sets of variable instructions in
// the deduplicated outlined regions.
bool visitVAArgInst(VAArgInst &VI) { return false; }
// We exclude all exception handling cases since they are so context
// dependent.
bool visitLandingPadInst(LandingPadInst &LPI) { return false; }
bool visitFuncletPadInst(FuncletPadInst &FPI) { return false; }
// DebugInfo should be included in the regions, but should not be
// analyzed for similarity as it has no bearing on the outcome of the
// program.
bool visitDbgInfoIntrinsic(DbgInfoIntrinsic &DII) { return true; }
// TODO: Handle specific intrinsics individually from those that can be
// handled.
bool IntrinsicInst(IntrinsicInst &II) { return EnableIntrinsics; }
// We only handle CallInsts that are not indirect, since we cannot guarantee
// that they have a name in these cases.
bool visitCallInst(CallInst &CI) {
Function *F = CI.getCalledFunction();
bool IsIndirectCall = CI.isIndirectCall();
if (IsIndirectCall && !EnableIndirectCalls)
return false;
if (!F && !IsIndirectCall)
return false;
// Returning twice can cause issues with the state of the function call
// that were not expected when the function was used, so we do not include
// the call in outlined functions.
if (CI.canReturnTwice())
return false;
// TODO: Update the outliner to capture whether the outlined function
// needs these extra attributes.
// `nomerge` states that calls to this function should never be merged
// during optimisation. Outlining would have the effect of merging
// callsites from separate functions into a single callsite in the
// outlined function.
if (CI.hasFnAttr(Attribute::NoMerge))
return false;
// Functions marked with the swifttailcc and tailcc calling conventions
// require special handling when outlining musttail functions. The
// calling convention must be passed down to the outlined function as
// well. Further, there is special handling for musttail calls as well,
// requiring a return call directly after. For now, the outliner does not
// support this.
bool IsTailCC = CI.getCallingConv() == CallingConv::SwiftTail ||
CI.getCallingConv() == CallingConv::Tail;
if (IsTailCC && !EnableMustTailCalls)
return false;
if (CI.isMustTailCall() && !EnableMustTailCalls)
return false;
// The outliner can only handle musttail items if it is also accompanied
// by the tailcc or swifttailcc calling convention.
if (CI.isMustTailCall() && !IsTailCC)
return false;
return true;
}
// TODO: Handle FreezeInsts. Since a frozen value could be frozen inside
// the outlined region, and then returned as an output, this will have to be
// handled differently.
bool visitFreezeInst(FreezeInst &CI) { return false; }
// TODO: We do not current handle similarity that changes the control flow.
bool visitInvokeInst(InvokeInst &II) { return false; }
// TODO: We do not current handle similarity that changes the control flow.
bool visitCallBrInst(CallBrInst &CBI) { return false; }
// TODO: Handle interblock similarity.
bool visitTerminator(Instruction &I) { return false; }
bool visitInstruction(Instruction &I) { return true; }
// The flag variable that marks whether we should allow branch instructions
// to be outlined.
bool EnableBranches = false;
// The flag variable that marks whether we should allow indirect calls
// to be outlined.
bool EnableIndirectCalls = true;
// The flag variable that marks whether we should allow intrinsics
// instructions to be outlined.
bool EnableIntrinsics = false;
// The flag variable that marks whether we should allow musttail calls.
bool EnableMustTailCalls = false;
};
/// A InstVisitor used to exclude certain instructions from being outlined.
InstructionAllowed InstructionClassifier;
};
/// Pass to outline similar regions.
class IROutlinerPass : public OptionalPassInfoMixin<IROutlinerPass> {
public:
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
};
} // end namespace llvm
#endif // LLVM_TRANSFORMS_IPO_IROUTLINER_H

View file

@ -46,7 +46,6 @@ void llvm::initializeAnalysis(PassRegistry &Registry) {
initializeExternalAAWrapperPassPass(Registry);
initializeImmutableModuleSummaryIndexWrapperPassPass(Registry);
initializeIVUsersWrapperPassPass(Registry);
initializeIRSimilarityIdentifierWrapperPassPass(Registry);
initializeLazyBranchProbabilityInfoPassPass(Registry);
initializeLazyBFIPassPass(Registry);
initializeLazyBlockFrequencyInfoPassPass(Registry);

View file

@ -85,7 +85,6 @@ add_llvm_component_library(LLVMAnalysis
HashRecognize.cpp
HeatUtils.cpp
IR2Vec.cpp
IRSimilarityIdentifier.cpp
IVDescriptors.cpp
IVUsers.cpp
ImportedFunctionsInliningStatistics.cpp

File diff suppressed because it is too large Load diff

View file

@ -240,7 +240,6 @@
#include "llvm/Transforms/IPO/GlobalOpt.h"
#include "llvm/Transforms/IPO/GlobalSplit.h"
#include "llvm/Transforms/IPO/HotColdSplitting.h"
#include "llvm/Transforms/IPO/IROutliner.h"
#include "llvm/Transforms/IPO/InferFunctionAttrs.h"
#include "llvm/Transforms/IPO/Instrumentor.h"
#include "llvm/Transforms/IPO/Internalize.h"

View file

@ -62,7 +62,6 @@
#include "llvm/Transforms/IPO/GlobalOpt.h"
#include "llvm/Transforms/IPO/GlobalSplit.h"
#include "llvm/Transforms/IPO/HotColdSplitting.h"
#include "llvm/Transforms/IPO/IROutliner.h"
#include "llvm/Transforms/IPO/InferFunctionAttrs.h"
#include "llvm/Transforms/IPO/Inliner.h"
#include "llvm/Transforms/IPO/Instrumentor.h"
@ -243,10 +242,6 @@ static cl::opt<bool>
EnableHotColdSplit("hot-cold-split",
cl::desc("Enable hot-cold splitting pass"));
static cl::opt<bool> EnableIROutliner("ir-outliner", cl::init(false),
cl::Hidden,
cl::desc("Enable ir outliner pass"));
static cl::opt<bool>
DisablePreInliner("disable-preinline", cl::init(false), cl::Hidden,
cl::desc("Disable pre-instrumentation inliner"));
@ -1701,13 +1696,6 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
if (EnableHotColdSplit && !isLTOPreLink(LTOPhase))
MPM.addPass(HotColdSplittingPass());
// Search the code for similar regions of code. If enough similar regions can
// be found where extracting the regions into their own function will decrease
// the size of the program, we extract the regions, a deduplicate the
// structurally similar regions.
if (EnableIROutliner)
MPM.addPass(IROutlinerPass());
// Now we need to do some global optimization transforms.
// FIXME: It would seem like these should come first in the optimization
// pipeline and maybe be the bottom of the canonicalization pipeline? Weird

View file

@ -27,7 +27,6 @@ MODULE_ANALYSIS("dxil-resource-type", DXILResourceTypeAnalysis())
MODULE_ANALYSIS("dxil-resource-bindings", DXILResourceBindingAnalysis())
MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis())
MODULE_ANALYSIS("ir2vec-vocab", IR2VecVocabAnalysis())
MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis())
MODULE_ANALYSIS("last-run-tracking", LastRunTrackingAnalysis())
MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
MODULE_ANALYSIS("libcall-lowering-info", LibcallLoweringModuleAnalysis())
@ -108,7 +107,6 @@ MODULE_PASS("ctx-instr-lower", PGOCtxProfLoweringPass())
MODULE_PASS("print<ctx-prof-analysis>", CtxProfAnalysisPrinterPass(errs()))
MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass())
MODULE_PASS("instrumentor", InstrumentorPass())
MODULE_PASS("iroutliner", IROutlinerPass())
MODULE_PASS("jmc-instrumenter", JMCInstrumenterPass())
MODULE_PASS("lower-emutls", LowerEmuTLSPass())
MODULE_PASS("lower-global-dtors", LowerGlobalDtorsPass())
@ -144,7 +142,6 @@ MODULE_PASS("pre-isel-intrinsic-lowering", PreISelIntrinsicLoweringPass(TM))
MODULE_PASS("print", PrintModulePass(errs()))
MODULE_PASS("print-callgraph", CallGraphPrinterPass(errs()))
MODULE_PASS("print-callgraph-sccs", CallGraphSCCsPrinterPass(errs()))
MODULE_PASS("print-ir-similarity", IRSimilarityAnalysisPrinterPass(errs()))
MODULE_PASS("print-lcg", LazyCallGraphPrinterPass(errs()))
MODULE_PASS("print-lcg-dot", LazyCallGraphDOTPrinterPass(errs()))
MODULE_PASS("print-must-be-executed-contexts",

View file

@ -24,7 +24,6 @@ add_llvm_component_library(LLVMipo
GlobalSplit.cpp
HotColdSplitting.cpp
IPO.cpp
IROutliner.cpp
InferFunctionAttrs.cpp
Inliner.cpp
Instrumentor.cpp

File diff suppressed because it is too large Load diff

View file

@ -1,140 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -disable-output -S -passes=print-ir-similarity < %s 2>&1 | FileCheck %s
; This is a simple test to make sure the IRSimilarityIdentifier and
; IRSimilarityPrinterPass is working.
; CHECK: 4 candidates of length 6. Found in:
; CHECK-NEXT: Function: turtle, Basic Block: (unnamed)
; CHECK-NEXT: Start Instruction: store i32 1, ptr %1, align 4
; CHECK-NEXT: End Instruction: store i32 6, ptr %6, align 4
; CHECK-NEXT: Function: cat, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 6, ptr %0, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: fish, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 6, ptr %0, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: dog, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 6, ptr %0, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT:4 candidates of length 5. Found in:
; CHECK-NEXT: Function: turtle, Basic Block: (unnamed)
; CHECK-NEXT: Start Instruction: store i32 2, ptr %2, align 4
; CHECK-NEXT: End Instruction: store i32 6, ptr %6, align 4
; CHECK-NEXT: Function: cat, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 1, ptr %1, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: fish, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 1, ptr %1, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: dog, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 1, ptr %1, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT:4 candidates of length 4. Found in:
; CHECK-NEXT: Function: turtle, Basic Block: (unnamed)
; CHECK-NEXT: Start Instruction: store i32 3, ptr %3, align 4
; CHECK-NEXT: End Instruction: store i32 6, ptr %6, align 4
; CHECK-NEXT: Function: cat, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 2, ptr %2, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: fish, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 2, ptr %2, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: dog, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 2, ptr %2, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT:4 candidates of length 3. Found in:
; CHECK-NEXT: Function: turtle, Basic Block: (unnamed)
; CHECK-NEXT: Start Instruction: store i32 4, ptr %4, align 4
; CHECK-NEXT: End Instruction: store i32 6, ptr %6, align 4
; CHECK-NEXT: Function: cat, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 3, ptr %3, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: fish, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 3, ptr %3, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: dog, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 3, ptr %3, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT:4 candidates of length 2. Found in:
; CHECK-NEXT: Function: turtle, Basic Block: (unnamed)
; CHECK-NEXT: Start Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: End Instruction: store i32 6, ptr %6, align 4
; CHECK-NEXT: Function: cat, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 4, ptr %4, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: fish, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 4, ptr %4, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: Function: dog, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 4, ptr %4, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
define linkonce_odr void @fish() {
entry:
%0 = alloca i32, align 4
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca i32, align 4
store i32 6, ptr %0, align 4
store i32 1, ptr %1, align 4
store i32 2, ptr %2, align 4
store i32 3, ptr %3, align 4
store i32 4, ptr %4, align 4
store i32 5, ptr %5, align 4
ret void
}
define void @turtle() {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca i32, align 4
%6 = alloca i32, align 4
store i32 1, ptr %1, align 4
store i32 2, ptr %2, align 4
store i32 3, ptr %3, align 4
store i32 4, ptr %4, align 4
store i32 5, ptr %5, align 4
store i32 6, ptr %6, align 4
ret void
}
define void @cat() {
entry:
%0 = alloca i32, align 4
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca i32, align 4
store i32 6, ptr %0, align 4
store i32 1, ptr %1, align 4
store i32 2, ptr %2, align 4
store i32 3, ptr %3, align 4
store i32 4, ptr %4, align 4
store i32 5, ptr %5, align 4
ret void
}
define void @dog() {
entry:
%0 = alloca i32, align 4
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca i32, align 4
store i32 6, ptr %0, align 4
store i32 1, ptr %1, align 4
store i32 2, ptr %2, align 4
store i32 3, ptr %3, align 4
store i32 4, ptr %4, align 4
store i32 5, ptr %5, align 4
ret void
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK: {{.*}}

View file

@ -1,77 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -disable-output -S -passes=print-ir-similarity < %s 2>&1 | FileCheck %s
; When a debug instruction is the first instruction in a block, when that block
; has not been given a canonical numbering, since debug instructions are not
; counted in similarity matching they must be ignored when creating canonical
; relations from one region to another. This checks that this is enforced.
; CHECK: 2 candidates of length 4. Found in:
; CHECK-NEXT: Function: main, Basic Block: entry
; CHECK-NEXT: Start Instruction: %0 = add i32 1, 4
; CHECK-NEXT: End Instruction: %1 = sub i32 1, 4
; CHECK-NEXT: Function: main, Basic Block: for.body169
; CHECK-NEXT: Start Instruction: %2 = add i32 1, 4
; CHECK-NEXT: End Instruction: %3 = sub i32 1, 4
; CHECK-NEXT: 2 candidates of length 3. Found in:
; CHECK-NEXT: Function: main, Basic Block: entry
; CHECK-NEXT: Start Instruction: br label %for.body169
; CHECK-NEXT: End Instruction: %1 = sub i32 1, 4
; CHECK-NEXT: Function: main, Basic Block: for.body169
; CHECK-NEXT: Start Instruction: br label %for.end122
; CHECK-NEXT: End Instruction: %3 = sub i32 1, 4
; CHECK-NEXT: 2 candidates of length 2. Found in:
; CHECK-NEXT: Function: main, Basic Block: for.end122
; CHECK-NEXT: Start Instruction: store i32 30, ptr undef, align 1
; CHECK-NEXT: End Instruction: %1 = sub i32 1, 4
; CHECK-NEXT: Function: main, Basic Block: for.end246
; CHECK-NEXT: Start Instruction: store i32 0, ptr undef, align 1
; CHECK-NEXT: End Instruction: %3 = sub i32 1, 4
source_filename = "irsimilarity_crash.ll"
@v_13 = external dso_local global ptr, align 1
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
define dso_local i16 @main() {
entry:
%0 = add i32 1, 4
br label %for.body169
for.end122: ; preds = %for.cond108
store i32 30, ptr undef, align 1
%1 = sub i32 1, 4
ret i16 1
for.body169: ; preds = %for.cond167
%2 = add i32 1, 4
br label %for.end122
for.end246: ; preds = %for.cond167
call void @llvm.dbg.declare(metadata ptr undef, metadata !1, metadata !DIExpression()), !dbg !11
store i32 0, ptr undef, align 1
%3 = sub i32 1, 4
unreachable
}
attributes #0 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
!llvm.dbg.cu = !{}
!llvm.module.flags = !{!0}
!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = !DILocalVariable(name: "v_68", scope: !2, file: !3, line: 522, type: !10)
!2 = distinct !DILexicalBlock(scope: !4, file: !3, line: 522, column: 9)
!3 = !DIFile(filename: "41097217.c", directory: "rt.outdir")
!4 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 480, type: !5, scopeLine: 481, spFlags: DISPFlagDefinition, unit: !8, retainedNodes: !9)
!5 = !DISubroutineType(types: !6)
!6 = !{!7}
!7 = !DIBasicType(name: "int", size: 16, encoding: DW_ATE_signed)
!8 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 15.0.0.prerel", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !9, globals: !9, splitDebugInlining: false, nameTableKind: None)
!9 = !{}
!10 = !DIBasicType(name: "long", size: 32, encoding: DW_ATE_signed)
!11 = !DILocation(line: 522, column: 23, scope: !2)
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK: {{.*}}

View file

@ -1,48 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -disable-output -S -passes=print-ir-similarity < %s 2>&1 | FileCheck --allow-empty %s
; Check to make sure that the IRSimilarityIdentifier and IRSimilarityPrinterPass
; return items only within the same function when there are different sets of
; instructions in functions.
; CHECK: 2 candidates of length 5. Found in:
; CHECK-NEXT: Function: fish, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 6, ptr %0, align 4
; CHECK-NEXT: End Instruction: store i32 4, ptr %4, align 4
; CHECK-NEXT: Function: fish, Basic Block: entry
; CHECK-NEXT: Start Instruction: store i32 1, ptr %1, align 4
; CHECK-NEXT: End Instruction: store i32 5, ptr %5, align 4
; CHECK-NEXT: 2 candidates of length 3. Found in:
; CHECK-NEXT: Function: turtle, Basic Block: (unnamed)
; CHECK-NEXT: Start Instruction: %b = load i32, ptr %1, align 4
; CHECK-NEXT: End Instruction: %d = load i32, ptr %3, align 4
; CHECK-NEXT: Function: turtle, Basic Block: (unnamed)
; CHECK-NEXT: Start Instruction: %a = load i32, ptr %0, align 4
; CHECK-NEXT: End Instruction: %c = load i32, ptr %2, align 4
define linkonce_odr void @fish() {
entry:
%0 = alloca i32, align 4
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
%4 = alloca i32, align 4
%5 = alloca i32, align 4
store i32 6, ptr %0, align 4
store i32 1, ptr %1, align 4
store i32 2, ptr %2, align 4
store i32 3, ptr %3, align 4
store i32 4, ptr %4, align 4
store i32 5, ptr %5, align 4
ret void
}
define void @turtle(ptr %0, ptr %1, ptr %2, ptr %3) {
%a = load i32, ptr %0
%b = load i32, ptr %1
%c = load i32, ptr %2
%d = load i32, ptr %3
ret void
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK: {{.*}}

View file

@ -1,14 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -disable-output -S -passes=print-ir-similarity < %s 2>&1 | FileCheck --allow-empty %s
; This is a simple test to make sure the IRSimilarityPrinterPass returns
; nothing when there is nothing to analyze.
; CHECK-NOT: Found in
define linkonce_odr void @fish() {
entry:
ret void
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK: {{.*}}

View file

@ -140,7 +140,6 @@ set(LLVM_TEST_DEPENDS
llvm-reduce
llvm-remarkutil
llvm-rtdyld
llvm-sim
llvm-size
llvm-split
llvm-stress

View file

@ -1,162 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -passes=verify,iroutliner -ir-outlining-no-cost < %s | \
; RUN: llc -filetype=obj -mtriple=aarch64-- | llvm-dwarfdump - | FileCheck %s
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck -check-prefix=IRDEBUG %s
; Ensure that the IR Outliner produces valid DWARF debug information when
; creating outlined functions.
; CHECK: DW_TAG_compile_unit
; CHECK-DAG: DW_AT_name ("outline_debug1")
; Check the high address of bar. This is one past the end of bar. It should be
; the beginning of the outlined function.
; CHECK: DW_AT_high_pc ([[ONE_PAST_BAR:0x[a-f0-9]+]])
; CHECK-NEXT: DW_AT_frame_base (DW_OP_reg31 WSP)
; CHECK-NEXT: DW_AT_linkage_name ("outline_debug2")
; CHECK-NEXT: DW_AT_name ("outline_debug2")
; Check the outlined function's DWARF.
; CHECK-DAG: DW_TAG_subprogram
; CHECK-NEXT: DW_AT_low_pc ([[ONE_PAST_BAR]])
; CHECK-NEXT: DW_AT_high_pc (0x{{[0-9a-f]+}})
; CHECK-NEXT: DW_AT_frame_base (DW_OP_reg31 WSP)
; CHECK-NEXT: DW_AT_linkage_name ("[[NAME:outlined_ir_func_[0-9]+]]")
; CHECK-NEXT: DW_AT_name ("[[NAME]]")
; CHECK-NEXT: DW_AT_artificial (true)
; CHECK-NEXT: DW_AT_external (true)
define void @outline_debug1() !dbg !6 {
entry:
%a = alloca i32, align 4, !dbg !17
call void @llvm.dbg.value(metadata ptr %a, metadata !9, metadata !DIExpression()), !dbg !17
%b = alloca i32, align 4, !dbg !18
call void @llvm.dbg.value(metadata ptr %b, metadata !11, metadata !DIExpression()), !dbg !18
%c = alloca i32, align 4, !dbg !19
call void @llvm.dbg.value(metadata ptr %c, metadata !12, metadata !DIExpression()), !dbg !19
store i32 2, ptr %a, align 4, !dbg !20
store i32 3, ptr %b, align 4, !dbg !21
store i32 4, ptr %c, align 4, !dbg !22
%al = load i32, ptr %a, align 4, !dbg !23
call void @llvm.dbg.value(metadata i32 %al, metadata !13, metadata !DIExpression()), !dbg !23
%bl = load i32, ptr %b, align 4, !dbg !24
call void @llvm.dbg.value(metadata i32 %bl, metadata !15, metadata !DIExpression()), !dbg !24
%cl = load i32, ptr %c, align 4, !dbg !25
call void @llvm.dbg.value(metadata i32 %cl, metadata !16, metadata !DIExpression()), !dbg !25
ret void, !dbg !26
}
define void @outline_debug2() !dbg !27 {
entry:
%a = alloca i32, align 4, !dbg !35
call void @llvm.dbg.value(metadata ptr %a, metadata !29, metadata !DIExpression()), !dbg !35
%b = alloca i32, align 4, !dbg !36
call void @llvm.dbg.value(metadata ptr %b, metadata !30, metadata !DIExpression()), !dbg !36
%c = alloca i32, align 4, !dbg !37
call void @llvm.dbg.value(metadata ptr %c, metadata !31, metadata !DIExpression()), !dbg !37
store i32 2, ptr %a, align 4, !dbg !38
store i32 3, ptr %b, align 4, !dbg !39
store i32 4, ptr %c, align 4, !dbg !40
%al = load i32, ptr %a, align 4, !dbg !41
call void @llvm.dbg.value(metadata i32 %al, metadata !32, metadata !DIExpression()), !dbg !41
%bl = load i32, ptr %b, align 4, !dbg !42
call void @llvm.dbg.value(metadata i32 %bl, metadata !33, metadata !DIExpression()), !dbg !42
%cl = load i32, ptr %c, align 4, !dbg !43
call void @llvm.dbg.value(metadata i32 %cl, metadata !34, metadata !DIExpression()), !dbg !43
ret void, !dbg !44
}
; Function Attrs: nounwind readnone speculatable willreturn
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
attributes #0 = { nounwind readnone speculatable willreturn }
!llvm.dbg.cu = !{!0}
!llvm.debugify = !{!3, !4}
!llvm.module.flags = !{!5}
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "llvm/test/DebugInfo/ir-outliner.ll", directory: "/")
!2 = !{}
!3 = !{i32 20}
!4 = !{i32 12}
!5 = !{i32 2, !"Debug Info Version", i32 3}
!6 = distinct !DISubprogram(name: "outline_debug1", linkageName: "outline_debug1", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
!7 = !DISubroutineType(types: !2)
!8 = !{!9, !11, !12, !13, !15, !16}
!9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
!10 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned)
!11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !10)
!12 = !DILocalVariable(name: "3", scope: !6, file: !1, line: 3, type: !10)
!13 = !DILocalVariable(name: "4", scope: !6, file: !1, line: 7, type: !14)
!14 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
!15 = !DILocalVariable(name: "5", scope: !6, file: !1, line: 8, type: !14)
!16 = !DILocalVariable(name: "6", scope: !6, file: !1, line: 9, type: !14)
!17 = !DILocation(line: 1, column: 1, scope: !6)
!18 = !DILocation(line: 2, column: 1, scope: !6)
!19 = !DILocation(line: 3, column: 1, scope: !6)
!20 = !DILocation(line: 4, column: 1, scope: !6)
!21 = !DILocation(line: 5, column: 1, scope: !6)
!22 = !DILocation(line: 6, column: 1, scope: !6)
!23 = !DILocation(line: 7, column: 1, scope: !6)
!24 = !DILocation(line: 8, column: 1, scope: !6)
!25 = !DILocation(line: 9, column: 1, scope: !6)
!26 = !DILocation(line: 10, column: 1, scope: !6)
!27 = distinct !DISubprogram(name: "outline_debug2", linkageName: "outline_debug2", scope: null, file: !1, line: 11, type: !7, scopeLine: 11, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !28)
!28 = !{!29, !30, !31, !32, !33, !34}
!29 = !DILocalVariable(name: "7", scope: !27, file: !1, line: 11, type: !10)
!30 = !DILocalVariable(name: "8", scope: !27, file: !1, line: 12, type: !10)
!31 = !DILocalVariable(name: "9", scope: !27, file: !1, line: 13, type: !10)
!32 = !DILocalVariable(name: "10", scope: !27, file: !1, line: 17, type: !14)
!33 = !DILocalVariable(name: "11", scope: !27, file: !1, line: 18, type: !14)
!34 = !DILocalVariable(name: "12", scope: !27, file: !1, line: 19, type: !14)
!35 = !DILocation(line: 11, column: 1, scope: !27)
!36 = !DILocation(line: 12, column: 1, scope: !27)
!37 = !DILocation(line: 13, column: 1, scope: !27)
!38 = !DILocation(line: 14, column: 1, scope: !27)
!39 = !DILocation(line: 15, column: 1, scope: !27)
!40 = !DILocation(line: 16, column: 1, scope: !27)
!41 = !DILocation(line: 17, column: 1, scope: !27)
!42 = !DILocation(line: 18, column: 1, scope: !27)
!43 = !DILocation(line: 19, column: 1, scope: !27)
!44 = !DILocation(line: 20, column: 1, scope: !27)
; IRDEBUG-LABEL: @outline_debug1(
; IRDEBUG-NEXT: entry:
; IRDEBUG-NEXT: [[A:%.*]] = alloca i32, align 4, !dbg [[DBG17:![0-9]+]]
; IRDEBUG-NEXT: #dbg_value(ptr [[A]], [[META9:![0-9]+]], !DIExpression(), [[DBG17]])
; IRDEBUG-NEXT: [[B:%.*]] = alloca i32, align 4, !dbg [[DBG18:![0-9]+]]
; IRDEBUG-NEXT: #dbg_value(ptr [[B]], [[META11:![0-9]+]], !DIExpression(), [[DBG18]])
; IRDEBUG-NEXT: [[C:%.*]] = alloca i32, align 4, !dbg [[DBG19:![0-9]+]]
; IRDEBUG-NEXT: #dbg_value(ptr [[C]], [[META12:![0-9]+]], !DIExpression(), [[DBG19]])
; IRDEBUG-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]]), !dbg [[DBG20:![0-9]+]]
; IRDEBUG-NEXT: ret void, !dbg [[DBG21:![0-9]+]]
;
;
; IRDEBUG-LABEL: @outline_debug2(
; IRDEBUG-NEXT: entry:
; IRDEBUG-NEXT: [[A:%.*]] = alloca i32, align 4, !dbg [[DBG30:![0-9]+]]
; IRDEBUG-NEXT: #dbg_value(ptr [[A]], [[META24:![0-9]+]], !DIExpression(), [[DBG30]])
; IRDEBUG-NEXT: [[B:%.*]] = alloca i32, align 4, !dbg [[DBG31:![0-9]+]]
; IRDEBUG-NEXT: #dbg_value(ptr [[B]], [[META25:![0-9]+]], !DIExpression(), [[DBG31]])
; IRDEBUG-NEXT: [[C:%.*]] = alloca i32, align 4, !dbg [[DBG32:![0-9]+]]
; IRDEBUG-NEXT: #dbg_value(ptr [[C]], [[META26:![0-9]+]], !DIExpression(), [[DBG32]])
; IRDEBUG-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]]), !dbg [[DBG33:![0-9]+]]
; IRDEBUG-NEXT: ret void, !dbg [[DBG34:![0-9]+]]
;
;
; IRDEBUG-LABEL: define {{.+}} @outlined_ir_func_0(
; IRDEBUG-NEXT: newFuncRoot:
; IRDEBUG-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; IRDEBUG: entry_to_outline:
; IRDEBUG-NEXT: store i32 2, ptr [[TMP0:%.*]], align 4
; IRDEBUG-NEXT: store i32 3, ptr [[TMP1:%.*]], align 4
; IRDEBUG-NEXT: store i32 4, ptr [[TMP2:%.*]], align 4
; IRDEBUG-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
; IRDEBUG-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
; IRDEBUG-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
; IRDEBUG-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; IRDEBUG: entry_after_outline.exitStub:
; IRDEBUG-NEXT: ret void
;

View file

@ -77,10 +77,6 @@
; RUN: -passes='default<O3>' -enable-merge-functions -S %s 2>&1 \
; RUN: | FileCheck %s --check-prefixes=CHECK-O,CHECK-DEFAULT,CHECK-O3,CHECK-O23,%llvmcheckext,CHECK-MERGE-FUNCS
; RUN: opt -disable-verify -verify-analysis-invalidation=0 -eagerly-invalidate-analyses=0 -debug-pass-manager \
; RUN: -passes='default<O3>' -ir-outliner -S %s 2>&1 \
; RUN: | FileCheck %s --check-prefixes=CHECK-O,CHECK-DEFAULT,CHECK-O3,CHECK-O23,%llvmcheckext,CHECK-IR-OUTLINER
; RUN: opt -disable-verify -verify-analysis-invalidation=0 -eagerly-invalidate-analyses=0 -debug-pass-manager \
; RUN: -passes='default<O3>' -hot-cold-split -S %s 2>&1 \
; RUN: | FileCheck %s --check-prefixes=CHECK-O,CHECK-DEFAULT,CHECK-O3,CHECK-O23,%llvmcheckext,CHECK-HOT-COLD-SPLIT
@ -277,8 +273,6 @@
; CHECK-DEFAULT-NEXT: Running pass: AllocToken
; CHECK-EP-OPTIMIZER-LAST: Running pass: NoOpModulePass
; CHECK-HOT-COLD-SPLIT-NEXT: Running pass: HotColdSplittingPass
; CHECK-IR-OUTLINER-NEXT: Running pass: IROutlinerPass
; CHECK-IR-OUTLINER-NEXT: Running analysis: IRSimilarityAnalysis
; CHECK-O-NEXT: Running pass: GlobalDCEPass
; CHECK-O-NEXT: Running pass: ConstantMergePass
; CHECK-MERGE-FUNCS-NEXT: Running pass: MergeFunctionsPass

View file

@ -1,46 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs
; RUN: opt -S -passes=iroutliner -ir-outlining-no-cost < %s | FileCheck %s
target datalayout = "A5"
define i32 @func_with_outgoing_new_allocas() {
bb:
%i = tail call i32 @func0(i32 0, i32 1)
%i1 = or i32 0, %i
%i2 = tail call i32 @func0(i32 %i1, i32 0)
%i3 = or i32 %i1, %i2
%i4 = tail call i32 @llvm.foo(i32 %i3, i32 0)
ret i32 0
}
declare i32 @func0(i32, i32)
declare i32 @llvm.foo(i32, i32)
; CHECK-LABEL: define {{[^@]+}}@func_with_outgoing_new_allocas() {
; CHECK-NEXT: bb:
; CHECK-NEXT: [[I3_LOC:%.*]] = alloca i32, align 4, addrspace(5)
; CHECK-NEXT: [[I1_LOC:%.*]] = alloca i32, align 4, addrspace(5)
; CHECK-NEXT: call void @llvm.lifetime.start.p5(ptr addrspace(5) [[I1_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i32 0, i32 1, ptr addrspace(5) [[I1_LOC]])
; CHECK-NEXT: [[I1_RELOAD:%.*]] = load i32, ptr addrspace(5) [[I1_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p5(ptr addrspace(5) [[I1_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p5(ptr addrspace(5) [[I3_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[I1_RELOAD]], i32 0, ptr addrspace(5) [[I3_LOC]])
; CHECK-NEXT: [[I3_RELOAD:%.*]] = load i32, ptr addrspace(5) [[I3_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p5(ptr addrspace(5) [[I3_LOC]])
; CHECK-NEXT: [[I4:%.*]] = tail call i32 @llvm.foo(i32 [[I3_RELOAD]], i32 0)
; CHECK-NEXT: ret i32 0
;
;
; CHECK-LABEL: define {{[^@]+}}@outlined_ir_func_0
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], ptr addrspace(5) [[TMP2:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BB_TO_OUTLINE:%.*]]
; CHECK: bb_to_outline:
; CHECK-NEXT: [[I:%.*]] = tail call i32 @func0(i32 [[TMP0]], i32 [[TMP1]])
; CHECK-NEXT: [[I1:%.*]] = or i32 [[TMP0]], [[I]]
; CHECK-NEXT: br label [[BB_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: bb_after_outline.exitStub:
; CHECK-NEXT: store i32 [[I1]], ptr addrspace(5) [[TMP2]], align 4
; CHECK-NEXT: ret void
;

View file

@ -1,46 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs
; RUN: opt -S -passes=iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Check alloca with non-0 address spaces works correctly.
target datalayout = "A5"
define i32 @outlineable() {
bb:
%i = tail call i32 @func(i32 0, i32 1)
%i1 = or i32 0, %i
%i2 = tail call i32 @func(i32 %i1, i32 0)
%i3 = or i32 %i1, %i2
ret i32 0
}
declare i32 @func(i32, i32)
; CHECK-LABEL: define {{[^@]+}}@outlineable() {
; CHECK-NEXT: bb:
; CHECK-NEXT: [[I1_LOC:%.*]] = alloca i32, align 4, addrspace(5)
; CHECK-NEXT: call void @llvm.lifetime.start.p5(ptr addrspace(5) [[I1_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i32 0, i32 1, ptr addrspace(5) [[I1_LOC]], i32 0)
; CHECK-NEXT: [[I1_RELOAD:%.*]] = load i32, ptr addrspace(5) [[I1_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p5(ptr addrspace(5) [[I1_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[I1_RELOAD]], i32 0, ptr addrspace(5) null, i32 -1)
; CHECK-NEXT: ret i32 0
;
;
; CHECK-LABEL: define {{[^@]+}}@outlined_ir_func_0
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], ptr addrspace(5) [[TMP2:%.*]], i32 [[TMP3:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BB_TO_OUTLINE:%.*]]
; CHECK: bb_to_outline:
; CHECK-NEXT: [[I:%.*]] = tail call i32 @func(i32 [[TMP0]], i32 [[TMP1]])
; CHECK-NEXT: [[I1:%.*]] = or i32 [[TMP0]], [[I]]
; CHECK-NEXT: br label [[BB_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: bb_after_outline.exitStub:
; CHECK-NEXT: switch i32 [[TMP3]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_0_0:
; CHECK-NEXT: store i32 [[I1]], ptr addrspace(5) [[TMP2]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: final_block_0:
; CHECK-NEXT: ret void
;

View file

@ -1,92 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we do not outline different intrinsics as the same
; function or as a value like we would for non-intrinsic functions.
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)
declare void @llvm.memmove.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)
define i8 @function1(ptr noalias %s, ptr noalias %d, i64 %len) {
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memcpy.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
define i8 @function2(ptr noalias %s, ptr noalias %d, i64 %len) {
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memmove.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[A_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[S:%.*]], ptr [[D:%.*]], ptr [[A_LOC]], ptr [[B_LOC]])
; CHECK-NEXT: [[A_RELOAD:%.*]] = load i8, ptr [[A_LOC]], align 1
; CHECK-NEXT: [[B_RELOAD:%.*]] = load i8, ptr [[B_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[D]], ptr [[S]], i64 [[LEN:%.*]], i1 false)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i8 [[A_RELOAD]], i8 [[B_RELOAD]], ptr [[S]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[A_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[S:%.*]], ptr [[D:%.*]], ptr [[A_LOC]], ptr [[B_LOC]])
; CHECK-NEXT: [[A_RELOAD:%.*]] = load i8, ptr [[A_LOC]], align 1
; CHECK-NEXT: [[B_RELOAD:%.*]] = load i8, ptr [[B_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[D]], ptr [[S]], i64 [[LEN:%.*]], i1 false)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i8 [[A_RELOAD]], i8 [[B_RELOAD]], ptr [[S]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[C:%.*]] = add i8 [[TMP0:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: [[RET:%.*]] = load i8, ptr [[TMP2:%.*]], align 1
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: store i8 [[RET]], ptr [[TMP3:%.*]], align 1
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_1(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[TMP0:%.*]], align 1
; CHECK-NEXT: [[B:%.*]] = load i8, ptr [[TMP1:%.*]], align 1
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: store i8 [[A]], ptr [[TMP2:%.*]], align 1
; CHECK-NEXT: store i8 [[B]], ptr [[TMP3:%.*]], align 1
; CHECK-NEXT: ret void
;

View file

@ -1,113 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Check that differently ordered phi nodes are not matched when merged, instead
; generating two output paths.
define void @f1() {
bb1:
%0 = add i32 1, 2
%1 = add i32 3, 4
%2 = add i32 5, 6
%3 = add i32 7, 8
br i1 true, label %bb2, label %bb5
bb2:
%4 = mul i32 5, 4
br label %bb5
placeholder:
%a = sub i32 5, 4
ret void
bb5:
%phinode = phi i32 [%3, %bb1], [%2, %bb2]
ret void
}
define void @f2() {
bb1:
%0 = add i32 1, 2
%1 = add i32 3, 4
%2 = add i32 5, 6
%3 = add i32 7, 8
br i1 true, label %bb2, label %bb5
bb2:
%4 = mul i32 5, 4
br label %bb5
placeholder:
%a = sub i32 5, 4
ret void
bb5:
%phinode = phi i32 [%2, %bb1], [%3, %bb2]
ret void
}
; CHECK-LABEL: @f1(
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[PHINODE_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[PHINODE_CE_LOC]], i32 0)
; CHECK-NEXT: [[PHINODE_CE_RELOAD:%.*]] = load i32, ptr [[PHINODE_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: br i1 [[TMP0]], label [[BB5:%.*]], label [[BB1_AFTER_OUTLINE:%.*]]
; CHECK: bb1_after_outline:
; CHECK-NEXT: ret void
; CHECK: bb5:
; CHECK-NEXT: [[PHINODE:%.*]] = phi i32 [ [[PHINODE_CE_RELOAD]], [[BB1:%.*]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @f2(
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[PHINODE_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[PHINODE_CE_LOC]], i32 1)
; CHECK-NEXT: [[PHINODE_CE_RELOAD:%.*]] = load i32, ptr [[PHINODE_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: br i1 [[TMP0]], label [[BB5:%.*]], label [[BB1_AFTER_OUTLINE:%.*]]
; CHECK: bb1_after_outline:
; CHECK-NEXT: ret void
; CHECK: bb5:
; CHECK-NEXT: [[PHINODE:%.*]] = phi i32 [ [[PHINODE_CE_RELOAD]], [[BB1:%.*]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal i1 @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BB1_TO_OUTLINE:%.*]]
; CHECK: bb1_to_outline:
; CHECK-NEXT: [[TMP2:%.*]] = add i32 1, 2
; CHECK-NEXT: [[TMP3:%.*]] = add i32 3, 4
; CHECK-NEXT: [[TMP4:%.*]] = add i32 5, 6
; CHECK-NEXT: [[TMP5:%.*]] = add i32 7, 8
; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB5_SPLIT:%.*]]
; CHECK: bb2:
; CHECK-NEXT: [[TMP6:%.*]] = mul i32 5, 4
; CHECK-NEXT: br label [[BB5_SPLIT]]
; CHECK: placeholder:
; CHECK-NEXT: [[A:%.*]] = sub i32 5, 4
; CHECK-NEXT: br label [[BB1_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: bb5.split:
; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP4]], [[BB1_TO_OUTLINE]] ], [ [[TMP5]], [[BB2]] ]
; CHECK-NEXT: [[PHINODE_CE:%.*]] = phi i32 [ [[TMP5]], [[BB1_TO_OUTLINE]] ], [ [[TMP4]], [[BB2]] ]
; CHECK-NEXT: br label [[BB5_EXITSTUB:%.*]]
; CHECK: bb5.exitStub:
; CHECK-NEXT: switch i32 [[TMP1:%.*]], label [[FINAL_BLOCK_1:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_1:%.*]]
; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_1:%.*]]
; CHECK-NEXT: ]
; CHECK: bb1_after_outline.exitStub:
; CHECK-NEXT: switch i32 [[TMP1]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: ]
; CHECK: output_block_0_1:
; CHECK-NEXT: store i32 [[PHINODE_CE]], ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: output_block_1_1:
; CHECK-NEXT: store i32 [[TMP7]], ptr [[TMP0]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: final_block_0:
; CHECK-NEXT: ret i1 false
; CHECK: final_block_1:
; CHECK-NEXT: ret i1 true
;

View file

@ -1,113 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Make sure that when we merge phi nodes, we do not merge two different PHINodes
; as the same phi node.
define void @f1() {
bb1:
%0 = add i32 1, 2
%1 = add i32 3, 4
%2 = add i32 5, 6
%3 = add i32 7, 8
br label %bb5
bb2:
%4 = mul i32 5, 4
br label %bb5
placeholder:
%a = sub i32 5, 4
ret void
bb5:
%phinode = phi i32 [5, %bb1], [5, %bb2]
%phinode1 = phi i32 [5, %bb1], [5, %bb2]
ret void
}
define void @f2() {
bb1:
%0 = add i32 1, 2
%1 = add i32 3, 4
%2 = add i32 5, 6
%3 = add i32 7, 8
br label %bb5
bb2:
%4 = mul i32 5, 4
br label %bb5
placeholder:
%a = sub i32 5, 4
ret void
bb5:
%phinode = phi i32 [5, %bb1], [5, %bb2]
%phinode1 = phi i32 [5, %bb1], [5, %bb2]
ret void
}
; CHECK-LABEL: @f1(
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[PHINODE1_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[PHINODE_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PHINODE1_CE_LOC]])
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(ptr [[PHINODE_CE_LOC]], ptr [[PHINODE1_CE_LOC]])
; CHECK-NEXT: [[PHINODE_CE_RELOAD:%.*]] = load i32, ptr [[PHINODE_CE_LOC]], align 4
; CHECK-NEXT: [[PHINODE1_CE_RELOAD:%.*]] = load i32, ptr [[PHINODE1_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PHINODE1_CE_LOC]])
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[BB5:%.*]], label [[BB1_AFTER_OUTLINE:%.*]]
; CHECK: bb1_after_outline:
; CHECK-NEXT: ret void
; CHECK: bb5:
; CHECK-NEXT: [[PHINODE:%.*]] = phi i32 [ [[PHINODE_CE_RELOAD]], [[BB1:%.*]] ]
; CHECK-NEXT: [[PHINODE1:%.*]] = phi i32 [ [[PHINODE1_CE_RELOAD]], [[BB1]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @f2(
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[PHINODE1_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[PHINODE_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PHINODE1_CE_LOC]])
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(ptr [[PHINODE_CE_LOC]], ptr [[PHINODE1_CE_LOC]])
; CHECK-NEXT: [[PHINODE_CE_RELOAD:%.*]] = load i32, ptr [[PHINODE_CE_LOC]], align 4
; CHECK-NEXT: [[PHINODE1_CE_RELOAD:%.*]] = load i32, ptr [[PHINODE1_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PHINODE1_CE_LOC]])
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[BB5:%.*]], label [[BB1_AFTER_OUTLINE:%.*]]
; CHECK: bb1_after_outline:
; CHECK-NEXT: ret void
; CHECK: bb5:
; CHECK-NEXT: [[PHINODE:%.*]] = phi i32 [ [[PHINODE_CE_RELOAD]], [[BB1:%.*]] ]
; CHECK-NEXT: [[PHINODE1:%.*]] = phi i32 [ [[PHINODE1_CE_RELOAD]], [[BB1]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal i1 @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BB1_TO_OUTLINE:%.*]]
; CHECK: bb1_to_outline:
; CHECK-NEXT: [[TMP2:%.*]] = add i32 1, 2
; CHECK-NEXT: [[TMP3:%.*]] = add i32 3, 4
; CHECK-NEXT: [[TMP4:%.*]] = add i32 5, 6
; CHECK-NEXT: [[TMP5:%.*]] = add i32 7, 8
; CHECK-NEXT: br label [[BB5_SPLIT:%.*]]
; CHECK: bb2:
; CHECK-NEXT: [[TMP6:%.*]] = mul i32 5, 4
; CHECK-NEXT: br label [[BB5_SPLIT]]
; CHECK: placeholder:
; CHECK-NEXT: [[A:%.*]] = sub i32 5, 4
; CHECK-NEXT: br label [[BB1_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: bb5.split:
; CHECK-NEXT: [[PHINODE_CE:%.*]] = phi i32 [ 5, [[BB1_TO_OUTLINE]] ], [ 5, [[BB2:%.*]] ]
; CHECK-NEXT: [[PHINODE1_CE:%.*]] = phi i32 [ 5, [[BB1_TO_OUTLINE]] ], [ 5, [[BB2]] ]
; CHECK-NEXT: br label [[BB5_EXITSTUB:%.*]]
; CHECK: bb5.exitStub:
; CHECK-NEXT: store i32 [[PHINODE_CE]], ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: store i32 [[PHINODE1_CE]], ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: ret i1 true
; CHECK: bb1_after_outline.exitStub:
; CHECK-NEXT: ret i1 false
;

View file

@ -1,96 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Make sure that each outlined region only analyzes on the incoming values in exit
; block phi nodes that come from the outlined region. Without this, more incoming
; values from the phi node would be considered if the incoming value is
; included in the outlined region. This is particularly likely to happen for
; constants.
define void @f1() {
bb1:
%0 = add i32 1, 2
%1 = add i32 3, 4
%2 = add i32 5, 6
%3 = add i32 7, 8
br label %bb5
bb2:
%4 = mul i32 5, 4
br label %bb5
placeholder:
%a = sub i32 5, 4
br label %bb5
bb3:
%5 = add i32 1, 2
%6 = add i32 3, 4
%7 = add i32 5, 6
%8 = add i32 7, 8
br label %bb5
bb4:
%9 = mul i32 5, 4
br label %bb5
placeholder1:
%b = add i32 5, 4
ret void
bb5:
%phinode = phi i32 [5, %placeholder], [5, %bb1], [5, %bb2], [4, %bb3], [4, %bb4]
ret void
}
; CHECK-LABEL: @f1(
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[PHINODE_CE_LOC1:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[PHINODE_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[PHINODE_CE_LOC]], i32 0)
; CHECK-NEXT: [[PHINODE_CE_RELOAD:%.*]] = load i32, ptr [[PHINODE_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PHINODE_CE_LOC]])
; CHECK-NEXT: br label [[BB5:%.*]]
; CHECK: placeholder:
; CHECK-NEXT: [[A:%.*]] = sub i32 5, 4
; CHECK-NEXT: br label [[BB5]]
; CHECK: bb3:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[PHINODE_CE_LOC1]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[PHINODE_CE_LOC1]], i32 1)
; CHECK-NEXT: [[PHINODE_CE_RELOAD2:%.*]] = load i32, ptr [[PHINODE_CE_LOC1]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[PHINODE_CE_LOC1]])
; CHECK-NEXT: br label [[BB5]]
; CHECK: placeholder1:
; CHECK-NEXT: [[B:%.*]] = add i32 5, 4
; CHECK-NEXT: ret void
; CHECK: bb5:
; CHECK-NEXT: [[PHINODE:%.*]] = phi i32 [ 5, [[PLACEHOLDER:%.*]] ], [ [[PHINODE_CE_RELOAD]], [[BB1:%.*]] ], [ [[PHINODE_CE_RELOAD2]], [[BB3:%.*]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BB1_TO_OUTLINE:%.*]]
; CHECK: bb1_to_outline:
; CHECK-NEXT: [[TMP2:%.*]] = add i32 1, 2
; CHECK-NEXT: [[TMP3:%.*]] = add i32 3, 4
; CHECK-NEXT: [[TMP4:%.*]] = add i32 5, 6
; CHECK-NEXT: [[TMP5:%.*]] = add i32 7, 8
; CHECK-NEXT: br label [[BB5_SPLIT:%.*]]
; CHECK: bb2:
; CHECK-NEXT: [[TMP6:%.*]] = mul i32 5, 4
; CHECK-NEXT: br label [[BB5_SPLIT]]
; CHECK: bb5.split:
; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ 4, [[BB1_TO_OUTLINE]] ], [ 4, [[BB2:%.*]] ]
; CHECK-NEXT: [[PHINODE_CE:%.*]] = phi i32 [ 5, [[BB1_TO_OUTLINE]] ], [ 5, [[BB2]] ]
; CHECK-NEXT: br label [[BB5_EXITSTUB:%.*]]
; CHECK: bb5.exitStub:
; CHECK-NEXT: switch i32 [[TMP1:%.*]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_0:%.*]]
; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_0_0:
; CHECK-NEXT: store i32 [[PHINODE_CE]], ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: output_block_1_0:
; CHECK-NEXT: store i32 [[TMP7]], ptr [[TMP0]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: final_block_0:
; CHECK-NEXT: ret void
;

View file

@ -1,110 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; When consolidating PHINodes, the outliner replaces the incoming value with
; a corresponding value from the first outlined section. When this replaced
; value is passed in as an argument, the corresponding value is found outside
; of the outlined region, and must be replaced with an argument to avoid
; dominating value errors. This checks that we use the argument to replace
; the incoming value.
define void @func1(i32 %0, i32 %1) local_unnamed_addr #0 {
bb1:
br label %bb5
bb2:
%a = add i32 %0, %1
%b = add i32 %0, %1
%c = icmp eq i32 %b, %a
br i1 %c, label %bb5, label %bb3
bb3:
%d = add i32 %0, %1
br label %bb5
bb4:
%e = sub i32 %0, %1
br label %bb2
bb5:
ret void
}
define void @func2(i32 %0, i32 %1) local_unnamed_addr #0 {
bb1:
br label %bb5
bb2:
%a = sub i32 %0, %1
%b = add i32 %0, %1
%c = icmp eq i32 %b, 1
br i1 %c, label %bb5, label %bb3
bb3:
%d = add i32 %0, %1
br label %bb5
bb4:
%e = add i32 %0, %1
br label %bb2
bb5:
%f = phi i32 [ 0, %bb1 ], [ 1, %bb2 ], [ 1, %bb3 ]
ret void
}
; CHECK-LABEL: @func1(
; CHECK-NEXT: bb1:
; CHECK-NEXT: br label [[BB5:%.*]]
; CHECK: bb2:
; CHECK-NEXT: [[A:%.*]] = add i32 [[TMP0:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[TMP0]], i32 [[TMP1]], i32 [[A]], ptr null, i32 -1)
; CHECK-NEXT: br label [[BB5]]
; CHECK: bb4:
; CHECK-NEXT: [[E:%.*]] = sub i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb5:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @func2(
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[F_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BB5:%.*]]
; CHECK: bb2:
; CHECK-NEXT: [[A:%.*]] = sub i32 [[TMP0:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[F_CE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[TMP0]], i32 [[TMP1]], i32 1, ptr [[F_CE_LOC]], i32 0)
; CHECK-NEXT: [[F_CE_RELOAD:%.*]] = load i32, ptr [[F_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[F_CE_LOC]])
; CHECK-NEXT: br label [[BB5]]
; CHECK: bb4:
; CHECK-NEXT: [[E:%.*]] = add i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb5:
; CHECK-NEXT: [[F:%.*]] = phi i32 [ 0, [[BB1:%.*]] ], [ [[F_CE_RELOAD]], [[BB2]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BB2_TO_OUTLINE:%.*]]
; CHECK: bb2_to_outline:
; CHECK-NEXT: [[B:%.*]] = add i32 [[TMP0:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[B]], [[TMP2:%.*]]
; CHECK-NEXT: br i1 [[C]], label [[PHI_BLOCK:%.*]], label [[BB3:%.*]]
; CHECK: bb3:
; CHECK-NEXT: [[D:%.*]] = add i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: br label [[PHI_BLOCK]]
; CHECK: bb5.exitStub:
; CHECK-NEXT: switch i32 [[TMP4:%.*]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_1_0:
; CHECK-NEXT: store i32 [[TMP5:%.*]], ptr [[TMP3:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: phi_block:
; CHECK-NEXT: [[TMP5]] = phi i32 [ [[TMP2]], [[BB2_TO_OUTLINE]] ], [ [[TMP2]], [[BB3]] ]
; CHECK-NEXT: br label [[BB5_EXITSTUB:%.*]]
; CHECK: final_block_0:
; CHECK-NEXT: ret void
;

View file

@ -1,127 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test makes sure we are extracting the found similarity sections
; correctly at the call site.
define void @extract1() {
; CHECK-LABEL: @extract1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @extract2() {
; CHECK-LABEL: @extract2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; There are potential ouptuts in this sections, but we do not extract sections
; with outputs right now, since they cannot be consolidated.
define void @extract_outs1() #0 {
; CHECK-LABEL: @extract_outs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTLOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTLOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[ADD_LOC]], ptr [[DOTLOC]])
; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
; CHECK-NEXT: [[DOTRELOAD:%.*]] = load i32, ptr [[DOTLOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTLOC]])
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[OUTPUT]], align 4
; CHECK-NEXT: call void @outlined_ir_func_2(i32 [[DOTRELOAD]], i32 [[ADD_RELOAD]], ptr [[RESULT]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
store i32 %add, ptr %output, align 4
%2 = load i32, ptr %output, align 4
%3 = load i32, ptr %output, align 4
%mul = mul i32 %2, %add
store i32 %mul, ptr %result, align 4
ret void
}
; There are potential ouptuts in this sections, but we do not extract sections
; with outputs right now, since they cannot be consolidated.
define void @extract_outs2() #0 {
; CHECK-LABEL: @extract_outs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTLOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTLOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[ADD_LOC]], ptr [[DOTLOC]])
; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
; CHECK-NEXT: [[DOTRELOAD:%.*]] = load i32, ptr [[DOTLOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTLOC]])
; CHECK-NEXT: call void @outlined_ir_func_2(i32 [[DOTRELOAD]], i32 [[ADD_RELOAD]], ptr [[RESULT]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
store i32 %add, ptr %output, align 4
%2 = load i32, ptr %output, align 4
%mul = mul i32 %2, %add
store i32 %mul, ptr %result, align 4
ret void
}

View file

@ -1,119 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we do differentiate between outputs of the region stored in PHINodes
; versus those stored outside of PHINodes.
define void @function1(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br i1 true, label %first, label %test
test:
%d = load i32, ptr %0, align 4
br i1 true, label %first, label %next
first:
%1 = phi i32 [ %c, %test ], [ %e, %test1 ]
ret void
next:
ret void
}
define void @function2(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br i1 true, label %first, label %test
test:
%d = load i32, ptr %0, align 4
br i1 true, label %first, label %next
first:
ret void
next:
%1 = add i32 %c, 1
%2 = add i32 %e, 1
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTCE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: [[TMP1:%.*]] = call i1 @outlined_ir_func_0(ptr [[TMP0]], ptr [[DOTCE_LOC]], ptr null, i32 0)
; CHECK-NEXT: [[DOTCE_RELOAD:%.*]] = load i32, ptr [[DOTCE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: br i1 [[TMP1]], label [[FIRST:%.*]], label [[NEXT:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[DOTCE_RELOAD]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[E_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[C_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[E_LOC]])
; CHECK-NEXT: [[TMP1:%.*]] = call i1 @outlined_ir_func_0(ptr [[TMP0]], ptr [[C_LOC]], ptr [[E_LOC]], i32 1)
; CHECK-NEXT: [[C_RELOAD:%.*]] = load i32, ptr [[C_LOC]], align 4
; CHECK-NEXT: [[E_RELOAD:%.*]] = load i32, ptr [[E_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[C_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[E_LOC]])
; CHECK-NEXT: br i1 [[TMP1]], label [[FIRST:%.*]], label [[NEXT:%.*]]
; CHECK: first:
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[C_RELOAD]], 1
; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[E_RELOAD]], 1
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal i1 @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[TEST1:%.*]]
; CHECK: test1:
; CHECK-NEXT: [[E:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br i1 true, label [[FIRST_SPLIT:%.*]], label [[TEST:%.*]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br i1 true, label [[FIRST_SPLIT]], label [[NEXT_EXITSTUB:%.*]]
; CHECK: first.split:
; CHECK-NEXT: [[DOTCE:%.*]] = phi i32 [ [[C]], [[TEST]] ], [ [[E]], [[TEST1]] ]
; CHECK-NEXT: br label [[FIRST_EXITSTUB:%.*]]
; CHECK: first.exitStub:
; CHECK-NEXT: switch i32 [[TMP3:%.*]], label [[FINAL_BLOCK_1:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_1:%.*]]
; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_1:%.*]]
; CHECK-NEXT: ]
; CHECK: next.exitStub:
; CHECK-NEXT: switch i32 [[TMP3]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_0_1:
; CHECK-NEXT: store i32 [[DOTCE]], ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: output_block_1_0:
; CHECK-NEXT: store i32 [[C]], ptr [[TMP1]], align 4
; CHECK-NEXT: store i32 [[E]], ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: output_block_1_1:
; CHECK-NEXT: store i32 [[C]], ptr [[TMP1]], align 4
; CHECK-NEXT: store i32 [[E]], ptr [[TMP2]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: final_block_0:
; CHECK-NEXT: ret i1 false
; CHECK: final_block_1:
; CHECK-NEXT: ret i1 true
;

View file

@ -1,175 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "thumbv7-none-linux-android19"
define i32 @r() {
; CHECK-LABEL: define i32 @r() {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTLOC:%.*]] = alloca ptr, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTLOC]])
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[DOTLOC]], i32 0)
; CHECK-NEXT: [[DOTRELOAD:%.*]] = load ptr, ptr [[DOTLOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTLOC]])
; CHECK-NEXT: br i1 [[TMP0]], label [[IF_END8:%.*]], label [[ENTRY_AFTER_OUTLINE:%.*]]
; CHECK: entry_after_outline:
; CHECK-NEXT: [[CALL7:%.*]] = call i32 [[DOTRELOAD]]()
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.end8:
; CHECK-NEXT: ret i32 0
;
entry:
%.fca.2.insert = insertvalue [5 x i32] zeroinitializer, i32 0, 2
%.fca.3.load = load i32, ptr null, align 4
%.fca.3.insert = insertvalue [5 x i32] zeroinitializer, i32 0, 3
%.fca.4.load = load i32, ptr null, align 4
%.fca.4.insert = insertvalue [5 x i32] zeroinitializer, i32 0, 4
%call = call i32 @p()
%tobool.not = icmp eq i32 0, 0
br i1 false, label %if.end8, label %if.then
if.then: ; preds = %entry
%0 = load i32, ptr null, align 4
%tobool1.not = icmp eq i32 0, 0
%1 = load i32, ptr null, align 4
%2 = load i32, ptr null, align 4
%cond = select i1 false, i32 0, i32 0
%tobool5.not = icmp eq i32 0, 0
br i1 false, label %if.end8, label %if.then6
if.then6: ; preds = %if.then
%3 = load ptr, ptr null, align 4
%call7 = call i32 %3()
br label %if.end8
if.end8: ; preds = %if.then6, %if.then, %entry
ret i32 0
}
declare i32 @p()
define i32 @u() {
; CHECK-LABEL: define i32 @u() {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr null, i32 -1)
; CHECK-NEXT: br i1 [[TMP0]], label [[IF_END8:%.*]], label [[ENTRY_AFTER_OUTLINE:%.*]]
; CHECK: entry_after_outline:
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.end8:
; CHECK-NEXT: ret i32 0
;
entry:
%.fca.2.insert = insertvalue [5 x i32] zeroinitializer, i32 0, 2
%.fca.3.load = load i32, ptr null, align 4
%.fca.3.insert = insertvalue [5 x i32] zeroinitializer, i32 0, 3
%.fca.4.load = load i32, ptr null, align 4
%.fca.4.insert = insertvalue [5 x i32] zeroinitializer, i32 0, 4
%call = call i32 @p()
%tobool.not = icmp eq i32 0, 0
br i1 false, label %if.end8, label %if.then
if.then: ; preds = %entry
%0 = load i32, ptr null, align 4
%tobool1.not = icmp eq i32 0, 0
%1 = load i32, ptr null, align 4
%2 = load i32, ptr null, align 4
%cond = select i1 false, i32 0, i32 0
%tobool5.not = icmp eq i32 0, 0
br i1 false, label %if.end8, label %if.then6
if.then6: ; preds = %if.then
%3 = load ptr, ptr null, align 4
br label %if.end8
if.end8: ; preds = %if.then6, %if.then, %entry
ret i32 0
}
define i32 @w() !dbg !8 {
; CHECK-LABEL: define i32 @w(
; CHECK-SAME: ) !dbg [[DBG8:![0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RETVAL_1_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RETVAL_1_CE_LOC]])
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[RETVAL_1_CE_LOC]], i32 1), !dbg [[DBG11:![0-9]+]]
; CHECK-NEXT: [[RETVAL_1_CE_RELOAD:%.*]] = load i32, ptr [[RETVAL_1_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RETVAL_1_CE_LOC]])
; CHECK-NEXT: br i1 [[TMP0]], label [[CLEANUP10:%.*]], label [[ENTRY_AFTER_OUTLINE:%.*]]
; CHECK: entry_after_outline:
; CHECK-NEXT: [[CALL8:%.*]] = call i32 @llvm.bswap.i32(i32 0)
; CHECK-NEXT: br label [[CLEANUP10]]
; CHECK: cleanup10:
; CHECK-NEXT: [[RETVAL_1:%.*]] = phi i32 [ 0, [[ENTRY_AFTER_OUTLINE]] ], [ [[RETVAL_1_CE_RELOAD]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 0
;
entry:
%.fca.2.insert = insertvalue [5 x i32] zeroinitializer, i32 0, 2
%.fca.3.load = load i32, ptr null, align 4
%.fca.3.insert = insertvalue [5 x i32] zeroinitializer, i32 0, 3
%.fca.4.load = load i32, ptr null, align 4
%.fca.4.insert = insertvalue [5 x i32] zeroinitializer, i32 0, 4
%call = call i32 @p()
%tobool.not = icmp eq i32 0, 0
br i1 false, label %cleanup10, label %if.then
if.then: ; preds = %entry
call void @llvm.dbg.value(metadata i32 0, metadata !11, metadata !DIExpression()), !dbg !15
%0 = load i32, ptr null, align 4
%tobool1.not = icmp eq i32 0, 0
%1 = load i32, ptr null, align 4
%2 = load i32, ptr null, align 4
%cond = select i1 false, i32 0, i32 0
%tobool5.not = icmp eq i32 0, 0
br i1 false, label %cleanup10, label %cleanup
cleanup: ; preds = %if.then
%3 = load ptr, ptr null, align 4
%call8 = call i32 @llvm.bswap.i32(i32 0)
br label %cleanup10
cleanup10: ; preds = %cleanup, %if.then, %entry
%retval.1 = phi i32 [ 0, %cleanup ], [ 0, %entry ], [ 0, %if.then ]
ret i32 0
}
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.bswap.i32(i32) #0
attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!7}
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 18.0.0 (https://github.com/llvm/llvm-project.git 2ca028ce7c6de5f1350440012355a65383b8729a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "/tmp/foo.c", directory: "/home/davidino/llvm-build-upstream")
!2 = !{!3}
!3 = !DIGlobalVariableExpression(var: !4, expr: !DIExpression())
!4 = distinct !DIGlobalVariable(name: "n", scope: !0, file: !5, line: 19, type: !6, isLocal: false, isDefinition: true)
!5 = !DIFile(filename: "/tmp/foo.c", directory: "")
!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!7 = !{i32 2, !"Debug Info Version", i32 3}
!8 = distinct !DISubprogram(name: "w", scope: !5, file: !5, line: 54, type: !9, scopeLine: 54, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10)
!9 = !DISubroutineType(types: !10)
!10 = !{}
!11 = !DILocalVariable(name: "t", scope: !12, file: !5, line: 57, type: !14)
!12 = distinct !DILexicalBlock(scope: !13, file: !5, line: 56, column: 17)
!13 = distinct !DILexicalBlock(scope: !8, file: !5, line: 56, column: 11)
!14 = !DIDerivedType(tag: DW_TAG_typedef, name: "a", file: !5, line: 2, baseType: !6)
!15 = !DILocation(line: 0, scope: !12)
;.
; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], producer: "{{.*}}clang version {{.*}}", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: [[META2:![0-9]+]], splitDebugInlining: false, nameTableKind: None)
; CHECK: [[META1]] = !DIFile(filename: "/tmp/foo.c", directory: {{.*}})
; CHECK: [[META2]] = !{[[META3:![0-9]+]]}
; CHECK: [[META3]] = !DIGlobalVariableExpression(var: [[META4:![0-9]+]], expr: !DIExpression())
; CHECK: [[META4]] = distinct !DIGlobalVariable(name: "n", scope: [[META0]], file: [[META5:![0-9]+]], line: 19, type: [[META6:![0-9]+]], isLocal: false, isDefinition: true)
; CHECK: [[META5]] = !DIFile(filename: "/tmp/foo.c", directory: "")
; CHECK: [[META6]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
; CHECK: [[DBG8]] = distinct !DISubprogram(name: "w", scope: [[META5]], file: [[META5]], line: 54, type: [[META9:![0-9]+]], scopeLine: 54, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META10:![0-9]+]])
; CHECK: [[META9]] = !DISubroutineType(types: [[META10]])
; CHECK: [[META10]] = !{}
; CHECK: [[DBG11]] = !DILocation(line: 0, scope: [[DBG8]])
;.

View file

@ -1,36 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we do not extract allocas, as outlining allocas may cause
; inconsistencies with the CodeExtractor's algorithm.
define void @function1() {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
ret void
}
define void @function2() {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
ret void
}

View file

@ -1,143 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -p iroutliner,verify -ir-outlining-no-cost < %s | FileCheck %s
; This test ensures that we do not include llvm.assumes. There are exceptions
; in the CodeExtractor's algorithm for llvm.assumes, so we ignore it for now.
define void @outline_assumes() {
; CHECK-LABEL: @outline_assumes(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DL_LOC:%.*]] = alloca i1, align 1
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[D:%.*]] = alloca i1, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DL_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_4(i1 true, ptr [[D]], ptr [[DL_LOC]])
; CHECK-NEXT: [[DL_RELOAD:%.*]] = load i1, ptr [[DL_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DL_LOC]])
; CHECK-NEXT: [[SPLIT_INST:%.*]] = sub i1 [[DL_RELOAD]], [[DL_RELOAD]]
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: call void @llvm.assume(i1 [[DL_RELOAD]])
; CHECK-NEXT: call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i1, align 4
store i1 1, ptr %d, align 4
%dl = load i1, ptr %d
%split_inst = sub i1 %dl, %dl
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @llvm.assume(i1 %dl)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_assumes2() {
; CHECK-LABEL: @outline_assumes2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DL_LOC:%.*]] = alloca i1, align 1
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[D:%.*]] = alloca i1, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DL_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_4(i1 false, ptr [[D]], ptr [[DL_LOC]])
; CHECK-NEXT: [[DL_RELOAD:%.*]] = load i1, ptr [[DL_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DL_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: call void @llvm.assume(i1 [[DL_RELOAD]])
; CHECK-NEXT: call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i1, align 4
store i1 0, ptr %d, align 4
%dl = load i1, ptr %d
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @llvm.assume(i1 %dl)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_assumes3() {
; CHECK-LABEL: @outline_assumes3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DL_LOC:%.*]] = alloca i1, align 1
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[D:%.*]] = alloca i1, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DL_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i1 true, ptr [[D]], ptr [[A]], ptr [[B]], ptr [[C]], ptr [[DL_LOC]])
; CHECK-NEXT: [[DL_RELOAD:%.*]] = load i1, ptr [[DL_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DL_LOC]])
; CHECK-NEXT: call void @llvm.assume(i1 [[DL_RELOAD]])
; CHECK-NEXT: call void @outlined_ir_func_3(ptr [[A]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i1, align 4
store i1 1, ptr %d, align 4
%dl = load i1, ptr %d
%split_inst = add i1 %dl, %dl
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @llvm.assume(i1 %dl)
%al = load i32, ptr %a
%bl = add i32 %al, %al
ret void
}
define void @outline_assumes4() {
; CHECK-LABEL: @outline_assumes4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DL_LOC:%.*]] = alloca i1, align 1
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[D:%.*]] = alloca i1, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DL_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i1 false, ptr [[D]], ptr [[A]], ptr [[B]], ptr [[C]], ptr [[DL_LOC]])
; CHECK-NEXT: [[DL_RELOAD:%.*]] = load i1, ptr [[DL_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DL_LOC]])
; CHECK-NEXT: call void @llvm.assume(i1 [[DL_RELOAD]])
; CHECK-NEXT: call void @outlined_ir_func_3(ptr [[A]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i1, align 4
store i1 0, ptr %d, align 4
%dl = load i1, ptr %d
%split_inst = add i1 %dl, %dl
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @llvm.assume(i1 %dl)
%al = load i32, ptr %a
%bl = add i32 %al, %al
ret void
}
declare void @llvm.assume(i1)

View file

@ -1,51 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -no-ir-sim-branch-matching -ir-outlining-no-cost < %s | FileCheck %s
; Show that we do not extract sections with branches as it would require extra
; label and control flow checking.
define void @function1() {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
br label %next
next:
ret void
}
define void @function2() {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
br label %next
next:
ret void
}

View file

@ -1,64 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we do not outline callbr instruction since as we do not
; outline any control flow change instructions.
define i32 @function1(i32 %a, i32 %b) {
; CHECK-LABEL: @function1(
; CHECK-NEXT: bb0:
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[A:%.*]], 4
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B:%.*]])
; CHECK-NEXT: callbr void asm "xorl $0, $0
; CHECK-NEXT: to label [[NORMAL:%.*]] [label %fail1]
; CHECK: normal:
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]])
; CHECK-NEXT: ret i32 0
; CHECK: fail1:
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]])
; CHECK-NEXT: ret i32 0
;
bb0:
%0 = add i32 %a, 4
%1 = add i32 %b, 1
%2 = add i32 %b, 1
callbr void asm "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail1]
normal:
%3 = add i32 %b, 1
%4 = add i32 %b, 1
ret i32 0
fail1:
%5 = add i32 %b, 1
%6 = add i32 %b, 1
ret i32 0
}
define i32 @function2(i32 %a, i32 %b) {
; CHECK-LABEL: @function2(
; CHECK-NEXT: bb0:
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[A:%.*]], 4
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B:%.*]])
; CHECK-NEXT: callbr void asm "xorl $0, $0
; CHECK-NEXT: to label [[NORMAL:%.*]] [label %fail1]
; CHECK: normal:
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]])
; CHECK-NEXT: ret i32 0
; CHECK: fail1:
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]])
; CHECK-NEXT: ret i32 0
;
bb0:
%0 = add i32 %a, 4
%1 = add i32 %b, 1
%2 = add i32 %b, 1
callbr void asm "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail1]
normal:
%3 = add i32 %b, 1
%4 = add i32 %b, 1
ret i32 0
fail1:
%5 = add i32 %b, 1
%6 = add i32 %b, 1
ret i32 0
}

View file

@ -1,70 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -no-ir-sim-branch-matching -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that catchpad instructions are not outlined even if they
; in a similar section. Dealing with exception handling inside of an outlined
; function would require a lot of handling that is not implemented yet.
declare void @llvm.donothing() nounwind readnone
define void @function1() personality i8 3 {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catchpad1] unwind to caller
; CHECK: catchpad1:
; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS1]] []
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%cs1 = catchswitch within none [label %catchpad1] unwind to caller
catchpad1:
catchpad within %cs1 []
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
br label %normal
normal:
ret void
}
define void @function2() personality i8 3 {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catchpad1] unwind to caller
; CHECK: catchpad1:
; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS1]] []
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%cs1 = catchswitch within none [label %catchpad1] unwind to caller
catchpad1:
catchpad within %cs1 []
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
br label %normal
normal:
ret void
}

View file

@ -1,62 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -no-ir-sim-branch-matching -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that cleanuppad instructions are not outlined even if they
; in a similar section. Dealing with exception handling inside of an outlined
; function would require a lot of handling that is not implemented yet.
declare void @llvm.donothing() nounwind readnone
define void @function1() personality i8 3 {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CLEAN:%.*]] = cleanuppad within none []
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%clean = cleanuppad within none []
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
br label %normal
normal:
ret void
}
define void @function2() personality i8 3 {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CLEAN:%.*]] = cleanuppad within none []
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%clean = cleanuppad within none []
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
br label %normal
normal:
ret void
}

View file

@ -1,49 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we do not extract freeze instructions, since extra handling is
; required to mark any outputs used with freeze.
define void @function1(ptr %a, ptr %b) {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[C:%.*]] = freeze ptr [[A:%.*]]
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[C]], ptr [[B:%.*]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: br label [[FIRST]]
;
entry:
br label %first
first:
%c = freeze ptr %a
store i32 2, ptr %c, align 4
store i32 3, ptr %b, align 4
ret void
next:
br label %first
}
define void @function2(ptr %a, ptr %b) {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[C:%.*]] = freeze ptr [[A:%.*]]
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[C]], ptr [[B:%.*]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: br label [[FIRST]]
;
entry:
br label %first
first:
%c = freeze ptr %a
store i32 2, ptr %c, align 4
store i32 3, ptr %b, align 4
ret void
next:
br label %first
}

View file

@ -1,58 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost --no-ir-sim-indirect-calls < %s | FileCheck %s
; This test checks that we do not outline indirect calls when it is specified
; that we should not.
declare void @f1(ptr, ptr);
declare void @f2(ptr, ptr);
define void @function1(ptr %func) {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: call void [[FUNC:%.*]]()
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void %func()
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function2(ptr %func) {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: call void [[FUNC:%.*]]()
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void %func()
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}

View file

@ -1,64 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that invoke instructions are not outlined even if they
; in a similar section. Outlining does not currently handle control flow
; changes.
declare void @llvm.donothing() nounwind readnone
define void @function1() personality i8 3 {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CLEANUP:%.*]] = landingpad i8
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%cleanup = landingpad i8 cleanup
br label %normal
normal:
ret void
}
define void @function2() personality i8 3 {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CLEANUP:%.*]] = landingpad i8
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%cleanup = landingpad i8 cleanup
br label %normal
normal:
ret void
}

View file

@ -1,64 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -no-ir-sim-branch-matching -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that landingpad instructions are not outlined even if they
; in a similar section. Dealing with exception handling inside of an outlined
; function would require a lot of handling that is not implemented yet.
declare void @llvm.donothing() nounwind readnone
define void @function1() personality i8 3 {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CLEANUP:%.*]] = landingpad i8
; CHECK-NEXT: cleanup
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%cleanup = landingpad i8 cleanup
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
br label %normal
normal:
ret void
}
define void @function2() personality i8 3 {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CLEANUP:%.*]] = landingpad i8
; CHECK-NEXT: cleanup
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
invoke void @llvm.donothing() to label %normal unwind label %exception
exception:
%cleanup = landingpad i8 cleanup
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
br label %normal
normal:
ret void
}

View file

@ -1,65 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost -no-ir-sim-intrinsics < %s | FileCheck %s
; This test checks that we do not outline memcpy intrinsics since it may require
; extra address space checks.
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)
define i8 @function1(ptr noalias %s, ptr noalias %d, i64 %len) {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[A_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[S:%.*]], ptr [[D:%.*]], ptr [[A_LOC]], ptr [[B_LOC]])
; CHECK-NEXT: [[A_RELOAD:%.*]] = load i8, ptr [[A_LOC]], align 1
; CHECK-NEXT: [[B_RELOAD:%.*]] = load i8, ptr [[B_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[D]], ptr [[S]], i64 [[LEN:%.*]], i1 false)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i8 [[A_RELOAD]], i8 [[B_RELOAD]], ptr [[S]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memcpy.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
define i8 @function2(ptr noalias %s, ptr noalias %d, i64 %len) {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[A_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[S:%.*]], ptr [[D:%.*]], ptr [[A_LOC]], ptr [[B_LOC]])
; CHECK-NEXT: [[A_RELOAD:%.*]] = load i8, ptr [[A_LOC]], align 1
; CHECK-NEXT: [[B_RELOAD:%.*]] = load i8, ptr [[B_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[D]], ptr [[S]], i64 [[LEN:%.*]], i1 false)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i8 [[A_RELOAD]], i8 [[B_RELOAD]], ptr [[S]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memcpy.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}

View file

@ -1,65 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost -no-ir-sim-intrinsics < %s | FileCheck %s
; This test checks that we do not outline memcpy intrinsics since it may require
; extra address space checks.
declare void @llvm.memmove.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)
define i8 @function1(ptr noalias %s, ptr noalias %d, i64 %len) {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[A_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[S:%.*]], ptr [[D:%.*]], ptr [[A_LOC]], ptr [[B_LOC]])
; CHECK-NEXT: [[A_RELOAD:%.*]] = load i8, ptr [[A_LOC]], align 1
; CHECK-NEXT: [[B_RELOAD:%.*]] = load i8, ptr [[B_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[D]], ptr [[S]], i64 [[LEN:%.*]], i1 false)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i8 [[A_RELOAD]], i8 [[B_RELOAD]], ptr [[S]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memmove.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
define i8 @function2(ptr noalias %s, ptr noalias %d, i64 %len) {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[A_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[S:%.*]], ptr [[D:%.*]], ptr [[A_LOC]], ptr [[B_LOC]])
; CHECK-NEXT: [[A_RELOAD:%.*]] = load i8, ptr [[A_LOC]], align 1
; CHECK-NEXT: [[B_RELOAD:%.*]] = load i8, ptr [[B_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B_LOC]])
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[D]], ptr [[S]], i64 [[LEN:%.*]], i1 false)
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i8 [[A_RELOAD]], i8 [[B_RELOAD]], ptr [[S]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memmove.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}

View file

@ -1,41 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost -no-ir-sim-intrinsics < %s | FileCheck %s
; This test checks that we do not outline memset intrinsics since it requires
; extra address space checks.
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i32, i1)
define i64 @function1(i64 %x, i64 %z, i64 %n) {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[POOL:%.*]] = alloca [59 x i64], align 4
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr nonnull align 4 [[POOL]], i8 0, i64 236, i1 false)
; CHECK-NEXT: call void @outlined_ir_func_0(i64 [[N:%.*]], i64 [[X:%.*]], i64 [[Z:%.*]])
; CHECK-NEXT: ret i64 0
;
entry:
%pool = alloca [59 x i64], align 4
call void @llvm.memset.p0.i64(ptr nonnull %pool, i8 0, i64 236, i32 4, i1 false)
%cmp3 = icmp eq i64 %n, 0
%a = add i64 %x, %z
%c = add i64 %x, %z
ret i64 0
}
define i64 @function2(i64 %x, i64 %z, i64 %n) {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[POOL:%.*]] = alloca [59 x i64], align 4
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr nonnull align 4 [[POOL]], i8 0, i64 236, i1 false)
; CHECK-NEXT: call void @outlined_ir_func_0(i64 [[N:%.*]], i64 [[X:%.*]], i64 [[Z:%.*]])
; CHECK-NEXT: ret i64 0
;
entry:
%pool = alloca [59 x i64], align 4
call void @llvm.memset.p0.i64(ptr nonnull %pool, i8 0, i64 236, i32 4, i1 false)
%cmp3 = icmp eq i64 %n, 0
%a = add i64 %x, %z
%c = add i64 %x, %z
ret i64 0
}

View file

@ -1,104 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs --version 6
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Verify that the IR outliner refuses to outline regions that contain
; callsites marked with `nomerge`.
declare void @f1(ptr, ptr);
declare void @f2(ptr, ptr);
define void @function1() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f1(ptr %a, ptr %b) nomerge
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function2() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f1(ptr %a, ptr %b) nomerge
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function3() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f2(ptr %a, ptr %b) nomerge
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK-LABEL: define void @function1() {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: call void @f1(ptr [[A]], ptr [[B]]) #[[ATTR1:[0-9]+]]
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define void @function2() {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: call void @f1(ptr [[A]], ptr [[B]]) #[[ATTR1]]
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define void @function3() {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: call void @f2(ptr [[A]], ptr [[B]]) #[[ATTR1]]
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-SAME: ptr [[TMP0:%.*]], ptr [[TMP1:%.*]], ptr [[TMP2:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[NEWFUNCROOT:.*:]]
; CHECK-NEXT: br label %[[ENTRY_TO_OUTLINE:.*]]
; CHECK: [[ENTRY_TO_OUTLINE]]:
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK-NEXT: br label %[[ENTRY_AFTER_OUTLINE_EXITSTUB:.*]]
; CHECK: [[ENTRY_AFTER_OUTLINE_EXITSTUB]]:
; CHECK-NEXT: ret void
;

View file

@ -1,49 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we do not extract phi nodes as it would require extra label and
; control flow checking.
define void @function1(ptr %a, ptr %b) {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 3, [[NEXT:%.*]] ]
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A:%.*]], ptr [[B:%.*]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: br label [[FIRST]]
;
entry:
br label %first
first:
%0 = phi i32 [ 0, %entry ], [ 3, %next ]
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
ret void
next:
br label %first
}
define void @function2(ptr %a, ptr %b) {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 3, [[NEXT:%.*]] ]
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A:%.*]], ptr [[B:%.*]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: br label [[FIRST]]
;
entry:
br label %first
first:
%0 = phi i32 [ 0, %entry ], [ 3, %next ]
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
ret void
next:
br label %first
}

View file

@ -1,66 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we do not outline functions that are marked as returns
; twice, since these can alter the frame of the function and affect how the
; outliner behaves, causing miscompiles.
; Function Attrs: optsize returns_twice
declare i32 @setjmp(ptr) local_unnamed_addr #1
@tmp_jmpb = global [37 x i32] zeroinitializer, align 16
define void @function1() {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: [[CALL:%.*]] = call i32 @setjmp(ptr @tmp_jmpb)
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%call = call i32 @setjmp(ptr @tmp_jmpb)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function2() {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: [[CALL:%.*]] = call i32 @setjmp(ptr @tmp_jmpb)
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%call = call i32 @setjmp(ptr @tmp_jmpb)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
attributes #1 = { optsize returns_twice }

View file

@ -1,127 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs --version 6
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost -no-ir-sim-intrinsics=0 < %s | FileCheck %s
; Verify that @llvm.eh.typeid.for is not outlined
%C6object9ClassInfo = type { ptr, ptr }
%C6object9ClassInfo__vtbl = type { ptr }
@C6object9ClassInfo__ClassInfo = linkonce_odr constant %C6object9ClassInfo { ptr @C6object9ClassInfo__vtblZ, ptr @C6object8TypeInfo__ClassInfo }
@C6object9ClassInfo__vtblZ = linkonce_odr constant %C6object9ClassInfo__vtbl { ptr @C6object9ClassInfo__ClassInfo }
@C6object8TypeInfo__ClassInfo = linkonce_odr constant %C6object9ClassInfo { ptr @C6object9ClassInfo__vtblZ, ptr @C6object6Object__ClassInfo }
@C6object6Object__ClassInfo = linkonce_odr constant %C6object9ClassInfo { ptr @C6object9ClassInfo__vtblZ, ptr @C6object6Object__ClassInfo }
@C6object9Throwable__ClassInfo = linkonce_odr constant %C6object9ClassInfo { ptr @C6object9ClassInfo__vtblZ, ptr @C6object6Object__ClassInfo }
declare i32 @__sd_eh_personality(i32, i32, i64, ptr, ptr)
declare void @test2(ptr)
declare void @test3(ptr)
declare void @test4(ptr)
define i32 @test1(ptr %arg0) personality ptr @__sd_eh_personality {
body:
invoke void @test2(ptr %arg0) to label %then1 unwind label %lpad1
then1:
invoke void @test3(ptr %arg0) to label %then2 unwind label %lpad2
then2:
invoke void @test4(ptr %arg0) to label %then3 unwind label %lpad3
then3:
ret i32 0
unwind:
%0 = phi { ptr, i32 } [ %1, %lpad1 ], [ %5, %lpad2 ], [ %9, %lpad3 ]
resume { ptr, i32 } %0
lpad1:
%1 = landingpad { ptr, i32 } cleanup catch ptr @C6object9Throwable__ClassInfo
%2 = extractvalue { ptr, i32 } %1, 1
%3 = call i32 @llvm.eh.typeid.for(ptr nonnull @C6object9Throwable__ClassInfo)
%4 = icmp eq i32 %3, %2
br i1 %4, label %catch1, label %unwind
catch1:
ret i32 1
lpad2:
%5 = landingpad { ptr, i32 } cleanup catch ptr @C6object9Throwable__ClassInfo
%6 = extractvalue { ptr, i32 } %5, 1
%7 = call i32 @llvm.eh.typeid.for(ptr nonnull @C6object9Throwable__ClassInfo)
%8 = icmp eq i32 %7, %6
br i1 %8, label %catch2, label %unwind
catch2:
ret i32 2
lpad3:
%9 = landingpad { ptr, i32 } cleanup catch ptr @C6object9Throwable__ClassInfo
%10 = extractvalue { ptr, i32 } %9, 1
%11 = call i32 @llvm.eh.typeid.for(ptr nonnull @C6object9Throwable__ClassInfo)
%12 = icmp eq i32 %11, %10
br i1 %12, label %catch2, label %unwind
catch3:
ret i32 3
}
; CHECK-LABEL: define i32 @test1(
; CHECK-SAME: ptr [[ARG0:%.*]]) personality ptr @__sd_eh_personality {
; CHECK-NEXT: [[BODY:.*:]]
; CHECK-NEXT: invoke void @test2(ptr [[ARG0]])
; CHECK-NEXT: to label %[[THEN1:.*]] unwind label %[[LPAD1:.*]]
; CHECK: [[THEN1]]:
; CHECK-NEXT: invoke void @test3(ptr [[ARG0]])
; CHECK-NEXT: to label %[[THEN2:.*]] unwind label %[[LPAD2:.*]]
; CHECK: [[THEN2]]:
; CHECK-NEXT: invoke void @test4(ptr [[ARG0]])
; CHECK-NEXT: to label %[[THEN3:.*]] unwind label %[[UNWIND2:.*]]
; CHECK: [[THEN3]]:
; CHECK-NEXT: ret i32 0
; CHECK: [[UNWIND1:.*]]:
; CHECK-NEXT: [[TMP6:%.*]] = phi { ptr, i32 } [ [[TMP0:%.*]], %[[LPAD1]] ], [ [[TMP3:%.*]], %[[LPAD2]] ], [ [[TMP7:%.*]], %[[UNWIND2]] ]
; CHECK-NEXT: resume { ptr, i32 } [[TMP6]]
; CHECK: [[LPAD1]]:
; CHECK-NEXT: [[TMP0]] = landingpad { ptr, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch ptr @C6object9Throwable__ClassInfo
; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.eh.typeid.for.p0(ptr nonnull @C6object9Throwable__ClassInfo)
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(i32 [[TMP2]], i32 [[TMP1]])
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label %[[CATCH1:.*]], label %[[UNWIND1]]
; CHECK: [[CATCH1]]:
; CHECK-NEXT: ret i32 1
; CHECK: [[LPAD2]]:
; CHECK-NEXT: [[TMP3]] = landingpad { ptr, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch ptr @C6object9Throwable__ClassInfo
; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 1
; CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.eh.typeid.for.p0(ptr nonnull @C6object9Throwable__ClassInfo)
; CHECK-NEXT: [[TARGETBLOCK1:%.*]] = call i1 @outlined_ir_func_0(i32 [[TMP5]], i32 [[TMP4]])
; CHECK-NEXT: br i1 [[TARGETBLOCK1]], label %[[CATCH2:.*]], label %[[UNWIND1]]
; CHECK: [[CATCH2]]:
; CHECK-NEXT: ret i32 2
; CHECK: [[UNWIND2]]:
; CHECK-NEXT: [[TMP7]] = landingpad { ptr, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch ptr @C6object9Throwable__ClassInfo
; CHECK-NEXT: [[TMP8:%.*]] = extractvalue { ptr, i32 } [[TMP7]], 1
; CHECK-NEXT: [[TMP9:%.*]] = call i32 @llvm.eh.typeid.for.p0(ptr nonnull @C6object9Throwable__ClassInfo)
; CHECK-NEXT: [[TARGETBLOCK2:%.*]] = call i1 @outlined_ir_func_0(i32 [[TMP9]], i32 [[TMP8]])
; CHECK-NEXT: br i1 [[TARGETBLOCK2]], label %[[CATCH2]], label %[[UNWIND1]]
; CHECK: [[CATCH3:.*:]]
; CHECK-NEXT: ret i32 3
;
;
; CHECK-LABEL: define internal i1 @outlined_ir_func_0(
; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: [[NEWFUNCROOT:.*:]]
; CHECK-NEXT: br label %[[LPAD1_TO_OUTLINE:.*]]
; CHECK: [[LPAD1_TO_OUTLINE]]:
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: br i1 [[TMP2]], label %[[CATCH1_EXITSTUB:.*]], label %[[UNWIND1_EXITSTUB:.*]]
; CHECK: [[CATCH1_EXITSTUB]]:
; CHECK-NEXT: ret i1 true
; CHECK: [[UNWIND1_EXITSTUB]]:
; CHECK-NEXT: ret i1 false
;

View file

@ -1,79 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost -no-ir-sim-intrinsics < %s | FileCheck %s
; This test ensures that we do not outline vararg instructions or intrinsics, as
; they may cause inconsistencies when outlining.
declare void @llvm.va_start(ptr)
declare void @llvm.va_copy(ptr, ptr)
declare void @llvm.va_end(ptr)
define i32 @func1(i32 %a, double %b, ptr %v, ...) nounwind {
; CHECK-LABEL: @func1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B_ADDR:%.*]] = alloca double, align 8
; CHECK-NEXT: [[AP:%.*]] = alloca ptr, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[A:%.*]], ptr [[A_ADDR]], double [[B:%.*]], ptr [[B_ADDR]])
; CHECK-NEXT: call void @llvm.va_start.p0(ptr [[AP]])
; CHECK-NEXT: [[TMP0:%.*]] = va_arg ptr [[AP]], i32
; CHECK-NEXT: call void @llvm.va_copy.p0(ptr [[V:%.*]], ptr [[AP]])
; CHECK-NEXT: call void @llvm.va_end.p0(ptr [[AP]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[TMP_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[TMP0]], ptr [[C]], ptr [[TMP_LOC]])
; CHECK-NEXT: [[TMP_RELOAD:%.*]] = load i32, ptr [[TMP_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[TMP_LOC]])
; CHECK-NEXT: ret i32 [[TMP_RELOAD]]
;
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca double, align 8
%ap = alloca ptr, align 4
%c = alloca i32, align 4
store i32 %a, ptr %a.addr, align 4
store double %b, ptr %b.addr, align 8
call void @llvm.va_start(ptr %ap)
%0 = va_arg ptr %ap, i32
call void @llvm.va_copy(ptr %v, ptr %ap)
call void @llvm.va_end(ptr %ap)
store i32 %0, ptr %c, align 4
%tmp = load i32, ptr %c, align 4
ret i32 %tmp
}
define i32 @func2(i32 %a, double %b, ptr %v, ...) nounwind {
; CHECK-LABEL: @func2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B_ADDR:%.*]] = alloca double, align 8
; CHECK-NEXT: [[AP:%.*]] = alloca ptr, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[A:%.*]], ptr [[A_ADDR]], double [[B:%.*]], ptr [[B_ADDR]])
; CHECK-NEXT: call void @llvm.va_start.p0(ptr [[AP]])
; CHECK-NEXT: [[TMP0:%.*]] = va_arg ptr [[AP]], i32
; CHECK-NEXT: call void @llvm.va_copy.p0(ptr [[V:%.*]], ptr [[AP]])
; CHECK-NEXT: call void @llvm.va_end.p0(ptr [[AP]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[TMP_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[TMP0]], ptr [[C]], ptr [[TMP_LOC]])
; CHECK-NEXT: [[TMP_RELOAD:%.*]] = load i32, ptr [[TMP_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[TMP_LOC]])
; CHECK-NEXT: ret i32 [[TMP_RELOAD]]
;
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca double, align 8
%ap = alloca ptr, align 4
%c = alloca i32, align 4
store i32 %a, ptr %a.addr, align 4
store double %b, ptr %b.addr, align 8
call void @llvm.va_start(ptr %ap)
%0 = va_arg ptr %ap, i32
call void @llvm.va_copy(ptr %v, ptr %ap)
call void @llvm.va_end(ptr %ap)
store i32 %0, ptr %c, align 4
%tmp = load i32, ptr %c, align 4
ret i32 %tmp
}

View file

@ -1,93 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we are able to outline when all of the phi nodes in the starting
; block are included in the region and there is no more than one predecessor
; into those phi nodes from outside of the region.
define void @function1(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
%y = add i32 %c, %c
br label %test1
dummy:
ret void
test1:
%1 = phi i32 [ %e, %test1 ], [ %y, %entry ]
%2 = phi i32 [ %e, %test1 ], [ %y, %entry ]
%e = load i32, ptr %0, align 4
%3 = add i32 %c, %c
br i1 true, label %test, label %test1
test:
%d = load i32, ptr %0, align 4
br label %first
first:
ret void
}
define void @function2(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
%y = mul i32 %c, %c
br label %test1
dummy:
ret void
test1:
%1 = phi i32 [ %e, %test1 ], [ %y, %entry ]
%2 = phi i32 [ %e, %test1 ], [ %y, %entry ]
%e = load i32, ptr %0, align 4
%3 = add i32 %c, %c
br i1 true, label %test, label %test1
test:
%d = load i32, ptr %0, align 4
br label %first
first:
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[Y:%.*]] = add i32 [[C]], [[C]]
; CHECK-NEXT: br label [[TEST1:%.*]]
; CHECK: dummy:
; CHECK-NEXT: ret void
; CHECK: test1:
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[Y]], ptr [[TMP0]], i32 [[C]])
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[Y:%.*]] = mul i32 [[C]], [[C]]
; CHECK-NEXT: br label [[TEST1:%.*]]
; CHECK: dummy:
; CHECK-NEXT: ret void
; CHECK: test1:
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[Y]], ptr [[TMP0]], i32 [[C]])
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: ret void
;
;
; CHECK: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[TEST1_TO_OUTLINE:%.*]]
; CHECK: test1_to_outline:
; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[E:%.*]], [[TEST1_TO_OUTLINE]] ], [ [[TMP0:%.*]], [[NEWFUNCROOT:%.*]] ]
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ [[E]], [[TEST1_TO_OUTLINE]] ], [ [[TMP0]], [[NEWFUNCROOT]] ]
; CHECK-NEXT: [[E]] = load i32, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP2:%.*]], [[TMP2]]
; CHECK-NEXT: br i1 true, label [[TEST:%.*]], label [[TEST1_TO_OUTLINE]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: br label [[FIRST_EXITSTUB:%.*]]
; CHECK: first.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,94 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we are able to propagate inputs to the region into the split PHINode
; outside of the region if necessary.
define void @function1(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
%z = add i32 %c, %c
br i1 true, label %test1, label %first
test1:
%e = load i32, ptr %0, align 4
%1 = add i32 %c, %c
br i1 true, label %first, label %test
test:
%d = load i32, ptr %0, align 4
br i1 true, label %first, label %next
first:
%2 = phi i32 [ %d, %test ], [ %e, %test1 ], [ %c, %entry ]
%3 = phi i32 [ %d, %test ], [ %e, %test1 ], [ %c, %entry ]
ret void
next:
ret void
}
define void @function2(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
%z = mul i32 %c, %c
br i1 true, label %test1, label %first
test1:
%e = load i32, ptr %0, align 4
%1 = add i32 %c, %c
br i1 true, label %first, label %test
test:
%d = load i32, ptr %0, align 4
br i1 true, label %first, label %next
first:
%2 = phi i32 [ %d, %test ], [ %e, %test1 ], [ %c, %entry ]
%3 = phi i32 [ %d, %test ], [ %e, %test1 ], [ %c, %entry ]
ret void
next:
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[Z:%.*]] = add i32 [[C]], [[C]]
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(ptr [[TMP0]], i32 [[C]])
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[NEXT:%.*]], label [[ENTRY_AFTER_OUTLINE:%.*]]
; CHECK: entry_after_outline:
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[Z:%.*]] = mul i32 [[C]], [[C]]
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(ptr [[TMP0]], i32 [[C]])
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[NEXT:%.*]], label [[ENTRY_AFTER_OUTLINE:%.*]]
; CHECK: entry_after_outline:
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: ret void
;
;
; CHECK: define internal i1 @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: br i1 true, label [[TEST1:%.*]], label [[FIRST:%.*]]
; CHECK: test1:
; CHECK-NEXT: [[E:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1:%.*]], [[TMP1]]
; CHECK-NEXT: br i1 true, label [[FIRST]], label [[TEST:%.*]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br i1 true, label [[FIRST]], label [[NEXT_EXITSTUB:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[D]], [[TEST]] ], [ [[E]], [[TEST1]] ], [ [[TMP1]], [[ENTRY_TO_OUTLINE]] ]
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ [[D]], [[TEST]] ], [ [[E]], [[TEST1]] ], [ [[TMP1]], [[ENTRY_TO_OUTLINE]] ]
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: next.exitStub:
; CHECK-NEXT: ret i1 true
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret i1 false
;

View file

@ -1,139 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that debug info is recognized as able to be extracted along
; with the other instructions, but is not included in the consolidated function.
define void @function1() !dbg !6 {
entry:
%a = alloca i32, align 4, !dbg !17
call void @llvm.dbg.value(metadata ptr %a, metadata !9, metadata !DIExpression()), !dbg !17
%b = alloca i32, align 4, !dbg !18
call void @llvm.dbg.value(metadata ptr %b, metadata !11, metadata !DIExpression()), !dbg !18
%c = alloca i32, align 4, !dbg !19
call void @llvm.dbg.value(metadata ptr %c, metadata !12, metadata !DIExpression()), !dbg !19
store i32 2, ptr %a, align 4, !dbg !20
store i32 3, ptr %b, align 4, !dbg !21
store i32 4, ptr %c, align 4, !dbg !22
%al = load i32, ptr %a, align 4, !dbg !23
call void @llvm.dbg.value(metadata i32 %al, metadata !13, metadata !DIExpression()), !dbg !23
%bl = load i32, ptr %b, align 4, !dbg !24
call void @llvm.dbg.value(metadata i32 %bl, metadata !15, metadata !DIExpression()), !dbg !24
%cl = load i32, ptr %c, align 4, !dbg !25
call void @llvm.dbg.value(metadata i32 %cl, metadata !16, metadata !DIExpression()), !dbg !25
ret void, !dbg !26
}
define void @function2() !dbg !27 {
entry:
%a = alloca i32, align 4, !dbg !35
call void @llvm.dbg.value(metadata ptr %a, metadata !29, metadata !DIExpression()), !dbg !35
%b = alloca i32, align 4, !dbg !36
call void @llvm.dbg.value(metadata ptr %b, metadata !30, metadata !DIExpression()), !dbg !36
%c = alloca i32, align 4, !dbg !37
call void @llvm.dbg.value(metadata ptr %c, metadata !31, metadata !DIExpression()), !dbg !37
store i32 2, ptr %a, align 4, !dbg !38
store i32 3, ptr %b, align 4, !dbg !39
store i32 4, ptr %c, align 4, !dbg !40
%al = load i32, ptr %a, align 4, !dbg !41
call void @llvm.dbg.value(metadata i32 %al, metadata !32, metadata !DIExpression()), !dbg !41
%bl = load i32, ptr %b, align 4, !dbg !42
call void @llvm.dbg.value(metadata i32 %bl, metadata !33, metadata !DIExpression()), !dbg !42
%cl = load i32, ptr %c, align 4, !dbg !43
call void @llvm.dbg.value(metadata i32 %cl, metadata !34, metadata !DIExpression()), !dbg !43
ret void, !dbg !44
}
; Function Attrs: nounwind readnone speculatable willreturn
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
attributes #0 = { nounwind readnone speculatable willreturn }
!llvm.dbg.cu = !{!0}
!llvm.debugify = !{!3, !4}
!llvm.module.flags = !{!5}
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "legal-debug.ll", directory: "/")
!2 = !{}
!3 = !{i32 20}
!4 = !{i32 12}
!5 = !{i32 2, !"Debug Info Version", i32 3}
!6 = distinct !DISubprogram(name: "function1", linkageName: "function1", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
!7 = !DISubroutineType(types: !2)
!8 = !{!9, !11, !12, !13, !15, !16}
!9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
!10 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_unsigned)
!11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !10)
!12 = !DILocalVariable(name: "3", scope: !6, file: !1, line: 3, type: !10)
!13 = !DILocalVariable(name: "4", scope: !6, file: !1, line: 7, type: !14)
!14 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
!15 = !DILocalVariable(name: "5", scope: !6, file: !1, line: 8, type: !14)
!16 = !DILocalVariable(name: "6", scope: !6, file: !1, line: 9, type: !14)
!17 = !DILocation(line: 1, column: 1, scope: !6)
!18 = !DILocation(line: 2, column: 1, scope: !6)
!19 = !DILocation(line: 3, column: 1, scope: !6)
!20 = !DILocation(line: 4, column: 1, scope: !6)
!21 = !DILocation(line: 5, column: 1, scope: !6)
!22 = !DILocation(line: 6, column: 1, scope: !6)
!23 = !DILocation(line: 7, column: 1, scope: !6)
!24 = !DILocation(line: 8, column: 1, scope: !6)
!25 = !DILocation(line: 9, column: 1, scope: !6)
!26 = !DILocation(line: 10, column: 1, scope: !6)
!27 = distinct !DISubprogram(name: "function2", linkageName: "function2", scope: null, file: !1, line: 11, type: !7, scopeLine: 11, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !28)
!28 = !{!29, !30, !31, !32, !33, !34}
!29 = !DILocalVariable(name: "7", scope: !27, file: !1, line: 11, type: !10)
!30 = !DILocalVariable(name: "8", scope: !27, file: !1, line: 12, type: !10)
!31 = !DILocalVariable(name: "9", scope: !27, file: !1, line: 13, type: !10)
!32 = !DILocalVariable(name: "10", scope: !27, file: !1, line: 17, type: !14)
!33 = !DILocalVariable(name: "11", scope: !27, file: !1, line: 18, type: !14)
!34 = !DILocalVariable(name: "12", scope: !27, file: !1, line: 19, type: !14)
!35 = !DILocation(line: 11, column: 1, scope: !27)
!36 = !DILocation(line: 12, column: 1, scope: !27)
!37 = !DILocation(line: 13, column: 1, scope: !27)
!38 = !DILocation(line: 14, column: 1, scope: !27)
!39 = !DILocation(line: 15, column: 1, scope: !27)
!40 = !DILocation(line: 16, column: 1, scope: !27)
!41 = !DILocation(line: 17, column: 1, scope: !27)
!42 = !DILocation(line: 18, column: 1, scope: !27)
!43 = !DILocation(line: 19, column: 1, scope: !27)
!44 = !DILocation(line: 20, column: 1, scope: !27)
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4, !dbg [[DBG17:![0-9]+]]
; CHECK-NEXT: #dbg_value(ptr [[A]], [[META9:![0-9]+]], !DIExpression(), [[DBG17]])
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4, !dbg [[DBG18:![0-9]+]]
; CHECK-NEXT: #dbg_value(ptr [[B]], [[META11:![0-9]+]], !DIExpression(), [[DBG18]])
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4, !dbg [[DBG19:![0-9]+]]
; CHECK-NEXT: #dbg_value(ptr [[C]], [[META12:![0-9]+]], !DIExpression(), [[DBG19]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]]), !dbg [[DBG20:![0-9]+]]
; CHECK-NEXT: ret void, !dbg [[DBG21:![0-9]+]]
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4, !dbg [[DBG30:![0-9]+]]
; CHECK-NEXT: #dbg_value(ptr [[A]], [[META24:![0-9]+]], !DIExpression(), [[DBG30]])
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4, !dbg [[DBG31:![0-9]+]]
; CHECK-NEXT: #dbg_value(ptr [[B]], [[META25:![0-9]+]], !DIExpression(), [[DBG31]])
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4, !dbg [[DBG32:![0-9]+]]
; CHECK-NEXT: #dbg_value(ptr [[C]], [[META26:![0-9]+]], !DIExpression(), [[DBG32]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]]), !dbg [[DBG33:![0-9]+]]
; CHECK-NEXT: ret void, !dbg [[DBG34:![0-9]+]]
;
;
; CHECK-LABEL: define {{.+}} @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: store i32 3, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: store i32 4, ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,71 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we do outline indirect calls when it is not specified
; that we should not.
declare void @f1(ptr, ptr);
declare void @f2(ptr, ptr);
define void @function1(ptr %func) {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void %func()
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function2(ptr %func) {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void %func()
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]], ptr [[FUNC:%.*]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]], ptr [[FUNC:%.*]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: store i32 3, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: store i32 4, ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: call void [[TMP3:%.*]]()
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,84 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we are able to extract blocks that contain PHINodes, and selectively
; store into it's respective block, creating a new block if needed.
define void @function1(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br label %first
test:
%d = load i32, ptr %0, align 4
br label %first
first:
ret void
}
define void @function2(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br label %first
test:
%d = load i32, ptr %0, align 4
br label %first
first:
%1 = phi i32 [ %c, %test ], [ %e, %test1 ]
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[TMP0]], ptr null, i32 -1)
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTCE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[TMP0]], ptr [[DOTCE_LOC]], i32 0)
; CHECK-NEXT: [[DOTCE_RELOAD:%.*]] = load i32, ptr [[DOTCE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[DOTCE_RELOAD]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[TEST1:%.*]]
; CHECK: test1:
; CHECK-NEXT: [[E:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br label [[PHI_BLOCK:%.*]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br label [[PHI_BLOCK]]
; CHECK: first.exitStub:
; CHECK-NEXT: switch i32 [[TMP2:%.*]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_1_0:
; CHECK-NEXT: store i32 [[TMP3:%.*]], ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: phi_block:
; CHECK-NEXT: [[TMP3]] = phi i32 [ [[C]], [[TEST:%.*]] ], [ [[E]], [[TEST1]] ]
; CHECK-NEXT: br label [[FIRST_EXITSTUB:%.*]]
; CHECK: final_block_0:
; CHECK-NEXT: ret void
;

View file

@ -1,84 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we are able to extract blocks that contain PHINodes, and selectively
; store into it's respective block, only using if needed.
define void @function1(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br label %first
test:
%d = load i32, ptr %0, align 4
br label %first
first:
%1 = phi i32 [ %c, %test ], [ %e, %test1 ]
ret void
}
define void @function2(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br label %first
test:
%d = load i32, ptr %0, align 4
br label %first
first:
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTCE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[TMP0]], ptr [[DOTCE_LOC]], i32 0)
; CHECK-NEXT: [[DOTCE_RELOAD:%.*]] = load i32, ptr [[DOTCE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[DOTCE_RELOAD]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[TMP0]], ptr null, i32 -1)
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[TEST1:%.*]]
; CHECK: test1:
; CHECK-NEXT: [[E:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br label [[FIRST_SPLIT:%.*]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br label [[FIRST_SPLIT]]
; CHECK: first.split:
; CHECK-NEXT: [[DOTCE:%.*]] = phi i32 [ [[C]], [[TEST:%.*]] ], [ [[E]], [[TEST1]] ]
; CHECK-NEXT: br label [[FIRST_EXITSTUB:%.*]]
; CHECK: first.exitStub:
; CHECK-NEXT: switch i32 [[TMP2:%.*]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_0_0:
; CHECK-NEXT: store i32 [[DOTCE]], ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: final_block_0:
; CHECK-NEXT: ret void
;

View file

@ -1,145 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we do not extract similar regions that would involve the splitting
; of phi nodes on exit.
define void @function1(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br i1 true, label %first, label %test
test:
%d = load i32, ptr %0, align 4
br i1 true, label %first, label %next
first:
%1 = phi i32 [ %c, %test ], [ %e, %test1 ]
ret void
next:
%2 = add i32 %d, 1
%3 = add i32 %e, 1
ret void
}
define void @function2(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br i1 true, label %first, label %test
test:
%d = load i32, ptr %0, align 4
br i1 true, label %first, label %next
first:
ret void
next:
%1 = add i32 %d, 1
%2 = add i32 %e, 1
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTCE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[D_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[E_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[E_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[D_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: [[TMP1:%.*]] = call i1 @outlined_ir_func_0(ptr [[TMP0]], ptr [[E_LOC]], ptr [[D_LOC]], ptr [[DOTCE_LOC]], i32 0)
; CHECK-NEXT: [[E_RELOAD:%.*]] = load i32, ptr [[E_LOC]], align 4
; CHECK-NEXT: [[D_RELOAD:%.*]] = load i32, ptr [[D_LOC]], align 4
; CHECK-NEXT: [[DOTCE_RELOAD:%.*]] = load i32, ptr [[DOTCE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[E_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[D_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: br i1 [[TMP1]], label [[FIRST:%.*]], label [[NEXT:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[DOTCE_RELOAD]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[D_RELOAD]], i32 [[E_RELOAD]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[D_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[E_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[E_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[D_LOC]])
; CHECK-NEXT: [[TMP1:%.*]] = call i1 @outlined_ir_func_0(ptr [[TMP0]], ptr [[E_LOC]], ptr [[D_LOC]], ptr null, i32 1)
; CHECK-NEXT: [[E_RELOAD:%.*]] = load i32, ptr [[E_LOC]], align 4
; CHECK-NEXT: [[D_RELOAD:%.*]] = load i32, ptr [[D_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[E_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[D_LOC]])
; CHECK-NEXT: br i1 [[TMP1]], label [[FIRST:%.*]], label [[NEXT:%.*]]
; CHECK: first:
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[D_RELOAD]], i32 [[E_RELOAD]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal i1 @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[TEST1:%.*]]
; CHECK: test1:
; CHECK-NEXT: [[E:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br i1 true, label [[FIRST_SPLIT:%.*]], label [[TEST:%.*]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br i1 true, label [[FIRST_SPLIT]], label [[NEXT_EXITSTUB:%.*]]
; CHECK: first.split:
; CHECK-NEXT: [[DOTCE:%.*]] = phi i32 [ [[C]], [[TEST]] ], [ [[E]], [[TEST1]] ]
; CHECK-NEXT: br label [[FIRST_EXITSTUB:%.*]]
; CHECK: first.exitStub:
; CHECK-NEXT: switch i32 [[TMP4:%.*]], label [[FINAL_BLOCK_1:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_1:%.*]]
; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_1:%.*]]
; CHECK-NEXT: ]
; CHECK: next.exitStub:
; CHECK-NEXT: switch i32 [[TMP4]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_0:%.*]]
; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_0_0:
; CHECK-NEXT: store i32 [[E]], ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: store i32 [[D]], ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: output_block_0_1:
; CHECK-NEXT: store i32 [[E]], ptr [[TMP1]], align 4
; CHECK-NEXT: store i32 [[DOTCE]], ptr [[TMP3:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: output_block_1_0:
; CHECK-NEXT: store i32 [[E]], ptr [[TMP1]], align 4
; CHECK-NEXT: store i32 [[D]], ptr [[TMP2]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: output_block_1_1:
; CHECK-NEXT: store i32 [[E]], ptr [[TMP1]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: final_block_0:
; CHECK-NEXT: ret i1 false
; CHECK: final_block_1:
; CHECK-NEXT: ret i1 true
;
;
; CHECK-LABEL: @outlined_ir_func_1(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[NEXT_TO_OUTLINE:%.*]]
; CHECK: next_to_outline:
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP0:%.*]], 1
; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP1:%.*]], 1
; CHECK-NEXT: br label [[NEXT_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: next_after_outline.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,106 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we do not outline when all of the phi nodes in the beginning
; block are included not in the region.
define void @function1(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
%y = add i32 %c, %c
br label %test1
dummy:
ret void
test1:
%1 = phi i32 [ %e, %test1 ], [ %y, %entry ]
%2 = phi i32 [ %e, %test1 ], [ %y, %entry ]
%e = load i32, ptr %0, align 4
%3 = add i32 %c, %c
br i1 true, label %test, label %test1
test:
%d = load i32, ptr %0, align 4
br label %first
first:
ret void
}
define void @function2(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
%y = mul i32 %c, %c
br label %test1
dummy:
ret void
test1:
%1 = phi i32 [ %e, %test1 ], [ %y, %entry ]
%2 = phi i32 [ %y, %entry ], [ %e, %test1 ]
%e = load i32, ptr %0, align 4
%3 = add i32 %c, %c
br i1 true, label %test, label %test1
test:
%d = load i32, ptr %0, align 4
br label %first
first:
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[E_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[Y:%.*]] = add i32 [[C]], [[C]]
; CHECK-NEXT: br label [[TEST1:%.*]]
; CHECK: dummy:
; CHECK-NEXT: ret void
; CHECK: test1:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[E_RELOAD:%.*]], [[TEST1]] ], [ [[Y]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[E_RELOAD]], [[TEST1]] ], [ [[Y]], [[ENTRY]] ]
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[E_LOC]])
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(ptr [[TMP0]], i32 [[C]], ptr [[E_LOC]])
; CHECK-NEXT: [[E_RELOAD]] = load i32, ptr [[E_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[E_LOC]])
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[TEST1]], label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[E_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[Y:%.*]] = mul i32 [[C]], [[C]]
; CHECK-NEXT: br label [[TEST1:%.*]]
; CHECK: dummy:
; CHECK-NEXT: ret void
; CHECK: test1:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[E_RELOAD:%.*]], [[TEST1]] ], [ [[Y]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[Y]], [[ENTRY]] ], [ [[E_RELOAD]], [[TEST1]] ]
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[E_LOC]])
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(ptr [[TMP0]], i32 [[C]], ptr [[E_LOC]])
; CHECK-NEXT: [[E_RELOAD]] = load i32, ptr [[E_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[E_LOC]])
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[TEST1]], label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: ret void
;
;
; CHECK: define internal i1 @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[TEST1_TO_OUTLINE:%.*]]
; CHECK: test1_to_outline:
; CHECK-NEXT: [[E:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP1:%.*]], [[TMP1]]
; CHECK-NEXT: br i1 true, label [[TEST:%.*]], label [[TEST1_EXITSTUB:%.*]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br label [[FIRST_EXITSTUB:%.*]]
; CHECK: test1.exitStub:
; CHECK-NEXT: store i32 [[E]], ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: ret i1 true
; CHECK: first.exitStub:
; CHECK-NEXT: store i32 [[E]], ptr [[TMP2]], align 4
; CHECK-NEXT: ret i1 false
;

View file

@ -1,88 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we do not outline when all of the phi nodes in the end
; block are not included in the region.
define void @function1(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
%z = add i32 %c, %c
br i1 true, label %test1, label %first
test1:
%e = load i32, ptr %0, align 4
%1 = add i32 %c, %c
br i1 true, label %first, label %test
test:
%d = load i32, ptr %0, align 4
br i1 true, label %first, label %next
first:
%2 = phi i32 [ %d, %test ], [ %e, %test1 ], [ %c, %entry ]
%3 = phi i32 [ %d, %test ], [ %e, %test1 ], [ %c, %entry ]
ret void
next:
ret void
}
define void @function2(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
%z = mul i32 %c, %c
br i1 true, label %test1, label %first
test1:
%e = load i32, ptr %0, align 4
%1 = add i32 %c, %c
br i1 true, label %first, label %test
test:
%d = load i32, ptr %0, align 4
br i1 true, label %first, label %next
first:
%2 = phi i32 [ %d, %test ], [ %e, %test1 ], [ %c, %entry ]
%3 = phi i32 [ %d, %test ], [ %c, %entry ], [ %e, %test1 ]
ret void
next:
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[Z:%.*]] = add i32 [[C]], [[C]]
; CHECK-NEXT: br i1 true, label [[TEST1:%.*]], label [[FIRST:%.*]]
; CHECK: test1:
; CHECK-NEXT: [[E:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[C]], [[C]]
; CHECK-NEXT: br i1 true, label [[FIRST]], label [[TEST:%.*]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br i1 true, label [[FIRST]], label [[NEXT:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[D]], [[TEST]] ], [ [[E]], [[TEST1]] ], [ [[C]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[D]], [[TEST]] ], [ [[E]], [[TEST1]] ], [ [[C]], [[ENTRY]] ]
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[Z:%.*]] = mul i32 [[C]], [[C]]
; CHECK-NEXT: br i1 true, label [[TEST1:%.*]], label [[FIRST:%.*]]
; CHECK: test1:
; CHECK-NEXT: [[E:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[C]], [[C]]
; CHECK-NEXT: br i1 true, label [[FIRST]], label [[TEST:%.*]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br i1 true, label [[FIRST]], label [[NEXT:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[D]], [[TEST]] ], [ [[E]], [[TEST1]] ], [ [[C]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[D]], [[TEST]] ], [ [[C]], [[ENTRY]] ], [ [[E]], [[TEST1]] ]
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: ret void
;

View file

@ -1,75 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; When the an outlined section contains a PHINode no incoming blocks outside
; the region, we need to make sure that we do not try to reassign
; the incoming blocks when splitting and reattaching the region.
define void @fn1() local_unnamed_addr #0 {
entry:
br label %block_2
block_1:
%a = phi i32 [ 0, %block_2], [ 1, %intermediate_block_1 ]
br i1 0, label %block_3, label %block_2
intermediate_block_1:
br label %block_1
block_2:
br i1 0, label %block_3, label %block_1
block_3:
%b = phi i32 [ 0, %block_2 ], [ 1, %block_1 ]
br label %block_5
block_4:
%c = phi i32 [ 0, %block_5 ], [ 1, %intermediate_block_2 ]
br i1 0, label %block_6, label %block_5
intermediate_block_2:
br label %block_4
block_5:
br i1 0, label %block_6, label %block_4
block_6:
unreachable
}
; CHECK-LABEL: @fn1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B_CE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[B_CE_LOC]], i32 0)
; CHECK-NEXT: [[B_CE_RELOAD:%.*]] = load i32, ptr [[B_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B_CE_LOC]])
; CHECK-NEXT: br label [[BLOCK_3:%.*]]
; CHECK: block_3:
; CHECK-NEXT: [[B:%.*]] = phi i32 [ [[B_CE_RELOAD]], [[ENTRY:%.*]] ]
; CHECK-NEXT: call void @outlined_ir_func_0(ptr null, i32 -1)
; CHECK-NEXT: br label [[BLOCK_6:%.*]]
; CHECK: block_6:
; CHECK-NEXT: unreachable
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A:%.*]] = phi i32 [ 0, [[BLOCK_2]] ], [ 1, [[INTERMEDIATE_BLOCK_1:%.*]] ]
; CHECK-NEXT: br i1 false, label [[BLOCK_3_SPLIT:%.*]], label [[BLOCK_2]]
; CHECK: intermediate_block_1:
; CHECK-NEXT: br label [[BLOCK_1:%.*]]
; CHECK: block_2:
; CHECK-NEXT: br i1 false, label [[BLOCK_3_SPLIT]], label [[BLOCK_1]]
; CHECK: block_3.split:
; CHECK-NEXT: [[B_CE:%.*]] = phi i32 [ 0, [[BLOCK_2]] ], [ 1, [[BLOCK_1]] ]
; CHECK-NEXT: br label [[BLOCK_3_EXITSTUB:%.*]]
; CHECK: block_3.exitStub:
; CHECK-NEXT: switch i32 [[TMP1:%.*]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_0_0:
; CHECK-NEXT: store i32 [[B_CE]], ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: final_block_0:
; CHECK-NEXT: ret void
;

View file

@ -1,61 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Ensure that a function is not outlined if a function has the optnone
; attribute.
define void @outline_constants1() optnone noinline {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 3, ptr %a, align 4
store i32 4, ptr %b, align 4
store i32 5, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_constants2() optnone noinline {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK-LABEL: @outline_constants1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 3, ptr [[A]], align 4
; CHECK-NEXT: store i32 4, ptr [[B]], align 4
; CHECK-NEXT: store i32 5, ptr [[C]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[C]], align 4
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outline_constants2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[C]], align 4
; CHECK-NEXT: ret void
;

View file

@ -1,30 +0,0 @@
; RUN: opt -S -debug-only=iroutliner -p=iroutliner -ir-outlining-no-cost %s -o - 2>&1 | FileCheck %s
; REQUIRES: asserts
; CHECK-NOT: ... Skipping function with nooutline attribute: outlinable
; CHECK-NOT: @outlined_ir_func
; CHECK: ... Skipping function with nooutline attribute: nooutline1
; CHECK: ... Skipping function with nooutline attribute: nooutline2
define void @outlinable() { ret void }
define i8 @nooutline1(ptr noalias %s, ptr noalias %d, i64 %len) nooutline {
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memcpy.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
define i8 @nooutline2(ptr noalias %s, ptr noalias %d, i64 %len) nooutline {
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memcpy.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)

View file

@ -1,71 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; When the an outlined section contains a PHINode with an incoming block
; outside of the region, the predecessors to be handled specially to ensure that
; a global value is properly assigned. This ensures that there is no crash
; in that situation.
define void @fn1() local_unnamed_addr #0 {
entry:
br label %block_1
block_1:
%a = phi i32 [ 0, %block_2], [ 1, %entry ]
br i1 0, label %block_3, label %block_2
block_2:
br i1 0, label %block_3, label %block_1
block_3:
%b = phi i32 [ 0, %block_2 ], [ 1, %block_1 ]
br label %block_4
block_4:
%c = phi i32 [ 0, %block_5 ], [ 1, %block_3 ]
br i1 0, label %block_6, label %block_5
block_5:
br i1 0, label %block_6, label %block_4
block_6:
unreachable
}
; CHECK-LABEL: @fn1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B_CE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[B_CE_LOC]], i32 0)
; CHECK-NEXT: [[B_CE_RELOAD:%.*]] = load i32, ptr [[B_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B_CE_LOC]])
; CHECK-NEXT: br label [[BLOCK_3:%.*]]
; CHECK: block_3:
; CHECK-NEXT: [[B:%.*]] = phi i32 [ [[B_CE_RELOAD]], [[ENTRY:%.*]] ]
; CHECK-NEXT: call void @outlined_ir_func_0(ptr null, i32 -1)
; CHECK-NEXT: br label [[BLOCK_6:%.*]]
; CHECK: block_6:
; CHECK-NEXT: unreachable
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: br label [[BLOCK_1:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A:%.*]] = phi i32 [ 0, [[BLOCK_2:%.*]] ], [ 1, [[ENTRY_TO_OUTLINE]] ]
; CHECK-NEXT: br i1 false, label [[BLOCK_3_SPLIT:%.*]], label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: br i1 false, label [[BLOCK_3_SPLIT]], label [[BLOCK_1]]
; CHECK: block_3.split:
; CHECK-NEXT: [[B_CE:%.*]] = phi i32 [ 0, [[BLOCK_2]] ], [ 1, [[BLOCK_1]] ]
; CHECK-NEXT: br label [[BLOCK_3_EXITSTUB:%.*]]
; CHECK: block_3.exitStub:
; CHECK-NEXT: switch i32 [[TMP1:%.*]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_0_0:
; CHECK-NEXT: store i32 [[B_CE]], ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: final_block_0:
; CHECK-NEXT: ret void
;

View file

@ -1,405 +0,0 @@
; RUN: opt -S -passes=verify,iroutliner -o /dev/null \
; RUN: -pass-remarks=iroutliner -pass-remarks-missed=iroutliner < %s \
; RUN: 2>&1 | FileCheck -check-prefix=CHECK %s
; RUN: opt -S -passes=verify,iroutliner -o /dev/null \
; RUN: -pass-remarks-output=%t < %s
; RUN: cat %t | FileCheck -check-prefix=YAML %s
; CHECK: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 10 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 4 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 0 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 10 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 1 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 11 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 12 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 2 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 3 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 13 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 4 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 14 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 5 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 10 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 11 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 6 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 7 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 17 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 13 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: did not outline 2 regions due to estimated increase of 8 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; CHECK-NEXT: remark: <unknown>:0:0: outlined 2 regions with decrease of 2 instructions at locations <UNKNOWN LOCATION> <UNKNOWN LOCATION>
; YAML: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '10'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '4'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '0'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function1
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '10'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '1'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function1
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '11'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function1
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '12'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '2'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '3'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function1
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '13'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '4'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function1
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '14'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '5'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function1
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '10'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function1
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '11'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '6'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '7'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function1
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '17'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function1
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '13'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Missed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: WouldNotDecreaseSize
; YAML-NEXT: Function: function3
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'did not outline '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions due to estimated increase of '
; YAML-NEXT: - InstructionIncrease: '8'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
; YAML-NEXT: --- !Passed
; YAML-NEXT: Pass: iroutliner
; YAML-NEXT: Name: Outlined
; YAML-NEXT: Function: function3.outlined
; YAML-NEXT: Args:
; YAML-NEXT: - String: 'outlined '
; YAML-NEXT: - String: '2'
; YAML-NEXT: - String: ' regions with decrease of '
; YAML-NEXT: - Benefit: '2'
; YAML-NEXT: - String: ' instructions at locations '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: - String: ' '
; YAML-NEXT: - DebugLoc: '<UNKNOWN LOCATION>'
; YAML-NEXT: ...
define void @function1() #0 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
store i32 %add, ptr %output, align 4
%2 = load i32, ptr %output, align 4
%3 = load i32, ptr %output, align 4
%mul = mul i32 %2, %add
store i32 %mul, ptr %result, align 4
ret void
}
define void @function2() #0 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
store i32 %add, ptr %output, align 4
%2 = load i32, ptr %output, align 4
%3 = load i32, ptr %output, align 4
%mul = mul i32 %2, %add
store i32 %mul, ptr %result, align 4
ret void
}
define void @function3() #0 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
%mul = mul i32 %0, %1
%sub = sub i32 %0, %1
%div = sdiv i32 %0, %1
%add1 = add i32 %0, %1
%mul1 = mul i32 %0, %1
%sub1 = sub i32 %0, %1
%div1 = sdiv i32 %0, %1
%add2 = add i32 %0, %1
%mul2 = mul i32 %0, %1
%sub2 = sub i32 %0, %1
%div2 = sdiv i32 %0, %1
%mul3 = mul i32 %0, %1
ret void
}
define void @function4() #0 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
%mul = mul i32 %0, %1
%sub = sub i32 %0, %1
%div = sdiv i32 %0, %1
%add1 = add i32 %0, %1
%mul1 = mul i32 %0, %1
%sub1 = sub i32 %0, %1
%div1 = sdiv i32 %0, %1
%add2 = add i32 %0, %1
%mul2 = mul i32 %0, %1
%sub2 = sub i32 %0, %1
%div2 = sdiv i32 %0, %1
%div3 = sdiv i32 %0, %1
ret void
}

View file

@ -1,60 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we successfully outline identical memcpy instructions.
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)
define i8 @function1(ptr noalias %s, ptr noalias %d, i64 %len) {
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memcpy.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
define i8 @function2(ptr noalias %s, ptr noalias %d, i64 %len) {
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memcpy.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[S:%.*]], ptr [[D:%.*]], i64 [[LEN:%.*]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[S:%.*]], ptr [[D:%.*]], i64 [[LEN:%.*]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
;
; CHECK: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[TMP0:%.*]], align 1
; CHECK-NEXT: [[B:%.*]] = load i8, ptr [[TMP1:%.*]], align 1
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[TMP1]], ptr [[TMP0]], i64 [[TMP2:%.*]], i1 false)
; CHECK-NEXT: [[C:%.*]] = add i8 [[A]], [[B]]
; CHECK-NEXT: [[RET:%.*]] = load i8, ptr [[TMP0]], align 1
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: store i8 [[RET]], ptr [[TMP3:%.*]], align 1
; CHECK-NEXT: ret void
;

View file

@ -1,60 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we sucecssfully outline identical memmove instructions.
declare void @llvm.memmove.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)
define i8 @function1(ptr noalias %s, ptr noalias %d, i64 %len) {
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memmove.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
define i8 @function2(ptr noalias %s, ptr noalias %d, i64 %len) {
entry:
%a = load i8, ptr %s
%b = load i8, ptr %d
call void @llvm.memmove.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false)
%c = add i8 %a, %b
%ret = load i8, ptr %s
ret i8 %ret
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[S:%.*]], ptr [[D:%.*]], i64 [[LEN:%.*]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RET_LOC:%.*]] = alloca i8, align 1
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[RET_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[S:%.*]], ptr [[D:%.*]], i64 [[LEN:%.*]], ptr [[RET_LOC]])
; CHECK-NEXT: [[RET_RELOAD:%.*]] = load i8, ptr [[RET_LOC]], align 1
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[RET_LOC]])
; CHECK-NEXT: ret i8 [[RET_RELOAD]]
;
;
; CHECK: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[A:%.*]] = load i8, ptr [[TMP0:%.*]], align 1
; CHECK-NEXT: [[B:%.*]] = load i8, ptr [[TMP1:%.*]], align 1
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[TMP1]], ptr [[TMP0]], i64 [[TMP2:%.*]], i1 false)
; CHECK-NEXT: [[C:%.*]] = add i8 [[A]], [[B]]
; CHECK-NEXT: [[RET:%.*]] = load i8, ptr [[TMP0]], align 1
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: store i8 [[RET]], ptr [[TMP3:%.*]], align 1
; CHECK-NEXT: ret void
;

View file

@ -1,52 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we successfully outline identical memset instructions.
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i32, i1)
define i64 @function1(i64 %x, i64 %z, i64 %n) {
entry:
%pool = alloca [59 x i64], align 4
call void @llvm.memset.p0.i64(ptr nonnull %pool, i8 0, i64 236, i32 4, i1 false)
%cmp3 = icmp eq i64 %n, 0
%a = add i64 %x, %z
%c = add i64 %x, %z
ret i64 0
}
define i64 @function2(i64 %x, i64 %z, i64 %n) {
entry:
%pool = alloca [59 x i64], align 4
call void @llvm.memset.p0.i64(ptr nonnull %pool, i8 0, i64 236, i32 4, i1 false)
%cmp3 = icmp eq i64 %n, 0
%a = add i64 %x, %z
%c = add i64 %x, %z
ret i64 0
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[POOL:%.*]] = alloca [59 x i64], align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[POOL]], i64 [[N:%.*]], i64 [[X:%.*]], i64 [[Z:%.*]])
; CHECK-NEXT: ret i64 0
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[POOL:%.*]] = alloca [59 x i64], align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[POOL]], i64 [[N:%.*]], i64 [[X:%.*]], i64 [[Z:%.*]])
; CHECK-NEXT: ret i64 0
;
;
; CHECK: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr nonnull align 4 [[TMP0:%.*]], i8 0, i64 236, i1 false)
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i64 [[TMP1:%.*]], 0
; CHECK-NEXT: [[A:%.*]] = add i64 [[TMP2:%.*]], [[TMP3:%.*]]
; CHECK-NEXT: [[C:%.*]] = add i64 [[TMP2]], [[TMP3]]
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,95 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we sucessfully outline identical memcpy var arg
; intrinsics, but not the var arg instruction itself.
declare void @llvm.va_start(ptr)
declare void @llvm.va_copy(ptr, ptr)
declare void @llvm.va_end(ptr)
define i32 @func1(i32 %a, double %b, ptr %v, ...) nounwind {
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca double, align 8
%ap = alloca ptr, align 4
%c = alloca i32, align 4
store i32 %a, ptr %a.addr, align 4
store double %b, ptr %b.addr, align 8
call void @llvm.va_start(ptr %ap)
%0 = va_arg ptr %ap, i32
call void @llvm.va_copy(ptr %v, ptr %ap)
call void @llvm.va_end(ptr %ap)
store i32 %0, ptr %c, align 4
%tmp = load i32, ptr %c, align 4
ret i32 %tmp
}
define i32 @func2(i32 %a, double %b, ptr %v, ...) nounwind {
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca double, align 8
%ap = alloca ptr, align 4
%c = alloca i32, align 4
store i32 %a, ptr %a.addr, align 4
store double %b, ptr %b.addr, align 8
call void @llvm.va_start(ptr %ap)
%0 = va_arg ptr %ap, i32
call void @llvm.va_copy(ptr %v, ptr %ap)
call void @llvm.va_end(ptr %ap)
store i32 %0, ptr %c, align 4
%tmp = load i32, ptr %c, align 4
ret i32 %tmp
}
; CHECK-LABEL: define {{[^@]+}}@func1
; CHECK-SAME: (i32 [[A:%.*]], double [[B:%.*]], ptr [[V:%.*]], ...) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B_ADDR:%.*]] = alloca double, align 8
; CHECK-NEXT: [[AP:%.*]] = alloca ptr, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4
; CHECK-NEXT: store double [[B]], ptr [[B_ADDR]], align 8
; CHECK-NEXT: call void @llvm.va_start.p0(ptr [[AP]])
; CHECK-NEXT: [[TMP0:%.*]] = va_arg ptr [[AP]], i32
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[TMP_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[V]], ptr [[AP]], i32 [[TMP0]], ptr [[C]], ptr [[TMP_LOC]])
; CHECK-NEXT: [[TMP_RELOAD:%.*]] = load i32, ptr [[TMP_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[TMP_LOC]])
; CHECK-NEXT: ret i32 [[TMP_RELOAD]]
;
;
; CHECK-LABEL: define {{[^@]+}}@func2
; CHECK-SAME: (i32 [[A:%.*]], double [[B:%.*]], ptr [[V:%.*]], ...) #[[ATTR1]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B_ADDR:%.*]] = alloca double, align 8
; CHECK-NEXT: [[AP:%.*]] = alloca ptr, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4
; CHECK-NEXT: store double [[B]], ptr [[B_ADDR]], align 8
; CHECK-NEXT: call void @llvm.va_start.p0(ptr [[AP]])
; CHECK-NEXT: [[TMP0:%.*]] = va_arg ptr [[AP]], i32
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[TMP_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[V]], ptr [[AP]], i32 [[TMP0]], ptr [[C]], ptr [[TMP_LOC]])
; CHECK-NEXT: [[TMP_RELOAD:%.*]] = load i32, ptr [[TMP_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[TMP_LOC]])
; CHECK-NEXT: ret i32 [[TMP_RELOAD]]
;
;
; CHECK-LABEL: define {{[^@]+}}@outlined_ir_func_0
; CHECK-SAME: (ptr [[TMP0:%.*]], ptr [[TMP1:%.*]], i32 [[TMP2:%.*]], ptr [[TMP3:%.*]], ptr [[TMP4:%.*]]) #[[ATTR3:[0-9]+]] {
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: call void @llvm.va_copy.p0(ptr [[TMP0]], ptr [[TMP1]])
; CHECK-NEXT: call void @llvm.va_end.p0(ptr [[TMP1]])
; CHECK-NEXT: store i32 [[TMP2]], ptr [[TMP3]], align 4
; CHECK-NEXT: [[TMP:%.*]] = load i32, ptr [[TMP3]], align 4
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: store i32 [[TMP]], ptr [[TMP4]], align 4
; CHECK-NEXT: ret void
;

View file

@ -1,77 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This checks that we are able to outline exactly the same branch structure
; while also outlining similar items on either side of the branch.
define void @outline_outputs1() #0 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
br label %next
next:
store i32 2, ptr %output, align 4
store i32 3, ptr %result, align 4
ret void
}
define void @outline_outputs2() #0 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
br label %next
next:
store i32 2, ptr %output, align 4
store i32 3, ptr %result, align 4
ret void
}
; CHECK-LABEL: @outline_outputs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outline_outputs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]])
; CHECK-NEXT: ret void
;
;
; CHECK: define internal void @outlined_ir_func_0(
; CHECK: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: store i32 3, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: store i32 2, ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: store i32 3, ptr [[TMP3:%.*]], align 4
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,91 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test shows that we do not outline from basic blocks with their address
; taken.
@ba1 = constant ptr blockaddress (@dontoutline, %new_block)
define void @outline_1() {
; CHECK-LABEL: @outline_1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @[[FUNCTION_1:.*]](ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_2() {
; CHECK-LABEL: @outline_2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @[[FUNCTION_1]](ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @dontoutline() {
; CHECK-LABEL: @dontoutline(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[NEW_BLOCK:%.*]]
; CHECK: new_block:
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[C]], align 4
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
br label %new_block
new_block:
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK: define internal void @[[FUNCTION_1]](ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4

View file

@ -1,50 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This checks that we are able to outline exactly the same structure without
; any other items to outline.
define void @outline_outputs1() #0 {
entry:
br label %next
next:
br label %next2
next2:
br label %next3
next3:
%a = alloca i32, align 4
br label %next4
next4:
br label %next5
next5:
br label %next6
next6:
%b = alloca i32, align 4
ret void
}
; CHECK-LABEL: @outline_outputs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: br label [[NEXT3:%.*]]
; CHECK: next3:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: br label [[NEXT6:%.*]]
; CHECK: next6:
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: ret void
;
;
; CHECK: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: br label [[NEXT2:%.*]]
; CHECK: next2:
; CHECK-NEXT: br label [[NEXT3_EXITSTUB:%.*]]
; CHECK: next3.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,127 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test ensures that an extra output is not added when there is a bitcast
; that is relocated to outside of the extraction due to a starting lifetime
; instruction outside of the extracted region.
; Additionally, we check that the newly added bitcast instruction is excluded in
; further extractions.
declare void @llvm.lifetime.start.p0(ptr nocapture)
declare void @llvm.lifetime.end.p0(ptr nocapture)
define void @outline_bitcast_base() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_bitcast_removed() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
%d = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
call void @llvm.lifetime.start.p0(ptr %d)
%am = load i32, ptr %b
%bm = load i32, ptr %a
%cm = load i32, ptr %c
call void @llvm.lifetime.end.p0(ptr %d)
ret void
}
; The first bitcast is moved down to lifetime start, and, since the original
; endpoint does not match the new endpoint, we cannot extract and outline the
; second bitcast and set of adds. Outlining only occurs in this case due to
; the lack of a cost model, as denoted by the debug command line argument.
define void @outline_bitcast_base2(i32 %a, i32 %b, i32 %c) {
entry:
%d = alloca i32, align 4
%al = add i32 %a, %b
%bl = add i32 %b, %a
%cl = add i32 %b, %c
%buffer = mul i32 %a, %b
%am = add i32 %a, %b
%bm = add i32 %b, %a
%cm = add i32 %b, %c
call void @llvm.lifetime.start.p0(ptr %d)
call void @llvm.lifetime.end.p0(ptr %d)
ret void
}
; CHECK-LABEL: @outline_bitcast_base(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[D:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outline_bitcast_removed(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: [[AM:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[BM:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[CM:%.*]] = load i32, ptr [[C]], align 4
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outline_bitcast_base2(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]])
; CHECK-NEXT: [[BUFFER:%.*]] = mul i32 [[A]], [[B]]
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[A]], i32 [[B]], i32 [[C]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: store i32 3, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: store i32 4, ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outlined_ir_func_1(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: [[D:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[D]])
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[AL:%.*]] = add i32 [[TMP0:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: [[BL:%.*]] = add i32 [[TMP1]], [[TMP0]]
; CHECK-NEXT: [[CL:%.*]] = add i32 [[TMP1]], [[TMP2:%.*]]
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[D]])
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,171 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Here we have multiple exits, but the different sources, same outputs are
; needed, this checks that they are compressed, and moved into the appropriate
; output blocks.
define void @outline_outputs1() #0 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_6
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_6
dummy:
ret void
block_6:
%diff = phi i32 [%aval, %block_4], [%a2val, %block_5]
ret void
}
define void @outline_outputs2() #0 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_6
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_6
dummy:
ret void
block_6:
%diff = phi i32 [%aval, %block_4], [%a2val, %block_5]
ret void
}
; CHECK-LABEL: @outline_outputs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DIFF_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DIFF_CE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[DIFF_CE_LOC]])
; CHECK-NEXT: [[DIFF_CE_RELOAD:%.*]] = load i32, ptr [[DIFF_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DIFF_CE_LOC]])
; CHECK-NEXT: br label [[BLOCK_6:%.*]]
; CHECK: dummy:
; CHECK-NEXT: ret void
; CHECK: block_6:
; CHECK-NEXT: [[DIFF:%.*]] = phi i32 [ [[DIFF_CE_RELOAD]], [[BLOCK_2]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outline_outputs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DIFF_CE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DIFF_CE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[DIFF_CE_LOC]])
; CHECK-NEXT: [[DIFF_CE_RELOAD:%.*]] = load i32, ptr [[DIFF_CE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DIFF_CE_LOC]])
; CHECK-NEXT: br label [[BLOCK_6:%.*]]
; CHECK: dummy:
; CHECK-NEXT: ret void
; CHECK: block_6:
; CHECK-NEXT: [[DIFF:%.*]] = phi i32 [ [[DIFF_CE_RELOAD]], [[BLOCK_2]] ]
; CHECK-NEXT: ret void
;
;
; CHECK: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BLOCK_2_TO_OUTLINE:%.*]]
; CHECK: block_2_to_outline:
; CHECK-NEXT: [[A2VAL:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: [[B2VAL:%.*]] = load i32, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: [[ADD2:%.*]] = add i32 2, [[A2VAL]]
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 2, [[B2VAL]]
; CHECK-NEXT: br label [[BLOCK_5:%.*]]
; CHECK: block_3:
; CHECK-NEXT: [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add i32 2, [[AVAL]]
; CHECK-NEXT: [[MUL:%.*]] = mul i32 2, [[BVAL]]
; CHECK-NEXT: br label [[BLOCK_4:%.*]]
; CHECK: block_4:
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP3:%.*]], align 4
; CHECK-NEXT: br label [[BLOCK_6_SPLIT:%.*]]
; CHECK: block_5:
; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP2]], align 4
; CHECK-NEXT: store i32 [[MUL2]], ptr [[TMP3]], align 4
; CHECK-NEXT: br label [[BLOCK_6_SPLIT]]
; CHECK: block_6.split:
; CHECK-NEXT: [[DIFF_CE:%.*]] = phi i32 [ [[AVAL]], [[BLOCK_4]] ], [ [[A2VAL]], [[BLOCK_5]] ]
; CHECK-NEXT: br label [[BLOCK_6_EXITSTUB:%.*]]
; CHECK: block_6.exitStub:
; CHECK-NEXT: store i32 [[DIFF_CE]], ptr [[TMP4:%.*]], align 4
; CHECK-NEXT: ret void
;

View file

@ -1,70 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we do can outline indirect and regular function calls
; when the type matches when it is not specified that the names must match.
declare void @f1();
define void @function1(ptr %func) {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void %func()
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function2() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f1()
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]], ptr [[FUNC:%.*]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]], ptr @f1)
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: store i32 3, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: store i32 4, ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: call void [[TMP3:%.*]]()
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,93 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost -ir-sim-calls-by-name < %s | FileCheck %s
; This test checks that we do can outline calls, but only if they have the same
; function type and the same name.
declare void @f1(ptr, ptr);
declare void @f2(ptr, ptr);
define void @function1() {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f1(ptr %a, ptr %b)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function2() {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f1(ptr %a, ptr %b)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function3() {
; CHECK-LABEL: @function3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: call void @f2(ptr [[A]], ptr [[B]])
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[C]], align 4
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f2(ptr %a, ptr %b)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT: call void @f1(ptr [[ARG0]], ptr [[ARG1]])
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4

View file

@ -1,96 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that we do can outline calls, but only if they have the same
; function type and the same name.
declare void @f1(ptr, ptr);
declare void @f2(ptr, ptr);
define void @function1() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f1(ptr %a, ptr %b)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function2() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f1(ptr %a, ptr %b)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @function3() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
call void @f2(ptr %a, ptr %b)
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]], ptr @f1)
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]], ptr @f1)
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]], ptr @f2)
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: store i32 3, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: store i32 4, ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: call void [[TMP3:%.*]](ptr [[TMP0]], ptr [[TMP1]])
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,107 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that floating point commutative instructions are not treated
; as commutative. Even though an ffadd is technically commutative, the order
; of operands still needs to be enforced since the process of fadding floating
; point values requires the order to be the same.
; We make sure that we outline the identical regions from the first two
; functions, but not the third. this is because the operands are in a different
; order in a floating point instruction in this section.
define void @outline_from_fadd1() {
; CHECK-LABEL: @outline_from_fadd1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca double, align 4
; CHECK-NEXT: [[B:%.*]] = alloca double, align 4
; CHECK-NEXT: [[C:%.*]] = alloca double, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca double, align 4
%b = alloca double, align 4
%c = alloca double, align 4
store double 2.0, ptr %a, align 4
store double 3.0, ptr %b, align 4
store double 4.0, ptr %c, align 4
%al = load double, ptr %a
%bl = load double, ptr %b
%cl = load double, ptr %c
%0 = fadd double %al, %bl
%1 = fadd double %al, %cl
%2 = fadd double %bl, %cl
ret void
}
define void @outline_from_fadd2.0() {
; CHECK-LABEL: @outline_from_fadd2.0(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca double, align 4
; CHECK-NEXT: [[B:%.*]] = alloca double, align 4
; CHECK-NEXT: [[C:%.*]] = alloca double, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca double, align 4
%b = alloca double, align 4
%c = alloca double, align 4
store double 2.0, ptr %a, align 4
store double 3.0, ptr %b, align 4
store double 4.0, ptr %c, align 4
%al = load double, ptr %a
%bl = load double, ptr %b
%cl = load double, ptr %c
%0 = fadd double %al, %bl
%1 = fadd double %al, %cl
%2 = fadd double %bl, %cl
ret void
}
define void @outline_from_flipped_fadd3.0() {
; CHECK-LABEL: @outline_from_flipped_fadd3.0(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca double, align 4
; CHECK-NEXT: [[B:%.*]] = alloca double, align 4
; CHECK-NEXT: [[C:%.*]] = alloca double, align 4
; CHECK-NEXT: store double 2.000000e+00, ptr [[A]], align 4
; CHECK-NEXT: store double 3.000000e+00, ptr [[B]], align 4
; CHECK-NEXT: store double 4.000000e+00, ptr [[C]], align 4
; CHECK-NEXT: [[AL:%.*]] = load double, ptr [[A]], align 8
; CHECK-NEXT: [[BL:%.*]] = load double, ptr [[B]], align 8
; CHECK-NEXT: [[CL:%.*]] = load double, ptr [[C]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = fadd double [[BL]], [[AL]]
; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[CL]], [[AL]]
; CHECK-NEXT: [[TMP2:%.*]] = fadd double [[CL]], [[BL]]
; CHECK-NEXT: ret void
;
entry:
%a = alloca double, align 4
%b = alloca double, align 4
%c = alloca double, align 4
store double 2.0, ptr %a, align 4
store double 3.0, ptr %b, align 4
store double 4.0, ptr %c, align 4
%al = load double, ptr %a
%bl = load double, ptr %b
%cl = load double, ptr %c
%0 = fadd double %bl, %al
%1 = fadd double %cl, %al
%2 = fadd double %cl, %bl
ret void
}
; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT: store double 2.000000e+00, ptr [[ARG0]], align 4
; CHECK-NEXT: store double 3.000000e+00, ptr [[ARG1]], align 4
; CHECK-NEXT: store double 4.000000e+00, ptr [[ARG2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load double, ptr [[ARG0]], align 8
; CHECK-NEXT: [[BL:%.*]] = load double, ptr [[ARG1]], align 8
; CHECK-NEXT: [[CL:%.*]] = load double, ptr [[ARG2]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = fadd double [[AL]], [[BL]]
; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[AL]], [[CL]]
; CHECK-NEXT: [[TMP2:%.*]] = fadd double [[BL]], [[CL]]

View file

@ -1,40 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
; RUN: opt -S -passes=iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This is a test to ensure that when the first instruction is a commutative
; instruction, but the order of operands is reversed, we pass the arguments
; in the correct order, such that we do not use the wrong arguments
; later on in the computation.
define void @fish(i32 %0, i32 %1, i32 %2) {
entry:
%3 = add nsw i32 %0, %1
%4 = sub nsw i32 %1, %2
%5 = sub nsw i32 %0, %2
ret void
}
define void @turtle(i32 %0, i32 %1, i32 %2) {
%4 = add nsw i32 %1, %0
%5 = sub nsw i32 %1, %2
%6 = sub nsw i32 %0, %2
ret void
}
; CHECK-LABEL: @fish(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @turtle(
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]])
; CHECK-NEXT: ret void
;
;
; CHECK: @outlined_ir_func_0(i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: [[TMP4:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[TMP5:%.*]] = sub nsw i32 [[TMP0]], [[TMP2]]
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
;

View file

@ -1,254 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that commutative instructions where the operands are
; swapped are outlined as the same function.
; It also checks that non-commutative instructions outlined as different
; functions when the operands are swapped;
; These are identical functions, except that in the flipped functions,
; the operands in the adds are commuted. However, since add instructions
; are commutative, we should still outline from all four as the same
; instruction.
define void @outline_from_add1() {
; CHECK-LABEL: @outline_from_add1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
%0 = add i32 %al, %bl
%1 = add i32 %al, %cl
%2 = add i32 %bl, %cl
ret void
}
define void @outline_from_add2() {
; CHECK-LABEL: @outline_from_add2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
%0 = add i32 %al, %bl
%1 = add i32 %al, %cl
%2 = add i32 %bl, %cl
ret void
}
define void @outline_from_flipped_add3() {
; CHECK-LABEL: @outline_from_flipped_add3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
%0 = add i32 %bl, %al
%1 = add i32 %cl, %al
%2 = add i32 %cl, %bl
ret void
}
define void @outline_from_flipped_add4() {
; CHECK-LABEL: @outline_from_flipped_add4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
%0 = add i32 %bl, %al
%1 = add i32 %cl, %al
%2 = add i32 %cl, %bl
ret void
}
; These are identical functions, except that in the flipped functions,
; the operands in the subtractions are commuted. Since subtraction
; instructions are not commutative, we should outline the first two functions
; differently than the second two functions.
define void @outline_from_sub1() {
; CHECK-LABEL: @outline_from_sub1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
%0 = sub i32 %al, %bl
%1 = sub i32 %al, %cl
%2 = sub i32 %bl, %cl
ret void
}
define void @outline_from_sub2() {
; CHECK-LABEL: @outline_from_sub2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
%0 = sub i32 %al, %bl
%1 = sub i32 %al, %cl
%2 = sub i32 %bl, %cl
ret void
}
define void @dontoutline_from_flipped_sub3() {
; CHECK-LABEL: @dontoutline_from_flipped_sub3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
%0 = sub i32 %bl, %al
%1 = sub i32 %cl, %al
%2 = sub i32 %cl, %bl
ret void
}
define void @dontoutline_from_flipped_sub4() {
; CHECK-LABEL: @dontoutline_from_flipped_sub4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
%0 = sub i32 %bl, %al
%1 = sub i32 %cl, %al
%2 = sub i32 %cl, %bl
ret void
}
; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[AL]], [[BL]]
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[AL]], [[CL]]
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[BL]], [[CL]]
; CHECK: define internal void @outlined_ir_func_1(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[BL]], [[AL]]
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[CL]], [[AL]]
; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[CL]], [[BL]]
; CHECK: define internal void @outlined_ir_func_2(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[AL]], [[BL]]
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[AL]], [[CL]]
; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[BL]], [[CL]]

View file

@ -1,125 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This has two compatible regions based on function attributes. We have
; attributes that should be transferred only if it is on all of the regions.
; This includes the attributes,
; no-signed-zeros-fp-math, less-precise-fpmad, and
; no-infs-fp-math. Only when each instance of similarity has these attributes
; can we say that the outlined function can have these attributes since that
; is the more general case for these attributes.
define void @outline_attrs1() #0 {
; CHECK-LABEL: @outline_attrs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_attrs2() #0 {
; CHECK-LABEL: @outline_attrs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_attrs3() #0 {
; CHECK-LABEL: @outline_attrs3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca float, align 4
; CHECK-NEXT: [[B:%.*]] = alloca float, align 4
; CHECK-NEXT: [[C:%.*]] = alloca float, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca float, align 4
%b = alloca float, align 4
%c = alloca float, align 4
store float 2.0, ptr %a, align 4
store float 3.0, ptr %b, align 4
store float 4.0, ptr %c, align 4
%al = load float, ptr %a
%bl = load float, ptr %b
%cl = load float, ptr %c
%0 = fmul float %al, %bl
ret void
}
define void @outline_attrs4() {
; CHECK-LABEL: @outline_attrs4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca float, align 4
; CHECK-NEXT: [[B:%.*]] = alloca float, align 4
; CHECK-NEXT: [[C:%.*]] = alloca float, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca float, align 4
%b = alloca float, align 4
%c = alloca float, align 4
store float 2.0, ptr %a, align 4
store float 3.0, ptr %b, align 4
store float 4.0, ptr %c, align 4
%al = load float, ptr %a
%bl = load float, ptr %b
%cl = load float, ptr %c
%0 = fmul float %al, %bl
ret void
}
attributes #0 = { "no-signed-zeros-fp-math"="true" "less-precise-fpmad"="true" }
; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) [[ATTR1:#[0-9]+]] {
; CHECK: entry_to_outline:
; CHECK-NEXT: store float 2.000000e+00, ptr [[ARG0]], align 4
; CHECK-NEXT: store float 3.000000e+00, ptr [[ARG1]], align 4
; CHECK-NEXT: store float 4.000000e+00, ptr [[ARG2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load float, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load float, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load float, ptr [[ARG2]], align 4
; CHECK: define internal void @outlined_ir_func_1(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) [[ATTR:#[0-9]+]] {
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
; CHECK: attributes [[ATTR1]] = { minsize optsize "less-precise-fpmad"="false" "no-signed-zeros-fp-math"="false" }
; CHECK: attributes [[ATTR]] = { minsize optsize "less-precise-fpmad"="true" "no-signed-zeros-fp-math"="true" }

View file

@ -1,298 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-globals --include-generated-funcs
; RUN: opt -mtriple=riscv32 -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; REQUIRES: riscv-registered-target
; This has two compatible regions based on function attributes. We have attributes
; that should never be transferred to the outlined functions:
; - `interrupt`=*
; On RISC-V, the `interrupt` attribute only applies to the prolog and epilog of
; the annotated function, and not any functions it calls. If this attribute is
; preserved, there will be codegen errors because of restrictions on the
; signatures of `interrupt` attributes.
define void @outline_attrs1() #0 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_attrs2() #1 {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_attrs3() {
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_outputs1() #0 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_6
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_7
block_6:
ret void
block_7:
ret void
}
define void @outline_outputs2() #1 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_7
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_6
block_6:
%diff = sub i32 %a2val, %b2val
ret void
block_7:
%quot = udiv i32 %add, %mul
ret void
}
attributes #0 = { "interrupt"="machine" optsize }
attributes #1 = { "interrupt"="qci-nest" optsize }
; CHECK-LABEL: define {{[^@]+}}@outline_attrs1
; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define {{[^@]+}}@outline_attrs2
; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define {{[^@]+}}@outline_attrs3() {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define {{[^@]+}}@outline_outputs1
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr null, ptr null, ptr null, ptr null, i32 -1)
; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_6:%.*]], label [[BLOCK_7:%.*]]
; CHECK: block_6:
; CHECK-NEXT: ret void
; CHECK: block_7:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define {{[^@]+}}@outline_outputs2
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[MUL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[MUL_LOC]])
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[ADD_LOC]], ptr [[MUL_LOC]], i32 0)
; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
; CHECK-NEXT: [[MUL_RELOAD:%.*]] = load i32, ptr [[MUL_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[MUL_LOC]])
; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_7:%.*]], label [[BLOCK_6:%.*]]
; CHECK: block_6:
; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
; CHECK-NEXT: ret void
; CHECK: block_7:
; CHECK-NEXT: [[QUOT:%.*]] = udiv i32 [[ADD_RELOAD]], [[MUL_RELOAD]]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define {{[^@]+}}@outlined_ir_func_0
; CHECK-SAME: (ptr [[TMP0:%.*]], ptr [[TMP1:%.*]], ptr [[TMP2:%.*]], ptr [[TMP3:%.*]], ptr [[TMP4:%.*]], ptr [[TMP5:%.*]], ptr [[TMP6:%.*]], ptr [[TMP7:%.*]], i32 [[TMP8:%.*]]) #[[ATTR3:[0-9]+]] {
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BLOCK_2_TO_OUTLINE:%.*]]
; CHECK: block_2_to_outline:
; CHECK-NEXT: [[A2VAL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[B2VAL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[ADD2:%.*]] = add i32 2, [[A2VAL]]
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 2, [[B2VAL]]
; CHECK-NEXT: br label [[BLOCK_5:%.*]]
; CHECK: block_3:
; CHECK-NEXT: [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add i32 2, [[AVAL]]
; CHECK-NEXT: [[MUL:%.*]] = mul i32 2, [[BVAL]]
; CHECK-NEXT: br label [[BLOCK_4:%.*]]
; CHECK: block_4:
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP2]], align 4
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP3]], align 4
; CHECK-NEXT: br label [[BLOCK_6_EXITSTUB:%.*]]
; CHECK: block_5:
; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP2]], align 4
; CHECK-NEXT: store i32 [[MUL2]], ptr [[TMP3]], align 4
; CHECK-NEXT: br label [[BLOCK_7_EXITSTUB:%.*]]
; CHECK: block_6.exitStub:
; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_1:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_1:%.*]]
; CHECK-NEXT: ]
; CHECK: block_7.exitStub:
; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_1_0:
; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4]], align 4
; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: output_block_1_1:
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP6]], align 4
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP7]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: final_block_0:
; CHECK-NEXT: ret i1 false
; CHECK: final_block_1:
; CHECK-NEXT: ret i1 true
;
;
; CHECK-LABEL: define {{[^@]+}}@outlined_ir_func_1
; CHECK-SAME: (ptr [[TMP0:%.*]], ptr [[TMP1:%.*]], ptr [[TMP2:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[TMP0]], align 4
; CHECK-NEXT: store i32 3, ptr [[TMP1]], align 4
; CHECK-NEXT: store i32 4, ptr [[TMP2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
; CHECK: entry_after_outline.exitStub:
; CHECK-NEXT: ret void
;
;.
; CHECK: attributes #[[ATTR0]] = { optsize "interrupt"="machine" }
; CHECK: attributes #[[ATTR1]] = { optsize "interrupt"="qci-nest" }
; CHECK: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
; CHECK: attributes #[[ATTR3]] = { minsize optsize }
;.

View file

@ -1,67 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < "%s" | FileCheck "%s"
; This has two compatible regions. We have attributes that should be transferred
; even if it is on only one of the regions.
; This includes the attributes no-jump-tables, profile-sample-accurate,
; speculative_load_hardening, and noimplicitfloat. When instance of similarity
; has these attributes can we say that the outlined function can have these
; attributes since that is the more general case.
define void @outline_attrs1() #0 {
; CHECK-LABEL: @outline_attrs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_attrs2() {
; CHECK-LABEL: @outline_attrs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
attributes #0 = { "no-jump-tables"="true" "profile-sample-accurate"="true" "speculative_load_hardening" "noimplicitfloat"="true" "use-sample-profile"="true"}
; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) [[ATTR:#[0-9]+]] {
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
; CHECK: attributes [[ATTR]] = { minsize optsize "no-jump-tables"="true" "noimplicitfloat"="true" "profile-sample-accurate"="true" "speculative_load_hardening" "use-sample-profile"="true" }

View file

@ -1,82 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test looks at instances of constants in the different regions. If there
; is a register in the same place as a constant in a similar region of code, we
; do not outline those regions.
; The first function tests that we do not outline with the register is
; seen first, and the second function checks that we do not outline when the
; constant is seen first.
define void @function_registers_first(i32 %0, i32 %1, i32 %2) {
; CHECK-LABEL: @function_registers_first(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[TMP0:%.*]], ptr [[A]], i32 [[TMP1:%.*]], ptr [[B]], i32 [[TMP2:%.*]], ptr [[C]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: call void @outlined_ir_func_1(i32 2, ptr [[A]], i32 3, ptr [[B]], i32 4, ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 %0, ptr %a, align 4
store i32 %1, ptr %b, align 4
store i32 %2, ptr %c, align 4
ret void
next:
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
ret void
}
define void @function_with_constants_first(i32 %0, i32 %1, i32 %2) {
; CHECK-LABEL: @function_with_constants_first(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[C]], align 4
; CHECK-NEXT: call void @outlined_ir_func_0(i32 2, i32 [[AL]], i32 3, i32 [[BL]], i32 4, i32 [[CL]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[TMP0:%.*]], i32 [[AL]], i32 [[TMP1:%.*]], i32 [[BL]], i32 [[TMP2:%.*]], i32 [[CL]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
%3 = add i32 2, %al
%4 = add i32 3, %bl
%5 = add i32 4, %cl
ret void
next:
%6 = add i32 %0, %al
%7 = add i32 %1, %bl
%8 = add i32 %2, %cl
ret void
}
; CHECK: define internal void @outlined_ir_func_0(i32 [[ARG0:%.*]], i32 [[ARG1:%.*]], i32 [[ARG2:%.*]], i32 [[ARG3:%.*]], i32 [[ARG4:%.*]], i32 [[ARG5:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: add i32 [[ARG0]], [[ARG1]]
; CHECK-NEXT: add i32 [[ARG2]], [[ARG3]]
; CHECK-NEXT: add i32 [[ARG4]], [[ARG5]]
; CHECK: define internal void @outlined_ir_func_1(i32 [[ARG0:%.*]], ptr [[ARG1:%.*]], i32 [[ARG2:%.*]], ptr [[ARG3:%.*]], i32 [[ARG4:%.*]], ptr [[ARG5:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 [[ARG0]], ptr [[ARG1]]
; CHECK-NEXT: store i32 [[ARG2]], ptr [[ARG3]]
; CHECK-NEXT: store i32 [[ARG4]], ptr [[ARG5]]

View file

@ -1,187 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner < %s | FileCheck %s
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s -check-prefix=NOCOST
; This test checks that we have different results from when the cost model
; is on versus when it is off. That is, if the number of instructions needed to
; handle the arguments is greater than the number of instructions being added,
; we do not outline.
define void @function1() #0 {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: ret void
;
; NOCOST-LABEL: @function1(
; NOCOST-NEXT: entry:
; NOCOST-NEXT: [[A:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[B:%.*]] = alloca i32, align 4
; NOCOST-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; NOCOST-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
%mul = mul i32 %0, %1
%sub = sub i32 %0, %1
%div = sdiv i32 %0, %1
%add1 = add i32 %0, %1
%mul1 = mul i32 %0, %1
%sub1 = sub i32 %0, %1
%div1 = sdiv i32 %0, %1
%add2 = add i32 %0, %1
%mul2 = mul i32 %0, %1
%sub2 = sub i32 %0, %1
%div2 = sdiv i32 %0, %1
ret void
}
define void @function2() #0 {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: ret void
;
; NOCOST-LABEL: @function2(
; NOCOST-NEXT: entry:
; NOCOST-NEXT: [[A:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[B:%.*]] = alloca i32, align 4
; NOCOST-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; NOCOST-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
%mul = mul i32 %0, %1
%sub = sub i32 %0, %1
%div = sdiv i32 %0, %1
%add1 = add i32 %0, %1
%mul1 = mul i32 %0, %1
%sub1 = sub i32 %0, %1
%div1 = sdiv i32 %0, %1
%add2 = add i32 %0, %1
%mul2 = mul i32 %0, %1
%sub2 = sub i32 %0, %1
%div2 = sdiv i32 %0, %1
ret void
}
define void @function3() #0 {
; CHECK-LABEL: @function3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: store i32 [[ADD]], ptr [[OUTPUT]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[OUTPUT]], align 4
; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[OUTPUT]], align 4
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP2]], [[ADD]]
; CHECK-NEXT: store i32 [[MUL]], ptr [[RESULT]], align 4
; CHECK-NEXT: ret void
;
; NOCOST-LABEL: @function3(
; NOCOST-NEXT: entry:
; NOCOST-NEXT: [[DOTLOC:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[A:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[B:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; NOCOST-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
; NOCOST-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTLOC]])
; NOCOST-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[ADD_LOC]], ptr [[DOTLOC]])
; NOCOST-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
; NOCOST-NEXT: [[DOTRELOAD:%.*]] = load i32, ptr [[DOTLOC]], align 4
; NOCOST-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
; NOCOST-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTLOC]])
; NOCOST-NEXT: [[TMP0:%.*]] = load i32, ptr [[OUTPUT]], align 4
; NOCOST-NEXT: call void @outlined_ir_func_2(i32 [[DOTRELOAD]], i32 [[ADD_RELOAD]], ptr [[RESULT]])
; NOCOST-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
store i32 %add, ptr %output, align 4
%2 = load i32, ptr %output, align 4
%3 = load i32, ptr %output, align 4
%mul = mul i32 %2, %add
store i32 %mul, ptr %result, align 4
ret void
}
define void @function4() #0 {
; CHECK-LABEL: @function4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: store i32 [[ADD]], ptr [[OUTPUT]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[OUTPUT]], align 4
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP2]], [[ADD]]
; CHECK-NEXT: store i32 [[MUL]], ptr [[RESULT]], align 4
; CHECK-NEXT: ret void
;
; NOCOST-LABEL: @function4(
; NOCOST-NEXT: entry:
; NOCOST-NEXT: [[DOTLOC:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[A:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[B:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; NOCOST-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; NOCOST-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
; NOCOST-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTLOC]])
; NOCOST-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[ADD_LOC]], ptr [[DOTLOC]])
; NOCOST-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
; NOCOST-NEXT: [[DOTRELOAD:%.*]] = load i32, ptr [[DOTLOC]], align 4
; NOCOST-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
; NOCOST-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTLOC]])
; NOCOST-NEXT: call void @outlined_ir_func_2(i32 [[DOTRELOAD]], i32 [[ADD_RELOAD]], ptr [[RESULT]])
; NOCOST-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
store i32 %add, ptr %output, align 4
%2 = load i32, ptr %output, align 4
%mul = mul i32 %2, %add
store i32 %mul, ptr %result, align 4
ret void
}

View file

@ -1,65 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test makes sure that we do not include debug statements in outlined
; functions.
define void @outline_dbg1() {
; CHECK-LABEL: @outline_dbg1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
call void @llvm.dbg.value(metadata i64 0, metadata !14, metadata !DIExpression()), !dbg !15
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
declare void @llvm.dbg.value(metadata, metadata, metadata)
define void @outline_dbg2() {
; CHECK-LABEL: @outline_dbg2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK: entry_to_outline:
!0 = !DIFile(filename: "foo.c", directory: "/tmp")
!1 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!5 = distinct !DICompileUnit(language: DW_LANG_C, file: !0, producer: "My Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !6, retainedTypes: !6, globals: !7)
!6 = !{}
!7 = !{}
!11 = distinct !DISubprogram(name: "func_5", scope: !0, file: !0, line: 117, type: !12, isLocal: true, isDefinition: true, scopeLine: 118, isOptimized: false, unit: !5, retainedNodes: !6)
!12 = !DISubroutineType(types: !13)
!13 = !{}
!14 = !DILocalVariable(name: "p_6", arg: 1, scope: !11, line: 117, type: !1)
!15 = !DILocation(line: 1, scope: !11)

View file

@ -1,58 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test looks at the constants in the regions, and if it they are the
; differents it elevates the constants to arguments.
define void @outline_constants1() {
; CHECK-LABEL: @outline_constants1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(i32 3, ptr [[A]], i32 4, ptr [[B]], i32 5, ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 3, ptr %a, align 4
store i32 4, ptr %b, align 4
store i32 5, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_constants2() {
; CHECK-LABEL: @outline_constants2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(i32 2, ptr [[A]], i32 3, ptr [[B]], i32 4, ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK: define internal void @outlined_ir_func_0(i32 [[ARG0:%.*]], ptr [[ARG1:%.*]], i32 [[ARG2:%.*]], ptr [[ARG3:%.*]], i32 [[ARG4:%.*]], ptr [[ARG5:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 [[ARG0]], ptr [[ARG1]], align 4
; CHECK-NEXT: store i32 [[ARG2]], ptr [[ARG3]], align 4
; CHECK-NEXT: store i32 [[ARG4]], ptr [[ARG5]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG3]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG5]], align 4

View file

@ -1,42 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test looks at the globals in the regions, and makes sure they are not
; outlined if they are different values.
@global1 = global i32 1, align 4
@global2 = global i32 2, align 4
@global3 = global i32 3, align 4
@global4 = global i32 4, align 4
define void @outline_globals1() {
; CHECK-LABEL: @outline_globals1(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @outlined_ir_func_0(ptr @global1, ptr @global2)
; CHECK-NEXT: ret void
;
entry:
%0 = load i32, ptr @global1
%1 = load i32, ptr @global2
%2 = add i32 %0, %1
ret void
}
define void @outline_globals2() {
; CHECK-LABEL: @outline_globals2(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @outlined_ir_func_0(ptr @global3, ptr @global4)
; CHECK-NEXT: ret void
;
entry:
%0 = load i32, ptr @global3
%1 = load i32, ptr @global4
%2 = add i32 %0, %1
ret void
}
; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARG0]]
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARG1]]
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP0]], [[TMP1]]

View file

@ -1,106 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; These functions are constructed slightly differently so that they require
; different output blocks for the values used outside of the region. We are
; checking that two output blocks are created with different values.
define void @outline_outputs1() #0 {
; CHECK-LABEL: @outline_outputs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTLOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTLOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[ADD_LOC]], ptr [[DOTLOC]], i32 0)
; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
; CHECK-NEXT: [[DOTRELOAD:%.*]] = load i32, ptr [[DOTLOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTLOC]])
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[OUTPUT]], align 4
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[DOTRELOAD]], i32 [[ADD_RELOAD]], ptr [[RESULT]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
%sub = sub i32 %0, %1
store i32 %add, ptr %output, align 4
%2 = load i32, ptr %output, align 4
%3 = load i32, ptr %output, align 4
%mul = mul i32 %2, %add
store i32 %mul, ptr %result, align 4
ret void
}
define void @outline_outputs2() #0 {
; CHECK-LABEL: @outline_outputs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTLOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[SUB_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[SUB_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTLOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[SUB_LOC]], ptr [[DOTLOC]], i32 1)
; CHECK-NEXT: [[SUB_RELOAD:%.*]] = load i32, ptr [[SUB_LOC]], align 4
; CHECK-NEXT: [[DOTRELOAD:%.*]] = load i32, ptr [[DOTLOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[SUB_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTLOC]])
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[DOTRELOAD]], i32 [[SUB_RELOAD]], ptr [[RESULT]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
%sub = sub i32 %0, %1
store i32 %add, ptr %output, align 4
%2 = load i32, ptr %output, align 4
%mul = mul i32 %2, %sub
store i32 %mul, ptr %result, align 4
ret void
}
; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]], i32 [[ARG5:%.*]]) #1 {
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: store i32 [[ADD]], ptr [[ARG2]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG2]], align 4
; CHECK: _after_outline.exitStub:
; CHECK-NEXT: switch i32 [[ARG5]], label [[BLOCK:%.*]] [
; CHECK-NEXT: i32 0, label %[[BLOCK_0:.*]]
; CHECK-NEXT: i32 1, label %[[BLOCK_1:.*]]
; CHECK: [[BLOCK_0]]:
; CHECK-NEXT: store i32 [[ADD]], ptr [[ARG3]], align 4
; CHECK-NEXT: store i32 [[TMP2]], ptr [[ARG4]], align 4
; CHECK: [[BLOCK_1]]:
; CHECK-NEXT: store i32 [[SUB]], ptr [[ARG3]], align 4
; CHECK-NEXT: store i32 [[TMP2]], ptr [[ARG4]], align 4

View file

@ -1,62 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This is a negative case to show that when we have the same set of
; instructions, but in a different order, they are not outlined in the same way.
; In this case, the arguments passed into the function are in a different order.
define void @outline_constants1() {
; CHECK-LABEL: @outline_constants1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: call void @[[FUNCTION_0:.*]](ptr [[A]], ptr [[C]], ptr [[B]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%cl = load i32, ptr %c
%bl = load i32, ptr %b
ret void
}
define void @outline_constants2() {
; CHECK-LABEL: @outline_constants2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: call void @[[FUNCTION_0]](ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK: define internal void @[[FUNCTION_0]](ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4

View file

@ -1,92 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Show that we do not extract similar regions that would involve the splitting
; of phi nodes on exit.
define void @function1(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br label %first
test:
%d = load i32, ptr %0, align 4
br label %first
dummy:
ret void
first:
%1 = phi i32 [ %c, %test ], [ %e, %test1 ]
ret void
}
define void @function2(ptr %a, ptr %b) {
entry:
%0 = alloca i32, align 4
%c = load i32, ptr %0, align 4
br label %test1
test1:
%e = load i32, ptr %0, align 4
br label %first
test:
%d = load i32, ptr %0, align 4
br label %first
dummy:
ret void
first:
%1 = phi i32 [ %c, %test ], [ %e, %test1 ]
ret void
}
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTCE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[TMP0]], ptr [[DOTCE_LOC]])
; CHECK-NEXT: [[DOTCE_RELOAD:%.*]] = load i32, ptr [[DOTCE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: dummy:
; CHECK-NEXT: ret void
; CHECK: first:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[DOTCE_RELOAD]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTCE_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[TMP0]], ptr [[DOTCE_LOC]])
; CHECK-NEXT: [[DOTCE_RELOAD:%.*]] = load i32, ptr [[DOTCE_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTCE_LOC]])
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: dummy:
; CHECK-NEXT: ret void
; CHECK: first:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[DOTCE_RELOAD]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
; CHECK: entry_to_outline:
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: br label [[TEST1:%.*]]
; CHECK: test1:
; CHECK-NEXT: [[E:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br label [[FIRST_SPLIT:%.*]]
; CHECK: test:
; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: br label [[FIRST_SPLIT]]
; CHECK: first.split:
; CHECK-NEXT: [[DOTCE:%.*]] = phi i32 [ [[C]], [[TEST:%.*]] ], [ [[E]], [[TEST1]] ]
; CHECK-NEXT: br label [[FIRST_EXITSTUB:%.*]]
; CHECK: first.exitStub:
; CHECK-NEXT: store i32 [[DOTCE]], ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: ret void
;

View file

@ -1,67 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Make sure that we outline from all three of these functions, and that
; the first instruction in the module is included when it is the only
; instruction in the first basic block.
define void @f1() {
bb:
br label %bb1
bb1:
br label %bb2
bb2:
ret void
}
define void @f2() {
bb:
br label %bb1
bb1:
br label %bb2
bb2:
ret void
}
define void @f3() {
bb:
br label %bb1
bb1:
br label %bb2
bb2:
ret void
}
; CHECK-LABEL: @f1(
; CHECK-NEXT: bb:
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb2:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @f2(
; CHECK-NEXT: bb:
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb2:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @f3(
; CHECK-NEXT: bb:
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb2:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BB_TO_OUTLINE:%.*]]
; CHECK: bb_to_outline:
; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: br label [[BB2_EXITSTUB:%.*]]
; CHECK: bb2.exitStub:
; CHECK-NEXT: ret void
;

View file

@ -1,68 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks to make sure that we outline getelementptr instructions only
; when all the operands after the first are the exact same. In this case, we
; outline from the first two functions, but not the third.
%struct.RT = type { i8, [10 x [20 x i32]], i8 }
%struct.ST = type { i32, double, %struct.RT }
define void @function1(ptr %s, i64 %t) {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[S:%.*]], i64 [[T:%.*]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = getelementptr inbounds %struct.ST, ptr %s, i64 %t, i32 1
ret void
}
define void @function2(ptr %s, i64 %t) {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[S:%.*]], i64 [[T:%.*]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = getelementptr inbounds %struct.ST, ptr %s, i64 %t, i32 1
ret void
}
define void @function3(ptr %s, i64 %t) {
; CHECK-LABEL: @function3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], ptr [[S:%.*]], i64 [[T:%.*]], i32 0
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = getelementptr inbounds %struct.ST, ptr %s, i64 %t, i32 0
ret void
}
; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], i64 [[ARG3:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds %struct.ST, ptr [[ARG2]], i64 [[ARG3]], i32 1

View file

@ -1,170 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test checks the isomorphic comparisons can be outlined together into one
; function.
; The following three function are identical, except that in the third, the
; operand order, and predicate are swapped, meaning it is structurally the same
; and should be outlined together.
define void @outline_slt1() {
; CHECK-LABEL: @outline_slt1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%0 = icmp slt i32 %al, %bl
ret void
}
define void @outline_slt2() {
; CHECK-LABEL: @outline_slt2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%0 = icmp slt i32 %al, %bl
ret void
}
define void @outline_sgt() {
; CHECK-LABEL: @outline_sgt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%0 = icmp sgt i32 %bl, %al
ret void
}
; This has a swapped predicate, but not swapped operands, so it cannot use
; the same outlined function as the ones above.
define void @dontoutline_sgt() {
; CHECK-LABEL: @dontoutline_sgt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[AL]], [[BL]]
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%0 = icmp sgt i32 %al, %bl
ret void
}
; The below functions use a different kind of predicate that is not compatible
; with the ones above, and should use a different outlined function.
; The other difference here is that the predicate with swapped operands comes
; first this time.
define void @outline_ugt1() {
; CHECK-LABEL: @outline_ugt1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%0 = icmp ugt i32 %al, %bl
ret void
}
define void @outline_ugt2() {
; CHECK-LABEL: @outline_ugt2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%0 = icmp ugt i32 %al, %bl
ret void
}
define void @outline_ult() {
; CHECK-LABEL: @outline_ult(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%0 = icmp ult i32 %bl, %al
ret void
}
; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[AL]], [[BL]]
; CHECK: define internal void @outlined_ir_func_1(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[AL]], [[BL]]

View file

@ -1,89 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -p iroutliner,verify -ir-outlining-no-cost < %s | FileCheck %s
; This test checks that commutative instructions where the operands are
; swapped are outlined as the same function.
; It also checks that non-commutative instructions outlined as different
; functions when the operands are swapped;
; These are identical functions, except that in the flipped functions,
; the operands in the adds are commuted. However, since add instructions
; are commutative, we should still outline from all four as the same
; instruction.
define void @function1(i32 %a, i32 %b) {
; CHECK-LABEL: @function1(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[BLOCK_1:%.*]]
; CHECK: block_0:
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[TMP4:%.*]], 1
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP0]], [[TMP0]]
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP0]], [[TMP0]]
; CHECK-NEXT: br i1 [[TMP3]], label [[BLOCK_1]], label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[TMP4]] = phi i32 [ [[TMP1]], [[BLOCK_0:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]])
; CHECK-NEXT: br label [[BLOCK_0]]
; CHECK: block_2:
; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP2]], [[TMP2]]
; CHECK-NEXT: ret void
;
entry:
br label %block_1
block_0:
%0 = add i32 %a, %b
%1 = add i32 %4, 1
%2 = add i32 %0, %0
%3 = icmp sgt i32 %0, %0
br i1 %3, label %block_1, label %block_2
block_1:
%4 = phi i32 [ %1, %block_0 ], [ 0, %entry ]
%5 = add i32 %b, %b
br label %block_0
block_2:
%6 = add i32 %2, %2
ret void
}
define void @function2(i32 %a, i32 %b) {
; CHECK-LABEL: @function2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[BLOCK_1:%.*]]
; CHECK: block_0:
; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = add i32 1, [[TMP4:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP0]], [[TMP0]]
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP0]], [[TMP0]]
; CHECK-NEXT: br i1 [[TMP3]], label [[BLOCK_1]], label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[TMP4]] = phi i32 [ [[TMP1]], [[BLOCK_0:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]])
; CHECK-NEXT: br label [[BLOCK_0]]
; CHECK: block_2:
; CHECK-NEXT: [[TMP5:%.*]] = sub i32 [[TMP2]], [[TMP2]]
; CHECK-NEXT: ret void
;
entry:
br label %block_1
block_0:
%0 = sub i32 %a, %b
%1 = add i32 1, %4
%2 = add i32 %0, %0
%3 = icmp sgt i32 %0, %0
br i1 %3, label %block_1, label %block_2
block_1:
%4 = phi i32 [ %1, %block_0 ], [ 0, %entry ]
%5 = add i32 %b, %b
br label %block_0
block_2:
%6 = sub i32 %2, %2
ret void
}

View file

@ -1,221 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Here we have multiple exits, but the different sources, different outputs are
; needed, this checks that they are handled by separate switch statements.
define void @outline_outputs1() #0 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_6
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_7
block_6:
%div = udiv i32 %aval, %bval
ret void
block_7:
%sub = sub i32 %a2val, %b2val
ret void
}
define void @outline_outputs2() #0 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_7
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_6
block_6:
%diff = sub i32 %a2val, %b2val
ret void
block_7:
%quot = udiv i32 %add, %mul
ret void
}
; CHECK-LABEL: @outline_outputs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BVAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[AVAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[AVAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[BVAL_LOC]])
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[AVAL_LOC]], ptr [[BVAL_LOC]], i32 0)
; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
; CHECK-NEXT: [[AVAL_RELOAD:%.*]] = load i32, ptr [[AVAL_LOC]], align 4
; CHECK-NEXT: [[BVAL_RELOAD:%.*]] = load i32, ptr [[BVAL_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[AVAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[BVAL_LOC]])
; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_6:%.*]], label [[BLOCK_7:%.*]]
; CHECK: block_6:
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[AVAL_RELOAD]], [[BVAL_RELOAD]]
; CHECK-NEXT: ret void
; CHECK: block_7:
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outline_outputs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[MUL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[MUL_LOC]])
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[ADD_LOC]], ptr [[MUL_LOC]], i32 1)
; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
; CHECK-NEXT: [[MUL_RELOAD:%.*]] = load i32, ptr [[MUL_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[MUL_LOC]])
; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_7:%.*]], label [[BLOCK_6:%.*]]
; CHECK: block_6:
; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
; CHECK-NEXT: ret void
; CHECK: block_7:
; CHECK-NEXT: [[QUOT:%.*]] = udiv i32 [[ADD_RELOAD]], [[MUL_RELOAD]]
; CHECK-NEXT: ret void
;
;
; CHECK: define internal i1 @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BLOCK_2_TO_OUTLINE:%.*]]
; CHECK: block_2_to_outline:
; CHECK-NEXT: [[A2VAL:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: [[B2VAL:%.*]] = load i32, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: [[ADD2:%.*]] = add i32 2, [[A2VAL]]
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 2, [[B2VAL]]
; CHECK-NEXT: br label [[BLOCK_5:%.*]]
; CHECK: block_3:
; CHECK-NEXT: [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add i32 2, [[AVAL]]
; CHECK-NEXT: [[MUL:%.*]] = mul i32 2, [[BVAL]]
; CHECK-NEXT: br label [[BLOCK_4:%.*]]
; CHECK: block_4:
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP3:%.*]], align 4
; CHECK-NEXT: br label [[BLOCK_6_EXITSTUB:%.*]]
; CHECK: block_5:
; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP2]], align 4
; CHECK-NEXT: store i32 [[MUL2]], ptr [[TMP3]], align 4
; CHECK-NEXT: br label [[BLOCK_7_EXITSTUB:%.*]]
; CHECK: block_6.exitStub:
; CHECK-NEXT: switch i32 [[TMP8:%.*]], label [[FINAL_BLOCK_1:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_1:%.*]]
; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_1:%.*]]
; CHECK-NEXT: ]
; CHECK: block_7.exitStub:
; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_0:%.*]]
; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_0_0:
; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4:%.*]], align 4
; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: output_block_0_1:
; CHECK-NEXT: store i32 [[AVAL]], ptr [[TMP6:%.*]], align 4
; CHECK-NEXT: store i32 [[BVAL]], ptr [[TMP7:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: output_block_1_0:
; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4]], align 4
; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: output_block_1_1:
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP6]], align 4
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP7]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: final_block_0:
; CHECK-NEXT: ret i1 false
; CHECK: final_block_1:
; CHECK-NEXT: ret i1 true
;

View file

@ -1,192 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Here we have multiple exits, but different sources, and only one has an
; output set. We check to make sure that we do not generated extra output
; blocks or entries in the switch statement.
define void @outline_outputs1() #0 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_6
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_7
block_6:
ret void
block_7:
ret void
}
define void @outline_outputs2() #0 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_7
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_6
block_6:
%diff = sub i32 %a2val, %b2val
ret void
block_7:
%quot = udiv i32 %add, %mul
ret void
}
; CHECK-LABEL: @outline_outputs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr null, ptr null, ptr null, ptr null, i32 -1)
; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_6:%.*]], label [[BLOCK_7:%.*]]
; CHECK: block_6:
; CHECK-NEXT: ret void
; CHECK: block_7:
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outline_outputs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[MUL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[MUL_LOC]])
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[ADD_LOC]], ptr [[MUL_LOC]], i32 0)
; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
; CHECK-NEXT: [[MUL_RELOAD:%.*]] = load i32, ptr [[MUL_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[MUL_LOC]])
; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_7:%.*]], label [[BLOCK_6:%.*]]
; CHECK: block_6:
; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
; CHECK-NEXT: ret void
; CHECK: block_7:
; CHECK-NEXT: [[QUOT:%.*]] = udiv i32 [[ADD_RELOAD]], [[MUL_RELOAD]]
; CHECK-NEXT: ret void
;
;
; CHECK: define internal i1 @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BLOCK_2_TO_OUTLINE:%.*]]
; CHECK: block_2_to_outline:
; CHECK-NEXT: [[A2VAL:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: [[B2VAL:%.*]] = load i32, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: [[ADD2:%.*]] = add i32 2, [[A2VAL]]
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 2, [[B2VAL]]
; CHECK-NEXT: br label [[BLOCK_5:%.*]]
; CHECK: block_3:
; CHECK-NEXT: [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add i32 2, [[AVAL]]
; CHECK-NEXT: [[MUL:%.*]] = mul i32 2, [[BVAL]]
; CHECK-NEXT: br label [[BLOCK_4:%.*]]
; CHECK: block_4:
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP3:%.*]], align 4
; CHECK-NEXT: br label [[BLOCK_6_EXITSTUB:%.*]]
; CHECK: block_5:
; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP2]], align 4
; CHECK-NEXT: store i32 [[MUL2]], ptr [[TMP3]], align 4
; CHECK-NEXT: br label [[BLOCK_7_EXITSTUB:%.*]]
; CHECK: block_6.exitStub:
; CHECK-NEXT: switch i32 [[TMP8:%.*]], label [[FINAL_BLOCK_1:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_1:%.*]]
; CHECK-NEXT: ]
; CHECK: block_7.exitStub:
; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_0:%.*]] [
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_0:%.*]]
; CHECK-NEXT: ]
; CHECK: output_block_1_0:
; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4:%.*]], align 4
; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
; CHECK: output_block_1_1:
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP6:%.*]], align 4
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP7:%.*]], align 4
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
; CHECK: final_block_0:
; CHECK-NEXT: ret i1 false
; CHECK: final_block_1:
; CHECK-NEXT: ret i1 true
;

View file

@ -1,200 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Here we have multiple exits, but the different sources, same outputs are
; needed, this checks that they are compressed, and moved into the appropriate
; output blocks.
define void @outline_outputs1() #0 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_6
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_7
block_6:
%div = udiv i32 %aval, %bval
ret void
block_7:
%sub = sub i32 %a2val, %b2val
ret void
}
define void @outline_outputs2() #0 {
entry:
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
%a = alloca i32, align 4
%b = alloca i32, align 4
br label %block_2
block_1:
%a2 = alloca i32, align 4
%b2 = alloca i32, align 4
br label %block_2
block_2:
%a2val = load i32, ptr %a
%b2val = load i32, ptr %b
%add2 = add i32 2, %a2val
%mul2 = mul i32 2, %b2val
br label %block_5
block_3:
%aval = load i32, ptr %a
%bval = load i32, ptr %b
%add = add i32 2, %aval
%mul = mul i32 2, %bval
br label %block_4
block_4:
store i32 %add, ptr %output, align 4
store i32 %mul, ptr %result, align 4
br label %block_7
block_5:
store i32 %add2, ptr %output, align 4
store i32 %mul2, ptr %result, align 4
br label %block_6
block_6:
%diff = sub i32 %a2val, %b2val
ret void
block_7:
%quot = udiv i32 %aval, %bval
ret void
}
; CHECK-LABEL: @outline_outputs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BVAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[AVAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[AVAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[BVAL_LOC]])
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[AVAL_LOC]], ptr [[BVAL_LOC]])
; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
; CHECK-NEXT: [[AVAL_RELOAD:%.*]] = load i32, ptr [[AVAL_LOC]], align 4
; CHECK-NEXT: [[BVAL_RELOAD:%.*]] = load i32, ptr [[BVAL_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[AVAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[BVAL_LOC]])
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[BLOCK_6:%.*]], label [[BLOCK_7:%.*]]
; CHECK: block_6:
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[AVAL_RELOAD]], [[BVAL_RELOAD]]
; CHECK-NEXT: ret void
; CHECK: block_7:
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @outline_outputs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BVAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[AVAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
; CHECK: block_1:
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label [[BLOCK_2]]
; CHECK: block_2:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[AVAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[BVAL_LOC]])
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[AVAL_LOC]], ptr [[BVAL_LOC]])
; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
; CHECK-NEXT: [[AVAL_RELOAD:%.*]] = load i32, ptr [[AVAL_LOC]], align 4
; CHECK-NEXT: [[BVAL_RELOAD:%.*]] = load i32, ptr [[BVAL_LOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B2VAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[AVAL_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[BVAL_LOC]])
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[BLOCK_7:%.*]], label [[BLOCK_6:%.*]]
; CHECK: block_6:
; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
; CHECK-NEXT: ret void
; CHECK: block_7:
; CHECK-NEXT: [[QUOT:%.*]] = udiv i32 [[AVAL_RELOAD]], [[BVAL_RELOAD]]
; CHECK-NEXT: ret void
;
;
; CHECK: define internal i1 @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BLOCK_2_TO_OUTLINE:%.*]]
; CHECK: block_2_to_outline:
; CHECK-NEXT: [[A2VAL:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: [[B2VAL:%.*]] = load i32, ptr [[TMP1:%.*]], align 4
; CHECK-NEXT: [[ADD2:%.*]] = add i32 2, [[A2VAL]]
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 2, [[B2VAL]]
; CHECK-NEXT: br label [[BLOCK_5:%.*]]
; CHECK: block_3:
; CHECK-NEXT: [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4
; CHECK-NEXT: [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add i32 2, [[AVAL]]
; CHECK-NEXT: [[MUL:%.*]] = mul i32 2, [[BVAL]]
; CHECK-NEXT: br label [[BLOCK_4:%.*]]
; CHECK: block_4:
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP2:%.*]], align 4
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP3:%.*]], align 4
; CHECK-NEXT: br label [[BLOCK_6_EXITSTUB:%.*]]
; CHECK: block_5:
; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP2]], align 4
; CHECK-NEXT: store i32 [[MUL2]], ptr [[TMP3]], align 4
; CHECK-NEXT: br label [[BLOCK_7_EXITSTUB:%.*]]
; CHECK: block_6.exitStub:
; CHECK-NEXT: store i32 [[AVAL]], ptr [[TMP6:%.*]], align 4
; CHECK-NEXT: store i32 [[BVAL]], ptr [[TMP7:%.*]], align 4
; CHECK-NEXT: ret i1 true
; CHECK: block_7.exitStub:
; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4:%.*]], align 4
; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5:%.*]], align 4
; CHECK-NEXT: ret i1 false
;

View file

@ -1,34 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Check that we do not outline musttail when swifttaill cc or tailcc
; is not present.
declare void @musttail()
define void @f1() {
%a = alloca i32, align 4
store i32 2, ptr %a, align 4
musttail call void @musttail()
ret void
}
define void @f2() {
%a = alloca i32, align 4
store i32 2, ptr %a, align 4
musttail call void @musttail()
ret void
}
; CHECK-LABEL: @f1(
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: musttail call void @musttail()
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: @f2(
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: musttail call void @musttail()
; CHECK-NEXT: ret void
;

View file

@ -1,54 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; Make sure that we outline safely from functions with no return instructions.
; The code extractor will insert return instructions in the outer function
; due to assumptions about the contents of the outlined region.
define void @f1() {
bb:
br label %bb1
bb1:
br label %bb1
}
define void @f2() {
bb:
br label %bb1
bb1:
br label %bb1
}
define void @f3() {
bb:
br label %bb1
bb1:
br label %bb1
}
; CHECK-LABEL: @f1(
; CHECK-NEXT: bb:
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: unreachable
;
;
; CHECK-LABEL: @f2(
; CHECK-NEXT: bb:
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: unreachable
;
;
; CHECK-LABEL: @f3(
; CHECK-NEXT: bb:
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: unreachable
;
;
; CHECK-LABEL: define internal void @outlined_ir_func_0(
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label [[BB_TO_OUTLINE:%.*]]
; CHECK: bb_to_outline:
; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: br label [[BB1]]
;

View file

@ -1,70 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner --ir-outlining-no-cost < %s | FileCheck %s
; RUN: opt -S -passes=verify,iroutliner -enable-linkonceodr-ir-outlining --ir-outlining-no-cost < %s | FileCheck -check-prefix=ODR %s
; This test looks at the constants in the regions, and if it they are the
; same it outlines them as constants rather than elevating them to arguments.
define linkonce_odr void @outline_odr1() {
; ODR-LABEL: @outline_odr1(
; ODR-NEXT: entry:
; ODR-NEXT: [[A:%.*]] = alloca i32, align 4
; ODR-NEXT: [[B:%.*]] = alloca i32, align 4
; ODR-NEXT: [[C:%.*]] = alloca i32, align 4
; ODR-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; ODR-NEXT: ret void
; CHECK-LABEL: @outline_odr1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[C]], align 4
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_odr2() {
; ODR-LABEL: @outline_odr2(
; ODR-NEXT: entry:
; ODR-NEXT: [[A:%.*]] = alloca i32, align 4
; ODR-NEXT: [[B:%.*]] = alloca i32, align 4
; ODR-NEXT: [[C:%.*]] = alloca i32, align 4
; ODR-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; ODR-NEXT: ret void
; CHECK-LABEL: @outline_odr2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 2, ptr [[A]], align 4
; CHECK-NEXT: store i32 3, ptr [[B]], align 4
; CHECK-NEXT: store i32 4, ptr [[C]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[B]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[C]], align 4
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}

View file

@ -1,70 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test tests that inputs that are replaced with the output of an outlined
; function is still recognized as the same value.
define void @outline_outputs1() #0 {
; CHECK-LABEL: @outline_outputs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTLOC2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[ADD2_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[DOTLOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTLOC]])
; CHECK-NEXT: call void @outlined_ir_func_0(i32 2, ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[ADD_LOC]], ptr [[DOTLOC]])
; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
; CHECK-NEXT: [[DOTRELOAD:%.*]] = load i32, ptr [[DOTLOC]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTLOC]])
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[OUTPUT]], align 4
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[DOTRELOAD]], i32 [[ADD_RELOAD]], ptr [[RESULT]])
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD2_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[DOTLOC2]])
; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[ADD_RELOAD]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[OUTPUT2]], ptr [[ADD2_LOC]], ptr [[DOTLOC2]])
; CHECK-NEXT: [[ADD2_RELOAD:%.*]] = load i32, ptr [[ADD2_LOC]], align 4
; CHECK-NEXT: [[DOTRELOAD3:%.*]] = load i32, ptr [[DOTLOC2]], align 4
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD2_LOC]])
; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[DOTLOC2]])
; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[DOTRELOAD3]], i32 [[ADD2_RELOAD]], ptr [[RESULT2]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%output = alloca i32, align 4
%result = alloca i32, align 4
%output2 = alloca i32, align 4
%result2 = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
%0 = load i32, ptr %a, align 4
%1 = load i32, ptr %b, align 4
%add = add i32 %0, %1
store i32 %add, ptr %output, align 4
%2 = load i32, ptr %output, align 4
%3 = load i32, ptr %output, align 4
%mul = mul i32 %2, %add
store i32 %mul, ptr %result, align 4
br label %next
next:
store i32 %add, ptr %output, align 4
store i32 3, ptr %result, align 4
%4 = load i32, ptr %output, align 4
%5 = load i32, ptr %result, align 4
%add2 = add i32 %4, %5
store i32 %add2, ptr %output2, align 4
%6 = load i32, ptr %output2, align 4
%mul2 = mul i32 %6, %add2
store i32 %mul2, ptr %result2, align 4
ret void
}

View file

@ -1,58 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
; This test looks at the constants in the regions, and if it they are the
; same it outlines them as constants rather than elevating them to arguments.
define void @outline_constants1() {
; CHECK-LABEL: @outline_constants1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @[[FUNCTION_0:.*]](ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
define void @outline_constants2() {
; CHECK-LABEL: @outline_constants2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @[[FUNCTION_0]](ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT: ret void
;
entry:
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
store i32 2, ptr %a, align 4
store i32 3, ptr %b, align 4
store i32 4, ptr %c, align 4
%al = load i32, ptr %a
%bl = load i32, ptr %b
%cl = load i32, ptr %c
ret void
}
; CHECK: define internal void @[[FUNCTION_0]](ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]])
; CHECK: entry_to_outline:
; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4

View file

@ -1,41 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
@global1 = global i32 1, align 4
@global2 = global i32 2, align 4
; This test looks at the globals in the regions, and if it they are the
; same it outlines the region without elevating the globals to arguments.
define void @outline_globals1() {
; CHECK-LABEL: @outline_globals1(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: ret void
;
entry:
%0 = load i32, ptr @global1
%1 = load i32, ptr @global2
%2 = add i32 %0, %1
ret void
}
define void @outline_globals2() {
; CHECK-LABEL: @outline_globals2(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: ret void
;
entry:
%0 = load i32, ptr @global1
%1 = load i32, ptr @global2
%2 = add i32 %0, %1
ret void
}
; CHECK: define internal void @outlined_ir_func_0()
; CHECK: entry_to_outline:
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @global1, align 4
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @global2, align 4
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP1]], [[TMP2]]

Some files were not shown because too many files have changed in this diff Show more