From 42c0741b0df1bb812ee25d0ffa2fade90511936d Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Tue, 6 Oct 2015 15:49:14 +0000 Subject: [PATCH] [Hexagon] Add an early if-conversion pass git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249423 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Hexagon/CMakeLists.txt | 1 + lib/Target/Hexagon/HexagonEarlyIfConv.cpp | 1064 +++++++++++++++++ lib/Target/Hexagon/HexagonInstrInfo.cpp | 95 +- lib/Target/Hexagon/HexagonTargetMachine.cpp | 6 + .../Hexagon/early-if-conversion-bug1.ll | 412 +++++++ test/CodeGen/Hexagon/early-if-phi-i1.ll | 17 + test/CodeGen/Hexagon/early-if-spare.ll | 57 + test/CodeGen/Hexagon/early-if.ll | 75 ++ test/CodeGen/Hexagon/ifcvt-edge-weight.ll | 2 +- 9 files changed, 1711 insertions(+), 18 deletions(-) create mode 100644 lib/Target/Hexagon/HexagonEarlyIfConv.cpp create mode 100644 test/CodeGen/Hexagon/early-if-conversion-bug1.ll create mode 100644 test/CodeGen/Hexagon/early-if-phi-i1.ll create mode 100644 test/CodeGen/Hexagon/early-if-spare.ll create mode 100644 test/CodeGen/Hexagon/early-if.ll diff --git a/lib/Target/Hexagon/CMakeLists.txt b/lib/Target/Hexagon/CMakeLists.txt index 8c3c95bbfc5..9fe63f3dcc7 100644 --- a/lib/Target/Hexagon/CMakeLists.txt +++ b/lib/Target/Hexagon/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_target(HexagonCodeGen HexagonCFGOptimizer.cpp HexagonCommonGEP.cpp HexagonCopyToCombine.cpp + HexagonEarlyIfConv.cpp HexagonExpandCondsets.cpp HexagonExpandPredSpillCode.cpp HexagonFixupHwLoops.cpp diff --git a/lib/Target/Hexagon/HexagonEarlyIfConv.cpp b/lib/Target/Hexagon/HexagonEarlyIfConv.cpp new file mode 100644 index 00000000000..f7b69406fd8 --- /dev/null +++ b/lib/Target/Hexagon/HexagonEarlyIfConv.cpp @@ -0,0 +1,1064 @@ +//===--- HexagonEarlyIfConv.cpp -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements a Hexagon-specific if-conversion pass that runs on the +// SSA form. +// In SSA it is not straightforward to represent instructions that condi- +// tionally define registers, since a conditionally-defined register may +// only be used under the same condition on which the definition was based. +// To avoid complications of this nature, this patch will only generate +// predicated stores, and speculate other instructions from the "if-conver- +// ted" block. +// The code will recognize CFG patterns where a block with a conditional +// branch "splits" into a "true block" and a "false block". Either of these +// could be omitted (in case of a triangle, for example). +// If after conversion of the side block(s) the CFG allows it, the resul- +// ting blocks may be merged. If the "join" block contained PHI nodes, they +// will be replaced with MUX (or MUX-like) instructions to maintain the +// semantics of the PHI. +// +// Example: +// +// %vreg40 = L2_loadrub_io %vreg39, 1 +// %vreg41 = S2_tstbit_i %vreg40, 0 +// J2_jumpt %vreg41, , %PC +// J2_jump , %PC +// Successors according to CFG: BB#4(62) BB#5(62) +// +// BB#4: derived from LLVM BB %if.then +// Predecessors according to CFG: BB#3 +// %vreg11 = A2_addp %vreg6, %vreg10 +// S2_storerd_io %vreg32, 16, %vreg11 +// Successors according to CFG: BB#5 +// +// BB#5: derived from LLVM BB %if.end +// Predecessors according to CFG: BB#3 BB#4 +// %vreg12 = PHI %vreg6, , %vreg11, +// %vreg13 = A2_addp %vreg7, %vreg12 +// %vreg42 = C2_cmpeqi %vreg9, 10 +// J2_jumpf %vreg42, , %PC +// J2_jump , %PC +// Successors according to CFG: BB#6(4) BB#3(124) +// +// would become: +// +// %vreg40 = L2_loadrub_io %vreg39, 1 +// %vreg41 = S2_tstbit_i %vreg40, 0 +// spec-> %vreg11 = A2_addp %vreg6, %vreg10 +// pred-> S2_pstorerdf_io %vreg41, %vreg32, 16, %vreg11 +// %vreg46 = MUX64_rr %vreg41, %vreg6, %vreg11 +// %vreg13 = A2_addp %vreg7, %vreg46 +// %vreg42 = C2_cmpeqi %vreg9, 10 +// J2_jumpf %vreg42, , %PC +// J2_jump , %PC +// Successors according to CFG: BB#6 BB#3 + +#define DEBUG_TYPE "hexagon-eif" + +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/CodeGen/MachineBranchProbabilityInfo.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "HexagonTargetMachine.h" + +#include +#include +#include + +using namespace llvm; + +static cl::opt EnableHexagonBP("enable-hexagon-br-prob", cl::Hidden, + cl::init(false), cl::ZeroOrMore, cl::desc("Enable branch probability info")); + +namespace llvm { + FunctionPass *createHexagonEarlyIfConversion(); + void initializeHexagonEarlyIfConversionPass(PassRegistry& Registry); +} + +namespace { + cl::opt SizeLimit("eif-limit", cl::init(6), cl::Hidden, + cl::ZeroOrMore, cl::desc("Size limit in Hexagon early if-conversion")); + + struct PrintMB { + PrintMB(const MachineBasicBlock *B) : MB(B) {} + const MachineBasicBlock *MB; + }; + raw_ostream &operator<< (raw_ostream &OS, const PrintMB &P) { + if (!P.MB) + return OS << ""; + return OS << '#' << P.MB->getNumber(); + } + + struct FlowPattern { + FlowPattern() : SplitB(0), TrueB(0), FalseB(0), JoinB(0), PredR(0) {} + FlowPattern(MachineBasicBlock *B, unsigned PR, MachineBasicBlock *TB, + MachineBasicBlock *FB, MachineBasicBlock *JB) + : SplitB(B), TrueB(TB), FalseB(FB), JoinB(JB), PredR(PR) {} + + MachineBasicBlock *SplitB; + MachineBasicBlock *TrueB, *FalseB, *JoinB; + unsigned PredR; + }; + struct PrintFP { + PrintFP(const FlowPattern &P, const TargetRegisterInfo &T) + : FP(P), TRI(T) {} + const FlowPattern &FP; + const TargetRegisterInfo &TRI; + friend raw_ostream &operator<< (raw_ostream &OS, const PrintFP &P); + }; + raw_ostream &operator<<(raw_ostream &OS, + const PrintFP &P) LLVM_ATTRIBUTE_UNUSED; + raw_ostream &operator<<(raw_ostream &OS, const PrintFP &P) { + OS << "{ SplitB:" << PrintMB(P.FP.SplitB) + << ", PredR:" << PrintReg(P.FP.PredR, &P.TRI) + << ", TrueB:" << PrintMB(P.FP.TrueB) << ", FalseB:" + << PrintMB(P.FP.FalseB) + << ", JoinB:" << PrintMB(P.FP.JoinB) << " }"; + return OS; + } + + class HexagonEarlyIfConversion : public MachineFunctionPass { + public: + static char ID; + HexagonEarlyIfConversion() : MachineFunctionPass(ID), + TII(0), TRI(0), MFN(0), MRI(0), MDT(0), MLI(0) { + initializeHexagonEarlyIfConversionPass(*PassRegistry::getPassRegistry()); + } + const char *getPassName() const override { + return "Hexagon early if conversion"; + } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + MachineFunctionPass::getAnalysisUsage(AU); + } + bool runOnMachineFunction(MachineFunction &MF) override; + + private: + typedef DenseSet BlockSetType; + + bool isPreheader(const MachineBasicBlock *B) const; + bool matchFlowPattern(MachineBasicBlock *B, MachineLoop *L, + FlowPattern &FP); + bool visitBlock(MachineBasicBlock *B, MachineLoop *L); + bool visitLoop(MachineLoop *L); + + bool hasEHLabel(const MachineBasicBlock *B) const; + bool hasUncondBranch(const MachineBasicBlock *B) const; + bool isValidCandidate(const MachineBasicBlock *B) const; + bool usesUndefVReg(const MachineInstr *MI) const; + bool isValid(const FlowPattern &FP) const; + unsigned countPredicateDefs(const MachineBasicBlock *B) const; + unsigned computePhiCost(MachineBasicBlock *B) const; + bool isProfitable(const FlowPattern &FP) const; + bool isPredicableStore(const MachineInstr *MI) const; + bool isSafeToSpeculate(const MachineInstr *MI) const; + + unsigned getCondStoreOpcode(unsigned Opc, bool IfTrue) const; + void predicateInstr(MachineBasicBlock *ToB, MachineBasicBlock::iterator At, + MachineInstr *MI, unsigned PredR, bool IfTrue); + void predicateBlockNB(MachineBasicBlock *ToB, + MachineBasicBlock::iterator At, MachineBasicBlock *FromB, + unsigned PredR, bool IfTrue); + + void updatePhiNodes(MachineBasicBlock *WhereB, const FlowPattern &FP); + void convert(const FlowPattern &FP); + + void removeBlock(MachineBasicBlock *B); + void eliminatePhis(MachineBasicBlock *B); + void replacePhiEdges(MachineBasicBlock *OldB, MachineBasicBlock *NewB); + void mergeBlocks(MachineBasicBlock *PredB, MachineBasicBlock *SuccB); + void simplifyFlowGraph(const FlowPattern &FP); + + const TargetInstrInfo *TII; + const TargetRegisterInfo *TRI; + MachineFunction *MFN; + MachineRegisterInfo *MRI; + MachineDominatorTree *MDT; + MachineLoopInfo *MLI; + BlockSetType Deleted; + const MachineBranchProbabilityInfo *MBPI; + }; + + char HexagonEarlyIfConversion::ID = 0; +} + +INITIALIZE_PASS(HexagonEarlyIfConversion, "hexagon-eif", + "Hexagon early if conversion", false, false) + +bool HexagonEarlyIfConversion::isPreheader(const MachineBasicBlock *B) const { + if (B->succ_size() != 1) + return false; + MachineBasicBlock *SB = *B->succ_begin(); + MachineLoop *L = MLI->getLoopFor(SB); + return L && SB == L->getHeader(); +} + + +bool HexagonEarlyIfConversion::matchFlowPattern(MachineBasicBlock *B, + MachineLoop *L, FlowPattern &FP) { + DEBUG(dbgs() << "Checking flow pattern at BB#" << B->getNumber() << "\n"); + + // Interested only in conditional branches, no .new, no new-value, etc. + // Check the terminators directly, it's easier than handling all responses + // from AnalyzeBranch. + MachineBasicBlock *TB = 0, *FB = 0; + MachineBasicBlock::const_iterator T1I = B->getFirstTerminator(); + if (T1I == B->end()) + return false; + unsigned Opc = T1I->getOpcode(); + if (Opc != Hexagon::J2_jumpt && Opc != Hexagon::J2_jumpf) + return false; + unsigned PredR = T1I->getOperand(0).getReg(); + + // Get the layout successor, or 0 if B does not have one. + MachineFunction::iterator NextBI = std::next(MachineFunction::iterator(B)); + MachineBasicBlock *NextB = (NextBI != MFN->end()) ? &*NextBI : 0; + + MachineBasicBlock *T1B = T1I->getOperand(1).getMBB(); + MachineBasicBlock::const_iterator T2I = std::next(T1I); + // The second terminator should be an unconditional branch. + assert(T2I == B->end() || T2I->getOpcode() == Hexagon::J2_jump); + MachineBasicBlock *T2B = (T2I == B->end()) ? NextB + : T2I->getOperand(0).getMBB(); + if (T1B == T2B) { + // XXX merge if T1B == NextB, or convert branch to unconditional. + // mark as diamond with both sides equal? + return false; + } + // Loop could be null for both. + if (MLI->getLoopFor(T1B) != L || MLI->getLoopFor(T2B) != L) + return false; + + // Record the true/false blocks in such a way that "true" means "if (PredR)", + // and "false" means "if (!PredR)". + if (Opc == Hexagon::J2_jumpt) + TB = T1B, FB = T2B; + else + TB = T2B, FB = T1B; + + if (!MDT->properlyDominates(B, TB) || !MDT->properlyDominates(B, FB)) + return false; + + // Detect triangle first. In case of a triangle, one of the blocks TB/FB + // can fall through into the other, in other words, it will be executed + // in both cases. We only want to predicate the block that is executed + // conditionally. + unsigned TNP = TB->pred_size(), FNP = FB->pred_size(); + unsigned TNS = TB->succ_size(), FNS = FB->succ_size(); + + // A block is predicable if it has one predecessor (it must be B), and + // it has a single successor. In fact, the block has to end either with + // an unconditional branch (which can be predicated), or with a fall- + // through. + bool TOk = (TNP == 1) && (TNS == 1); + bool FOk = (FNP == 1) && (FNS == 1); + + // If neither is predicable, there is nothing interesting. + if (!TOk && !FOk) + return false; + + MachineBasicBlock *TSB = (TNS > 0) ? *TB->succ_begin() : 0; + MachineBasicBlock *FSB = (FNS > 0) ? *FB->succ_begin() : 0; + MachineBasicBlock *JB = 0; + + if (TOk) { + if (FOk) { + if (TSB == FSB) + JB = TSB; + // Diamond: "if (P) then TB; else FB;". + } else { + // TOk && !FOk + if (TSB == FB) { + JB = FB; + FB = 0; + } + } + } else { + // !TOk && FOk (at least one must be true by now). + if (FSB == TB) { + JB = TB; + TB = 0; + } + } + // Don't try to predicate loop preheaders. + if ((TB && isPreheader(TB)) || (FB && isPreheader(FB))) { + DEBUG(dbgs() << "One of blocks " << PrintMB(TB) << ", " << PrintMB(FB) + << " is a loop preheader. Skipping.\n"); + return false; + } + + FP = FlowPattern(B, PredR, TB, FB, JB); + DEBUG(dbgs() << "Detected " << PrintFP(FP, *TRI) << "\n"); + return true; +} + + +// KLUDGE: HexagonInstrInfo::AnalyzeBranch won't work on a block that +// contains EH_LABEL. +bool HexagonEarlyIfConversion::hasEHLabel(const MachineBasicBlock *B) const { + for (auto &I : *B) + if (I.isEHLabel()) + return true; + return false; +} + + +// KLUDGE: HexagonInstrInfo::AnalyzeBranch may be unable to recognize +// that a block can never fall-through. +bool HexagonEarlyIfConversion::hasUncondBranch(const MachineBasicBlock *B) + const { + MachineBasicBlock::const_iterator I = B->getFirstTerminator(), E = B->end(); + while (I != E) { + if (I->isBarrier()) + return true; + ++I; + } + return false; +} + + +bool HexagonEarlyIfConversion::isValidCandidate(const MachineBasicBlock *B) + const { + if (!B) + return true; + if (B->isEHPad() || B->hasAddressTaken()) + return false; + if (B->succ_size() == 0) + return false; + + for (auto &MI : *B) { + if (MI.isDebugValue()) + continue; + if (MI.isConditionalBranch()) + return false; + unsigned Opc = MI.getOpcode(); + bool IsJMP = (Opc == Hexagon::J2_jump); + if (!isPredicableStore(&MI) && !IsJMP && !isSafeToSpeculate(&MI)) + return false; + // Look for predicate registers defined by this instruction. It's ok + // to speculate such an instruction, but the predicate register cannot + // be used outside of this block (or else it won't be possible to + // update the use of it after predication). PHI uses will be updated + // to use a result of a MUX, and a MUX cannot be created for predicate + // registers. + for (ConstMIOperands MO(&MI); MO.isValid(); ++MO) { + if (!MO->isReg() || !MO->isDef()) + continue; + unsigned R = MO->getReg(); + if (!TargetRegisterInfo::isVirtualRegister(R)) + continue; + if (MRI->getRegClass(R) != &Hexagon::PredRegsRegClass) + continue; + for (auto U = MRI->use_begin(R); U != MRI->use_end(); ++U) + if (U->getParent()->isPHI()) + return false; + } + } + return true; +} + + +bool HexagonEarlyIfConversion::usesUndefVReg(const MachineInstr *MI) const { + for (ConstMIOperands MO(MI); MO.isValid(); ++MO) { + if (!MO->isReg() || !MO->isUse()) + continue; + unsigned R = MO->getReg(); + if (!TargetRegisterInfo::isVirtualRegister(R)) + continue; + const MachineInstr *DefI = MRI->getVRegDef(R); + // "Undefined" virtual registers are actually defined via IMPLICIT_DEF. + assert(DefI && "Expecting a reaching def in MRI"); + if (DefI->isImplicitDef()) + return true; + } + return false; +} + + +bool HexagonEarlyIfConversion::isValid(const FlowPattern &FP) const { + if (hasEHLabel(FP.SplitB)) // KLUDGE: see function definition + return false; + if (FP.TrueB && !isValidCandidate(FP.TrueB)) + return false; + if (FP.FalseB && !isValidCandidate(FP.FalseB)) + return false; + // Check the PHIs in the join block. If any of them use a register + // that is defined as IMPLICIT_DEF, do not convert this. This can + // legitimately happen if one side of the split never executes, but + // the compiler is unable to prove it. That side may then seem to + // provide an "undef" value to the join block, however it will never + // execute at run-time. If we convert this case, the "undef" will + // be used in a MUX instruction, and that may seem like actually + // using an undefined value to other optimizations. This could lead + // to trouble further down the optimization stream, cause assertions + // to fail, etc. + if (FP.JoinB) { + const MachineBasicBlock &B = *FP.JoinB; + for (auto &MI : B) { + if (!MI.isPHI()) + break; + if (usesUndefVReg(&MI)) + return false; + unsigned DefR = MI.getOperand(0).getReg(); + const TargetRegisterClass *RC = MRI->getRegClass(DefR); + if (RC == &Hexagon::PredRegsRegClass) + return false; + } + } + return true; +} + + +unsigned HexagonEarlyIfConversion::computePhiCost(MachineBasicBlock *B) const { + assert(B->pred_size() <= 2); + if (B->pred_size() < 2) + return 0; + + unsigned Cost = 0; + MachineBasicBlock::const_iterator I, E = B->getFirstNonPHI(); + for (I = B->begin(); I != E; ++I) { + const MachineOperand &RO1 = I->getOperand(1); + const MachineOperand &RO3 = I->getOperand(3); + assert(RO1.isReg() && RO3.isReg()); + // Must have a MUX if the phi uses a subregister. + if (RO1.getSubReg() != 0 || RO3.getSubReg() != 0) { + Cost++; + continue; + } + MachineInstr *Def1 = MRI->getVRegDef(RO1.getReg()); + MachineInstr *Def3 = MRI->getVRegDef(RO3.getReg()); + if (!TII->isPredicable(Def1) || !TII->isPredicable(Def3)) + Cost++; + } + return Cost; +} + + +unsigned HexagonEarlyIfConversion::countPredicateDefs( + const MachineBasicBlock *B) const { + unsigned PredDefs = 0; + for (auto &MI : *B) { + for (ConstMIOperands MO(&MI); MO.isValid(); ++MO) { + if (!MO->isReg() || !MO->isDef()) + continue; + unsigned R = MO->getReg(); + if (!TargetRegisterInfo::isVirtualRegister(R)) + continue; + if (MRI->getRegClass(R) == &Hexagon::PredRegsRegClass) + PredDefs++; + } + } + return PredDefs; +} + + +bool HexagonEarlyIfConversion::isProfitable(const FlowPattern &FP) const { + if (FP.TrueB && FP.FalseB) { + + // Do not IfCovert if the branch is one sided. + if (MBPI) { + BranchProbability Prob(9, 10); + if (MBPI->getEdgeProbability(FP.SplitB, FP.TrueB) > Prob) + return false; + if (MBPI->getEdgeProbability(FP.SplitB, FP.FalseB) > Prob) + return false; + } + + // If both sides are predicable, convert them if they join, and the + // join block has no other predecessors. + MachineBasicBlock *TSB = *FP.TrueB->succ_begin(); + MachineBasicBlock *FSB = *FP.FalseB->succ_begin(); + if (TSB != FSB) + return false; + if (TSB->pred_size() != 2) + return false; + } + + // Calculate the total size of the predicated blocks. + // Assume instruction counts without branches to be the approximation of + // the code size. If the predicated blocks are smaller than a packet size, + // approximate the spare room in the packet that could be filled with the + // predicated/speculated instructions. + unsigned TS = 0, FS = 0, Spare = 0; + if (FP.TrueB) { + TS = std::distance(FP.TrueB->begin(), FP.TrueB->getFirstTerminator()); + if (TS < HEXAGON_PACKET_SIZE) + Spare += HEXAGON_PACKET_SIZE-TS; + } + if (FP.FalseB) { + FS = std::distance(FP.FalseB->begin(), FP.FalseB->getFirstTerminator()); + if (FS < HEXAGON_PACKET_SIZE) + Spare += HEXAGON_PACKET_SIZE-TS; + } + unsigned TotalIn = TS+FS; + DEBUG(dbgs() << "Total number of instructions to be predicated/speculated: " + << TotalIn << ", spare room: " << Spare << "\n"); + if (TotalIn >= SizeLimit+Spare) + return false; + + // Count the number of PHI nodes that will need to be updated (converted + // to MUX). Those can be later converted to predicated instructions, so + // they aren't always adding extra cost. + // KLUDGE: Also, count the number of predicate register definitions in + // each block. The scheduler may increase the pressure of these and cause + // expensive spills (e.g. bitmnp01). + unsigned TotalPh = 0; + unsigned PredDefs = countPredicateDefs(FP.SplitB); + if (FP.JoinB) { + TotalPh = computePhiCost(FP.JoinB); + PredDefs += countPredicateDefs(FP.JoinB); + } else { + if (FP.TrueB && FP.TrueB->succ_size() > 0) { + MachineBasicBlock *SB = *FP.TrueB->succ_begin(); + TotalPh += computePhiCost(SB); + PredDefs += countPredicateDefs(SB); + } + if (FP.FalseB && FP.FalseB->succ_size() > 0) { + MachineBasicBlock *SB = *FP.FalseB->succ_begin(); + TotalPh += computePhiCost(SB); + PredDefs += countPredicateDefs(SB); + } + } + DEBUG(dbgs() << "Total number of extra muxes from converted phis: " + << TotalPh << "\n"); + if (TotalIn+TotalPh >= SizeLimit+Spare) + return false; + + DEBUG(dbgs() << "Total number of predicate registers: " << PredDefs << "\n"); + if (PredDefs > 4) + return false; + + return true; +} + + +bool HexagonEarlyIfConversion::visitBlock(MachineBasicBlock *B, + MachineLoop *L) { + bool Changed = false; + + // Visit all dominated blocks from the same loop first, then process B. + MachineDomTreeNode *N = MDT->getNode(B); + typedef GraphTraits GTN; + // We will change CFG/DT during this traversal, so take precautions to + // avoid problems related to invalidated iterators. In fact, processing + // a child C of B cannot cause another child to be removed, but it can + // cause a new child to be added (which was a child of C before C itself + // was removed. This new child C, however, would have been processed + // prior to processing B, so there is no need to process it again. + // Simply keep a list of children of B, and traverse that list. + typedef SmallVector DTNodeVectType; + DTNodeVectType Cn(GTN::child_begin(N), GTN::child_end(N)); + for (DTNodeVectType::iterator I = Cn.begin(), E = Cn.end(); I != E; ++I) { + MachineBasicBlock *SB = (*I)->getBlock(); + if (!Deleted.count(SB)) + Changed |= visitBlock(SB, L); + } + // When walking down the dominator tree, we want to traverse through + // blocks from nested (other) loops, because they can dominate blocks + // that are in L. Skip the non-L blocks only after the tree traversal. + if (MLI->getLoopFor(B) != L) + return Changed; + + FlowPattern FP; + if (!matchFlowPattern(B, L, FP)) + return Changed; + + if (!isValid(FP)) { + DEBUG(dbgs() << "Conversion is not valid\n"); + return Changed; + } + if (!isProfitable(FP)) { + DEBUG(dbgs() << "Conversion is not profitable\n"); + return Changed; + } + + convert(FP); + simplifyFlowGraph(FP); + return true; +} + + +bool HexagonEarlyIfConversion::visitLoop(MachineLoop *L) { + MachineBasicBlock *HB = L ? L->getHeader() : 0; + DEBUG((L ? dbgs() << "Visiting loop H:" << PrintMB(HB) + : dbgs() << "Visiting function") << "\n"); + bool Changed = false; + if (L) { + for (MachineLoop::iterator I = L->begin(), E = L->end(); I != E; ++I) + Changed |= visitLoop(*I); + } + + MachineBasicBlock *EntryB = GraphTraits::getEntryNode(MFN); + Changed |= visitBlock(L ? HB : EntryB, L); + return Changed; +} + + +bool HexagonEarlyIfConversion::isPredicableStore(const MachineInstr *MI) + const { + // Exclude post-increment stores. Those return a value, so we cannot + // predicate them. + unsigned Opc = MI->getOpcode(); + using namespace Hexagon; + switch (Opc) { + // Store byte: + case S2_storerb_io: case S4_storerb_rr: + case S2_storerbabs: case S4_storeirb_io: case S2_storerbgp: + // Store halfword: + case S2_storerh_io: case S4_storerh_rr: + case S2_storerhabs: case S4_storeirh_io: case S2_storerhgp: + // Store upper halfword: + case S2_storerf_io: case S4_storerf_rr: + case S2_storerfabs: case S2_storerfgp: + // Store word: + case S2_storeri_io: case S4_storeri_rr: + case S2_storeriabs: case S4_storeiri_io: case S2_storerigp: + // Store doubleword: + case S2_storerd_io: case S4_storerd_rr: + case S2_storerdabs: case S2_storerdgp: + return true; + } + return false; +} + + +bool HexagonEarlyIfConversion::isSafeToSpeculate(const MachineInstr *MI) + const { + if (MI->mayLoad() || MI->mayStore()) + return false; + if (MI->isCall() || MI->isBarrier() || MI->isBranch()) + return false; + if (MI->hasUnmodeledSideEffects()) + return false; + + return true; +} + + +unsigned HexagonEarlyIfConversion::getCondStoreOpcode(unsigned Opc, + bool IfTrue) const { + // Exclude post-increment stores. + using namespace Hexagon; + switch (Opc) { + case S2_storerb_io: + return IfTrue ? S2_pstorerbt_io : S2_pstorerbf_io; + case S4_storerb_rr: + return IfTrue ? S4_pstorerbt_rr : S4_pstorerbf_rr; + case S2_storerbabs: + case S2_storerbgp: + return IfTrue ? S4_pstorerbt_abs : S4_pstorerbf_abs; + case S4_storeirb_io: + return IfTrue ? S4_storeirbt_io : S4_storeirbf_io; + case S2_storerh_io: + return IfTrue ? S2_pstorerht_io : S2_pstorerhf_io; + case S4_storerh_rr: + return IfTrue ? S4_pstorerht_rr : S4_pstorerhf_rr; + case S2_storerhabs: + case S2_storerhgp: + return IfTrue ? S4_pstorerht_abs : S4_pstorerhf_abs; + case S2_storerf_io: + return IfTrue ? S2_pstorerft_io : S2_pstorerff_io; + case S4_storerf_rr: + return IfTrue ? S4_pstorerft_rr : S4_pstorerff_rr; + case S2_storerfabs: + case S2_storerfgp: + return IfTrue ? S4_pstorerft_abs : S4_pstorerff_abs; + case S4_storeirh_io: + return IfTrue ? S4_storeirht_io : S4_storeirhf_io; + case S2_storeri_io: + return IfTrue ? S2_pstorerit_io : S2_pstorerif_io; + case S4_storeri_rr: + return IfTrue ? S4_pstorerit_rr : S4_pstorerif_rr; + case S2_storeriabs: + case S2_storerigp: + return IfTrue ? S4_pstorerit_abs : S4_pstorerif_abs; + case S4_storeiri_io: + return IfTrue ? S4_storeirit_io : S4_storeirif_io; + case S2_storerd_io: + return IfTrue ? S2_pstorerdt_io : S2_pstorerdf_io; + case S4_storerd_rr: + return IfTrue ? S4_pstorerdt_rr : S4_pstorerdf_rr; + case S2_storerdabs: + case S2_storerdgp: + return IfTrue ? S4_pstorerdt_abs : S4_pstorerdf_abs; + } + llvm_unreachable("Unexpected opcode"); + return 0; +} + + +void HexagonEarlyIfConversion::predicateInstr(MachineBasicBlock *ToB, + MachineBasicBlock::iterator At, MachineInstr *MI, + unsigned PredR, bool IfTrue) { + DebugLoc DL; + if (At != ToB->end()) + DL = At->getDebugLoc(); + else if (!ToB->empty()) + DL = ToB->back().getDebugLoc(); + + unsigned Opc = MI->getOpcode(); + + if (isPredicableStore(MI)) { + unsigned COpc = getCondStoreOpcode(Opc, IfTrue); + assert(COpc); + MachineInstrBuilder MIB = BuildMI(*ToB, At, DL, TII->get(COpc)) + .addReg(PredR); + for (MIOperands MO(MI); MO.isValid(); ++MO) + MIB.addOperand(*MO); + + // Set memory references. + MachineInstr::mmo_iterator MMOBegin = MI->memoperands_begin(); + MachineInstr::mmo_iterator MMOEnd = MI->memoperands_end(); + MIB.setMemRefs(MMOBegin, MMOEnd); + + MI->eraseFromParent(); + return; + } + + if (Opc == Hexagon::J2_jump) { + MachineBasicBlock *TB = MI->getOperand(0).getMBB(); + const MCInstrDesc &D = TII->get(IfTrue ? Hexagon::J2_jumpt + : Hexagon::J2_jumpf); + BuildMI(*ToB, At, DL, D) + .addReg(PredR) + .addMBB(TB); + MI->eraseFromParent(); + return; + } + + // Print the offending instruction unconditionally as we are about to + // abort. + dbgs() << *MI; + llvm_unreachable("Unexpected instruction"); +} + + +// Predicate/speculate non-branch instructions from FromB into block ToB. +// Leave the branches alone, they will be handled later. Btw, at this point +// FromB should have at most one branch, and it should be unconditional. +void HexagonEarlyIfConversion::predicateBlockNB(MachineBasicBlock *ToB, + MachineBasicBlock::iterator At, MachineBasicBlock *FromB, + unsigned PredR, bool IfTrue) { + DEBUG(dbgs() << "Predicating block " << PrintMB(FromB) << "\n"); + MachineBasicBlock::iterator End = FromB->getFirstTerminator(); + MachineBasicBlock::iterator I, NextI; + + for (I = FromB->begin(); I != End; I = NextI) { + assert(!I->isPHI()); + NextI = std::next(I); + if (isSafeToSpeculate(&*I)) + ToB->splice(At, FromB, I); + else + predicateInstr(ToB, At, &*I, PredR, IfTrue); + } +} + + +void HexagonEarlyIfConversion::updatePhiNodes(MachineBasicBlock *WhereB, + const FlowPattern &FP) { + // Visit all PHI nodes in the WhereB block and generate MUX instructions + // in the split block. Update the PHI nodes with the values of the MUX. + auto NonPHI = WhereB->getFirstNonPHI(); + for (auto I = WhereB->begin(); I != NonPHI; ++I) { + MachineInstr *PN = &*I; + // Registers and subregisters corresponding to TrueB, FalseB and SplitB. + unsigned TR = 0, TSR = 0, FR = 0, FSR = 0, SR = 0, SSR = 0; + for (int i = PN->getNumOperands()-2; i > 0; i -= 2) { + const MachineOperand &RO = PN->getOperand(i), &BO = PN->getOperand(i+1); + if (BO.getMBB() == FP.SplitB) + SR = RO.getReg(), SSR = RO.getSubReg(); + else if (BO.getMBB() == FP.TrueB) + TR = RO.getReg(), TSR = RO.getSubReg(); + else if (BO.getMBB() == FP.FalseB) + FR = RO.getReg(), FSR = RO.getSubReg(); + else + continue; + PN->RemoveOperand(i+1); + PN->RemoveOperand(i); + } + if (TR == 0) + TR = SR, TSR = SSR; + else if (FR == 0) + FR = SR, FSR = SSR; + assert(TR && FR); + + using namespace Hexagon; + unsigned DR = PN->getOperand(0).getReg(); + const TargetRegisterClass *RC = MRI->getRegClass(DR); + const MCInstrDesc &D = RC == &IntRegsRegClass ? TII->get(C2_mux) + : TII->get(MUX64_rr); + + MachineBasicBlock::iterator MuxAt = FP.SplitB->getFirstTerminator(); + DebugLoc DL; + if (MuxAt != FP.SplitB->end()) + DL = MuxAt->getDebugLoc(); + unsigned MuxR = MRI->createVirtualRegister(RC); + BuildMI(*FP.SplitB, MuxAt, DL, D, MuxR) + .addReg(FP.PredR) + .addReg(TR, 0, TSR) + .addReg(FR, 0, FSR); + + PN->addOperand(MachineOperand::CreateReg(MuxR, false)); + PN->addOperand(MachineOperand::CreateMBB(FP.SplitB)); + } +} + + +void HexagonEarlyIfConversion::convert(const FlowPattern &FP) { + MachineBasicBlock *TSB = 0, *FSB = 0; + MachineBasicBlock::iterator OldTI = FP.SplitB->getFirstTerminator(); + assert(OldTI != FP.SplitB->end()); + DebugLoc DL = OldTI->getDebugLoc(); + + if (FP.TrueB) { + TSB = *FP.TrueB->succ_begin(); + predicateBlockNB(FP.SplitB, OldTI, FP.TrueB, FP.PredR, true); + } + if (FP.FalseB) { + FSB = *FP.FalseB->succ_begin(); + MachineBasicBlock::iterator At = FP.SplitB->getFirstTerminator(); + predicateBlockNB(FP.SplitB, At, FP.FalseB, FP.PredR, false); + } + + // Regenerate new terminators in the split block and update the successors. + // First, remember any information that may be needed later and remove the + // existing terminators/successors from the split block. + MachineBasicBlock *SSB = 0; + FP.SplitB->erase(OldTI, FP.SplitB->end()); + while (FP.SplitB->succ_size() > 0) { + MachineBasicBlock *T = *FP.SplitB->succ_begin(); + // It's possible that the split block had a successor that is not a pre- + // dicated block. This could only happen if there was only one block to + // be predicated. Example: + // split_b: + // if (p) jump true_b + // jump unrelated2_b + // unrelated1_b: + // ... + // unrelated2_b: ; can have other predecessors, so it's not "false_b" + // jump other_b + // true_b: ; only reachable from split_b, can be predicated + // ... + // + // Find this successor (SSB) if it exists. + if (T != FP.TrueB && T != FP.FalseB) { + assert(!SSB); + SSB = T; + } + FP.SplitB->removeSuccessor(FP.SplitB->succ_begin()); + } + + // Insert new branches and update the successors of the split block. This + // may create unconditional branches to the layout successor, etc., but + // that will be cleaned up later. For now, make sure that correct code is + // generated. + if (FP.JoinB) { + assert(!SSB || SSB == FP.JoinB); + BuildMI(*FP.SplitB, FP.SplitB->end(), DL, TII->get(Hexagon::J2_jump)) + .addMBB(FP.JoinB); + FP.SplitB->addSuccessor(FP.JoinB); + } else { + bool HasBranch = false; + if (TSB) { + BuildMI(*FP.SplitB, FP.SplitB->end(), DL, TII->get(Hexagon::J2_jumpt)) + .addReg(FP.PredR) + .addMBB(TSB); + FP.SplitB->addSuccessor(TSB); + HasBranch = true; + } + if (FSB) { + const MCInstrDesc &D = HasBranch ? TII->get(Hexagon::J2_jump) + : TII->get(Hexagon::J2_jumpf); + MachineInstrBuilder MIB = BuildMI(*FP.SplitB, FP.SplitB->end(), DL, D); + if (!HasBranch) + MIB.addReg(FP.PredR); + MIB.addMBB(FSB); + FP.SplitB->addSuccessor(FSB); + } + if (SSB) { + // This cannot happen if both TSB and FSB are set. [TF]SB are the + // successor blocks of the TrueB and FalseB (or null of the TrueB + // or FalseB block is null). SSB is the potential successor block + // of the SplitB that is neither TrueB nor FalseB. + BuildMI(*FP.SplitB, FP.SplitB->end(), DL, TII->get(Hexagon::J2_jump)) + .addMBB(SSB); + FP.SplitB->addSuccessor(SSB); + } + } + + // What is left to do is to update the PHI nodes that could have entries + // referring to predicated blocks. + if (FP.JoinB) { + updatePhiNodes(FP.JoinB, FP); + } else { + if (TSB) + updatePhiNodes(TSB, FP); + if (FSB) + updatePhiNodes(FSB, FP); + // Nothing to update in SSB, since SSB's predecessors haven't changed. + } +} + + +void HexagonEarlyIfConversion::removeBlock(MachineBasicBlock *B) { + DEBUG(dbgs() << "Removing block " << PrintMB(B) << "\n"); + + // Transfer the immediate dominator information from B to its descendants. + MachineDomTreeNode *N = MDT->getNode(B); + MachineDomTreeNode *IDN = N->getIDom(); + if (IDN) { + MachineBasicBlock *IDB = IDN->getBlock(); + typedef GraphTraits GTN; + typedef SmallVector DTNodeVectType; + DTNodeVectType Cn(GTN::child_begin(N), GTN::child_end(N)); + for (DTNodeVectType::iterator I = Cn.begin(), E = Cn.end(); I != E; ++I) { + MachineBasicBlock *SB = (*I)->getBlock(); + MDT->changeImmediateDominator(SB, IDB); + } + } + + while (B->succ_size() > 0) + B->removeSuccessor(B->succ_begin()); + + for (auto I = B->pred_begin(), E = B->pred_end(); I != E; ++I) + (*I)->removeSuccessor(B); + + Deleted.insert(B); + MDT->eraseNode(B); + MachineFunction::iterator BI = B; + MFN->erase(BI); +} + + +void HexagonEarlyIfConversion::eliminatePhis(MachineBasicBlock *B) { + DEBUG(dbgs() << "Removing phi nodes from block " << PrintMB(B) << "\n"); + MachineBasicBlock::iterator I, NextI, NonPHI = B->getFirstNonPHI(); + for (I = B->begin(); I != NonPHI; I = NextI) { + NextI = std::next(I); + MachineInstr *PN = &*I; + assert(PN->getNumOperands() == 3 && "Invalid phi node"); + MachineOperand &UO = PN->getOperand(1); + unsigned UseR = UO.getReg(), UseSR = UO.getSubReg(); + unsigned DefR = PN->getOperand(0).getReg(); + unsigned NewR = UseR; + if (UseSR) { + // MRI.replaceVregUsesWith does not allow to update the subregister, + // so instead of doing the use-iteration here, create a copy into a + // "non-subregistered" register. + DebugLoc DL = PN->getDebugLoc(); + const TargetRegisterClass *RC = MRI->getRegClass(DefR); + NewR = MRI->createVirtualRegister(RC); + NonPHI = BuildMI(*B, NonPHI, DL, TII->get(TargetOpcode::COPY), NewR) + .addReg(UseR, 0, UseSR); + } + MRI->replaceRegWith(DefR, NewR); + B->erase(I); + } +} + + +void HexagonEarlyIfConversion::replacePhiEdges(MachineBasicBlock *OldB, + MachineBasicBlock *NewB) { + for (auto I = OldB->succ_begin(), E = OldB->succ_end(); I != E; ++I) { + MachineBasicBlock *SB = *I; + MachineBasicBlock::iterator P, N = SB->getFirstNonPHI(); + for (P = SB->begin(); P != N; ++P) { + MachineInstr *PN = &*P; + for (MIOperands MO(PN); MO.isValid(); ++MO) + if (MO->isMBB() && MO->getMBB() == OldB) + MO->setMBB(NewB); + } + } +} + + +void HexagonEarlyIfConversion::mergeBlocks(MachineBasicBlock *PredB, + MachineBasicBlock *SuccB) { + DEBUG(dbgs() << "Merging blocks " << PrintMB(PredB) << " and " + << PrintMB(SuccB) << "\n"); + bool TermOk = hasUncondBranch(SuccB); + eliminatePhis(SuccB); + TII->RemoveBranch(*PredB); + PredB->removeSuccessor(SuccB); + PredB->splice(PredB->end(), SuccB, SuccB->begin(), SuccB->end()); + MachineBasicBlock::succ_iterator I, E = SuccB->succ_end(); + for (I = SuccB->succ_begin(); I != E; ++I) + PredB->addSuccessor(*I); + replacePhiEdges(SuccB, PredB); + removeBlock(SuccB); + if (!TermOk) + PredB->updateTerminator(); +} + + +void HexagonEarlyIfConversion::simplifyFlowGraph(const FlowPattern &FP) { + if (FP.TrueB) + removeBlock(FP.TrueB); + if (FP.FalseB) + removeBlock(FP.FalseB); + + FP.SplitB->updateTerminator(); + if (FP.SplitB->succ_size() != 1) + return; + + MachineBasicBlock *SB = *FP.SplitB->succ_begin(); + if (SB->pred_size() != 1) + return; + + // By now, the split block has only one successor (SB), and SB has only + // one predecessor. We can try to merge them. We will need to update ter- + // minators in FP.Split+SB, and that requires working AnalyzeBranch, which + // fails on Hexagon for blocks that have EH_LABELs. However, if SB ends + // with an unconditional branch, we won't need to touch the terminators. + if (!hasEHLabel(SB) || hasUncondBranch(SB)) + mergeBlocks(FP.SplitB, SB); +} + + +bool HexagonEarlyIfConversion::runOnMachineFunction(MachineFunction &MF) { + auto &ST = MF.getSubtarget(); + TII = ST.getInstrInfo(); + TRI = ST.getRegisterInfo(); + MFN = &MF; + MRI = &MF.getRegInfo(); + MDT = &getAnalysis(); + MLI = &getAnalysis(); + MBPI = EnableHexagonBP ? &getAnalysis() : + nullptr; + + Deleted.clear(); + bool Changed = false; + + for (MachineLoopInfo::iterator I = MLI->begin(), E = MLI->end(); I != E; ++I) + Changed |= visitLoop(*I); + Changed |= visitLoop(0); + + return Changed; +} + +//===----------------------------------------------------------------------===// +// Public Constructor Functions +//===----------------------------------------------------------------------===// +FunctionPass *llvm::createHexagonEarlyIfConversion() { + return new HexagonEarlyIfConversion(); +} + diff --git a/lib/Target/Hexagon/HexagonInstrInfo.cpp b/lib/Target/Hexagon/HexagonInstrInfo.cpp index 9b12f148219..23849793445 100644 --- a/lib/Target/Hexagon/HexagonInstrInfo.cpp +++ b/lib/Target/Hexagon/HexagonInstrInfo.cpp @@ -684,7 +684,7 @@ void HexagonInstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg, } bool HexagonInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { - const HexagonRegisterInfo &TRI = getRegisterInfo(); + const HexagonRegisterInfo &HRI = getRegisterInfo(); MachineRegisterInfo &MRI = MI->getParent()->getParent()->getRegInfo(); MachineBasicBlock &MBB = *MI->getParent(); DebugLoc DL = MI->getDebugLoc(); @@ -693,7 +693,7 @@ HexagonInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { switch (Opc) { case Hexagon::ALIGNA: BuildMI(MBB, MI, DL, get(Hexagon::A2_andir), MI->getOperand(0).getReg()) - .addReg(TRI.getFrameRegister()) + .addReg(HRI.getFrameRegister()) .addImm(-MI->getOperand(1).getImm()); MBB.erase(MI); return true; @@ -718,15 +718,15 @@ HexagonInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { unsigned DstReg = MI->getOperand(0).getReg(); unsigned Src1Reg = MI->getOperand(1).getReg(); unsigned Src2Reg = MI->getOperand(2).getReg(); - unsigned Src1SubHi = TRI.getSubReg(Src1Reg, Hexagon::subreg_hireg); - unsigned Src1SubLo = TRI.getSubReg(Src1Reg, Hexagon::subreg_loreg); - unsigned Src2SubHi = TRI.getSubReg(Src2Reg, Hexagon::subreg_hireg); - unsigned Src2SubLo = TRI.getSubReg(Src2Reg, Hexagon::subreg_loreg); + unsigned Src1SubHi = HRI.getSubReg(Src1Reg, Hexagon::subreg_hireg); + unsigned Src1SubLo = HRI.getSubReg(Src1Reg, Hexagon::subreg_loreg); + unsigned Src2SubHi = HRI.getSubReg(Src2Reg, Hexagon::subreg_hireg); + unsigned Src2SubLo = HRI.getSubReg(Src2Reg, Hexagon::subreg_loreg); BuildMI(MBB, MI, MI->getDebugLoc(), get(Hexagon::M2_mpyi), - TRI.getSubReg(DstReg, Hexagon::subreg_hireg)).addReg(Src1SubHi) + HRI.getSubReg(DstReg, Hexagon::subreg_hireg)).addReg(Src1SubHi) .addReg(Src2SubHi); BuildMI(MBB, MI, MI->getDebugLoc(), get(Hexagon::M2_mpyi), - TRI.getSubReg(DstReg, Hexagon::subreg_loreg)).addReg(Src1SubLo) + HRI.getSubReg(DstReg, Hexagon::subreg_loreg)).addReg(Src1SubLo) .addReg(Src2SubLo); MBB.erase(MI); MRI.clearKillFlags(Src1SubHi); @@ -741,17 +741,17 @@ HexagonInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { unsigned Src1Reg = MI->getOperand(1).getReg(); unsigned Src2Reg = MI->getOperand(2).getReg(); unsigned Src3Reg = MI->getOperand(3).getReg(); - unsigned Src1SubHi = TRI.getSubReg(Src1Reg, Hexagon::subreg_hireg); - unsigned Src1SubLo = TRI.getSubReg(Src1Reg, Hexagon::subreg_loreg); - unsigned Src2SubHi = TRI.getSubReg(Src2Reg, Hexagon::subreg_hireg); - unsigned Src2SubLo = TRI.getSubReg(Src2Reg, Hexagon::subreg_loreg); - unsigned Src3SubHi = TRI.getSubReg(Src3Reg, Hexagon::subreg_hireg); - unsigned Src3SubLo = TRI.getSubReg(Src3Reg, Hexagon::subreg_loreg); + unsigned Src1SubHi = HRI.getSubReg(Src1Reg, Hexagon::subreg_hireg); + unsigned Src1SubLo = HRI.getSubReg(Src1Reg, Hexagon::subreg_loreg); + unsigned Src2SubHi = HRI.getSubReg(Src2Reg, Hexagon::subreg_hireg); + unsigned Src2SubLo = HRI.getSubReg(Src2Reg, Hexagon::subreg_loreg); + unsigned Src3SubHi = HRI.getSubReg(Src3Reg, Hexagon::subreg_hireg); + unsigned Src3SubLo = HRI.getSubReg(Src3Reg, Hexagon::subreg_loreg); BuildMI(MBB, MI, MI->getDebugLoc(), get(Hexagon::M2_maci), - TRI.getSubReg(DstReg, Hexagon::subreg_hireg)).addReg(Src1SubHi) + HRI.getSubReg(DstReg, Hexagon::subreg_hireg)).addReg(Src1SubHi) .addReg(Src2SubHi).addReg(Src3SubHi); BuildMI(MBB, MI, MI->getDebugLoc(), get(Hexagon::M2_maci), - TRI.getSubReg(DstReg, Hexagon::subreg_loreg)).addReg(Src1SubLo) + HRI.getSubReg(DstReg, Hexagon::subreg_loreg)).addReg(Src1SubLo) .addReg(Src2SubLo).addReg(Src3SubLo); MBB.erase(MI); MRI.clearKillFlags(Src1SubHi); @@ -762,6 +762,30 @@ HexagonInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { MRI.clearKillFlags(Src3SubLo); return true; } + case Hexagon::MUX64_rr: { + const MachineOperand &Op0 = MI->getOperand(0); + const MachineOperand &Op1 = MI->getOperand(1); + const MachineOperand &Op2 = MI->getOperand(2); + const MachineOperand &Op3 = MI->getOperand(3); + unsigned Rd = Op0.getReg(); + unsigned Pu = Op1.getReg(); + unsigned Rs = Op2.getReg(); + unsigned Rt = Op3.getReg(); + DebugLoc DL = MI->getDebugLoc(); + unsigned K1 = getKillRegState(Op1.isKill()); + unsigned K2 = getKillRegState(Op2.isKill()); + unsigned K3 = getKillRegState(Op3.isKill()); + if (Rd != Rs) + BuildMI(MBB, MI, DL, get(Hexagon::A2_tfrpt), Rd) + .addReg(Pu, (Rd == Rt) ? K1 : 0) + .addReg(Rs, K2); + if (Rd != Rt) + BuildMI(MBB, MI, DL, get(Hexagon::A2_tfrpf), Rd) + .addReg(Pu, K1) + .addReg(Rt, K3); + MBB.erase(MI); + return true; + } case Hexagon::TCRETURNi: MI->setDesc(get(Hexagon::J2_jump)); return true; @@ -1285,7 +1309,44 @@ bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset, case Hexagon::TFR_FIA: case Hexagon::INLINEASM: return true; - } + + case Hexagon::L2_ploadrbt_io: + case Hexagon::L2_ploadrbf_io: + case Hexagon::L2_ploadrubt_io: + case Hexagon::L2_ploadrubf_io: + case Hexagon::S2_pstorerbt_io: + case Hexagon::S2_pstorerbf_io: + case Hexagon::S4_storeirb_io: + case Hexagon::S4_storeirbt_io: + case Hexagon::S4_storeirbf_io: + return isUInt<6>(Offset); + + case Hexagon::L2_ploadrht_io: + case Hexagon::L2_ploadrhf_io: + case Hexagon::L2_ploadruht_io: + case Hexagon::L2_ploadruhf_io: + case Hexagon::S2_pstorerht_io: + case Hexagon::S2_pstorerhf_io: + case Hexagon::S4_storeirh_io: + case Hexagon::S4_storeirht_io: + case Hexagon::S4_storeirhf_io: + return isShiftedUInt<6,1>(Offset); + + case Hexagon::L2_ploadrit_io: + case Hexagon::L2_ploadrif_io: + case Hexagon::S2_pstorerit_io: + case Hexagon::S2_pstorerif_io: + case Hexagon::S4_storeiri_io: + case Hexagon::S4_storeirit_io: + case Hexagon::S4_storeirif_io: + return isShiftedUInt<6,2>(Offset); + + case Hexagon::L2_ploadrdt_io: + case Hexagon::L2_ploadrdf_io: + case Hexagon::S2_pstorerdt_io: + case Hexagon::S2_pstorerdf_io: + return isShiftedUInt<6,3>(Offset); + } // switch llvm_unreachable("No offset range is defined for this opcode. " "Please define it in the above switch statement!"); diff --git a/lib/Target/Hexagon/HexagonTargetMachine.cpp b/lib/Target/Hexagon/HexagonTargetMachine.cpp index cd05ecec68a..6ed0d19a175 100644 --- a/lib/Target/Hexagon/HexagonTargetMachine.cpp +++ b/lib/Target/Hexagon/HexagonTargetMachine.cpp @@ -37,6 +37,9 @@ static cl::opt EnableExpandCondsets("hexagon-expand-condsets", cl::init(true), cl::Hidden, cl::ZeroOrMore, cl::desc("Early expansion of MUX")); +static cl::opt EnableEarlyIf("hexagon-eif", cl::init(true), cl::Hidden, + cl::ZeroOrMore, cl::desc("Enable early if-conversion")); + static cl::opt EnableGenInsert("hexagon-insert", cl::init(true), cl::Hidden, cl::desc("Generate \"insert\" instructions")); @@ -78,6 +81,7 @@ namespace llvm { FunctionPass *createHexagonCFGOptimizer(); FunctionPass *createHexagonCommonGEP(); FunctionPass *createHexagonCopyToCombine(); + FunctionPass *createHexagonEarlyIfConversion(); FunctionPass *createHexagonExpandCondsets(); FunctionPass *createHexagonExpandPredSpillCode(); FunctionPass *createHexagonFixupHwLoops(); @@ -214,6 +218,8 @@ bool HexagonPassConfig::addInstSelector() { printAndVerify("After hexagon peephole pass"); if (EnableGenInsert) addPass(createHexagonGenInsert(), false); + if (EnableEarlyIf) + addPass(createHexagonEarlyIfConversion(), false); } return false; diff --git a/test/CodeGen/Hexagon/early-if-conversion-bug1.ll b/test/CodeGen/Hexagon/early-if-conversion-bug1.ll new file mode 100644 index 00000000000..6739b03985d --- /dev/null +++ b/test/CodeGen/Hexagon/early-if-conversion-bug1.ll @@ -0,0 +1,412 @@ +; RUN: llc -O2 -march=hexagon -mcpu=hexagonv5 < %s | FileCheck %s +; we do not want to see a segv. +; CHECK-NOT: segmentation +; CHECK: call + +target datalayout = "e-m:e-p:32:32-i1:32-i64:64-a:0-v32:32-n16:32" +target triple = "hexagon" + +%"class.std::__1::basic_string" = type { %"class.std::__1::__compressed_pair" } +%"class.std::__1::__compressed_pair" = type { %"class.std::__1::__libcpp_compressed_pair_imp" } +%"class.std::__1::__libcpp_compressed_pair_imp" = type { %"struct.std::__1::basic_string, std::__1::allocator >::__rep" } +%"struct.std::__1::basic_string, std::__1::allocator >::__rep" = type { %union.anon } +%union.anon = type { %"struct.std::__1::basic_string, std::__1::allocator >::__long" } +%"struct.std::__1::basic_string, std::__1::allocator >::__long" = type { i32, i32, i8* } +%"class.std::__1::ios_base" = type { i32 (...)**, i32, i32, i32, i32, i32, i8*, i8*, void (i8, %"class.std::__1::ios_base"*, i32)**, i32*, i32, i32, i32*, i32, i32, i8**, i32, i32 } +%"class.std::__1::basic_streambuf" = type { i32 (...)**, %"class.std::__1::locale", i8*, i8*, i8*, i8*, i8*, i8* } +%"class.std::__1::locale" = type { %"class.std::__1::locale::__imp"* } +%"class.std::__1::locale::__imp" = type opaque +%"class.std::__1::allocator" = type { i8 } +%"class.std::__1::ostreambuf_iterator" = type { %"class.std::__1::basic_streambuf"* } +%"class.std::__1::__basic_string_common" = type { i8 } +%"struct.std::__1::basic_string, std::__1::allocator >::__short" = type { %union.anon.0, [11 x i8] } +%union.anon.0 = type { i8 } + +; Function Attrs: nounwind +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0 + +declare i32 @__gxx_personality_v0(...) + +; Function Attrs: nounwind +declare void @_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev(%"class.std::__1::basic_string"*) #1 + +define weak_odr hidden i32 @_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_(i32 %__s.coerce, i8* %__ob, i8* %__op, i8* %__oe, %"class.std::__1::ios_base"* nonnull %__iob, i8 zeroext %__fl) #2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %this.addr.i66 = alloca %"class.std::__1::basic_streambuf"*, align 4 + %__s.addr.i67 = alloca i8*, align 4 + %__n.addr.i68 = alloca i32, align 4 + %__p.addr.i.i = alloca i8*, align 4 + %this.addr.i.i.i13.i.i = alloca %"class.std::__1::__libcpp_compressed_pair_imp"*, align 4 + %this.addr.i.i14.i.i = alloca %"class.std::__1::__compressed_pair"*, align 4 + %this.addr.i15.i.i = alloca %"class.std::__1::basic_string"*, align 4 + %__x.addr.i.i.i.i.i = alloca i8*, align 4 + %__r.addr.i.i.i.i = alloca i8*, align 4 + %this.addr.i.i.i4.i.i = alloca %"class.std::__1::__libcpp_compressed_pair_imp"*, align 4 + %this.addr.i.i5.i.i = alloca %"class.std::__1::__compressed_pair"*, align 4 + %this.addr.i6.i.i = alloca %"class.std::__1::basic_string"*, align 4 + %this.addr.i.i.i.i.i56 = alloca %"class.std::__1::__libcpp_compressed_pair_imp"*, align 4 + %this.addr.i.i.i.i57 = alloca %"class.std::__1::__compressed_pair"*, align 4 + %this.addr.i.i.i58 = alloca %"class.std::__1::basic_string"*, align 4 + %this.addr.i.i59 = alloca %"class.std::__1::basic_string"*, align 4 + %this.addr.i60 = alloca %"class.std::__1::basic_string"*, align 4 + %this.addr.i.i.i.i.i = alloca %"class.std::__1::allocator"*, align 4 + %this.addr.i.i.i.i = alloca %"class.std::__1::__libcpp_compressed_pair_imp"*, align 4 + %this.addr.i.i.i = alloca %"class.std::__1::__compressed_pair"*, align 4 + %this.addr.i.i = alloca %"class.std::__1::basic_string"*, align 4 + %__n.addr.i.i = alloca i32, align 4 + %__c.addr.i.i = alloca i8, align 1 + %this.addr.i53 = alloca %"class.std::__1::basic_string"*, align 4 + %__n.addr.i54 = alloca i32, align 4 + %__c.addr.i = alloca i8, align 1 + %this.addr.i46 = alloca %"class.std::__1::basic_streambuf"*, align 4 + %__s.addr.i47 = alloca i8*, align 4 + %__n.addr.i48 = alloca i32, align 4 + %this.addr.i44 = alloca %"class.std::__1::basic_streambuf"*, align 4 + %__s.addr.i = alloca i8*, align 4 + %__n.addr.i = alloca i32, align 4 + %this.addr.i41 = alloca %"class.std::__1::ios_base"*, align 4 + %__wide.addr.i = alloca i32, align 4 + %__r.i = alloca i32, align 4 + %this.addr.i = alloca %"class.std::__1::ios_base"*, align 4 + %retval = alloca %"class.std::__1::ostreambuf_iterator", align 4 + %__s = alloca %"class.std::__1::ostreambuf_iterator", align 4 + %__ob.addr = alloca i8*, align 4 + %__op.addr = alloca i8*, align 4 + %__oe.addr = alloca i8*, align 4 + %__iob.addr = alloca %"class.std::__1::ios_base"*, align 4 + %__fl.addr = alloca i8, align 1 + %__sz = alloca i32, align 4 + %__ns = alloca i32, align 4 + %__np = alloca i32, align 4 + %__sp = alloca %"class.std::__1::basic_string", align 4 + %exn.slot = alloca i8* + %ehselector.slot = alloca i32 + %cleanup.dest.slot = alloca i32 + %coerce.dive = getelementptr %"class.std::__1::ostreambuf_iterator", %"class.std::__1::ostreambuf_iterator"* %__s, i32 0, i32 0 + %coerce.val.ip = inttoptr i32 %__s.coerce to %"class.std::__1::basic_streambuf"* + store %"class.std::__1::basic_streambuf"* %coerce.val.ip, %"class.std::__1::basic_streambuf"** %coerce.dive + store i8* %__ob, i8** %__ob.addr, align 4 + store i8* %__op, i8** %__op.addr, align 4 + store i8* %__oe, i8** %__oe.addr, align 4 + store %"class.std::__1::ios_base"* %__iob, %"class.std::__1::ios_base"** %__iob.addr, align 4 + store i8 %__fl, i8* %__fl.addr, align 1 + %__sbuf_ = getelementptr inbounds %"class.std::__1::ostreambuf_iterator", %"class.std::__1::ostreambuf_iterator"* %__s, i32 0, i32 0 + %0 = load %"class.std::__1::basic_streambuf"*, %"class.std::__1::basic_streambuf"** %__sbuf_, align 4 + %cmp = icmp eq %"class.std::__1::basic_streambuf"* %0, null + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %1 = bitcast %"class.std::__1::ostreambuf_iterator"* %retval to i8* + %2 = bitcast %"class.std::__1::ostreambuf_iterator"* %__s to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %1, i8* %2, i32 4, i32 4, i1 false) + br label %return + +if.end: ; preds = %entry + %3 = load i8*, i8** %__oe.addr, align 4 + %4 = load i8*, i8** %__ob.addr, align 4 + %sub.ptr.lhs.cast = ptrtoint i8* %3 to i32 + %sub.ptr.rhs.cast = ptrtoint i8* %4 to i32 + %sub.ptr.sub = sub i32 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast + store i32 %sub.ptr.sub, i32* %__sz, align 4 + %5 = load %"class.std::__1::ios_base"*, %"class.std::__1::ios_base"** %__iob.addr, align 4 + store %"class.std::__1::ios_base"* %5, %"class.std::__1::ios_base"** %this.addr.i, align 4 + %this1.i = load %"class.std::__1::ios_base"*, %"class.std::__1::ios_base"** %this.addr.i + %__width_.i = getelementptr inbounds %"class.std::__1::ios_base", %"class.std::__1::ios_base"* %this1.i, i32 0, i32 3 + %6 = load i32, i32* %__width_.i, align 4 + store i32 %6, i32* %__ns, align 4 + %7 = load i32, i32* %__ns, align 4 + %8 = load i32, i32* %__sz, align 4 + %cmp1 = icmp sgt i32 %7, %8 + br i1 %cmp1, label %if.then2, label %if.else + +if.then2: ; preds = %if.end + %9 = load i32, i32* %__sz, align 4 + %10 = load i32, i32* %__ns, align 4 + %sub = sub nsw i32 %10, %9 + store i32 %sub, i32* %__ns, align 4 + br label %if.end3 + +if.else: ; preds = %if.end + store i32 0, i32* %__ns, align 4 + br label %if.end3 + +if.end3: ; preds = %if.else, %if.then2 + %11 = load i8*, i8** %__op.addr, align 4 + %12 = load i8*, i8** %__ob.addr, align 4 + %sub.ptr.lhs.cast4 = ptrtoint i8* %11 to i32 + %sub.ptr.rhs.cast5 = ptrtoint i8* %12 to i32 + %sub.ptr.sub6 = sub i32 %sub.ptr.lhs.cast4, %sub.ptr.rhs.cast5 + store i32 %sub.ptr.sub6, i32* %__np, align 4 + %13 = load i32, i32* %__np, align 4 + %cmp7 = icmp sgt i32 %13, 0 + br i1 %cmp7, label %if.then8, label %if.end15 + +if.then8: ; preds = %if.end3 + %__sbuf_9 = getelementptr inbounds %"class.std::__1::ostreambuf_iterator", %"class.std::__1::ostreambuf_iterator"* %__s, i32 0, i32 0 + %14 = load %"class.std::__1::basic_streambuf"*, %"class.std::__1::basic_streambuf"** %__sbuf_9, align 4 + %15 = load i8*, i8** %__ob.addr, align 4 + %16 = load i32, i32* %__np, align 4 + store %"class.std::__1::basic_streambuf"* %14, %"class.std::__1::basic_streambuf"** %this.addr.i46, align 4 + store i8* %15, i8** %__s.addr.i47, align 4 + store i32 %16, i32* %__n.addr.i48, align 4 + %this1.i49 = load %"class.std::__1::basic_streambuf"*, %"class.std::__1::basic_streambuf"** %this.addr.i46 + %17 = bitcast %"class.std::__1::basic_streambuf"* %this1.i49 to i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*** + %vtable.i50 = load i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)**, i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*** %17 + %vfn.i51 = getelementptr inbounds i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*, i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)** %vtable.i50, i64 12 + %18 = load i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*, i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)** %vfn.i51 + %19 = load i8*, i8** %__s.addr.i47, align 4 + %20 = load i32, i32* %__n.addr.i48, align 4 + %call.i52 = call i32 %18(%"class.std::__1::basic_streambuf"* %this1.i49, i8* %19, i32 %20) + %21 = load i32, i32* %__np, align 4 + %cmp11 = icmp ne i32 %call.i52, %21 + br i1 %cmp11, label %if.then12, label %if.end14 + +if.then12: ; preds = %if.then8 + %__sbuf_13 = getelementptr inbounds %"class.std::__1::ostreambuf_iterator", %"class.std::__1::ostreambuf_iterator"* %__s, i32 0, i32 0 + store %"class.std::__1::basic_streambuf"* null, %"class.std::__1::basic_streambuf"** %__sbuf_13, align 4 + %22 = bitcast %"class.std::__1::ostreambuf_iterator"* %retval to i8* + %23 = bitcast %"class.std::__1::ostreambuf_iterator"* %__s to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %22, i8* %23, i32 4, i32 4, i1 false) + br label %return + +if.end14: ; preds = %if.then8 + br label %if.end15 + +if.end15: ; preds = %if.end14, %if.end3 + %24 = load i32, i32* %__ns, align 4 + %cmp16 = icmp sgt i32 %24, 0 + br i1 %cmp16, label %if.then17, label %if.end25 + +if.then17: ; preds = %if.end15 + %25 = load i32, i32* %__ns, align 4 + %26 = load i8, i8* %__fl.addr, align 1 + store %"class.std::__1::basic_string"* %__sp, %"class.std::__1::basic_string"** %this.addr.i53, align 4 + store i32 %25, i32* %__n.addr.i54, align 4 + store i8 %26, i8* %__c.addr.i, align 1 + %this1.i55 = load %"class.std::__1::basic_string"*, %"class.std::__1::basic_string"** %this.addr.i53 + %27 = load i32, i32* %__n.addr.i54, align 4 + %28 = load i8, i8* %__c.addr.i, align 1 + store %"class.std::__1::basic_string"* %this1.i55, %"class.std::__1::basic_string"** %this.addr.i.i, align 4 + store i32 %27, i32* %__n.addr.i.i, align 4 + store i8 %28, i8* %__c.addr.i.i, align 1 + %this1.i.i = load %"class.std::__1::basic_string"*, %"class.std::__1::basic_string"** %this.addr.i.i + %29 = bitcast %"class.std::__1::basic_string"* %this1.i.i to %"class.std::__1::__basic_string_common"* + %__r_.i.i = getelementptr inbounds %"class.std::__1::basic_string", %"class.std::__1::basic_string"* %this1.i.i, i32 0, i32 0 + store %"class.std::__1::__compressed_pair"* %__r_.i.i, %"class.std::__1::__compressed_pair"** %this.addr.i.i.i, align 4 + %this1.i.i.i = load %"class.std::__1::__compressed_pair"*, %"class.std::__1::__compressed_pair"** %this.addr.i.i.i + %30 = bitcast %"class.std::__1::__compressed_pair"* %this1.i.i.i to %"class.std::__1::__libcpp_compressed_pair_imp"* + store %"class.std::__1::__libcpp_compressed_pair_imp"* %30, %"class.std::__1::__libcpp_compressed_pair_imp"** %this.addr.i.i.i.i, align 4 + %this1.i.i.i.i = load %"class.std::__1::__libcpp_compressed_pair_imp"*, %"class.std::__1::__libcpp_compressed_pair_imp"** %this.addr.i.i.i.i + %31 = bitcast %"class.std::__1::__libcpp_compressed_pair_imp"* %this1.i.i.i.i to %"class.std::__1::allocator"* + store %"class.std::__1::allocator"* %31, %"class.std::__1::allocator"** %this.addr.i.i.i.i.i, align 4 + %this1.i.i.i.i.i = load %"class.std::__1::allocator"*, %"class.std::__1::allocator"** %this.addr.i.i.i.i.i + %__first_.i.i.i.i = getelementptr inbounds %"class.std::__1::__libcpp_compressed_pair_imp", %"class.std::__1::__libcpp_compressed_pair_imp"* %this1.i.i.i.i, i32 0, i32 0 + %32 = load i32, i32* %__n.addr.i.i, align 4 + %33 = load i8, i8* %__c.addr.i.i, align 1 + call void @_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEjc(%"class.std::__1::basic_string"* %this1.i.i, i32 %32, i8 zeroext %33) + %__sbuf_18 = getelementptr inbounds %"class.std::__1::ostreambuf_iterator", %"class.std::__1::ostreambuf_iterator"* %__s, i32 0, i32 0 + %34 = load %"class.std::__1::basic_streambuf"*, %"class.std::__1::basic_streambuf"** %__sbuf_18, align 4 + store %"class.std::__1::basic_string"* %__sp, %"class.std::__1::basic_string"** %this.addr.i60, align 4 + %this1.i61 = load %"class.std::__1::basic_string"*, %"class.std::__1::basic_string"** %this.addr.i60 + store %"class.std::__1::basic_string"* %this1.i61, %"class.std::__1::basic_string"** %this.addr.i.i59, align 4 + %this1.i.i62 = load %"class.std::__1::basic_string"*, %"class.std::__1::basic_string"** %this.addr.i.i59 + store %"class.std::__1::basic_string"* %this1.i.i62, %"class.std::__1::basic_string"** %this.addr.i.i.i58, align 4 + %this1.i.i.i63 = load %"class.std::__1::basic_string"*, %"class.std::__1::basic_string"** %this.addr.i.i.i58 + %__r_.i.i.i = getelementptr inbounds %"class.std::__1::basic_string", %"class.std::__1::basic_string"* %this1.i.i.i63, i32 0, i32 0 + store %"class.std::__1::__compressed_pair"* %__r_.i.i.i, %"class.std::__1::__compressed_pair"** %this.addr.i.i.i.i57, align 4 + %this1.i.i.i.i64 = load %"class.std::__1::__compressed_pair"*, %"class.std::__1::__compressed_pair"** %this.addr.i.i.i.i57 + %35 = bitcast %"class.std::__1::__compressed_pair"* %this1.i.i.i.i64 to %"class.std::__1::__libcpp_compressed_pair_imp"* + store %"class.std::__1::__libcpp_compressed_pair_imp"* %35, %"class.std::__1::__libcpp_compressed_pair_imp"** %this.addr.i.i.i.i.i56, align 4 + %this1.i.i.i.i.i65 = load %"class.std::__1::__libcpp_compressed_pair_imp"*, %"class.std::__1::__libcpp_compressed_pair_imp"** %this.addr.i.i.i.i.i56 + %__first_.i.i.i.i.i = getelementptr inbounds %"class.std::__1::__libcpp_compressed_pair_imp", %"class.std::__1::__libcpp_compressed_pair_imp"* %this1.i.i.i.i.i65, i32 0, i32 0 + %36 = getelementptr inbounds %"struct.std::__1::basic_string, std::__1::allocator >::__rep", %"struct.std::__1::basic_string, std::__1::allocator >::__rep"* %__first_.i.i.i.i.i, i32 0, i32 0 + %__s.i.i.i = bitcast %union.anon* %36 to %"struct.std::__1::basic_string, std::__1::allocator >::__short"* + %37 = getelementptr inbounds %"struct.std::__1::basic_string, std::__1::allocator >::__short", %"struct.std::__1::basic_string, std::__1::allocator >::__short"* %__s.i.i.i, i32 0, i32 0 + %__size_.i.i.i = bitcast %union.anon.0* %37 to i8* + %38 = load i8, i8* %__size_.i.i.i, align 1 + %conv.i.i.i = zext i8 %38 to i32 + %and.i.i.i = and i32 %conv.i.i.i, 1 + %tobool.i.i.i = icmp ne i32 %and.i.i.i, 0 + br i1 %tobool.i.i.i, label %cond.true.i.i, label %cond.false.i.i + +cond.true.i.i: ; preds = %if.then17 + store %"class.std::__1::basic_string"* %this1.i.i62, %"class.std::__1::basic_string"** %this.addr.i15.i.i, align 4 + %this1.i16.i.i = load %"class.std::__1::basic_string"*, %"class.std::__1::basic_string"** %this.addr.i15.i.i + %__r_.i17.i.i = getelementptr inbounds %"class.std::__1::basic_string", %"class.std::__1::basic_string"* %this1.i16.i.i, i32 0, i32 0 + store %"class.std::__1::__compressed_pair"* %__r_.i17.i.i, %"class.std::__1::__compressed_pair"** %this.addr.i.i14.i.i, align 4 + %this1.i.i18.i.i = load %"class.std::__1::__compressed_pair"*, %"class.std::__1::__compressed_pair"** %this.addr.i.i14.i.i + %39 = bitcast %"class.std::__1::__compressed_pair"* %this1.i.i18.i.i to %"class.std::__1::__libcpp_compressed_pair_imp"* + store %"class.std::__1::__libcpp_compressed_pair_imp"* %39, %"class.std::__1::__libcpp_compressed_pair_imp"** %this.addr.i.i.i13.i.i, align 4 + %this1.i.i.i19.i.i = load %"class.std::__1::__libcpp_compressed_pair_imp"*, %"class.std::__1::__libcpp_compressed_pair_imp"** %this.addr.i.i.i13.i.i + %__first_.i.i.i20.i.i = getelementptr inbounds %"class.std::__1::__libcpp_compressed_pair_imp", %"class.std::__1::__libcpp_compressed_pair_imp"* %this1.i.i.i19.i.i, i32 0, i32 0 + %40 = getelementptr inbounds %"struct.std::__1::basic_string, std::__1::allocator >::__rep", %"struct.std::__1::basic_string, std::__1::allocator >::__rep"* %__first_.i.i.i20.i.i, i32 0, i32 0 + %__l.i.i.i = bitcast %union.anon* %40 to %"struct.std::__1::basic_string, std::__1::allocator >::__long"* + %__data_.i21.i.i = getelementptr inbounds %"struct.std::__1::basic_string, std::__1::allocator >::__long", %"struct.std::__1::basic_string, std::__1::allocator >::__long"* %__l.i.i.i, i32 0, i32 2 + %41 = load i8*, i8** %__data_.i21.i.i, align 4 + br label %_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv.exit + +cond.false.i.i: ; preds = %if.then17 + store %"class.std::__1::basic_string"* %this1.i.i62, %"class.std::__1::basic_string"** %this.addr.i6.i.i, align 4 + %this1.i7.i.i = load %"class.std::__1::basic_string"*, %"class.std::__1::basic_string"** %this.addr.i6.i.i + %__r_.i8.i.i = getelementptr inbounds %"class.std::__1::basic_string", %"class.std::__1::basic_string"* %this1.i7.i.i, i32 0, i32 0 + store %"class.std::__1::__compressed_pair"* %__r_.i8.i.i, %"class.std::__1::__compressed_pair"** %this.addr.i.i5.i.i, align 4 + %this1.i.i9.i.i = load %"class.std::__1::__compressed_pair"*, %"class.std::__1::__compressed_pair"** %this.addr.i.i5.i.i + %42 = bitcast %"class.std::__1::__compressed_pair"* %this1.i.i9.i.i to %"class.std::__1::__libcpp_compressed_pair_imp"* + store %"class.std::__1::__libcpp_compressed_pair_imp"* %42, %"class.std::__1::__libcpp_compressed_pair_imp"** %this.addr.i.i.i4.i.i, align 4 + %this1.i.i.i10.i.i = load %"class.std::__1::__libcpp_compressed_pair_imp"*, %"class.std::__1::__libcpp_compressed_pair_imp"** %this.addr.i.i.i4.i.i + %__first_.i.i.i11.i.i = getelementptr inbounds %"class.std::__1::__libcpp_compressed_pair_imp", %"class.std::__1::__libcpp_compressed_pair_imp"* %this1.i.i.i10.i.i, i32 0, i32 0 + %43 = getelementptr inbounds %"struct.std::__1::basic_string, std::__1::allocator >::__rep", %"struct.std::__1::basic_string, std::__1::allocator >::__rep"* %__first_.i.i.i11.i.i, i32 0, i32 0 + %__s.i12.i.i = bitcast %union.anon* %43 to %"struct.std::__1::basic_string, std::__1::allocator >::__short"* + %__data_.i.i.i = getelementptr inbounds %"struct.std::__1::basic_string, std::__1::allocator >::__short", %"struct.std::__1::basic_string, std::__1::allocator >::__short"* %__s.i12.i.i, i32 0, i32 1 + %arrayidx.i.i.i = getelementptr inbounds [11 x i8], [11 x i8]* %__data_.i.i.i, i32 0, i32 0 + store i8* %arrayidx.i.i.i, i8** %__r.addr.i.i.i.i, align 4 + %44 = load i8*, i8** %__r.addr.i.i.i.i, align 4 + store i8* %44, i8** %__x.addr.i.i.i.i.i, align 4 + %45 = load i8*, i8** %__x.addr.i.i.i.i.i, align 4 + br label %_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv.exit + +_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv.exit: ; preds = %cond.false.i.i, %cond.true.i.i + %cond.i.i = phi i8* [ %41, %cond.true.i.i ], [ %45, %cond.false.i.i ] + store i8* %cond.i.i, i8** %__p.addr.i.i, align 4 + %46 = load i8*, i8** %__p.addr.i.i, align 4 + %47 = load i32, i32* %__ns, align 4 + store %"class.std::__1::basic_streambuf"* %34, %"class.std::__1::basic_streambuf"** %this.addr.i66, align 4 + store i8* %46, i8** %__s.addr.i67, align 4 + store i32 %47, i32* %__n.addr.i68, align 4 + %this1.i69 = load %"class.std::__1::basic_streambuf"*, %"class.std::__1::basic_streambuf"** %this.addr.i66 + %48 = bitcast %"class.std::__1::basic_streambuf"* %this1.i69 to i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*** + %vtable.i70 = load i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)**, i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*** %48 + %vfn.i71 = getelementptr inbounds i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*, i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)** %vtable.i70, i64 12 + %49 = load i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*, i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)** %vfn.i71 + %50 = load i8*, i8** %__s.addr.i67, align 4 + %51 = load i32, i32* %__n.addr.i68, align 4 + %call.i7273 = invoke i32 %49(%"class.std::__1::basic_streambuf"* %this1.i69, i8* %50, i32 %51) + to label %_ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5sputnEPKci.exit unwind label %lpad + +_ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5sputnEPKci.exit: ; preds = %_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv.exit + br label %invoke.cont + +invoke.cont: ; preds = %_ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5sputnEPKci.exit + %52 = load i32, i32* %__ns, align 4 + %cmp21 = icmp ne i32 %call.i7273, %52 + br i1 %cmp21, label %if.then22, label %if.end24 + +if.then22: ; preds = %invoke.cont + %__sbuf_23 = getelementptr inbounds %"class.std::__1::ostreambuf_iterator", %"class.std::__1::ostreambuf_iterator"* %__s, i32 0, i32 0 + store %"class.std::__1::basic_streambuf"* null, %"class.std::__1::basic_streambuf"** %__sbuf_23, align 4 + %53 = bitcast %"class.std::__1::ostreambuf_iterator"* %retval to i8* + %54 = bitcast %"class.std::__1::ostreambuf_iterator"* %__s to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %53, i8* %54, i32 4, i32 4, i1 false) + store i32 1, i32* %cleanup.dest.slot + br label %cleanup + +lpad: ; preds = %_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv.exit + %55 = landingpad { i8*, i32 } + cleanup + %56 = extractvalue { i8*, i32 } %55, 0 + store i8* %56, i8** %exn.slot + %57 = extractvalue { i8*, i32 } %55, 1 + store i32 %57, i32* %ehselector.slot + call void @_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev(%"class.std::__1::basic_string"* %__sp) #0 + br label %eh.resume + +if.end24: ; preds = %invoke.cont + store i32 0, i32* %cleanup.dest.slot + br label %cleanup + +cleanup: ; preds = %if.end24, %if.then22 + call void @_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev(%"class.std::__1::basic_string"* %__sp) #0 + %cleanup.dest = load i32, i32* %cleanup.dest.slot + switch i32 %cleanup.dest, label %unreachable [ + i32 0, label %cleanup.cont + i32 1, label %return + ] + +cleanup.cont: ; preds = %cleanup + br label %if.end25 + +if.end25: ; preds = %cleanup.cont, %if.end15 + %58 = load i8*, i8** %__oe.addr, align 4 + %59 = load i8*, i8** %__op.addr, align 4 + %sub.ptr.lhs.cast26 = ptrtoint i8* %58 to i32 + %sub.ptr.rhs.cast27 = ptrtoint i8* %59 to i32 + %sub.ptr.sub28 = sub i32 %sub.ptr.lhs.cast26, %sub.ptr.rhs.cast27 + store i32 %sub.ptr.sub28, i32* %__np, align 4 + %60 = load i32, i32* %__np, align 4 + %cmp29 = icmp sgt i32 %60, 0 + br i1 %cmp29, label %if.then30, label %if.end37 + +if.then30: ; preds = %if.end25 + %__sbuf_31 = getelementptr inbounds %"class.std::__1::ostreambuf_iterator", %"class.std::__1::ostreambuf_iterator"* %__s, i32 0, i32 0 + %61 = load %"class.std::__1::basic_streambuf"*, %"class.std::__1::basic_streambuf"** %__sbuf_31, align 4 + %62 = load i8*, i8** %__op.addr, align 4 + %63 = load i32, i32* %__np, align 4 + store %"class.std::__1::basic_streambuf"* %61, %"class.std::__1::basic_streambuf"** %this.addr.i44, align 4 + store i8* %62, i8** %__s.addr.i, align 4 + store i32 %63, i32* %__n.addr.i, align 4 + %this1.i45 = load %"class.std::__1::basic_streambuf"*, %"class.std::__1::basic_streambuf"** %this.addr.i44 + %64 = bitcast %"class.std::__1::basic_streambuf"* %this1.i45 to i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*** + %vtable.i = load i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)**, i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*** %64 + %vfn.i = getelementptr inbounds i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*, i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)** %vtable.i, i64 12 + %65 = load i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)*, i32 (%"class.std::__1::basic_streambuf"*, i8*, i32)** %vfn.i + %66 = load i8*, i8** %__s.addr.i, align 4 + %67 = load i32, i32* %__n.addr.i, align 4 + %call.i = call i32 %65(%"class.std::__1::basic_streambuf"* %this1.i45, i8* %66, i32 %67) + %68 = load i32, i32* %__np, align 4 + %cmp33 = icmp ne i32 %call.i, %68 + br i1 %cmp33, label %if.then34, label %if.end36 + +if.then34: ; preds = %if.then30 + %__sbuf_35 = getelementptr inbounds %"class.std::__1::ostreambuf_iterator", %"class.std::__1::ostreambuf_iterator"* %__s, i32 0, i32 0 + store %"class.std::__1::basic_streambuf"* null, %"class.std::__1::basic_streambuf"** %__sbuf_35, align 4 + %69 = bitcast %"class.std::__1::ostreambuf_iterator"* %retval to i8* + %70 = bitcast %"class.std::__1::ostreambuf_iterator"* %__s to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %69, i8* %70, i32 4, i32 4, i1 false) + br label %return + +if.end36: ; preds = %if.then30 + br label %if.end37 + +if.end37: ; preds = %if.end36, %if.end25 + %71 = load %"class.std::__1::ios_base"*, %"class.std::__1::ios_base"** %__iob.addr, align 4 + store %"class.std::__1::ios_base"* %71, %"class.std::__1::ios_base"** %this.addr.i41, align 4 + store i32 0, i32* %__wide.addr.i, align 4 + %this1.i42 = load %"class.std::__1::ios_base"*, %"class.std::__1::ios_base"** %this.addr.i41 + %__width_.i43 = getelementptr inbounds %"class.std::__1::ios_base", %"class.std::__1::ios_base"* %this1.i42, i32 0, i32 3 + %72 = load i32, i32* %__width_.i43, align 4 + store i32 %72, i32* %__r.i, align 4 + %73 = load i32, i32* %__wide.addr.i, align 4 + %__width_2.i = getelementptr inbounds %"class.std::__1::ios_base", %"class.std::__1::ios_base"* %this1.i42, i32 0, i32 3 + store i32 %73, i32* %__width_2.i, align 4 + %74 = load i32, i32* %__r.i, align 4 + %75 = bitcast %"class.std::__1::ostreambuf_iterator"* %retval to i8* + %76 = bitcast %"class.std::__1::ostreambuf_iterator"* %__s to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %75, i8* %76, i32 4, i32 4, i1 false) + br label %return + +return: ; preds = %if.end37, %if.then34, %cleanup, %if.then12, %if.then + %coerce.dive39 = getelementptr %"class.std::__1::ostreambuf_iterator", %"class.std::__1::ostreambuf_iterator"* %retval, i32 0, i32 0 + %77 = load %"class.std::__1::basic_streambuf"*, %"class.std::__1::basic_streambuf"** %coerce.dive39 + %coerce.val.pi = ptrtoint %"class.std::__1::basic_streambuf"* %77 to i32 + ret i32 %coerce.val.pi + +eh.resume: ; preds = %lpad + %exn = load i8*, i8** %exn.slot + %sel = load i32, i32* %ehselector.slot + %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0 + %lpad.val40 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1 + resume { i8*, i32 } %lpad.val40 + +unreachable: ; preds = %cleanup + unreachable +} + +declare void @_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEjc(%"class.std::__1::basic_string"*, i32, i8 zeroext) #2 + +attributes #0 = { nounwind } +attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.ident = !{!0} + +!0 = !{!"Clang 3.1"} diff --git a/test/CodeGen/Hexagon/early-if-phi-i1.ll b/test/CodeGen/Hexagon/early-if-phi-i1.ll new file mode 100644 index 00000000000..1649d51269e --- /dev/null +++ b/test/CodeGen/Hexagon/early-if-phi-i1.ll @@ -0,0 +1,17 @@ +; RUN: llc < %s +; REQUIRES: asserts +; Check that the early if-conversion does not predicate block1 (where the +; join block has a phi node of type i1). + +define i1 @foo(i32 %x, i32* %p) { +entry: + %c = icmp sgt i32 %x, 0 + %c1 = icmp sgt i32 %x, 10 + br i1 %c, label %block2, label %block1 +block1: + store i32 1, i32* %p, align 4 + br label %block2 +block2: + %b = phi i1 [ 0, %entry ], [ %c1, %block1 ] + ret i1 %b +} diff --git a/test/CodeGen/Hexagon/early-if-spare.ll b/test/CodeGen/Hexagon/early-if-spare.ll new file mode 100644 index 00000000000..7497b53ba3c --- /dev/null +++ b/test/CodeGen/Hexagon/early-if-spare.ll @@ -0,0 +1,57 @@ +; RUN: llc -O2 -mcpu=hexagonv5 < %s | FileCheck %s +; Check if the three stores in the loop were predicated. +; CHECK: if{{.*}}memw +; CHECK: if{{.*}}memw +; CHECK: if{{.*}}memw + +target datalayout = "e-p:32:32:32-i64:64:64-i32:32:32-i16:16:16-i1:32:32-f64:64:64-f32:32:32-v64:64:64-v32:32:32-a0:0-n16:32" +target triple = "hexagon" + +define void @fred(i32 %n, i32* %bp) nounwind { +entry: + %cmp16 = icmp eq i32 %n, 0 + br i1 %cmp16, label %for.end, label %for.body.lr.ph + +for.body.lr.ph: ; preds = %entry + %cmp2 = icmp ugt i32 %n, 32 + br label %for.body + +for.body: ; preds = %for.inc, %for.body.lr.ph + %i.017 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ] + %call = tail call i32 @foo(i32* %bp) nounwind + %call1 = tail call i32 @bar(i32* %bp) nounwind + br i1 %cmp2, label %if.then, label %if.else + +if.then: ; preds = %for.body + %arrayidx = getelementptr inbounds i32, i32* %bp, i32 %i.017 + store i32 %call, i32* %arrayidx, align 4, !tbaa !0 + %add = add i32 %i.017, 2 + %arrayidx3 = getelementptr inbounds i32, i32* %bp, i32 %add + store i32 %call1, i32* %arrayidx3, align 4, !tbaa !0 + br label %for.inc + +if.else: ; preds = %for.body + %or = or i32 %call1, %call + %arrayidx4 = getelementptr inbounds i32, i32* %bp, i32 %i.017 + store i32 %or, i32* %arrayidx4, align 4, !tbaa !0 + br label %for.inc + +for.inc: ; preds = %if.then, %if.else + %inc = add i32 %i.017, 1 + %exitcond = icmp eq i32 %inc, %n + br i1 %exitcond, label %for.end.loopexit, label %for.body + +for.end.loopexit: ; preds = %for.inc + br label %for.end + +for.end: ; preds = %for.end.loopexit, %entry + ret void +} + +declare i32 @foo(i32*) nounwind + +declare i32 @bar(i32*) nounwind + +!0 = !{!"int", !1} +!1 = !{!"omnipotent char", !2} +!2 = !{!"Simple C/C++ TBAA"} diff --git a/test/CodeGen/Hexagon/early-if.ll b/test/CodeGen/Hexagon/early-if.ll new file mode 100644 index 00000000000..dcb1dd20b51 --- /dev/null +++ b/test/CodeGen/Hexagon/early-if.ll @@ -0,0 +1,75 @@ +; RUN: llc -O2 -march=hexagon -mcpu=hexagonv5 < %s | FileCheck %s +; Rely on the comments generated by llc. Check that "if.then" was predicated. +; CHECK: while.body13 +; CHECK: if{{.*}}memd +; CHECK: while.end + +%struct.1 = type { i32, i32 } +%struct.2 = type { [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [24 x i32], [3 x i32], [24 x i32], [8 x %struct.1], [5 x i32] } + +@A1 = global i64 zeroinitializer +@A2 = global i64 zeroinitializer +@B1 = global i32 zeroinitializer +@B2 = global i32 zeroinitializer +@C1 = global i8 zeroinitializer + +declare i32 @llvm.hexagon.S2.cl0(i32) nounwind readnone +declare i32 @llvm.hexagon.S2.setbit.r(i32, i32) nounwind readnone +declare i64 @llvm.hexagon.M2.vmpy2s.s0(i32, i32) nounwind readnone +declare i64 @llvm.hexagon.M2.vmac2s.s0(i64, i32, i32) nounwind readnone +declare i64 @llvm.hexagon.A2.vaddws(i64, i64) nounwind readnone +declare i64 @llvm.hexagon.A2.vsubws(i64, i64) nounwind readnone +declare i32 @llvm.hexagon.A4.modwrapu(i32, i32) nounwind readnone + +define void @foo(i32 %n, i64* %ptr) nounwind { +entry: + br label %while.body + +while.body: + %count = phi i32 [ 0, %entry ], [ %next, %while.end ] + %idx = phi i32 [ 0, %entry ], [ %15, %while.end ] + %0 = load i32, i32* @B1, align 4 + %1 = load i32, i32* @B2, align 8 + %2 = and i32 %1, %0 + br label %while.body13 + +while.body13: ; preds = %while.body, %if.end + %3 = phi i64 [ %13, %if.end ], [ 0, %while.body ] + %4 = phi i64 [ %14, %if.end ], [ 0, %while.body ] + %m = phi i32 [ %6, %if.end ], [ %2, %while.body ] + %5 = tail call i32 @llvm.hexagon.S2.cl0(i32 %m) + %6 = tail call i32 @llvm.hexagon.S2.setbit.r(i32 %m, i32 %5) + %cgep85 = getelementptr [10 x %struct.2], [10 x %struct.2]* inttoptr (i32 -121502345 to [10 x %struct.2]*), i32 0, i32 %idx + %cgep90 = getelementptr %struct.2, %struct.2* %cgep85, i32 0, i32 12, i32 %5 + %7 = load i32, i32* %cgep90, align 4 + %8 = tail call i64 @llvm.hexagon.M2.vmpy2s.s0(i32 %7, i32 %7) + %cgep91 = getelementptr %struct.2, %struct.2* %cgep85, i32 0, i32 13, i32 %5 + %9 = load i32, i32* %cgep91, align 4 + %10 = tail call i64 @llvm.hexagon.M2.vmac2s.s0(i64 %8, i32 %9, i32 %9) + %11 = load i8, i8* @C1, align 1 + %and24 = and i8 %11, 1 + %cmp = icmp eq i8 %and24, 0 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %while.body13 + %12 = tail call i64 @llvm.hexagon.A2.vaddws(i64 %3, i64 %10) + store i64 %12, i64* %ptr, align 8 + br label %if.end + +if.end: ; preds = %if.then, %while.body13 + %13 = phi i64 [ %12, %if.then ], [ %3, %while.body13 ] + %14 = tail call i64 @llvm.hexagon.A2.vsubws(i64 %4, i64 %10) + %tobool12 = icmp eq i32 %6, 0 + br i1 %tobool12, label %while.end, label %while.body13 + +while.end: + %add40 = add i32 %idx, 1 + %15 = tail call i32 @llvm.hexagon.A4.modwrapu(i32 %add40, i32 10) nounwind + %next = add i32 %count, 1 + %cc = icmp eq i32 %next, %n + br i1 %cc, label %end, label %while.body + +end: + store i64 %10, i64* @A2, align 8 + ret void +} diff --git a/test/CodeGen/Hexagon/ifcvt-edge-weight.ll b/test/CodeGen/Hexagon/ifcvt-edge-weight.ll index 89bb1a62f17..0137501f838 100644 --- a/test/CodeGen/Hexagon/ifcvt-edge-weight.ll +++ b/test/CodeGen/Hexagon/ifcvt-edge-weight.ll @@ -1,4 +1,4 @@ -; RUN: llc -march=hexagon -mcpu=hexagonv5 -print-machineinstrs=if-converter %s -o /dev/null 2>&1 | FileCheck %s +; RUN: llc -march=hexagon -mcpu=hexagonv5 -hexagon-eif=0 -print-machineinstrs=if-converter %s -o /dev/null 2>&1 | FileCheck %s ; Check that the edge weights are updated correctly after if-conversion. ; CHECK: BB#3: -- 2.34.1