From lattner at cs.uiuc.edu Mon Sep 19 00:23:55 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 00:23:55 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86RegisterInfo.cpp X86RegisterInfo.h Message-ID: <200509190523.AAA00430@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86RegisterInfo.cpp updated: 1.108 -> 1.109 X86RegisterInfo.h updated: 1.30 -> 1.31 --- Log message: Implement the isLoadFromStackSlot interface --- Diffs of the changes: (+28 -0) X86RegisterInfo.cpp | 25 +++++++++++++++++++++++++ X86RegisterInfo.h | 3 +++ 2 files changed, 28 insertions(+) Index: llvm/lib/Target/X86/X86RegisterInfo.cpp diff -u llvm/lib/Target/X86/X86RegisterInfo.cpp:1.108 llvm/lib/Target/X86/X86RegisterInfo.cpp:1.109 --- llvm/lib/Target/X86/X86RegisterInfo.cpp:1.108 Fri Aug 19 13:32:03 2005 +++ llvm/lib/Target/X86/X86RegisterInfo.cpp Mon Sep 19 00:23:44 2005 @@ -92,6 +92,31 @@ BuildMI(MBB, MI, Opc, 1, DestReg).addReg(SrcReg); } +unsigned X86RegisterInfo::isLoadFromStackSlot(MachineInstr *MI, + int &FrameIndex) const { + switch (MI->getOpcode()) { + default: break; + case X86::MOV8rm: + case X86::MOV16rm: + case X86::MOV32rm: + case X86::FLD64m: + case X86::FLD80m: + case X86::MOVAPDrm: + case X86::MOVSDrm: + if (MI->getOperand(1).isFrameIndex() && MI->getOperand(2).isImmediate() && + MI->getOperand(3).isRegister() && MI->getOperand(4).isImmediate() && + MI->getOperand(2).getImmedValue() == 1 && + MI->getOperand(3).getReg() == 0 && + MI->getOperand(4).getImmedValue() == 0) { + FrameIndex = MI->getOperand(1).getFrameIndex(); + return MI->getOperand(0).getReg(); + } + break; + } + return 0; +} + + static MachineInstr *MakeMInst(unsigned Opcode, unsigned FrameIndex, MachineInstr *MI) { return addFrameReference(BuildMI(Opcode, 4), FrameIndex); Index: llvm/lib/Target/X86/X86RegisterInfo.h diff -u llvm/lib/Target/X86/X86RegisterInfo.h:1.30 llvm/lib/Target/X86/X86RegisterInfo.h:1.31 --- llvm/lib/Target/X86/X86RegisterInfo.h:1.30 Fri Aug 19 13:32:03 2005 +++ llvm/lib/Target/X86/X86RegisterInfo.h Mon Sep 19 00:23:44 2005 @@ -39,6 +39,9 @@ unsigned DestReg, unsigned SrcReg, const TargetRegisterClass *RC) const; + unsigned isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const; + + /// foldMemoryOperand - If this target supports it, fold a load or store of /// the specified stack slot into the specified machine instruction for the /// specified operand. If this is possible, the target should perform the From lattner at cs.uiuc.edu Mon Sep 19 01:56:33 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 01:56:33 -0500 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/VirtRegMap.cpp Message-ID: <200509190656.BAA10993@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: VirtRegMap.cpp updated: 1.38 -> 1.39 --- Log message: Teach the local spiller to turn stack slot loads into register-register copies when possible, avoiding the load (and avoiding the copy if the value is already in the right register). This patch came about when I noticed code like the following being generated: store R17 -> [SS1] ...blah... R4 = load [SS1] This was causing an LSU reject on the G5. This problem was due to the register allocator folding spill code into a reg-reg copy (producing the load), which prevented the spiller from being able to rewrite the load into a copy, despite the fact that the value was already available in a register. In the case above, we now rip out the R4 load and replace it with a R4 = R17 copy. This speeds up several programs on X86 (which spills a lot :) ), e.g. smg2k from 22.39->20.60s, povray from 12.93->12.66s, 168.wupwise from 68.54->53.83s (!), 197.parser from 7.33->6.62s (!), etc. This may have a larger impact in some cases on the G5 (by avoiding LSU rejects), though it probably won't trigger as often (less spilling in general). Targets that implement folding of loads/stores into copies should implement the isLoadFromStackSlot hook to get this. --- Diffs of the changes: (+52 -26) VirtRegMap.cpp | 78 ++++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 52 insertions(+), 26 deletions(-) Index: llvm/lib/CodeGen/VirtRegMap.cpp diff -u llvm/lib/CodeGen/VirtRegMap.cpp:1.38 llvm/lib/CodeGen/VirtRegMap.cpp:1.39 --- llvm/lib/CodeGen/VirtRegMap.cpp:1.38 Fri Sep 9 15:29:51 2005 +++ llvm/lib/CodeGen/VirtRegMap.cpp Mon Sep 19 01:56:21 2005 @@ -466,36 +466,61 @@ << I->second.second); unsigned VirtReg = I->second.first; VirtRegMap::ModRef MR = I->second.second; - if (VRM.hasStackSlot(VirtReg)) { - int SS = VRM.getStackSlot(VirtReg); - DEBUG(std::cerr << " - StackSlot: " << SS << "\n"); - - // If this reference is not a use, any previous store is now dead. - // Otherwise, the store to this stack slot is not dead anymore. - std::map::iterator MDSI = MaybeDeadStores.find(SS); - if (MDSI != MaybeDeadStores.end()) { - if (MR & VirtRegMap::isRef) // Previous store is not dead. - MaybeDeadStores.erase(MDSI); - else { - // If we get here, the store is dead, nuke it now. - assert(MR == VirtRegMap::isMod && "Can't be modref!"); - MBB.erase(MDSI->second); - MaybeDeadStores.erase(MDSI); - ++NumDSE; + if (!VRM.hasStackSlot(VirtReg)) { + DEBUG(std::cerr << ": No stack slot!\n"); + continue; + } + int SS = VRM.getStackSlot(VirtReg); + DEBUG(std::cerr << " - StackSlot: " << SS << "\n"); + + // If this folded instruction is just a use, check to see if it's a + // straight load from the virt reg slot. + if ((MR & VirtRegMap::isRef) && !(MR & VirtRegMap::isMod)) { + int FrameIdx; + if (unsigned DestReg = MRI->isLoadFromStackSlot(&MI, FrameIdx)) { + // If this spill slot is available, insert a copy for it! + std::map::iterator It = SpillSlotsAvailable.find(SS); + if (FrameIdx == SS && It != SpillSlotsAvailable.end()) { + DEBUG(std::cerr << "Promoted Load To Copy: " << MI); + MachineFunction &MF = *MBB.getParent(); + if (DestReg != It->second) { + MRI->copyRegToReg(MBB, &MI, DestReg, It->second, + MF.getSSARegMap()->getRegClass(VirtReg)); + // Revisit the copy if the destination is a vreg. + if (MRegisterInfo::isVirtualRegister(DestReg)) { + NextMII = &MI; + --NextMII; // backtrack to the copy. + } + } + MBB.erase(&MI); + goto ProcessNextInst; } } + } + + // If this reference is not a use, any previous store is now dead. + // Otherwise, the store to this stack slot is not dead anymore. + std::map::iterator MDSI = MaybeDeadStores.find(SS); + if (MDSI != MaybeDeadStores.end()) { + if (MR & VirtRegMap::isRef) // Previous store is not dead. + MaybeDeadStores.erase(MDSI); + else { + // If we get here, the store is dead, nuke it now. + assert(MR == VirtRegMap::isMod && "Can't be modref!"); + MBB.erase(MDSI->second); + MaybeDeadStores.erase(MDSI); + ++NumDSE; + } + } - // If the spill slot value is available, and this is a new definition of - // the value, the value is not available anymore. - if (MR & VirtRegMap::isMod) { - std::map::iterator It = SpillSlotsAvailable.find(SS); - if (It != SpillSlotsAvailable.end()) { - PhysRegsAvailable.erase(It->second); - SpillSlotsAvailable.erase(It); - } + // If the spill slot value is available, and this is a new definition of + // the value, the value is not available anymore. + if (MR & VirtRegMap::isMod) { + std::map::iterator It = SpillSlotsAvailable.find(SS); + if (It != SpillSlotsAvailable.end()) { + PhysRegsAvailable.erase(It->second); + SpillSlotsAvailable.erase(It); } - } else { - DEBUG(std::cerr << ": No stack slot!\n"); } } @@ -575,6 +600,7 @@ } } } + ProcessNextInst: MII = NextMII; } } From natebegeman at mac.com Mon Sep 19 17:34:12 2005 From: natebegeman at mac.com (Nate Begeman) Date: Mon, 19 Sep 2005 17:34:12 -0500 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp Message-ID: <200509192234.RAA00686@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen/SelectionDAG: DAGCombiner.cpp updated: 1.12 -> 1.13 --- Log message: Stub out the rest of the DAG Combiner. Just need to fill in the select_cc bits and then wrap it in a convenience function for use with regular select. --- Diffs of the changes: (+105 -9) DAGCombiner.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 105 insertions(+), 9 deletions(-) Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp diff -u llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.12 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.13 --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.12 Thu Sep 15 19:54:12 2005 +++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp Mon Sep 19 17:34:01 2005 @@ -20,6 +20,14 @@ // ZERO_EXTEND/SIGN_EXTEND by converting them to an ANY_EXTEND node which // we don't have yet. // +// FIXME: select C, 16, 0 -> shr C, 4 +// FIXME: select C, pow2, pow2 -> something smart +// FIXME: trunc(select X, Y, Z) -> select X, trunc(Y), trunc(Z) +// FIXME: (select C, load A, load B) -> load (select C, A, B) +// FIXME: store -> load -> forward substitute +// FIXME: Dead stores -> nuke +// FIXME: shr X, (and Y,31) -> shr X, Y +// FIXME: TRUNC (LOAD) -> EXT_LOAD/LOAD(smaller) // FIXME: mul (x, const) -> shifts + adds // FIXME: undef values // FIXME: zero extend when top bits are 0 -> drop it ? @@ -117,10 +125,13 @@ SDOperand visitFNEG(SDNode *N); SDOperand visitFABS(SDNode *N); SDOperand visitBRCOND(SDNode *N); - // brcondtwoway - // br_cc - // brtwoway_cc - + SDOperand visitBRCONDTWOWAY(SDNode *N); + SDOperand visitBR_CC(SDNode *N); + SDOperand visitBRTWOWAY_CC(SDNode *N); + + SDOperand SimplifySelect(SDOperand N0, SDOperand N1, SDOperand N2); + SDOperand SimplifySelectCC(SDOperand N0, SDOperand N1, SDOperand N2, + SDOperand N3, ISD::CondCode CC); SDOperand SimplifySetCC(MVT::ValueType VT, SDOperand N0, SDOperand N1, ISD::CondCode Cond); public: @@ -339,6 +350,10 @@ case ISD::FP_EXTEND: return visitFP_EXTEND(N); case ISD::FNEG: return visitFNEG(N); case ISD::FABS: return visitFABS(N); + case ISD::BRCOND: return visitBRCOND(N); + case ISD::BRCONDTWOWAY: return visitBRCONDTWOWAY(N); + case ISD::BR_CC: return visitBR_CC(N); + case ISD::BRTWOWAY_CC: return visitBRTWOWAY_CC(N); } return SDOperand(); } @@ -1029,7 +1044,7 @@ ConstantSDNode *N1C = dyn_cast(N1); ConstantSDNode *N2C = dyn_cast(N2); MVT::ValueType VT = N->getValueType(0); - + // fold select C, X, X -> X if (N1 == N2) return N1; @@ -1040,7 +1055,7 @@ if (N0C && N0C->isNullValue()) return N2; // fold select C, 1, X -> C | X - if (MVT::i1 == VT && N1C && !N1C->isNullValue()) + if (MVT::i1 == VT && N1C && N1C->getValue() == 1) return DAG.getNode(ISD::OR, VT, N0, N2); // fold select C, 0, X -> ~C & X // FIXME: this should check for C type == X type, not i1? @@ -1050,7 +1065,7 @@ return DAG.getNode(ISD::AND, VT, XORNode, N2); } // fold select C, X, 1 -> ~C | X - if (MVT::i1 == VT && N2C && !N2C->isNullValue()) { + if (MVT::i1 == VT && N2C && N2C->getValue() == 1) { SDOperand XORNode = DAG.getNode(ISD::XOR, VT, N0, DAG.getConstant(1, VT)); WorkList.push_back(XORNode.Val); return DAG.getNode(ISD::OR, VT, XORNode, N1); @@ -1065,12 +1080,40 @@ // fold X ? Y : X --> X ? Y : 0 --> X & Y if (MVT::i1 == VT && N0 == N2) return DAG.getNode(ISD::AND, VT, N0, N1); - + // fold selects based on a setcc into other things, such as min/max/abs + if (N0.getOpcode() == ISD::SETCC) + return SimplifySelect(N0, N1, N2); return SDOperand(); } SDOperand DAGCombiner::visitSELECT_CC(SDNode *N) { - return SDOperand(); + SDOperand N0 = N->getOperand(0); + SDOperand N1 = N->getOperand(1); + SDOperand N2 = N->getOperand(2); + SDOperand N3 = N->getOperand(3); + SDOperand N4 = N->getOperand(4); + ConstantSDNode *N0C = dyn_cast(N0); + ConstantSDNode *N1C = dyn_cast(N1); + ConstantSDNode *N2C = dyn_cast(N2); + ISD::CondCode CC = cast(N4)->get(); + + // Determine if the condition we're dealing with is constant + SDOperand SCC = SimplifySetCC(TLI.getSetCCResultTy(), N0, N1, CC); + ConstantSDNode *SCCC = dyn_cast(SCC); + bool constTrue = SCCC && SCCC->getValue() == 1; + bool constFalse = SCCC && SCCC->isNullValue(); + + // fold select_cc lhs, rhs, x, x, cc -> x + if (N2 == N3) + return N2; + // fold select_cc true, x, y -> x + if (constTrue) + return N2; + // fold select_cc false, x, y -> y + if (constFalse) + return N3; + // fold select_cc into other things, such as min/max/abs + return SimplifySelectCC(N0, N1, N2, N3, CC); } SDOperand DAGCombiner::visitSETCC(SDNode *N) { @@ -1290,6 +1333,59 @@ return SDOperand(); } +SDOperand DAGCombiner::visitBRCOND(SDNode *N) { + SDOperand Chain = N->getOperand(0); + SDOperand N1 = N->getOperand(1); + SDOperand N2 = N->getOperand(2); + ConstantSDNode *N1C = dyn_cast(N1); + + // never taken branch, fold to chain + if (N1C && N1C->isNullValue()) + return Chain; + // unconditional branch + if (N1C && !N1C->isNullValue()) + return DAG.getNode(ISD::BR, MVT::Other, Chain, N2); + return SDOperand(); +} + +SDOperand DAGCombiner::visitBRCONDTWOWAY(SDNode *N) { + SDOperand Chain = N->getOperand(0); + SDOperand N1 = N->getOperand(1); + SDOperand N2 = N->getOperand(2); + SDOperand N3 = N->getOperand(3); + ConstantSDNode *N1C = dyn_cast(N1); + + // unconditional branch to true mbb + if (N1C && N1C->getValue() == 1) + return DAG.getNode(ISD::BR, MVT::Other, Chain, N2); + // unconditional branch to false mbb + if (N1C && N1C->isNullValue()) + return DAG.getNode(ISD::BR, MVT::Other, Chain, N3); + return SDOperand(); +} + +SDOperand DAGCombiner::visitBR_CC(SDNode *N) { + // FIXME: come up with a common way between br_cc, brtwoway_cc, and select_cc + // to canonicalize the condition without calling getnode a bazillion times. + return SDOperand(); +} + +SDOperand DAGCombiner::visitBRTWOWAY_CC(SDNode *N) { + // FIXME: come up with a common way between br_cc, brtwoway_cc, and select_cc + // to canonicalize the condition without calling getnode a bazillion times. + return SDOperand(); +} + +SDOperand DAGCombiner::SimplifySelect(SDOperand N0, SDOperand N1, SDOperand N2){ + return SDOperand(); +} + +SDOperand DAGCombiner::SimplifySelectCC(SDOperand N0, SDOperand N1, + SDOperand N2, SDOperand N3, + ISD::CondCode CC) { + return SDOperand(); +} + SDOperand DAGCombiner::SimplifySetCC(MVT::ValueType VT, SDOperand N0, SDOperand N1, ISD::CondCode Cond) { // These setcc operations always fold. From lattner at cs.uiuc.edu Mon Sep 19 18:48:15 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 18:48:15 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll Message-ID: <200509192348.SAA01088@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/SimplifyCFG: branch-phi-thread.ll added (r1.1) --- Log message: new testcase. --- Diffs of the changes: (+26 -0) branch-phi-thread.ll | 26 ++++++++++++++++++++++++++ 1 files changed, 26 insertions(+) Index: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll diff -c /dev/null llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.1 *** /dev/null Mon Sep 19 18:48:14 2005 --- llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll Mon Sep 19 18:48:04 2005 *************** *** 0 **** --- 1,26 ---- + ; RUN: llvm-as < %s | opt -simplifycfg -adce | llvm-dis | not grep 'call void %f1' + declare void %f1() + declare void %f2() + declare void %f3() + declare void %f4() + + implementation + + int %test2(int %X, bool %D) { + E: + %C = seteq int %X, 0 + br bool %C, label %T, label %F + T: + %P = phi bool [true, %E], [%C, %A] + br bool %P, label %B, label %A + A: + call void %f1() + br bool %D, label %T, label %F + B: + call void %f2() + ret int 345 + F: + call void %f3() + ret int 123 + } + From lattner at cs.uiuc.edu Mon Sep 19 18:49:48 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 18:49:48 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp Message-ID: <200509192349.SAA01125@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: SimplifyCFG.cpp updated: 1.82 -> 1.83 --- Log message: Implement SimplifyCFG/branch-phi-thread.ll, the most trivial case of threading control across branches with determined outcomes. More generality to follow. This triggers a couple thousand times in specint. --- Diffs of the changes: (+73 -0) SimplifyCFG.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 73 insertions(+) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.82 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.83 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.82 Wed Aug 3 12:59:45 2005 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 18:49:37 2005 @@ -18,6 +18,7 @@ #include "llvm/Type.h" #include "llvm/Support/CFG.h" #include "llvm/Support/Debug.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include #include #include @@ -889,6 +890,70 @@ return true; } +/// FoldCondBranchOnPHI - If we have a conditional branch on a PHI node value +/// that is defined in the same block as the branch and if any PHI entries are +/// constants, thread edges corresponding to that entry to be branches to their +/// ultimate destination. +static bool FoldCondBranchOnPHI(BranchInst *BI) { + BasicBlock *BB = BI->getParent(); + PHINode *PN = dyn_cast(BI->getCondition()); + if (!PN || PN->getParent() != BB) return false; + + // Degenerate case of a single entry PHI. + if (PN->getNumIncomingValues() == 1) { + if (PN->getIncomingValue(0) != PN) + PN->replaceAllUsesWith(PN->getIncomingValue(0)); + else + PN->replaceAllUsesWith(UndefValue::get(PN->getType())); + PN->eraseFromParent(); + return true; + } + + // Now we know that this block has multiple preds and two succs. + + // If this basic block contains anything other than the PHI and branch, bail + // out. FIXME: improve this in the future. + BasicBlock::iterator BBI = BB->begin(); + if (&*BBI != PN || &*++BBI != BI) + return false; + + // Okay, this is a simple enough basic block. See if any phi values are + // constants. + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) + if (ConstantBool *CB = dyn_cast(PN->getIncomingValue(i))) { + // Okay, we now know that all edges from PredBB should be revectored to + // branch to RealDest. + BasicBlock *PredBB = PN->getIncomingBlock(i); + BasicBlock *RealDest = BI->getSuccessor(!CB->getValue()); + + // If there are PHI nodes in the destination block, we have to add an + // entry for PredBB. Instead of being smart about this, just split the + // critical edge, which will eliminate the PHI-ness. + if (isa(RealDest->begin())) { + SplitCriticalEdge(BI, !CB->getValue()); + RealDest = BI->getSuccessor(!CB->getValue()); + } + assert(!isa(RealDest->begin()) && "Crit edge split failure!"); + + // Loop over all of the edges from PredBB to BB, changing them to branch + // to RealDest instead. + TerminatorInst *PredBBTI = PredBB->getTerminator(); + for (unsigned i = 0, e = PredBBTI->getNumSuccessors(); i != e; ++i) + if (PredBBTI->getSuccessor(i) == BB) { + BB->removePredecessor(PredBB); + PredBBTI->setSuccessor(i, RealDest); + } + + std::cerr << *BB; + + // Recurse, simplifying any other constants. + return FoldCondBranchOnPHI(BI) | true; + } + + return false; +} + + namespace { /// ConstantIntOrdering - This class implements a stable ordering of constant /// integers that does not depend on their address. This is important for @@ -1144,6 +1209,14 @@ if (FoldValueComparisonIntoPredecessors(BI)) return SimplifyCFG(BB) | true; } + + // If this is a branch on a phi node in the current block, thread control + // through this block if any PHI node entries are constants. + if (PHINode *PN = dyn_cast(BI->getCondition())) + if (PN->getParent() == BI->getParent()) + if (FoldCondBranchOnPHI(BI)) + return SimplifyCFG(BB) | true; + // If this basic block is ONLY a setcc and a branch, and if a predecessor // branches to us and one of our successors, fold the setcc into the From lattner at cs.uiuc.edu Mon Sep 19 18:50:26 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 18:50:26 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp Message-ID: <200509192350.SAA01193@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: SimplifyCFG.cpp updated: 1.83 -> 1.84 --- Log message: remove debugging code :-/ --- Diffs of the changes: (+0 -2) SimplifyCFG.cpp | 2 -- 1 files changed, 2 deletions(-) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.83 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.84 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.83 Mon Sep 19 18:49:37 2005 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 18:50:15 2005 @@ -944,8 +944,6 @@ PredBBTI->setSuccessor(i, RealDest); } - std::cerr << *BB; - // Recurse, simplifying any other constants. return FoldCondBranchOnPHI(BI) | true; } From lattner at cs.uiuc.edu Mon Sep 19 18:57:16 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 18:57:16 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp Message-ID: <200509192357.SAA01269@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: SimplifyCFG.cpp updated: 1.84 -> 1.85 --- Log message: Reject a case we don't handle yet --- Diffs of the changes: (+3 -1) SimplifyCFG.cpp | 4 +++- 1 files changed, 3 insertions(+), 1 deletion(-) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.84 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.85 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.84 Mon Sep 19 18:50:15 2005 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 18:57:04 2005 @@ -897,7 +897,9 @@ static bool FoldCondBranchOnPHI(BranchInst *BI) { BasicBlock *BB = BI->getParent(); PHINode *PN = dyn_cast(BI->getCondition()); - if (!PN || PN->getParent() != BB) return false; + // NOTE: we currently cannot transform this case if the PHI node is used + // outside of the block. + if (!PN || PN->getParent() != BB || !PN->hasOneUse()) return false; // Degenerate case of a single entry PHI. if (PN->getNumIncomingValues() == 1) { From lattner at cs.uiuc.edu Mon Sep 19 19:42:06 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 19:42:06 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll Message-ID: <200509200042.TAA01480@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/SimplifyCFG: branch-phi-thread.ll updated: 1.1 -> 1.2 --- Log message: new testcase --- Diffs of the changes: (+19 -1) branch-phi-thread.ll | 20 +++++++++++++++++++- 1 files changed, 19 insertions(+), 1 deletion(-) Index: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll diff -u llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.1 llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.2 --- llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.1 Mon Sep 19 18:48:04 2005 +++ llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll Mon Sep 19 19:41:55 2005 @@ -1,4 +1,5 @@ -; RUN: llvm-as < %s | opt -simplifycfg -adce | llvm-dis | not grep 'call void %f1' +; RUN: llvm-as < %s | opt -simplifycfg -adce | llvm-dis | not grep 'call void %f1' && +; RUN: llvm-as < %s | opt -simplifycfg -adce -disable-output declare void %f1() declare void %f2() declare void %f3() @@ -6,6 +7,23 @@ implementation +int %test1(int %X, bool %D) { +E: + %C = seteq int %X, 0 + br bool %C, label %T, label %F +T: + br bool %C, label %B, label %A +A: + call void %f1() + br bool %D, label %T, label %F +B: + call void %f2() + ret int 345 +F: + call void %f3() + ret int 123 +} + int %test2(int %X, bool %D) { E: %C = seteq int %X, 0 From lattner at cs.uiuc.edu Mon Sep 19 19:43:28 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 19:43:28 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp Message-ID: <200509200043.TAA01546@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: SimplifyCFG.cpp updated: 1.85 -> 1.86 --- Log message: Implement merging of blocks with the same condition if the block has multiple predecessors. This implements branch-phi-thread.ll::test1 --- Diffs of the changes: (+59 -21) SimplifyCFG.cpp | 80 +++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 59 insertions(+), 21 deletions(-) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.85 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.86 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.85 Mon Sep 19 18:57:04 2005 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 19:43:16 2005 @@ -890,6 +890,26 @@ return true; } +/// BlockIsSimpleEnoughToThreadThrough - Return true if we can thread a branch +/// across this block. +static bool BlockIsSimpleEnoughToThreadThrough(BasicBlock *BB) { + BranchInst *BI = cast(BB->getTerminator()); + Value *Cond = BI->getCondition(); + + // If this basic block contains anything other than a PHI (which controls the + // branch) and branch itself, bail out. FIXME: improve this in the future. + for (BasicBlock::iterator BBI = BB->begin(); &*BBI != BI; ++BBI) { + if (!isa(BBI)) return false; + + if (&*BBI != Cond || !Cond->hasOneUse()) + return false; + + // Looks ok, continue checking. + } + + return true; +} + /// FoldCondBranchOnPHI - If we have a conditional branch on a PHI node value /// that is defined in the same block as the branch and if any PHI entries are /// constants, thread edges corresponding to that entry to be branches to their @@ -899,7 +919,8 @@ PHINode *PN = dyn_cast(BI->getCondition()); // NOTE: we currently cannot transform this case if the PHI node is used // outside of the block. - if (!PN || PN->getParent() != BB || !PN->hasOneUse()) return false; + if (!PN || PN->getParent() != BB || !PN->hasOneUse()) + return false; // Degenerate case of a single entry PHI. if (PN->getNumIncomingValues() == 1) { @@ -912,12 +933,7 @@ } // Now we know that this block has multiple preds and two succs. - - // If this basic block contains anything other than the PHI and branch, bail - // out. FIXME: improve this in the future. - BasicBlock::iterator BBI = BB->begin(); - if (&*BBI != PN || &*++BBI != BI) - return false; + if (!BlockIsSimpleEnoughToThreadThrough(BB)) return false; // Okay, this is a simple enough basic block. See if any phi values are // constants. @@ -1272,22 +1288,44 @@ } } - // If this block ends with a branch instruction, and if there is one - // predecessor, see if the previous block ended with a branch on the same - // condition, which makes this conditional branch redundant. - if (BasicBlock *OnlyPred = BB->getSinglePredecessor()) - if (BranchInst *PBI = dyn_cast(OnlyPred->getTerminator())) - if (PBI->isConditional() && + // If this block ends with a branch instruction, and if there is a + // predecessor that ends on a branch of the same condition, make this + // conditional branch redundant. + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) + if (BranchInst *PBI = dyn_cast((*PI)->getTerminator())) + if (PBI != BI && PBI->isConditional() && PBI->getCondition() == BI->getCondition() && - (PBI->getSuccessor(0) != BB || PBI->getSuccessor(1) != BB)) { + PBI->getSuccessor(0) != PBI->getSuccessor(1)) { // Okay, the outcome of this conditional branch is statically - // knowable. Delete the outgoing CFG edge that is impossible to - // execute. - bool CondIsTrue = PBI->getSuccessor(0) == BB; - BI->getSuccessor(CondIsTrue)->removePredecessor(BB); - new BranchInst(BI->getSuccessor(!CondIsTrue), BB); - BB->getInstList().erase(BI); - return SimplifyCFG(BB) | true; + // knowable. If this block had a single pred, handle specially. + if (BB->getSinglePredecessor()) { + // Turn this into a branch on constant. + bool CondIsTrue = PBI->getSuccessor(0) == BB; + BI->setCondition(ConstantBool::get(CondIsTrue)); + return SimplifyCFG(BB); // Nuke the branch on constant. + } + + // Otherwise, if there are multiple predecessors, insert a PHI that + // merges in the constant and simplify the block result. + if (BlockIsSimpleEnoughToThreadThrough(BB)) { + PHINode *NewPN = new PHINode(Type::BoolTy, + BI->getCondition()->getName()+".pr", + BB->begin()); + for (PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) + if ((PBI = dyn_cast((*PI)->getTerminator())) && + PBI != BI && PBI->isConditional() && + PBI->getCondition() == BI->getCondition() && + PBI->getSuccessor(0) != PBI->getSuccessor(1)) { + bool CondIsTrue = PBI->getSuccessor(0) == BB; + NewPN->addIncoming(ConstantBool::get(CondIsTrue), *PI); + } else { + NewPN->addIncoming(BI->getCondition(), *PI); + } + + BI->setCondition(NewPN); + // This will thread the branch. + return SimplifyCFG(BB) | true; + } } } } else if (isa(BB->getTerminator())) { From lattner at cs.uiuc.edu Mon Sep 19 20:43:52 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 20:43:52 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll Message-ID: <200509200143.UAA01928@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/SimplifyCFG: branch-phi-thread.ll updated: 1.2 -> 1.3 --- Log message: make this test harder: add a case where instructions are in the bb to be threaded over --- Diffs of the changes: (+19 -0) branch-phi-thread.ll | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+) Index: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll diff -u llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.2 llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.3 --- llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.2 Mon Sep 19 19:41:55 2005 +++ llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll Mon Sep 19 20:43:41 2005 @@ -42,3 +42,22 @@ ret int 123 } +int %test3(int %X, bool %D, int* %AP, int* %BP) { +E: + %C = seteq int %X, 0 + br bool %C, label %T, label %F +T: + call void %f3() ;; Inst in block. + %XX = load int* %AP + store int %XX, int* %BP + br bool %C, label %B, label %A +A: + call void %f1() + br bool %D, label %T, label %F +B: + call void %f2() + ret int 345 +F: + call void %f3() + ret int 123 +} From lattner at cs.uiuc.edu Mon Sep 19 20:48:51 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 19 Sep 2005 20:48:51 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp Message-ID: <200509200148.UAA02081@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: SimplifyCFG.cpp updated: 1.86 -> 1.87 --- Log message: Start threading across blocks with code in them, so long as the code does not define a value that is used outside of it's block. This catches many more simplifications, e.g. 854 in 176.gcc, 137 in vpr, etc. This implements branch-phi-thread.ll:test3.ll --- Diffs of the changes: (+64 -15) SimplifyCFG.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 64 insertions(+), 15 deletions(-) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.86 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.87 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.86 Mon Sep 19 19:43:16 2005 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 20:48:40 2005 @@ -896,17 +896,24 @@ BranchInst *BI = cast(BB->getTerminator()); Value *Cond = BI->getCondition(); + unsigned Size = 0; + // If this basic block contains anything other than a PHI (which controls the // branch) and branch itself, bail out. FIXME: improve this in the future. - for (BasicBlock::iterator BBI = BB->begin(); &*BBI != BI; ++BBI) { - if (!isa(BBI)) return false; + for (BasicBlock::iterator BBI = BB->begin(); &*BBI != BI; ++BBI, ++Size) { + if (Size > 10) return false; // Don't clone large BB's. - if (&*BBI != Cond || !Cond->hasOneUse()) - return false; + // We can only support instructions that are do not define values that are + // live outside of the current basic block. + for (Value::use_iterator UI = BBI->use_begin(), E = BBI->use_end(); + UI != E; ++UI) { + Instruction *U = cast(*UI); + if (U->getParent() != BB || isa(U)) return false; + } // Looks ok, continue checking. } - + return true; } @@ -944,22 +951,64 @@ BasicBlock *PredBB = PN->getIncomingBlock(i); BasicBlock *RealDest = BI->getSuccessor(!CB->getValue()); - // If there are PHI nodes in the destination block, we have to add an - // entry for PredBB. Instead of being smart about this, just split the - // critical edge, which will eliminate the PHI-ness. - if (isa(RealDest->begin())) { - SplitCriticalEdge(BI, !CB->getValue()); - RealDest = BI->getSuccessor(!CB->getValue()); - } - assert(!isa(RealDest->begin()) && "Crit edge split failure!"); + if (RealDest == BB) continue; // Skip self loops. + // The dest block might have PHI nodes, other predecessors and other + // difficult cases. Instead of being smart about this, just insert a new + // block that jumps to the destination block, effectively splitting + // the edge we are about to create. + BasicBlock *EdgeBB = new BasicBlock(RealDest->getName()+".critedge", + RealDest->getParent(), RealDest); + new BranchInst(RealDest, EdgeBB); + PHINode *PN; + for (BasicBlock::iterator BBI = RealDest->begin(); + (PN = dyn_cast(BBI)); ++BBI) { + Value *V = PN->getIncomingValueForBlock(BB); + PN->addIncoming(V, EdgeBB); + } + + // BB may have instructions that are being threaded over. Clone these + // instructions into EdgeBB. We know that there will be no uses of the + // cloned instructions outside of EdgeBB. + BasicBlock::iterator InsertPt = EdgeBB->begin(); + std::map TranslateMap; // Track translated values. + for (BasicBlock::iterator BBI = BB->begin(); &*BBI != BI; ++BBI) { + if (PHINode *PN = dyn_cast(BBI)) { + TranslateMap[PN] = PN->getIncomingValueForBlock(PredBB); + } else { + // Clone the instruction. + Instruction *N = BBI->clone(); + if (BBI->hasName()) N->setName(BBI->getName()+".c"); + + // Update operands due to translation. + for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { + std::map::iterator PI = + TranslateMap.find(N->getOperand(i)); + if (PI != TranslateMap.end()) + N->setOperand(i, PI->second); + } + + // Check for trivial simplification. + if (Constant *C = ConstantFoldInstruction(N)) { + std::cerr << "FOLDED: " << *N; + TranslateMap[BBI] = C; + delete N; // Constant folded away, don't need actual inst + } else { + // Insert the new instruction into its new home. + EdgeBB->getInstList().insert(InsertPt, N); + if (!BBI->use_empty()) + TranslateMap[BBI] = N; + } + } + } + // Loop over all of the edges from PredBB to BB, changing them to branch - // to RealDest instead. + // to EdgeBB instead. TerminatorInst *PredBBTI = PredBB->getTerminator(); for (unsigned i = 0, e = PredBBTI->getNumSuccessors(); i != e; ++i) if (PredBBTI->getSuccessor(i) == BB) { BB->removePredecessor(PredBB); - PredBBTI->setSuccessor(i, RealDest); + PredBBTI->setSuccessor(i, EdgeBB); } // Recurse, simplifying any other constants. From lattner at cs.uiuc.edu Tue Sep 20 22:56:38 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 20 Sep 2005 22:56:38 -0500 Subject: [llvm-commits] CVS: llvm/docs/CFEBuildInstrs.html Message-ID: <200509210356.WAA26115@zion.cs.uiuc.edu> Changes in directory llvm/docs: CFEBuildInstrs.html updated: 1.52 -> 1.53 --- Log message: Recommend what I actually test --- Diffs of the changes: (+3 -2) CFEBuildInstrs.html | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) Index: llvm/docs/CFEBuildInstrs.html diff -u llvm/docs/CFEBuildInstrs.html:1.52 llvm/docs/CFEBuildInstrs.html:1.53 --- llvm/docs/CFEBuildInstrs.html:1.52 Tue Jun 14 02:29:50 2005 +++ llvm/docs/CFEBuildInstrs.html Tue Sep 20 22:56:26 2005 @@ -103,7 +103,8 @@
  • Configure and build the LLVM libraries and tools. There are two ways to do this: either with objdir == srcdir or objdir != srcdir. It is recommended -that srcdir not be the same as objdir:

    +that srcdir be the same as objdir for your LLVM tree (but note +that you should always use srcdir != objdir for llvm-gcc):

    • With objdir != srcdir:
        % cd objdir
      @@ -355,7 +356,7 @@
       
         Brian Gaeke
      LLVM Compiler Infrastructure
      - Last modified: $Date: 2005/06/14 07:29:50 $ + Last modified: $Date: 2005/09/21 03:56:26 $ From lattner at cs.uiuc.edu Tue Sep 20 23:18:36 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 20 Sep 2005 23:18:36 -0500 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h Message-ID: <200509210418.XAA26549@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: LiveIntervalAnalysis.h updated: 1.46 -> 1.47 --- Log message: move the live interval headers out of lib/CodeGen/ --- Diffs of the changes: (+1 -1) LiveIntervalAnalysis.h | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-) Index: llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h diff -u llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h:1.46 llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h:1.47 --- llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h:1.46 Thu Sep 1 19:20:32 2005 +++ llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h Tue Sep 20 23:18:25 2005 @@ -22,7 +22,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "LiveInterval.h" +#include "llvm/CodeGen/LiveInterval.h" namespace llvm { From lattner at cs.uiuc.edu Tue Sep 20 23:19:21 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 20 Sep 2005 23:19:21 -0500 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/LiveInterval.cpp LiveIntervalAnalysis.cpp RegAllocIterativeScan.cpp RegAllocLinearScan.cpp LiveInterval.h LiveIntervalAnalysis.h Message-ID: <200509210419.XAA26636@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: LiveInterval.cpp updated: 1.21 -> 1.22 LiveIntervalAnalysis.cpp updated: 1.148 -> 1.149 RegAllocIterativeScan.cpp updated: 1.21 -> 1.22 RegAllocLinearScan.cpp updated: 1.113 -> 1.114 LiveInterval.h (r1.14) removed LiveIntervalAnalysis.h (r1.46) removed --- Log message: Expose the LiveInterval interfaces as public headers. --- Diffs of the changes: (+4 -4) LiveInterval.cpp | 2 +- LiveIntervalAnalysis.cpp | 2 +- RegAllocIterativeScan.cpp | 2 +- RegAllocLinearScan.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) Index: llvm/lib/CodeGen/LiveInterval.cpp diff -u llvm/lib/CodeGen/LiveInterval.cpp:1.21 llvm/lib/CodeGen/LiveInterval.cpp:1.22 --- llvm/lib/CodeGen/LiveInterval.cpp:1.21 Sat May 14 00:34:15 2005 +++ llvm/lib/CodeGen/LiveInterval.cpp Tue Sep 20 23:19:08 2005 @@ -18,7 +18,7 @@ // //===----------------------------------------------------------------------===// -#include "LiveInterval.h" +#include "llvm/CodeGen/LiveInterval.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Target/MRegisterInfo.h" #include Index: llvm/lib/CodeGen/LiveIntervalAnalysis.cpp diff -u llvm/lib/CodeGen/LiveIntervalAnalysis.cpp:1.148 llvm/lib/CodeGen/LiveIntervalAnalysis.cpp:1.149 --- llvm/lib/CodeGen/LiveIntervalAnalysis.cpp:1.148 Fri Sep 9 14:19:20 2005 +++ llvm/lib/CodeGen/LiveIntervalAnalysis.cpp Tue Sep 20 23:19:09 2005 @@ -16,7 +16,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "liveintervals" -#include "LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "VirtRegMap.h" #include "llvm/Value.h" #include "llvm/Analysis/LoopInfo.h" Index: llvm/lib/CodeGen/RegAllocIterativeScan.cpp diff -u llvm/lib/CodeGen/RegAllocIterativeScan.cpp:1.21 llvm/lib/CodeGen/RegAllocIterativeScan.cpp:1.22 --- llvm/lib/CodeGen/RegAllocIterativeScan.cpp:1.21 Sun Jan 23 16:45:12 2005 +++ llvm/lib/CodeGen/RegAllocIterativeScan.cpp Tue Sep 20 23:19:09 2005 @@ -28,7 +28,7 @@ #include "llvm/Support/Debug.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/STLExtras.h" -#include "LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "PhysRegTracker.h" #include "VirtRegMap.h" #include Index: llvm/lib/CodeGen/RegAllocLinearScan.cpp diff -u llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.113 llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.114 --- llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.113 Tue Aug 30 16:03:36 2005 +++ llvm/lib/CodeGen/RegAllocLinearScan.cpp Tue Sep 20 23:19:09 2005 @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "regalloc" -#include "LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "PhysRegTracker.h" #include "VirtRegMap.h" #include "llvm/Function.h" From lattner at cs.uiuc.edu Wed Sep 21 01:54:07 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 21 Sep 2005 01:54:07 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/CFrontend/2005-09-20-ComplexConstants.c Message-ID: <200509210654.BAA27353@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/CFrontend: 2005-09-20-ComplexConstants.c added (r1.1) --- Log message: Testcase for PR629: http://llvm.cs.uiuc.edu/PR629 --- Diffs of the changes: (+5 -0) 2005-09-20-ComplexConstants.c | 5 +++++ 1 files changed, 5 insertions(+) Index: llvm/test/Regression/CFrontend/2005-09-20-ComplexConstants.c diff -c /dev/null llvm/test/Regression/CFrontend/2005-09-20-ComplexConstants.c:1.1 *** /dev/null Wed Sep 21 01:54:06 2005 --- llvm/test/Regression/CFrontend/2005-09-20-ComplexConstants.c Wed Sep 21 01:53:56 2005 *************** *** 0 **** --- 1,5 ---- + // RUN: %llvmgcc %s -S -o - && \ + // RUN: %llvmgcc %s -S -o - | llvm-as -o /dev/null -f + + const double _Complex x[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + From lattner at cs.uiuc.edu Wed Sep 21 01:54:40 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 21 Sep 2005 01:54:40 -0500 Subject: [llvm-commits] CVS: llvm-gcc/gcc/llvm-expand.c Message-ID: <200509210654.BAA27364@zion.cs.uiuc.edu> Changes in directory llvm-gcc/gcc: llvm-expand.c updated: 1.112 -> 1.113 --- Log message: Fix PR629: http://llvm.cs.uiuc.edu/PR629 and Regression/CFrontend/2005-09-20-ComplexConstants.c --- Diffs of the changes: (+14 -2) llvm-expand.c | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) Index: llvm-gcc/gcc/llvm-expand.c diff -u llvm-gcc/gcc/llvm-expand.c:1.112 llvm-gcc/gcc/llvm-expand.c:1.113 --- llvm-gcc/gcc/llvm-expand.c:1.112 Thu Jul 28 17:37:20 2005 +++ llvm-gcc/gcc/llvm-expand.c Wed Sep 21 01:54:29 2005 @@ -5390,6 +5390,20 @@ } break; + case COMPLEX_CST: { + llvm_value **Vals = (llvm_value **)xmalloc(2*sizeof(llvm_value *)); + assert(ReqTy == Ty); + assert(Ty->ID == StructTyID && Ty->NumElements == 2 && + Ty->Elements[0] == Ty->Elements[1] && + "Very strange complex number."); + Vals[0] = D2V(llvm_expand_constant_expr(TREE_REALPART(exp), + Ty->Elements[0])); + Vals[1] = D2V(llvm_expand_constant_expr(TREE_IMAGPART(exp), + Ty->Elements[1])); + Val = G2V(llvm_constant_aggregate_new(Ty, Vals)); + break; + } + case NOP_EXPR: /* Cast constant_expr */ case NON_LVALUE_EXPR: case CONVERT_EXPR: @@ -6368,13 +6382,11 @@ op1 = llvm_expand_expr(Fn, TREE_IMAGPART(exp), 0); InitializeComplex(Fn, DestLoc, op0, op1, expVolatile); break; - case COMPLEX_EXPR: op0 = llvm_expand_expr(Fn, TREE_OPERAND(exp, 0), 0); op1 = llvm_expand_expr(Fn, TREE_OPERAND(exp, 1), 0); InitializeComplex(Fn, DestLoc, op0, op1, expVolatile); break; - case INTEGER_CST: case REAL_CST: Result = D2V(llvm_expand_constant_expr(exp, DestTy)); From lattner at cs.uiuc.edu Thu Sep 22 19:53:17 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 22 Sep 2005 19:53:17 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/CodeGen/PowerPC/inverted-bool-compares.ll Message-ID: <200509230053.TAA26630@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/CodeGen/PowerPC: inverted-bool-compares.ll added (r1.1) --- Log message: new testcase --- Diffs of the changes: (+11 -0) inverted-bool-compares.ll | 11 +++++++++++ 1 files changed, 11 insertions(+) Index: llvm/test/Regression/CodeGen/PowerPC/inverted-bool-compares.ll diff -c /dev/null llvm/test/Regression/CodeGen/PowerPC/inverted-bool-compares.ll:1.1 *** /dev/null Thu Sep 22 19:53:16 2005 --- llvm/test/Regression/CodeGen/PowerPC/inverted-bool-compares.ll Thu Sep 22 19:53:06 2005 *************** *** 0 **** --- 1,11 ---- + ; RUN: llvm-as < %s | llc -march=ppc32 | not grep xori && + ; RUN: llvm-as < %s | llc -march=ppc32 + + int %test(bool %B, int* %P) { + br bool %B, label %T, label %F + T: + store int 123, int* %P + ret int 0 + F: + ret int 17 + } From lattner at cs.uiuc.edu Thu Sep 22 19:56:04 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 22 Sep 2005 19:56:04 -0500 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Message-ID: <200509230056.TAA26720@zion.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen/SelectionDAG: SelectionDAG.cpp updated: 1.192 -> 1.193 --- Log message: Turn (X^C1) == C2 into X == C1^C2 iff X&~C1 = 0 (and move a function) This happens all the time on PPC for bool values, e.g. eliminating a xori in inverted-bool-compares.ll. This should be added to the dag combiner as well. --- Diffs of the changes: (+86 -72) SelectionDAG.cpp | 158 +++++++++++++++++++++++++++++-------------------------- 1 files changed, 86 insertions(+), 72 deletions(-) Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp diff -u llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp:1.192 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp:1.193 --- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp:1.192 Fri Sep 9 18:00:07 2005 +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Thu Sep 22 19:55:52 2005 @@ -580,6 +580,80 @@ return SDOperand(Reg, 0); } +/// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use +/// this predicate to simplify operations downstream. V and Mask are known to +/// be the same type. +static bool MaskedValueIsZero(const SDOperand &Op, uint64_t Mask, + const TargetLowering &TLI) { + unsigned SrcBits; + if (Mask == 0) return true; + + // If we know the result of a setcc has the top bits zero, use this info. + switch (Op.getOpcode()) { + case ISD::Constant: + return (cast(Op)->getValue() & Mask) == 0; + + case ISD::SETCC: + return ((Mask & 1) == 0) && + TLI.getSetCCResultContents() == TargetLowering::ZeroOrOneSetCCResult; + + case ISD::ZEXTLOAD: + SrcBits = MVT::getSizeInBits(cast(Op.getOperand(3))->getVT()); + return (Mask & ((1ULL << SrcBits)-1)) == 0; // Returning only the zext bits. + case ISD::ZERO_EXTEND: + SrcBits = MVT::getSizeInBits(Op.getOperand(0).getValueType()); + return MaskedValueIsZero(Op.getOperand(0),Mask & ((1ULL << SrcBits)-1),TLI); + case ISD::AssertZext: + SrcBits = MVT::getSizeInBits(cast(Op.getOperand(1))->getVT()); + return (Mask & ((1ULL << SrcBits)-1)) == 0; // Returning only the zext bits. + case ISD::AND: + // (X & C1) & C2 == 0 iff C1 & C2 == 0. + if (ConstantSDNode *AndRHS = dyn_cast(Op.getOperand(1))) + return MaskedValueIsZero(Op.getOperand(0),AndRHS->getValue() & Mask, TLI); + + // FALL THROUGH + case ISD::OR: + case ISD::XOR: + return MaskedValueIsZero(Op.getOperand(0), Mask, TLI) && + MaskedValueIsZero(Op.getOperand(1), Mask, TLI); + case ISD::SELECT: + return MaskedValueIsZero(Op.getOperand(1), Mask, TLI) && + MaskedValueIsZero(Op.getOperand(2), Mask, TLI); + case ISD::SELECT_CC: + return MaskedValueIsZero(Op.getOperand(2), Mask, TLI) && + MaskedValueIsZero(Op.getOperand(3), Mask, TLI); + case ISD::SRL: + // (ushr X, C1) & C2 == 0 iff X & (C2 << C1) == 0 + if (ConstantSDNode *ShAmt = dyn_cast(Op.getOperand(1))) { + uint64_t NewVal = Mask << ShAmt->getValue(); + SrcBits = MVT::getSizeInBits(Op.getValueType()); + if (SrcBits != 64) NewVal &= (1ULL << SrcBits)-1; + return MaskedValueIsZero(Op.getOperand(0), NewVal, TLI); + } + return false; + case ISD::SHL: + // (ushl X, C1) & C2 == 0 iff X & (C2 >> C1) == 0 + if (ConstantSDNode *ShAmt = dyn_cast(Op.getOperand(1))) { + uint64_t NewVal = Mask >> ShAmt->getValue(); + return MaskedValueIsZero(Op.getOperand(0), NewVal, TLI); + } + return false; + case ISD::CTTZ: + case ISD::CTLZ: + case ISD::CTPOP: + // Bit counting instructions can not set the high bits of the result + // register. The max number of bits sets depends on the input. + return (Mask & (MVT::getSizeInBits(Op.getValueType())*2-1)) == 0; + + // TODO we could handle some SRA cases here. + default: break; + } + + return false; +} + + + SDOperand SelectionDAG::SimplifySetCC(MVT::ValueType VT, SDOperand N1, SDOperand N2, ISD::CondCode Cond) { // These setcc operations always fold. @@ -816,6 +890,18 @@ // FIXME: move this stuff to the DAG Combiner when it exists! + // Turn (X^C1) == C2 into X == C1^C2 iff X&~C1 = 0. Common for condcodes. + if (N1.getOpcode() == ISD::XOR) + if (ConstantSDNode *XORC = dyn_cast(N1.getOperand(1))) + if (ConstantSDNode *RHSC = dyn_cast(N2)) { + // If we know that all of the inverted bits are zero, don't bother + // performing the inversion. + if (MaskedValueIsZero(N1.getOperand(0), ~XORC->getValue(), TLI)) + return getSetCC(VT, N1.getOperand(0), + getConstant(XORC->getValue()^RHSC->getValue(), + N1.getValueType()), Cond); + } + // Simplify (X+Z) == X --> Z == 0 if (N1.getOperand(0) == N2) return getSetCC(VT, N1.getOperand(1), @@ -1126,78 +1212,6 @@ return SDOperand(N, 0); } -/// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use -/// this predicate to simplify operations downstream. V and Mask are known to -/// be the same type. -static bool MaskedValueIsZero(const SDOperand &Op, uint64_t Mask, - const TargetLowering &TLI) { - unsigned SrcBits; - if (Mask == 0) return true; - - // If we know the result of a setcc has the top bits zero, use this info. - switch (Op.getOpcode()) { - case ISD::Constant: - return (cast(Op)->getValue() & Mask) == 0; - - case ISD::SETCC: - return ((Mask & 1) == 0) && - TLI.getSetCCResultContents() == TargetLowering::ZeroOrOneSetCCResult; - - case ISD::ZEXTLOAD: - SrcBits = MVT::getSizeInBits(cast(Op.getOperand(3))->getVT()); - return (Mask & ((1ULL << SrcBits)-1)) == 0; // Returning only the zext bits. - case ISD::ZERO_EXTEND: - SrcBits = MVT::getSizeInBits(Op.getOperand(0).getValueType()); - return MaskedValueIsZero(Op.getOperand(0),Mask & ((1ULL << SrcBits)-1),TLI); - case ISD::AssertZext: - SrcBits = MVT::getSizeInBits(cast(Op.getOperand(1))->getVT()); - return (Mask & ((1ULL << SrcBits)-1)) == 0; // Returning only the zext bits. - case ISD::AND: - // (X & C1) & C2 == 0 iff C1 & C2 == 0. - if (ConstantSDNode *AndRHS = dyn_cast(Op.getOperand(1))) - return MaskedValueIsZero(Op.getOperand(0),AndRHS->getValue() & Mask, TLI); - - // FALL THROUGH - case ISD::OR: - case ISD::XOR: - return MaskedValueIsZero(Op.getOperand(0), Mask, TLI) && - MaskedValueIsZero(Op.getOperand(1), Mask, TLI); - case ISD::SELECT: - return MaskedValueIsZero(Op.getOperand(1), Mask, TLI) && - MaskedValueIsZero(Op.getOperand(2), Mask, TLI); - case ISD::SELECT_CC: - return MaskedValueIsZero(Op.getOperand(2), Mask, TLI) && - MaskedValueIsZero(Op.getOperand(3), Mask, TLI); - case ISD::SRL: - // (ushr X, C1) & C2 == 0 iff X & (C2 << C1) == 0 - if (ConstantSDNode *ShAmt = dyn_cast(Op.getOperand(1))) { - uint64_t NewVal = Mask << ShAmt->getValue(); - SrcBits = MVT::getSizeInBits(Op.getValueType()); - if (SrcBits != 64) NewVal &= (1ULL << SrcBits)-1; - return MaskedValueIsZero(Op.getOperand(0), NewVal, TLI); - } - return false; - case ISD::SHL: - // (ushl X, C1) & C2 == 0 iff X & (C2 >> C1) == 0 - if (ConstantSDNode *ShAmt = dyn_cast(Op.getOperand(1))) { - uint64_t NewVal = Mask >> ShAmt->getValue(); - return MaskedValueIsZero(Op.getOperand(0), NewVal, TLI); - } - return false; - case ISD::CTTZ: - case ISD::CTLZ: - case ISD::CTPOP: - // Bit counting instructions can not set the high bits of the result - // register. The max number of bits sets depends on the input. - return (Mask & (MVT::getSizeInBits(Op.getValueType())*2-1)) == 0; - - // TODO we could handle some SRA cases here. - default: break; - } - - return false; -} - SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT, From lattner at cs.uiuc.edu Fri Sep 23 01:05:58 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 01:05:58 -0500 Subject: [llvm-commits] CVS: llvm/tools/gccld/GenerateCode.cpp Message-ID: <200509230605.BAA23240@zion.cs.uiuc.edu> Changes in directory llvm/tools/gccld: GenerateCode.cpp updated: 1.51 -> 1.52 --- Log message: 1. Do not use .c_str() to keep a persistent handle on a temporary string. 2. Concatenate -lfoo and -L/bar options into a single option instead of passing "-L /bar" (for example) which doesn't work on Darwin. 3. Send -v output to stderr instead of stdout --- Diffs of the changes: (+32 -23) GenerateCode.cpp | 55 ++++++++++++++++++++++++++++++++----------------------- 1 files changed, 32 insertions(+), 23 deletions(-) Index: llvm/tools/gccld/GenerateCode.cpp diff -u llvm/tools/gccld/GenerateCode.cpp:1.51 llvm/tools/gccld/GenerateCode.cpp:1.52 --- llvm/tools/gccld/GenerateCode.cpp:1.51 Tue Aug 2 17:07:38 2005 +++ llvm/tools/gccld/GenerateCode.cpp Fri Sep 23 01:05:46 2005 @@ -116,15 +116,13 @@ else *p = '='; } - - return; } static void dumpArgs(const char **args) { - std::cout << *args++; + std::cerr << *args++; while (*args) - std::cout << ' ' << *args++; - std::cout << '\n'; + std::cerr << ' ' << *args++; + std::cerr << '\n' << std::flush; } static inline void addPass(PassManager &PM, Pass *P) { @@ -159,13 +157,10 @@ return isBytecodeLPath; // Make sure its a directory - try - { + try { if (!LPath.isDirectory()) return isBytecodeLPath; - } - catch (std::string& xcptn) - { + } catch (std::string& xcptn) { return isBytecodeLPath; } @@ -399,15 +394,23 @@ args.push_back(OutputFilename.c_str()); args.push_back(InputFilename.c_str()); + // StringsToDelete - We don't want to call c_str() on temporary strings. + // If we need a temporary string, copy it here so that the memory is not + // reclaimed until after the exec call. All of these strings are allocated + // with strdup. + std::vector StringsToDelete; + if (Shared) args.push_back("-shared"); if (ExportAllAsDynamic) args.push_back("-export-dynamic"); if (!RPath.empty()) { std::string rp = "-Wl,-rpath," + RPath; - args.push_back(rp.c_str()); + StringsToDelete.push_back(strdup(rp.c_str())); + args.push_back(StringsToDelete.back()); } if (!SOName.empty()) { std::string so = "-Wl,-soname," + SOName; - args.push_back(so.c_str()); + StringsToDelete.push_back(strdup(so.c_str())); + args.push_back(StringsToDelete.back()); } // Add in the libpaths to find the libraries. @@ -419,24 +422,30 @@ // Further, we don't want any -L paths that contain bytecode shared // libraries or true bytecode archive files. We omit them in all such // cases. - for (unsigned index = 0; index < LibPaths.size(); index++) { - if (!isBytecodeLPath( LibPaths[index]) ) { - args.push_back("-L"); - args.push_back(LibPaths[index].c_str()); + for (unsigned index = 0; index < LibPaths.size(); index++) + if (!isBytecodeLPath(LibPaths[index])) { + std::string Tmp = "-L"+LibPaths[index]; + StringsToDelete.push_back(strdup(Tmp.c_str())); + args.push_back(StringsToDelete.back()); } - } // Add in the libraries to link. - for (unsigned index = 0; index < Libraries.size(); index++) { + for (unsigned index = 0; index < Libraries.size(); index++) if (Libraries[index] != "crtend") { - args.push_back("-l"); - args.push_back(Libraries[index].c_str()); + std::string Tmp = "-l"+Libraries[index]; + StringsToDelete.push_back(strdup(Tmp.c_str())); + args.push_back(StringsToDelete.back()); } - } - args.push_back(0); + args.push_back(0); // Null terminate. // Run the compiler to assembly and link together the program. if (Verbose) dumpArgs(&args[0]); - return sys::Program::ExecuteAndWait(gcc, &args[0], (const char**)clean_env); + int Res = sys::Program::ExecuteAndWait(gcc, &args[0], (const char**)clean_env); + + while (!StringsToDelete.empty()) { + free(StringsToDelete.back()); + StringsToDelete.pop_back(); + } + return Res; } From lattner at cs.uiuc.edu Fri Sep 23 01:11:36 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 01:11:36 -0500 Subject: [llvm-commits] CVS: llvm/tools/gccld/GenerateCode.cpp Message-ID: <200509230611.BAA23351@zion.cs.uiuc.edu> Changes in directory llvm/tools/gccld: GenerateCode.cpp updated: 1.52 -> 1.53 --- Log message: Speed up isBytecodeLPath from 20s to .01s in common cases. This makes -native not completely painful to use. Once we decide a directory has a bytecode library, we know it this function returns true, no need to scan entire directories. --- Diffs of the changes: (+11 -17) GenerateCode.cpp | 28 +++++++++++----------------- 1 files changed, 11 insertions(+), 17 deletions(-) Index: llvm/tools/gccld/GenerateCode.cpp diff -u llvm/tools/gccld/GenerateCode.cpp:1.52 llvm/tools/gccld/GenerateCode.cpp:1.53 --- llvm/tools/gccld/GenerateCode.cpp:1.52 Fri Sep 23 01:05:46 2005 +++ llvm/tools/gccld/GenerateCode.cpp Fri Sep 23 01:11:24 2005 @@ -148,49 +148,43 @@ } static bool isBytecodeLPath(const std::string &LibPath) { - bool isBytecodeLPath = false; - sys::Path LPath(LibPath); - // Make sure it exists - if (!LPath.exists()) - return isBytecodeLPath; - - // Make sure its a directory + // Make sure it exists and is a directory try { - if (!LPath.isDirectory()) - return isBytecodeLPath; + if (!LPath.exists() || !LPath.isDirectory()) + return false; } catch (std::string& xcptn) { - return isBytecodeLPath; + return false; } - + // Grab the contents of the -L path std::set Files; LPath.getDirectoryContents(Files); - + // Iterate over the contents one by one to determine // if this -L path has any bytecode shared libraries // or archives std::set::iterator File = Files.begin(); + std::string dllsuffix = sys::Path::GetDLLSuffix(); for (; File != Files.end(); ++File) { if ( File->isDirectory() ) continue; std::string path = File->toString(); - std::string dllsuffix = sys::Path::GetDLLSuffix(); // Check for an ending '.dll,.so' or '.a' suffix as all // other files are not of interest to us here - if ( path.find(dllsuffix, path.size()-dllsuffix.size()) == std::string::npos - && path.find(".a", path.size()-2) == std::string::npos ) + if (path.find(dllsuffix, path.size()-dllsuffix.size()) == std::string::npos + && path.find(".a", path.size()-2) == std::string::npos) continue; // Finally, check to see if the file is a true bytecode file if (isBytecodeLibrary(*File)) - isBytecodeLPath = true; + return true; } - return isBytecodeLPath; + return false; } /// GenerateBytecode - generates a bytecode file from the specified module. From lattner at cs.uiuc.edu Fri Sep 23 01:23:09 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 01:23:09 -0500 Subject: [llvm-commits] CVS: llvm/lib/Bytecode/Archive/ArchiveReader.cpp Message-ID: <200509230623.BAA23494@zion.cs.uiuc.edu> Changes in directory llvm/lib/Bytecode/Archive: ArchiveReader.cpp updated: 1.41 -> 1.42 --- Log message: speed up Archive::isBytecodeArchive in the case when the archive doesn't have an llvm-ranlib symtab. This speeds up gccld -native on an almost empty .o file from 1.63s to 0.18s. --- Diffs of the changes: (+24 -18) ArchiveReader.cpp | 42 ++++++++++++++++++++++++------------------ 1 files changed, 24 insertions(+), 18 deletions(-) Index: llvm/lib/Bytecode/Archive/ArchiveReader.cpp diff -u llvm/lib/Bytecode/Archive/ArchiveReader.cpp:1.41 llvm/lib/Bytecode/Archive/ArchiveReader.cpp:1.42 --- llvm/lib/Bytecode/Archive/ArchiveReader.cpp:1.41 Thu Jul 7 18:21:43 2005 +++ llvm/lib/Bytecode/Archive/ArchiveReader.cpp Fri Sep 23 01:22:58 2005 @@ -504,19 +504,15 @@ } } -bool -Archive::isBytecodeArchive() -{ - //Make sure the symTab has been loaded... - //in most cases this should have been done - //when the archive was constructed, but still, - //this is just in case. - if ( !symTab.size() ) +bool Archive::isBytecodeArchive() { + // Make sure the symTab has been loaded. In most cases this should have been + // done when the archive was constructed, but still, this is just in case. + if (!symTab.size()) loadSymbolTable(); - //Now that we know it's been loaded, return true - //if it has a size - if ( symTab.size() ) return true; + // Now that we know it's been loaded, return true + // if it has a size + if (symTab.size()) return true; //We still can't be sure it isn't a bytecode archive loadArchive(); @@ -524,11 +520,21 @@ std::vector Modules; std::string ErrorMessage; - //If getAllModules gives an error then this isn't a proper - //bytecode archive - if ( getAllModules( Modules, &ErrorMessage ) ) return false; - - //Finally, if we find any bytecode modules then this is a proper - //bytecode archive - return Modules.size(); + // Scan the archive, trying to load a bytecode member. We only load one to + // see if this works. + for (iterator I = begin(), E = end(); I != E; ++I) { + if (!I->isBytecode() && !I->isCompressedBytecode()) + continue; + + std::string FullMemberName = + archPath.toString() + "(" + I->getPath().toString() + ")"; + Module* M = ParseBytecodeBuffer((const unsigned char*)I->getData(), + I->getSize(), FullMemberName); + if (!M) + return false; // Couldn't parse bytecode, not a bytecode archive. + delete M; + return true; + } + + return false; } From lattner at cs.uiuc.edu Fri Sep 23 01:39:41 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 01:39:41 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp Message-ID: <200509230639.BAA23684@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: SimplifyCFG.cpp updated: 1.87 -> 1.88 --- Log message: pull a bunch of logic out of SimplifyCFG into a helper fn --- Diffs of the changes: (+112 -112) SimplifyCFG.cpp | 224 ++++++++++++++++++++++++++++---------------------------- 1 files changed, 112 insertions(+), 112 deletions(-) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.87 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.88 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.87 Mon Sep 19 20:48:40 2005 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Fri Sep 23 01:39:30 2005 @@ -1018,6 +1018,116 @@ return false; } +/// FoldTwoEntryPHINode - Given a BB that starts with the specified two-entry +/// PHI node, see if we can eliminate it. +static bool FoldTwoEntryPHINode(PHINode *PN) { + // Ok, this is a two entry PHI node. Check to see if this is a simple "if + // statement", which has a very simple dominance structure. Basically, we + // are trying to find the condition that is being branched on, which + // subsequently causes this merge to happen. We really want control + // dependence information for this check, but simplifycfg can't keep it up + // to date, and this catches most of the cases we care about anyway. + // + BasicBlock *BB = PN->getParent(); + BasicBlock *IfTrue, *IfFalse; + Value *IfCond = GetIfCondition(BB, IfTrue, IfFalse); + if (!IfCond) return false; + + DEBUG(std::cerr << "FOUND IF CONDITION! " << *IfCond << " T: " + << IfTrue->getName() << " F: " << IfFalse->getName() << "\n"); + + // Loop over the PHI's seeing if we can promote them all to select + // instructions. While we are at it, keep track of the instructions + // that need to be moved to the dominating block. + std::set AggressiveInsts; + + bool CanPromote = true; + BasicBlock::iterator AfterPHIIt = BB->begin(); + while (isa(AfterPHIIt)) { + PHINode *PN = cast(AfterPHIIt++); + if (PN->getIncomingValue(0) == PN->getIncomingValue(1)) { + if (PN->getIncomingValue(0) != PN) + PN->replaceAllUsesWith(PN->getIncomingValue(0)); + else + PN->replaceAllUsesWith(UndefValue::get(PN->getType())); + } else if (!DominatesMergePoint(PN->getIncomingValue(0), BB, + &AggressiveInsts) || + !DominatesMergePoint(PN->getIncomingValue(1), BB, + &AggressiveInsts)) { + CanPromote = false; + } + } + + // Did we eliminate all PHI's? + if (!CanPromote && AfterPHIIt != BB->begin()) + return false; + + // If we all PHI nodes are promotable, check to make sure that all + // instructions in the predecessor blocks can be promoted as well. If + // not, we won't be able to get rid of the control flow, so it's not + // worth promoting to select instructions. + BasicBlock *DomBlock = 0, *IfBlock1 = 0, *IfBlock2 = 0; + PN = cast(BB->begin()); + BasicBlock *Pred = PN->getIncomingBlock(0); + if (cast(Pred->getTerminator())->isUnconditional()) { + IfBlock1 = Pred; + DomBlock = *pred_begin(Pred); + for (BasicBlock::iterator I = Pred->begin(); + !isa(I); ++I) + if (!AggressiveInsts.count(I)) { + // This is not an aggressive instruction that we can promote. + // Because of this, we won't be able to get rid of the control + // flow, so the xform is not worth it. + return false; + } + } + + Pred = PN->getIncomingBlock(1); + if (cast(Pred->getTerminator())->isUnconditional()) { + IfBlock2 = Pred; + DomBlock = *pred_begin(Pred); + for (BasicBlock::iterator I = Pred->begin(); + !isa(I); ++I) + if (!AggressiveInsts.count(I)) { + // This is not an aggressive instruction that we can promote. + // Because of this, we won't be able to get rid of the control + // flow, so the xform is not worth it. + return false; + } + } + + // If we can still promote the PHI nodes after this gauntlet of tests, + // do all of the PHI's now. + + // Move all 'aggressive' instructions, which are defined in the + // conditional parts of the if's up to the dominating block. + if (IfBlock1) { + DomBlock->getInstList().splice(DomBlock->getTerminator(), + IfBlock1->getInstList(), + IfBlock1->begin(), + IfBlock1->getTerminator()); + } + if (IfBlock2) { + DomBlock->getInstList().splice(DomBlock->getTerminator(), + IfBlock2->getInstList(), + IfBlock2->begin(), + IfBlock2->getTerminator()); + } + + while (PHINode *PN = dyn_cast(BB->begin())) { + // Change the PHI node into a select instruction. + Value *TrueVal = + PN->getIncomingValue(PN->getIncomingBlock(0) == IfFalse); + Value *FalseVal = + PN->getIncomingValue(PN->getIncomingBlock(0) == IfTrue); + + std::string Name = PN->getName(); PN->setName(""); + PN->replaceAllUsesWith(new SelectInst(IfCond, TrueVal, FalseVal, + Name, AfterPHIIt)); + BB->getInstList().erase(PN); + } + return true; +} namespace { /// ConstantIntOrdering - This class implements a stable ordering of constant @@ -1620,118 +1730,8 @@ // If there is a trivial two-entry PHI node in this basic block, and we can // eliminate it, do so now. if (PHINode *PN = dyn_cast(BB->begin())) - if (PN->getNumIncomingValues() == 2) { - // Ok, this is a two entry PHI node. Check to see if this is a simple "if - // statement", which has a very simple dominance structure. Basically, we - // are trying to find the condition that is being branched on, which - // subsequently causes this merge to happen. We really want control - // dependence information for this check, but simplifycfg can't keep it up - // to date, and this catches most of the cases we care about anyway. - // - BasicBlock *IfTrue, *IfFalse; - if (Value *IfCond = GetIfCondition(BB, IfTrue, IfFalse)) { - DEBUG(std::cerr << "FOUND IF CONDITION! " << *IfCond << " T: " - << IfTrue->getName() << " F: " << IfFalse->getName() << "\n"); - - // Loop over the PHI's seeing if we can promote them all to select - // instructions. While we are at it, keep track of the instructions - // that need to be moved to the dominating block. - std::set AggressiveInsts; - bool CanPromote = true; - - BasicBlock::iterator AfterPHIIt = BB->begin(); - while (isa(AfterPHIIt)) { - PHINode *PN = cast(AfterPHIIt++); - if (PN->getIncomingValue(0) == PN->getIncomingValue(1)) { - if (PN->getIncomingValue(0) != PN) - PN->replaceAllUsesWith(PN->getIncomingValue(0)); - else - PN->replaceAllUsesWith(UndefValue::get(PN->getType())); - } else if (!DominatesMergePoint(PN->getIncomingValue(0), BB, - &AggressiveInsts) || - !DominatesMergePoint(PN->getIncomingValue(1), BB, - &AggressiveInsts)) { - CanPromote = false; - break; - } - } - - // Did we eliminate all PHI's? - CanPromote |= AfterPHIIt == BB->begin(); - - // If we all PHI nodes are promotable, check to make sure that all - // instructions in the predecessor blocks can be promoted as well. If - // not, we won't be able to get rid of the control flow, so it's not - // worth promoting to select instructions. - BasicBlock *DomBlock = 0, *IfBlock1 = 0, *IfBlock2 = 0; - if (CanPromote) { - PN = cast(BB->begin()); - BasicBlock *Pred = PN->getIncomingBlock(0); - if (cast(Pred->getTerminator())->isUnconditional()) { - IfBlock1 = Pred; - DomBlock = *pred_begin(Pred); - for (BasicBlock::iterator I = Pred->begin(); - !isa(I); ++I) - if (!AggressiveInsts.count(I)) { - // This is not an aggressive instruction that we can promote. - // Because of this, we won't be able to get rid of the control - // flow, so the xform is not worth it. - CanPromote = false; - break; - } - } - - Pred = PN->getIncomingBlock(1); - if (CanPromote && - cast(Pred->getTerminator())->isUnconditional()) { - IfBlock2 = Pred; - DomBlock = *pred_begin(Pred); - for (BasicBlock::iterator I = Pred->begin(); - !isa(I); ++I) - if (!AggressiveInsts.count(I)) { - // This is not an aggressive instruction that we can promote. - // Because of this, we won't be able to get rid of the control - // flow, so the xform is not worth it. - CanPromote = false; - break; - } - } - } - - // If we can still promote the PHI nodes after this gauntlet of tests, - // do all of the PHI's now. - if (CanPromote) { - // Move all 'aggressive' instructions, which are defined in the - // conditional parts of the if's up to the dominating block. - if (IfBlock1) { - DomBlock->getInstList().splice(DomBlock->getTerminator(), - IfBlock1->getInstList(), - IfBlock1->begin(), - IfBlock1->getTerminator()); - } - if (IfBlock2) { - DomBlock->getInstList().splice(DomBlock->getTerminator(), - IfBlock2->getInstList(), - IfBlock2->begin(), - IfBlock2->getTerminator()); - } - - while (PHINode *PN = dyn_cast(BB->begin())) { - // Change the PHI node into a select instruction. - Value *TrueVal = - PN->getIncomingValue(PN->getIncomingBlock(0) == IfFalse); - Value *FalseVal = - PN->getIncomingValue(PN->getIncomingBlock(0) == IfTrue); - - std::string Name = PN->getName(); PN->setName(""); - PN->replaceAllUsesWith(new SelectInst(IfCond, TrueVal, FalseVal, - Name, AfterPHIIt)); - BB->getInstList().erase(PN); - } - Changed = true; - } - } - } + if (PN->getNumIncomingValues() == 2) + Changed |= FoldTwoEntryPHINode(PN); return Changed; } From lattner at cs.uiuc.edu Fri Sep 23 02:23:30 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 02:23:30 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp Message-ID: <200509230723.CAA23900@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: SimplifyCFG.cpp updated: 1.88 -> 1.89 --- Log message: simplify some logic further --- Diffs of the changes: (+1 -6) SimplifyCFG.cpp | 7 +------ 1 files changed, 1 insertion(+), 6 deletions(-) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.88 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.89 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.88 Fri Sep 23 01:39:30 2005 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Fri Sep 23 02:23:18 2005 @@ -1041,7 +1041,6 @@ // that need to be moved to the dominating block. std::set AggressiveInsts; - bool CanPromote = true; BasicBlock::iterator AfterPHIIt = BB->begin(); while (isa(AfterPHIIt)) { PHINode *PN = cast(AfterPHIIt++); @@ -1054,14 +1053,10 @@ &AggressiveInsts) || !DominatesMergePoint(PN->getIncomingValue(1), BB, &AggressiveInsts)) { - CanPromote = false; + return false; } } - // Did we eliminate all PHI's? - if (!CanPromote && AfterPHIIt != BB->begin()) - return false; - // If we all PHI nodes are promotable, check to make sure that all // instructions in the predecessor blocks can be promoted as well. If // not, we won't be able to get rid of the control flow, so it's not From lattner at cs.uiuc.edu Fri Sep 23 13:44:08 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 13:44:08 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/SimplifyCFG/branch-fold.ll Message-ID: <200509231844.NAA11835@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/SimplifyCFG: branch-fold.ll added (r1.1) --- Log message: new testcase --- Diffs of the changes: (+12 -0) branch-fold.ll | 12 ++++++++++++ 1 files changed, 12 insertions(+) Index: llvm/test/Regression/Transforms/SimplifyCFG/branch-fold.ll diff -c /dev/null llvm/test/Regression/Transforms/SimplifyCFG/branch-fold.ll:1.1 *** /dev/null Fri Sep 23 13:44:07 2005 --- llvm/test/Regression/Transforms/SimplifyCFG/branch-fold.ll Fri Sep 23 13:43:57 2005 *************** *** 0 **** --- 1,12 ---- + ; RUN: llvm-as < %s | opt -simplifycfg | llvm-dis | grep 'br bool' | wc -l | grep 1 + + void %test(int* %P, int* %Q, bool %A, bool %B) { + br bool %A, label %a, label %b ;; fold the two branches into one + a: + br bool %B, label %b, label %c + b: + store int 123, int* %P + ret void + c: + ret void + } From lattner at cs.uiuc.edu Fri Sep 23 13:47:31 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 13:47:31 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp Message-ID: <200509231847.NAA11877@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: SimplifyCFG.cpp updated: 1.89 -> 1.90 --- Log message: Fold two consequtive branches that share a common destination between them. This implements SimplifyCFG/branch-fold.ll, and is useful on ?:/min/max heavy code --- Diffs of the changes: (+119 -33) SimplifyCFG.cpp | 152 +++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 119 insertions(+), 33 deletions(-) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.89 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.90 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.89 Fri Sep 23 02:23:18 2005 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Fri Sep 23 13:47:20 2005 @@ -1207,6 +1207,8 @@ if (!UncondBranchPreds.empty()) { while (!UncondBranchPreds.empty()) { BasicBlock *Pred = UncondBranchPreds.back(); + DEBUG(std::cerr << "FOLDING: " << *BB + << "INTO UNCOND BRANCH PRED: " << *Pred); UncondBranchPreds.pop_back(); Instruction *UncondBranch = Pred->getTerminator(); // Clone the return and add it to the end of the predecessor. @@ -1386,7 +1388,6 @@ if (PN->getParent() == BI->getParent()) if (FoldCondBranchOnPHI(BI)) return SimplifyCFG(BB) | true; - // If this basic block is ONLY a setcc and a branch, and if a predecessor // branches to us and one of our successors, fold the setcc into the @@ -1442,43 +1443,128 @@ } } - // If this block ends with a branch instruction, and if there is a - // predecessor that ends on a branch of the same condition, make this - // conditional branch redundant. + // Scan predessor blocks for conditional branchs. for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) if (BranchInst *PBI = dyn_cast((*PI)->getTerminator())) - if (PBI != BI && PBI->isConditional() && - PBI->getCondition() == BI->getCondition() && - PBI->getSuccessor(0) != PBI->getSuccessor(1)) { - // Okay, the outcome of this conditional branch is statically - // knowable. If this block had a single pred, handle specially. - if (BB->getSinglePredecessor()) { - // Turn this into a branch on constant. - bool CondIsTrue = PBI->getSuccessor(0) == BB; - BI->setCondition(ConstantBool::get(CondIsTrue)); - return SimplifyCFG(BB); // Nuke the branch on constant. + if (PBI != BI && PBI->isConditional()) { + + // If this block ends with a branch instruction, and if there is a + // predecessor that ends on a branch of the same condition, make this + // conditional branch redundant. + if (PBI->getCondition() == BI->getCondition() && + PBI->getSuccessor(0) != PBI->getSuccessor(1)) { + // Okay, the outcome of this conditional branch is statically + // knowable. If this block had a single pred, handle specially. + if (BB->getSinglePredecessor()) { + // Turn this into a branch on constant. + bool CondIsTrue = PBI->getSuccessor(0) == BB; + BI->setCondition(ConstantBool::get(CondIsTrue)); + return SimplifyCFG(BB); // Nuke the branch on constant. + } + + // Otherwise, if there are multiple predecessors, insert a PHI that + // merges in the constant and simplify the block result. + if (BlockIsSimpleEnoughToThreadThrough(BB)) { + PHINode *NewPN = new PHINode(Type::BoolTy, + BI->getCondition()->getName()+".pr", + BB->begin()); + for (PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) + if ((PBI = dyn_cast((*PI)->getTerminator())) && + PBI != BI && PBI->isConditional() && + PBI->getCondition() == BI->getCondition() && + PBI->getSuccessor(0) != PBI->getSuccessor(1)) { + bool CondIsTrue = PBI->getSuccessor(0) == BB; + NewPN->addIncoming(ConstantBool::get(CondIsTrue), *PI); + } else { + NewPN->addIncoming(BI->getCondition(), *PI); + } + + BI->setCondition(NewPN); + // This will thread the branch. + return SimplifyCFG(BB) | true; + } } - // Otherwise, if there are multiple predecessors, insert a PHI that - // merges in the constant and simplify the block result. - if (BlockIsSimpleEnoughToThreadThrough(BB)) { - PHINode *NewPN = new PHINode(Type::BoolTy, - BI->getCondition()->getName()+".pr", - BB->begin()); - for (PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) - if ((PBI = dyn_cast((*PI)->getTerminator())) && - PBI != BI && PBI->isConditional() && - PBI->getCondition() == BI->getCondition() && - PBI->getSuccessor(0) != PBI->getSuccessor(1)) { - bool CondIsTrue = PBI->getSuccessor(0) == BB; - NewPN->addIncoming(ConstantBool::get(CondIsTrue), *PI); - } else { - NewPN->addIncoming(BI->getCondition(), *PI); - } + // If this is a conditional branch in an empty block, and if any + // predecessors is a conditional branch to one of our destinations, + // fold the conditions into logical ops and one cond br. + if (&BB->front() == BI) { + int PBIOp, BIOp; + if (PBI->getSuccessor(0) == BI->getSuccessor(0)) { + PBIOp = BIOp = 0; + } else if (PBI->getSuccessor(0) == BI->getSuccessor(1)) { + PBIOp = 0; BIOp = 1; + } else if (PBI->getSuccessor(1) == BI->getSuccessor(0)) { + PBIOp = 1; BIOp = 0; + } else if (PBI->getSuccessor(1) == BI->getSuccessor(1)) { + PBIOp = BIOp = 1; + } else { + PBIOp = BIOp = -1; + } - BI->setCondition(NewPN); - // This will thread the branch. - return SimplifyCFG(BB) | true; + // Finally, if everything is ok, fold the branches to logical ops. + if (PBIOp != -1) { + BasicBlock *CommonDest = PBI->getSuccessor(PBIOp); + BasicBlock *OtherDest = BI->getSuccessor(BIOp ^ 1); + + DEBUG(std::cerr << "FOLDING BRs:" << *PBI->getParent() + << "AND: " << *BI->getParent()); + + // BI may have other predecessors. Because of this, we leave + // it alone, but modify PBI. + + // Make sure we get to CommonDest on True&True directions. + Value *PBICond = PBI->getCondition(); + if (PBIOp) + PBICond = BinaryOperator::createNot(PBICond, + PBICond->getName()+".not", + PBI); + Value *BICond = BI->getCondition(); + if (BIOp) + BICond = BinaryOperator::createNot(BICond, + BICond->getName()+".not", + PBI); + // Merge the conditions. + Value *Cond = + BinaryOperator::createOr(PBICond, BICond, "brmerge", PBI); + + // Modify PBI to branch on the new condition to the new dests. + PBI->setCondition(Cond); + PBI->setSuccessor(0, CommonDest); + PBI->setSuccessor(1, OtherDest); + + // OtherDest may have phi nodes. If so, add an entry from PBI's + // block that are identical to the entries for BI's block. + PHINode *PN; + for (BasicBlock::iterator II = OtherDest->begin(); + (PN = dyn_cast(II)); ++II) { + Value *V = PN->getIncomingValueForBlock(BB); + PN->addIncoming(V, PBI->getParent()); + } + + // We know that the CommonDest already had an edge from PBI to + // it. If it has PHIs though, the PHIs may have different + // entries for BB and PBI's BB. If so, insert a select to make + // them agree. + for (BasicBlock::iterator II = CommonDest->begin(); + (PN = dyn_cast(II)); ++II) { + Value * BIV = PN->getIncomingValueForBlock(BB); + unsigned PBBIdx = PN->getBasicBlockIndex(PBI->getParent()); + Value *PBIV = PN->getIncomingValue(PBBIdx); + if (BIV != PBIV) { + // Insert a select in PBI to pick the right value. + Value *NV = new SelectInst(PBICond, PBIV, BIV, + PBIV->getName()+".mux", PBI); + PN->setIncomingValue(PBBIdx, NV); + } + } + + DEBUG(std::cerr << "INTO: " << *PBI->getParent()); + + // This basic block is probably dead. We know it has at least + // one fewer predecessor. + return SimplifyCFG(BB) | true; + } } } } From lattner at cs.uiuc.edu Fri Sep 23 13:49:20 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 13:49:20 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp Message-ID: <200509231849.NAA11942@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: SimplifyCFG.cpp updated: 1.90 -> 1.91 --- Log message: remove some debugging code --- Diffs of the changes: (+0 -1) SimplifyCFG.cpp | 1 - 1 files changed, 1 deletion(-) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.90 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.91 --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.90 Fri Sep 23 13:47:20 2005 +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Fri Sep 23 13:49:09 2005 @@ -990,7 +990,6 @@ // Check for trivial simplification. if (Constant *C = ConstantFoldInstruction(N)) { - std::cerr << "FOLDED: " << *N; TranslateMap[BBI] = C; delete N; // Constant folded away, don't need actual inst } else { From lattner at cs.uiuc.edu Fri Sep 23 14:36:27 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 14:36:27 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/DAGISelEmitter.cpp DAGISelEmitter.h Message-ID: <200509231936.OAA12302@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: DAGISelEmitter.cpp updated: 1.33 -> 1.34 DAGISelEmitter.h updated: 1.20 -> 1.21 --- Log message: start filling in the switch stmt --- Diffs of the changes: (+19 -2) DAGISelEmitter.cpp | 18 +++++++++++++++++- DAGISelEmitter.h | 3 ++- 2 files changed, 19 insertions(+), 2 deletions(-) Index: llvm/utils/TableGen/DAGISelEmitter.cpp diff -u llvm/utils/TableGen/DAGISelEmitter.cpp:1.33 llvm/utils/TableGen/DAGISelEmitter.cpp:1.34 --- llvm/utils/TableGen/DAGISelEmitter.cpp:1.33 Thu Sep 15 19:29:46 2005 +++ llvm/utils/TableGen/DAGISelEmitter.cpp Fri Sep 23 14:36:15 2005 @@ -1001,8 +1001,24 @@ << " case ISD::AssertZext:\n" << " return Select(N->getOperand(0));\n"; - + // Group the patterns by their top-level opcodes. + std::map > PatternsByOpcode; + for (unsigned i = 0, e = PatternsToMatch.size(); i != e; ++i) + PatternsByOpcode[PatternsToMatch[i].first->getOperator()] + .push_back(&PatternsToMatch[i]); + + for (std::map >::iterator + PBOI = PatternsByOpcode.begin(), E = PatternsByOpcode.end(); PBOI != E; + ++PBOI) { + const SDNodeInfo &OpcodeInfo = getSDNodeInfo(PBOI->first); + std::vector &Patterns = PBOI->second; + + OS << " case " << OpcodeInfo.getEnumName() << ":\n"; + + OS << " break;\n"; + } + OS << " } // end of big switch.\n\n" << " std::cerr << \"Cannot yet select: \";\n" << " N->dump();\n" Index: llvm/utils/TableGen/DAGISelEmitter.h diff -u llvm/utils/TableGen/DAGISelEmitter.h:1.20 llvm/utils/TableGen/DAGISelEmitter.h:1.21 --- llvm/utils/TableGen/DAGISelEmitter.h:1.20 Thu Sep 15 17:23:50 2005 +++ llvm/utils/TableGen/DAGISelEmitter.h Fri Sep 23 14:36:15 2005 @@ -325,7 +325,8 @@ /// PatternsToMatch - All of the things we are matching on the DAG. The first /// value is the pattern to match, the second pattern is the result to /// emit. - std::vector > PatternsToMatch; + typedef std::pair PatternToMatch; + std::vector PatternsToMatch; public: DAGISelEmitter(RecordKeeper &R) : Records(R) {} From lattner at cs.uiuc.edu Fri Sep 23 15:53:00 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 15:53:00 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/DAGISelEmitter.cpp DAGISelEmitter.h Message-ID: <200509232053.PAA15069@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: DAGISelEmitter.cpp updated: 1.34 -> 1.35 DAGISelEmitter.h updated: 1.21 -> 1.22 --- Log message: emit information about the order patterns are to be matched. --- Diffs of the changes: (+60 -1) DAGISelEmitter.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ DAGISelEmitter.h | 5 +++- 2 files changed, 60 insertions(+), 1 deletion(-) Index: llvm/utils/TableGen/DAGISelEmitter.cpp diff -u llvm/utils/TableGen/DAGISelEmitter.cpp:1.34 llvm/utils/TableGen/DAGISelEmitter.cpp:1.35 --- llvm/utils/TableGen/DAGISelEmitter.cpp:1.34 Fri Sep 23 14:36:15 2005 +++ llvm/utils/TableGen/DAGISelEmitter.cpp Fri Sep 23 15:52:47 2005 @@ -985,6 +985,51 @@ }); } +void DAGISelEmitter::EmitCodeForPattern(PatternToMatch &Pattern, + std::ostream &OS) { + OS << " // "; + Pattern.first->print(OS); + OS << "\n"; + + + +} + +/// getPatternSize - Return the 'size' of this pattern. We want to match large +/// patterns before small ones. This is used to determine the size of a +/// pattern. +static unsigned getPatternSize(TreePatternNode *P) { + assert(MVT::isInteger(P->getType()) || MVT::isFloatingPoint(P->getType()) && + "Not a valid pattern node to size!"); + unsigned Size = 1; // The node itself. + + // Count children in the count if they are also nodes. + for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) { + TreePatternNode *Child = P->getChild(i); + if (!Child->isLeaf() && Child->getType() != MVT::Other) + Size += getPatternSize(Child); + } + + return Size; +} + +// PatternSortingPredicate - return true if we prefer to match LHS before RHS. +// In particular, we want to match maximal patterns first and lowest cost within +// a particular complexity first. +struct PatternSortingPredicate { + bool operator()(DAGISelEmitter::PatternToMatch *LHS, + DAGISelEmitter::PatternToMatch *RHS) { + unsigned LHSSize = getPatternSize(LHS->first); + unsigned RHSSize = getPatternSize(RHS->first); + if (LHSSize > RHSSize) return true; // LHS -> bigger -> less cost + if (LHSSize < RHSSize) return false; + + // If they are equal, compare cost. + // FIXME: Compute cost! + return false; + } +}; + void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) { // Emit boilerplate. OS << "// The main instruction selector code.\n" @@ -1007,6 +1052,7 @@ PatternsByOpcode[PatternsToMatch[i].first->getOperator()] .push_back(&PatternsToMatch[i]); + // Loop over all of the case statements. for (std::map >::iterator PBOI = PatternsByOpcode.begin(), E = PatternsByOpcode.end(); PBOI != E; ++PBOI) { @@ -1014,7 +1060,14 @@ std::vector &Patterns = PBOI->second; OS << " case " << OpcodeInfo.getEnumName() << ":\n"; + + // We want to emit all of the matching code now. However, we want to emit + // the matches in order of minimal cost. Sort the patterns so the least + // cost one is at the start. + std::sort(Patterns.begin(), Patterns.end(), PatternSortingPredicate()); + for (unsigned i = 0, e = Patterns.size(); i != e; ++i) + EmitCodeForPattern(*Patterns[i], OS); OS << " break;\n"; } @@ -1040,6 +1093,9 @@ ParsePatternFragments(OS); ParseInstructions(); ParsePatterns(); + + // FIXME: Generate variants. For example, commutative patterns can match + // multiple ways. Add them to PatternsToMatch as well. // At this point, we have full information about the 'Patterns' we need to // parse, both implicitly from instructions as well as from explicit pattern Index: llvm/utils/TableGen/DAGISelEmitter.h diff -u llvm/utils/TableGen/DAGISelEmitter.h:1.21 llvm/utils/TableGen/DAGISelEmitter.h:1.22 --- llvm/utils/TableGen/DAGISelEmitter.h:1.21 Fri Sep 23 14:36:15 2005 +++ llvm/utils/TableGen/DAGISelEmitter.h Fri Sep 23 15:52:47 2005 @@ -314,6 +314,9 @@ /// and emission of the instruction selector. /// class DAGISelEmitter : public TableGenBackend { +public: + typedef std::pair PatternToMatch; +private: RecordKeeper &Records; CodeGenTarget Target; @@ -325,7 +328,6 @@ /// PatternsToMatch - All of the things we are matching on the DAG. The first /// value is the pattern to match, the second pattern is the result to /// emit. - typedef std::pair PatternToMatch; std::vector PatternsToMatch; public: DAGISelEmitter(RecordKeeper &R) : Records(R) {} @@ -363,6 +365,7 @@ std::map &InstInputs, std::map &InstResults); + void EmitCodeForPattern(PatternToMatch &Pattern, std::ostream &OS); void EmitInstructionSelector(std::ostream &OS); }; From lattner at cs.uiuc.edu Fri Sep 23 16:33:34 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 16:33:34 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/DAGISelEmitter.cpp DAGISelEmitter.h Message-ID: <200509232133.QAA15269@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: DAGISelEmitter.cpp updated: 1.35 -> 1.36 DAGISelEmitter.h updated: 1.22 -> 1.23 --- Log message: Emit code that matches the incoming DAG pattern and checks predicates. This does not check that types match yet, but PPC only has one integer type ;-). This also doesn't have the code to build the resultant dag. --- Diffs of the changes: (+64 -4) DAGISelEmitter.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++++++---- DAGISelEmitter.h | 2 + 2 files changed, 64 insertions(+), 4 deletions(-) Index: llvm/utils/TableGen/DAGISelEmitter.cpp diff -u llvm/utils/TableGen/DAGISelEmitter.cpp:1.35 llvm/utils/TableGen/DAGISelEmitter.cpp:1.36 --- llvm/utils/TableGen/DAGISelEmitter.cpp:1.35 Fri Sep 23 15:52:47 2005 +++ llvm/utils/TableGen/DAGISelEmitter.cpp Fri Sep 23 16:33:23 2005 @@ -985,14 +985,71 @@ }); } +/// EmitMatchForPattern - Emit a matcher for N, going to the label for PatternNo +/// if the match fails. At this point, we already know that the opcode for N +/// matches, and the SDNode for the result has the RootName specified name. +void DAGISelEmitter::EmitMatchForPattern(TreePatternNode *N, + const std::string &RootName, + unsigned PatternNo, std::ostream &OS) { + assert(!N->isLeaf() && "Cannot match against a leaf!"); + // Emit code to load the child nodes and match their contents recursively. + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { + OS << " SDNode *" << RootName << i <<" = " << RootName + << "->getOperand(" << i << ").Val;\n"; + TreePatternNode *Child = N->getChild(i); + if (!Child->isLeaf()) { + // If it's not a leaf, recursively match. + const SDNodeInfo &CInfo = getSDNodeInfo(Child->getOperator()); + OS << " if (" << RootName << i << "->getOpcode() != " + << CInfo.getEnumName() << ") goto P" << PatternNo << "Fail;\n"; + EmitMatchForPattern(Child, RootName + utostr(i), PatternNo, OS); + } else { + // Handle leaves of various types. + Init *LeafVal = Child->getLeafValue(); + Record *LeafRec = dynamic_cast(LeafVal)->getDef(); + if (LeafRec->isSubClassOf("RegisterClass")) { + // Handle register references. Nothing to do here. + } else if (LeafRec->isSubClassOf("ValueType")) { + // Make sure this is the specified value type. + OS << " if (cast(" << RootName << i << ")->getVT() != " + << "MVT::" << LeafRec->getName() << ") goto P" << PatternNo + << "Fail;\n"; + } else { + Child->dump(); + assert(0 && "Unknown leaf type!"); + } + } + + // If this child has a name associated with it, capture it as a variable. + if (!Child->getName().empty()) + OS << " SDOperand op" << Child->getName() << "(" << RootName + << i << ", 0 /*FIXME*/);\n"; + } + + // If there is a node predicate for this, emit the call. + if (!N->getPredicateFn().empty()) + OS << " if (!" << N->getPredicateFn() << "(" << RootName + << ")) goto P" << PatternNo << "Fail;\n"; +} + +/// EmitCodeForPattern - Given a pattern to match, emit code to the specified +/// stream to match the pattern, and generate the code for the match if it +/// succeeds. void DAGISelEmitter::EmitCodeForPattern(PatternToMatch &Pattern, std::ostream &OS) { - OS << " // "; + static unsigned PatternCount = 0; + unsigned PatternNo = PatternCount++; + OS << " { // Pattern #" << PatternNo << ": "; Pattern.first->print(OS); OS << "\n"; + + EmitMatchForPattern(Pattern.first, "N", PatternNo, OS); + OS << " // Emit: "; + Pattern.second->print(OS); + OS << "\n"; - + OS << " }\n P" << PatternNo << "Fail:\n"; } /// getPatternSize - Return the 'size' of this pattern. We want to match large @@ -1064,11 +1121,12 @@ // We want to emit all of the matching code now. However, we want to emit // the matches in order of minimal cost. Sort the patterns so the least // cost one is at the start. - std::sort(Patterns.begin(), Patterns.end(), PatternSortingPredicate()); + std::stable_sort(Patterns.begin(), Patterns.end(), + PatternSortingPredicate()); for (unsigned i = 0, e = Patterns.size(); i != e; ++i) EmitCodeForPattern(*Patterns[i], OS); - OS << " break;\n"; + OS << " break;\n\n"; } Index: llvm/utils/TableGen/DAGISelEmitter.h diff -u llvm/utils/TableGen/DAGISelEmitter.h:1.22 llvm/utils/TableGen/DAGISelEmitter.h:1.23 --- llvm/utils/TableGen/DAGISelEmitter.h:1.22 Fri Sep 23 15:52:47 2005 +++ llvm/utils/TableGen/DAGISelEmitter.h Fri Sep 23 16:33:23 2005 @@ -365,6 +365,8 @@ std::map &InstInputs, std::map &InstResults); + void EmitMatchForPattern(TreePatternNode *N, const std::string &RootName, + unsigned PatternNo, std::ostream &OS); void EmitCodeForPattern(PatternToMatch &Pattern, std::ostream &OS); void EmitInstructionSelector(std::ostream &OS); }; From lattner at cs.uiuc.edu Fri Sep 23 16:53:56 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 16:53:56 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/DAGISelEmitter.cpp Message-ID: <200509232153.QAA15468@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: DAGISelEmitter.cpp updated: 1.36 -> 1.37 --- Log message: Fix a fixme by passing around SDOperand's instead of SDNode*'s --- Diffs of the changes: (+14 -15) DAGISelEmitter.cpp | 29 ++++++++++++++--------------- 1 files changed, 14 insertions(+), 15 deletions(-) Index: llvm/utils/TableGen/DAGISelEmitter.cpp diff -u llvm/utils/TableGen/DAGISelEmitter.cpp:1.36 llvm/utils/TableGen/DAGISelEmitter.cpp:1.37 --- llvm/utils/TableGen/DAGISelEmitter.cpp:1.36 Fri Sep 23 16:33:23 2005 +++ llvm/utils/TableGen/DAGISelEmitter.cpp Fri Sep 23 16:53:45 2005 @@ -994,13 +994,13 @@ assert(!N->isLeaf() && "Cannot match against a leaf!"); // Emit code to load the child nodes and match their contents recursively. for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { - OS << " SDNode *" << RootName << i <<" = " << RootName - << "->getOperand(" << i << ").Val;\n"; + OS << " SDOperand " << RootName << i <<" = " << RootName + << ".getOperand(" << i << ");\n"; TreePatternNode *Child = N->getChild(i); if (!Child->isLeaf()) { // If it's not a leaf, recursively match. const SDNodeInfo &CInfo = getSDNodeInfo(Child->getOperator()); - OS << " if (" << RootName << i << "->getOpcode() != " + OS << " if (" << RootName << i << ".getOpcode() != " << CInfo.getEnumName() << ") goto P" << PatternNo << "Fail;\n"; EmitMatchForPattern(Child, RootName + utostr(i), PatternNo, OS); } else { @@ -1022,14 +1022,14 @@ // If this child has a name associated with it, capture it as a variable. if (!Child->getName().empty()) - OS << " SDOperand op" << Child->getName() << "(" << RootName - << i << ", 0 /*FIXME*/);\n"; + OS << " SDOperand op" << Child->getName() << " = " << RootName + << i << ";\n"; } // If there is a node predicate for this, emit the call. if (!N->getPredicateFn().empty()) OS << " if (!" << N->getPredicateFn() << "(" << RootName - << ")) goto P" << PatternNo << "Fail;\n"; + << ".Val)) goto P" << PatternNo << "Fail;\n"; } /// EmitCodeForPattern - Given a pattern to match, emit code to the specified @@ -1090,18 +1090,17 @@ void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) { // Emit boilerplate. OS << "// The main instruction selector code.\n" - << "SDOperand SelectCode(SDOperand Op) {\n" - << " SDNode *N = Op.Val;\n" - << " if (N->getOpcode() >= ISD::BUILTIN_OP_END &&\n" - << " N->getOpcode() < PPCISD::FIRST_NUMBER)\n" - << " return Op; // Already selected.\n\n" - << " switch (N->getOpcode()) {\n" + << "SDOperand SelectCode(SDOperand N) {\n" + << " if (N.getOpcode() >= ISD::BUILTIN_OP_END &&\n" + << " N.getOpcode() < PPCISD::FIRST_NUMBER)\n" + << " return N; // Already selected.\n\n" + << " switch (N.getOpcode()) {\n" << " default: break;\n" << " case ISD::EntryToken: // These leaves remain the same.\n" - << " return Op;\n" + << " return N;\n" << " case ISD::AssertSext:\n" << " case ISD::AssertZext:\n" - << " return Select(N->getOperand(0));\n"; + << " return Select(N.getOperand(0));\n"; // Group the patterns by their top-level opcodes. std::map > PatternsByOpcode; @@ -1132,7 +1131,7 @@ OS << " } // end of big switch.\n\n" << " std::cerr << \"Cannot yet select: \";\n" - << " N->dump();\n" + << " N.Val->dump();\n" << " std::cerr << '\\n';\n" << " abort();\n" << "}\n"; From lattner at cs.uiuc.edu Fri Sep 23 18:17:03 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 18:17:03 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/DAGISelEmitter.cpp DAGISelEmitter.h Message-ID: <200509232317.SAA15912@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: DAGISelEmitter.cpp updated: 1.37 -> 1.38 DAGISelEmitter.h updated: 1.23 -> 1.24 --- Log message: Emit better code (no more copies for var references), and support DAG patterns (e.g. things like rotates). --- Diffs of the changes: (+25 -8) DAGISelEmitter.cpp | 32 ++++++++++++++++++++++++-------- DAGISelEmitter.h | 1 + 2 files changed, 25 insertions(+), 8 deletions(-) Index: llvm/utils/TableGen/DAGISelEmitter.cpp diff -u llvm/utils/TableGen/DAGISelEmitter.cpp:1.37 llvm/utils/TableGen/DAGISelEmitter.cpp:1.38 --- llvm/utils/TableGen/DAGISelEmitter.cpp:1.37 Fri Sep 23 16:53:45 2005 +++ llvm/utils/TableGen/DAGISelEmitter.cpp Fri Sep 23 18:16:51 2005 @@ -989,7 +989,8 @@ /// if the match fails. At this point, we already know that the opcode for N /// matches, and the SDNode for the result has the RootName specified name. void DAGISelEmitter::EmitMatchForPattern(TreePatternNode *N, - const std::string &RootName, + const std::string &RootName, + std::map &VarMap, unsigned PatternNo, std::ostream &OS) { assert(!N->isLeaf() && "Cannot match against a leaf!"); // Emit code to load the child nodes and match their contents recursively. @@ -997,12 +998,30 @@ OS << " SDOperand " << RootName << i <<" = " << RootName << ".getOperand(" << i << ");\n"; TreePatternNode *Child = N->getChild(i); + + // If this child has a name associated with it, capture it in VarMap. If + // we already saw this in the pattern, emit code to verify dagness. + if (!Child->getName().empty()) { + std::string &VarMapEntry = VarMap[Child->getName()]; + if (VarMapEntry.empty()) { + VarMapEntry = RootName + utostr(i); + } else { + // If we get here, this is a second reference to a specific name. Since + // we already have checked that the first reference is valid, we don't + // have to recursively match it, just check that it's the same as the + // previously named thing. + OS << " if (" << VarMapEntry << " != " << RootName << i + << ") goto P" << PatternNo << "Fail;\n"; + continue; + } + } + if (!Child->isLeaf()) { // If it's not a leaf, recursively match. const SDNodeInfo &CInfo = getSDNodeInfo(Child->getOperator()); OS << " if (" << RootName << i << ".getOpcode() != " << CInfo.getEnumName() << ") goto P" << PatternNo << "Fail;\n"; - EmitMatchForPattern(Child, RootName + utostr(i), PatternNo, OS); + EmitMatchForPattern(Child, RootName + utostr(i), VarMap, PatternNo, OS); } else { // Handle leaves of various types. Init *LeafVal = Child->getLeafValue(); @@ -1019,11 +1038,6 @@ assert(0 && "Unknown leaf type!"); } } - - // If this child has a name associated with it, capture it as a variable. - if (!Child->getName().empty()) - OS << " SDOperand op" << Child->getName() << " = " << RootName - << i << ";\n"; } // If there is a node predicate for this, emit the call. @@ -1043,7 +1057,9 @@ Pattern.first->print(OS); OS << "\n"; - EmitMatchForPattern(Pattern.first, "N", PatternNo, OS); + // Emit the matcher, capturing named arguments in VariableMap. + std::map VariableMap; + EmitMatchForPattern(Pattern.first, "N", VariableMap, PatternNo, OS); OS << " // Emit: "; Pattern.second->print(OS); Index: llvm/utils/TableGen/DAGISelEmitter.h diff -u llvm/utils/TableGen/DAGISelEmitter.h:1.23 llvm/utils/TableGen/DAGISelEmitter.h:1.24 --- llvm/utils/TableGen/DAGISelEmitter.h:1.23 Fri Sep 23 16:33:23 2005 +++ llvm/utils/TableGen/DAGISelEmitter.h Fri Sep 23 18:16:51 2005 @@ -366,6 +366,7 @@ TreePatternNode*> &InstInputs, std::map &InstResults); void EmitMatchForPattern(TreePatternNode *N, const std::string &RootName, + std::map &VarMap, unsigned PatternNo, std::ostream &OS); void EmitCodeForPattern(PatternToMatch &Pattern, std::ostream &OS); void EmitInstructionSelector(std::ostream &OS); From lattner at cs.uiuc.edu Fri Sep 23 19:40:35 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 19:40:35 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/DAGISelEmitter.cpp DAGISelEmitter.h Message-ID: <200509240040.TAA16254@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: DAGISelEmitter.cpp updated: 1.38 -> 1.39 DAGISelEmitter.h updated: 1.24 -> 1.25 --- Log message: Teach the DAG isel generator to emit code that creates nodes. Fix a few corner cases parsing things like (i32 imm:$foo) --- Diffs of the changes: (+110 -18) DAGISelEmitter.cpp | 125 +++++++++++++++++++++++++++++++++++++++++++++-------- DAGISelEmitter.h | 3 + 2 files changed, 110 insertions(+), 18 deletions(-) Index: llvm/utils/TableGen/DAGISelEmitter.cpp diff -u llvm/utils/TableGen/DAGISelEmitter.cpp:1.38 llvm/utils/TableGen/DAGISelEmitter.cpp:1.39 --- llvm/utils/TableGen/DAGISelEmitter.cpp:1.38 Fri Sep 23 18:16:51 2005 +++ llvm/utils/TableGen/DAGISelEmitter.cpp Fri Sep 23 19:40:24 2005 @@ -405,7 +405,7 @@ return MVT::LAST_VALUETYPE; } - error("Unknown value used: " + R->getName()); + error("Unknown node flavor used in pattern: " + R->getName()); return MVT::Other; } @@ -421,6 +421,15 @@ Init *Arg = Dag->getArg(0); TreePatternNode *New; if (DefInit *DI = dynamic_cast(Arg)) { + Record *R = DI->getDef(); + if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag")) { + Dag->setArg(0, new DagInit(R, + std::vector >())); + TreePatternNode *TPN = ParseTreePattern(Dag); + TPN->setName(Dag->getArgName(0)); + return TPN; + } + New = new TreePatternNode(DI); // If it's a regclass or something else known, set the type. New->setType(getIntrinsicType(DI->getDef())); @@ -993,29 +1002,30 @@ std::map &VarMap, unsigned PatternNo, std::ostream &OS) { assert(!N->isLeaf() && "Cannot match against a leaf!"); + + // If this node has a name associated with it, capture it in VarMap. If + // we already saw this in the pattern, emit code to verify dagness. + if (!N->getName().empty()) { + std::string &VarMapEntry = VarMap[N->getName()]; + if (VarMapEntry.empty()) { + VarMapEntry = RootName; + } else { + // If we get here, this is a second reference to a specific name. Since + // we already have checked that the first reference is valid, we don't + // have to recursively match it, just check that it's the same as the + // previously named thing. + OS << " if (" << VarMapEntry << " != " << RootName + << ") goto P" << PatternNo << "Fail;\n"; + return; + } + } + // Emit code to load the child nodes and match their contents recursively. for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) { OS << " SDOperand " << RootName << i <<" = " << RootName << ".getOperand(" << i << ");\n"; TreePatternNode *Child = N->getChild(i); - // If this child has a name associated with it, capture it in VarMap. If - // we already saw this in the pattern, emit code to verify dagness. - if (!Child->getName().empty()) { - std::string &VarMapEntry = VarMap[Child->getName()]; - if (VarMapEntry.empty()) { - VarMapEntry = RootName + utostr(i); - } else { - // If we get here, this is a second reference to a specific name. Since - // we already have checked that the first reference is valid, we don't - // have to recursively match it, just check that it's the same as the - // previously named thing. - OS << " if (" << VarMapEntry << " != " << RootName << i - << ") goto P" << PatternNo << "Fail;\n"; - continue; - } - } - if (!Child->isLeaf()) { // If it's not a leaf, recursively match. const SDNodeInfo &CInfo = getSDNodeInfo(Child->getOperator()); @@ -1023,6 +1033,23 @@ << CInfo.getEnumName() << ") goto P" << PatternNo << "Fail;\n"; EmitMatchForPattern(Child, RootName + utostr(i), VarMap, PatternNo, OS); } else { + // If this child has a name associated with it, capture it in VarMap. If + // we already saw this in the pattern, emit code to verify dagness. + if (!Child->getName().empty()) { + std::string &VarMapEntry = VarMap[Child->getName()]; + if (VarMapEntry.empty()) { + VarMapEntry = RootName + utostr(i); + } else { + // If we get here, this is a second reference to a specific name. Since + // we already have checked that the first reference is valid, we don't + // have to recursively match it, just check that it's the same as the + // previously named thing. + OS << " if (" << VarMapEntry << " != " << RootName << i + << ") goto P" << PatternNo << "Fail;\n"; + continue; + } + } + // Handle leaves of various types. Init *LeafVal = Child->getLeafValue(); Record *LeafRec = dynamic_cast(LeafVal)->getDef(); @@ -1046,6 +1073,65 @@ << ".Val)) goto P" << PatternNo << "Fail;\n"; } + +unsigned DAGISelEmitter:: +CodeGenPatternResult(TreePatternNode *N, unsigned &Ctr, + std::map &VariableMap, + std::ostream &OS){ + // This is something selected from the pattern we matched. + if (!N->getName().empty()) { + const std::string &Val = VariableMap[N->getName()]; + assert(!Val.empty() && + "Variable referenced but not defined and not caught earlier!"); + if (Val[0] == 'T' && Val[1] == 'm' && Val[2] == 'p') { + // Already selected this operand, just return the tmpval. + // FIXME: DO THIS. + } else { + unsigned ResNo = Ctr++; + OS << " SDOperand Tmp" << ResNo << " = Select(" << Val << ");\n"; + // FIXME: Add Tmp to VariableMap. + return ResNo; + } + } + + if (N->isLeaf()) { + N->dump(); + assert(0 && "Unknown leaf type!"); + return ~0U; + } + + Record *Op = N->getOperator(); + if (Op->isSubClassOf("Instruction")) { + // Emit all of the operands. + std::vector Ops; + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) + Ops.push_back(CodeGenPatternResult(N->getChild(i), Ctr, VariableMap, OS)); + + CodeGenInstruction &II = Target.getInstruction(Op->getName()); + unsigned ResNo = Ctr++; + + OS << " SDOperand Tmp" << ResNo << " = CurDAG->getTargetNode(" + << II.Namespace << "::" << II.TheDef->getName() << ", MVT::" + << getEnumName(N->getType()); + for (unsigned i = 0, e = Ops.size(); i != e; ++i) + OS << ", Tmp" << Ops[i]; + OS << ");\n"; + return ResNo; + } else if (Op->isSubClassOf("SDNodeXForm")) { + assert(N->getNumChildren() == 1 && "node xform should have one child!"); + unsigned OpVal = CodeGenPatternResult(N->getChild(0), Ctr, VariableMap, OS); + + unsigned ResNo = Ctr++; + OS << " SDOperand Tmp" << ResNo << " = Transform_" << Op->getName() + << "(Tmp" << OpVal << ".Val);\n"; + return ResNo; + } else { + N->dump(); + assert(0 && "Unknown node in result pattern!"); + } +} + + /// EmitCodeForPattern - Given a pattern to match, emit code to the specified /// stream to match the pattern, and generate the code for the match if it /// succeeds. @@ -1065,6 +1151,9 @@ Pattern.second->print(OS); OS << "\n"; + unsigned TmpNo = 0; + unsigned Res = CodeGenPatternResult(Pattern.second, TmpNo, VariableMap, OS); + OS << " return Tmp" << Res << ";\n"; OS << " }\n P" << PatternNo << "Fail:\n"; } Index: llvm/utils/TableGen/DAGISelEmitter.h diff -u llvm/utils/TableGen/DAGISelEmitter.h:1.24 llvm/utils/TableGen/DAGISelEmitter.h:1.25 --- llvm/utils/TableGen/DAGISelEmitter.h:1.24 Fri Sep 23 18:16:51 2005 +++ llvm/utils/TableGen/DAGISelEmitter.h Fri Sep 23 19:40:24 2005 @@ -368,6 +368,9 @@ void EmitMatchForPattern(TreePatternNode *N, const std::string &RootName, std::map &VarMap, unsigned PatternNo, std::ostream &OS); + unsigned CodeGenPatternResult(TreePatternNode *N, unsigned &Ctr, + std::map &VariableMap, + std::ostream &OS); void EmitCodeForPattern(PatternToMatch &Pattern, std::ostream &OS); void EmitInstructionSelector(std::ostream &OS); }; From lattner at cs.uiuc.edu Fri Sep 23 19:42:09 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 19:42:09 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td Message-ID: <200509240042.TAA16314@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrInfo.td updated: 1.101 -> 1.102 --- Log message: Teach the dag isel generator how to construct arbitrary immediates. The generated isel now tries li then lis, then lis+ori. --- Diffs of the changes: (+6 -1) PowerPCInstrInfo.td | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletion(-) Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.101 llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.102 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.101 Thu Sep 15 16:44:00 2005 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.td Fri Sep 23 19:41:58 2005 @@ -774,7 +774,12 @@ def : Pat<(xor GPRC:$in, imm:$imm), (XORIS (XORI GPRC:$in, (LO16 imm:$imm)), (HI16 imm:$imm))>; -// Same as above, but using a temporary. +// Arbitrary immediate support. +def : Pat<(i32 imm:$imm), + (ORI (LIS (HI16 imm:$imm)), (LO16 imm:$imm))>; + + +// Same as above, but using a temporary. FIXME: implement temporaries :) /* def : Pattern<(xor GPRC:$in, imm:$imm), [(set GPRC:$tmp, (XORI GPRC:$in, (LO16 imm:$imm))), From lattner at cs.uiuc.edu Fri Sep 23 19:51:03 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 23 Sep 2005 19:51:03 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/DAGISelEmitter.cpp Message-ID: <200509240051.TAA16395@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: DAGISelEmitter.cpp updated: 1.39 -> 1.40 --- Log message: memoize translations --- Diffs of the changes: (+11 -0) DAGISelEmitter.cpp | 11 +++++++++++ 1 files changed, 11 insertions(+) Index: llvm/utils/TableGen/DAGISelEmitter.cpp diff -u llvm/utils/TableGen/DAGISelEmitter.cpp:1.39 llvm/utils/TableGen/DAGISelEmitter.cpp:1.40 --- llvm/utils/TableGen/DAGISelEmitter.cpp:1.39 Fri Sep 23 19:40:24 2005 +++ llvm/utils/TableGen/DAGISelEmitter.cpp Fri Sep 23 19:50:51 2005 @@ -1153,6 +1153,9 @@ unsigned TmpNo = 0; unsigned Res = CodeGenPatternResult(Pattern.second, TmpNo, VariableMap, OS); + + // Add the result to the map if it has multiple uses. + OS << " if (!N.Val->hasOneUse()) CodeGenMap[N] = Tmp" << Res << ";\n"; OS << " return Tmp" << Res << ";\n"; OS << " }\n P" << PatternNo << "Fail:\n"; } @@ -1199,6 +1202,10 @@ << " if (N.getOpcode() >= ISD::BUILTIN_OP_END &&\n" << " N.getOpcode() < PPCISD::FIRST_NUMBER)\n" << " return N; // Already selected.\n\n" + << " if (!N.Val->hasOneUse()) {\n" + << " std::map::iterator CGMI = CodeGenMap.find(N);\n" + << " if (CGMI != CodeGenMap.end()) return CGMI->second;\n" + << " }\n" << " switch (N.getOpcode()) {\n" << " default: break;\n" << " case ISD::EntryToken: // These leaves remain the same.\n" @@ -1250,6 +1257,10 @@ << "// *** instruction selector class. These functions are really " << "methods.\n\n"; + OS << "// Instance var to keep track of multiply used nodes that have \n" + << "// already been selected.\n" + << "std::map CodeGenMap;\n"; + ParseNodeInfo(); ParseNodeTransforms(OS); ParsePatternFragments(OS); From lattner at cs.uiuc.edu Sat Sep 24 03:24:06 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 03:24:06 -0500 Subject: [llvm-commits] CVS: llvm/include/llvm/Support/Mangler.h Message-ID: <200509240824.DAA31189@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Support: Mangler.h updated: 1.13 -> 1.14 --- Log message: change proto slightly --- Diffs of the changes: (+2 -1) Mangler.h | 3 ++- 1 files changed, 2 insertions(+), 1 deletion(-) Index: llvm/include/llvm/Support/Mangler.h diff -u llvm/include/llvm/Support/Mangler.h:1.13 llvm/include/llvm/Support/Mangler.h:1.14 --- llvm/include/llvm/Support/Mangler.h:1.13 Thu Apr 21 15:44:59 2005 +++ llvm/include/llvm/Support/Mangler.h Sat Sep 24 03:23:53 2005 @@ -64,7 +64,8 @@ /// does this for you, so there's no point calling it on the result /// from getValueName. /// - static std::string makeNameProper(const std::string &x); + static std::string makeNameProper(const std::string &x, + const char *Prefix = ""); }; } // End llvm namespace From lattner at cs.uiuc.edu Sat Sep 24 03:24:40 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 03:24:40 -0500 Subject: [llvm-commits] CVS: llvm/lib/VMCore/Mangler.cpp Message-ID: <200509240824.DAA31335@zion.cs.uiuc.edu> Changes in directory llvm/lib/VMCore: Mangler.cpp updated: 1.17 -> 1.18 --- Log message: Add support for a marker byte that indicates that we shouldn't add the user prefix to a symbol name --- Diffs of the changes: (+12 -7) Mangler.cpp | 19 ++++++++++++------- 1 files changed, 12 insertions(+), 7 deletions(-) Index: llvm/lib/VMCore/Mangler.cpp diff -u llvm/lib/VMCore/Mangler.cpp:1.17 llvm/lib/VMCore/Mangler.cpp:1.18 --- llvm/lib/VMCore/Mangler.cpp:1.17 Thu Apr 21 18:46:51 2005 +++ llvm/lib/VMCore/Mangler.cpp Sat Sep 24 03:24:28 2005 @@ -28,16 +28,21 @@ /// makeNameProper - We don't want identifier names non-C-identifier characters /// in them, so mangle them as appropriate. /// -std::string Mangler::makeNameProper(const std::string &X) { +std::string Mangler::makeNameProper(const std::string &X, const char *Prefix) { std::string Result; - // Mangle the first letter specially, don't allow numbers... - if ((X[0] < 'a' || X[0] > 'z') && (X[0] < 'A' || X[0] > 'Z') && X[0] != '_') - Result += MangleLetter(X[0]); + // If X does not start with (char)1, add the prefix. + std::string::const_iterator I = X.begin(); + if (*I != 1) + Result = Prefix; else - Result += X[0]; + ++I; // Skip over the marker. + + // Mangle the first letter specially, don't allow numbers... + if (*I >= '0' && *I <= '9') + Result += MangleLetter(*I++); - for (std::string::const_iterator I = X.begin()+1, E = X.end(); I != E; ++I) + for (std::string::const_iterator E = X.end(); I != E; ++I) if ((*I < 'a' || *I > 'z') && (*I < 'A' || *I > 'Z') && (*I < '0' || *I > '9') && *I != '_') Result += MangleLetter(*I); @@ -75,7 +80,7 @@ if (gv && isa(gv) && cast(gv)->getIntrinsicID()) { name = gv->getName(); // Is an intrinsic function } else if (gv && !gv->hasInternalLinkage() && !MangledGlobals.count(gv)) { - name = Prefix + makeNameProper(gv->getName()); + name = makeNameProper(gv->getName(), Prefix); } else { // Non-global, or global with internal linkage / colliding name // -> mangle. From lattner at cs.uiuc.edu Sat Sep 24 03:34:07 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 03:34:07 -0500 Subject: [llvm-commits] CVS: llvm-gcc/gcc/llvm-expand.c llvm-representation.c Message-ID: <200509240834.DAA00457@zion.cs.uiuc.edu> Changes in directory llvm-gcc/gcc: llvm-expand.c updated: 1.113 -> 1.114 llvm-representation.c updated: 1.19 -> 1.20 --- Log message: Patch to fix PR630: http://llvm.cs.uiuc.edu/PR630 . For asm labels, emit a prefix (char)1 byte to mark the asm label as not needing a user_label_prefix instead of a '*' like we used to. Change llvm-representation to not skip the '*' when emitting a label. Also teach it to correctly emit labels that have escape codes in it. Finally, for asm labels, if they start with the user_label_prefix, strip it off and make it a normal label. --- Diffs of the changes: (+39 -9) llvm-expand.c | 15 ++++++++++++--- llvm-representation.c | 33 +++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 9 deletions(-) Index: llvm-gcc/gcc/llvm-expand.c diff -u llvm-gcc/gcc/llvm-expand.c:1.113 llvm-gcc/gcc/llvm-expand.c:1.114 --- llvm-gcc/gcc/llvm-expand.c:1.113 Wed Sep 21 01:54:29 2005 +++ llvm-gcc/gcc/llvm-expand.c Sat Sep 24 03:33:56 2005 @@ -7556,10 +7556,19 @@ reg_number = decode_reg_name (asmspec); if (reg_number == -2) { /* ASMSPEC is given, and not the name of a register. Mark the - name with a star so assemble_name won't munge it. */ + name with a leading 1 so assemble_name won't munge it. */ char *starred = alloca (strlen (asmspec) + 2); - starred[0] = '*'; - strcpy (starred + 1, asmspec); + + /* If this thing just starts with user_label_prefix, there is no need for it + * to be an asm string. + */ + if (strncmp(user_label_prefix, asmspec, strlen(user_label_prefix)) == 0) { + strcpy(starred, asmspec+strlen(user_label_prefix)); + } else { + /* real asm label */ + starred[0] = 1; + strcpy (starred + 1, asmspec); + } SET_DECL_ASSEMBLER_NAME (decl, get_identifier (starred)); } Index: llvm-gcc/gcc/llvm-representation.c diff -u llvm-gcc/gcc/llvm-representation.c:1.19 llvm-gcc/gcc/llvm-representation.c:1.20 --- llvm-gcc/gcc/llvm-representation.c:1.19 Thu Jul 7 12:32:46 2005 +++ llvm-gcc/gcc/llvm-representation.c Sat Sep 24 03:33:56 2005 @@ -191,7 +191,6 @@ Val->VTy = VT; GlobalVal = llvm_value_is_global(Val) ? Val : 0; Val->Ty = (struct llvm_type*) Type; - if (Name[0] == '*') ++Name; Val->Name = Name[0] ? IdentifierTableGetName(Name, GlobalVal) : xstrdup(Name); } @@ -211,6 +210,23 @@ fprintf(stderr, "\n"); } +/* PrintIdentifier - Print the specified identifier to the specified file. If + * the identifier needs escaping, use "foo" style, otherwise use %foo style. + */ +static void PrintIdentifier(const char *ID, FILE *F) { + int isSafe = !isdigit(ID[0]), i; + for (i = 0; ID[i]; ++i) + if (!isalnum(ID[i]) && + ID[i] != '$' && ID[i] != '.' && ID[i] != '_' && ID[i] != '-') { + isSafe = 0; + break; + } + if (isSafe) + fprintf(F, "%%%s", ID); + else + fprintf(F, "\"%s\"", ID); +} + /* llvm_value_print_operand - Print the specified value formatted as an operand. If PrintType is true, the type is printed as a prefix. */ @@ -250,7 +266,7 @@ llvm_type_print(G2V(GV)->Ty, F); fprintf(F, ")"); } else if (V->Name[0]) { - fprintf(F, "%%%s", V->Name); + PrintIdentifier(V->Name, F); } else if (!PrintType) { fprintf(stderr, "ERROR, didn't print ANYTHING for operand!"); abort(); @@ -664,7 +680,8 @@ /* if it has a name... print it */ if (D2V(I)->Name && D2V(I)->Name[0]) { - fprintf(F, "%%%s = ", D2V(I)->Name); + PrintIdentifier(D2V(I)->Name, F); + fprintf(F, " = "); } if ((I->Opcode == O_Load || I->Opcode == O_Store) && @@ -880,7 +897,9 @@ } llvm_type_print(Ty->Elements[0], F); - fprintf(F, " %%%s(", G2V(Fn)->Name); + fprintf(F, " "); + PrintIdentifier(G2V(Fn)->Name, F); + fprintf(F, "("); /* Print out all of the arguments */ if (!isPrototype) { @@ -947,8 +966,10 @@ return; } - if (G2V(G)->Name) - fprintf(F, "%%%s = ", G2V(G)->Name); + if (G2V(G)->Name) { + PrintIdentifier(G2V(G)->Name, F); + fprintf(F, " = "); + } if (G->Init == 0) fprintf(F, "external "); From lattner at cs.uiuc.edu Sat Sep 24 03:38:39 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 03:38:39 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/CFrontend/2005-09-24-AsmUserPrefix.c Message-ID: <200509240838.DAA01023@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/CFrontend: 2005-09-24-AsmUserPrefix.c added (r1.1) --- Log message: new testcase for PR630: http://llvm.cs.uiuc.edu/PR630 --- Diffs of the changes: (+9 -0) 2005-09-24-AsmUserPrefix.c | 9 +++++++++ 1 files changed, 9 insertions(+) Index: llvm/test/Regression/CFrontend/2005-09-24-AsmUserPrefix.c diff -c /dev/null llvm/test/Regression/CFrontend/2005-09-24-AsmUserPrefix.c:1.1 *** /dev/null Sat Sep 24 03:38:38 2005 --- llvm/test/Regression/CFrontend/2005-09-24-AsmUserPrefix.c Sat Sep 24 03:38:28 2005 *************** *** 0 **** --- 1,9 ---- + // RUN: %llvmgcc %s -S -o - | gccas && + // RUN: %llvmgcc %s -S -o - | gccas | llc && + // RUN: %llvmgcc %s -S -o - | gccas | llc | not grep _foo2 + + void foo() __asm__("foo2"); + + void bar() { + foo(); + } From lattner at cs.uiuc.edu Sat Sep 24 15:54:45 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 15:54:45 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/CFrontend/2005-09-24-BitFieldCrash.c Message-ID: <200509242054.PAA12958@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/CFrontend: 2005-09-24-BitFieldCrash.c added (r1.1) --- Log message: new testcase that crashes the CFE --- Diffs of the changes: (+33 -0) 2005-09-24-BitFieldCrash.c | 33 +++++++++++++++++++++++++++++++++ 1 files changed, 33 insertions(+) Index: llvm/test/Regression/CFrontend/2005-09-24-BitFieldCrash.c diff -c /dev/null llvm/test/Regression/CFrontend/2005-09-24-BitFieldCrash.c:1.1 *** /dev/null Sat Sep 24 15:54:43 2005 --- llvm/test/Regression/CFrontend/2005-09-24-BitFieldCrash.c Sat Sep 24 15:54:33 2005 *************** *** 0 **** --- 1,33 ---- + // RUN: %llvmgcc %s -S -o - + + struct tree_common {}; + + struct tree_int_cst { + struct tree_common common; + struct tree_int_cst_lowhi { + unsigned long long low; + long long high; + } int_cst; + }; + + enum XXX { yyy }; + + struct tree_function_decl { + struct tree_common common; + long long locus, y; + __extension__ enum XXX built_in_class : 2; + + }; + + + union tree_node { + struct tree_int_cst int_cst; + struct tree_function_decl function_decl; + }; + + + void foo (union tree_node * decl) { + decl->function_decl.built_in_class != 0; + } + + From lattner at cs.uiuc.edu Sat Sep 24 15:55:42 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 15:55:42 -0500 Subject: [llvm-commits] CVS: llvm-gcc/gcc/llvm-types.c Message-ID: <200509242055.PAA13023@zion.cs.uiuc.edu> Changes in directory llvm-gcc/gcc: llvm-types.c updated: 1.29 -> 1.30 --- Log message: Fix CFrontend/2005-09-24-BitFieldCrash.c --- Diffs of the changes: (+1 -1) llvm-types.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-) Index: llvm-gcc/gcc/llvm-types.c diff -u llvm-gcc/gcc/llvm-types.c:1.29 llvm-gcc/gcc/llvm-types.c:1.30 --- llvm-gcc/gcc/llvm-types.c:1.29 Fri Jul 29 18:14:04 2005 +++ llvm-gcc/gcc/llvm-types.c Sat Sep 24 15:55:31 2005 @@ -1312,7 +1312,7 @@ * larger size. */ unsigned NumPad = llvm_type_get_size(Result) - MaxSize/8; - Result->x.Struct.MemberOffsets[1] = MaxSize; + Result->x.Struct.MemberOffsets[1] = MaxSize/8; Result->Elements[1] = llvm_type_get_array(UByteTy, NumPad); } From lattner at cs.uiuc.edu Sat Sep 24 16:01:56 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 16:01:56 -0500 Subject: [llvm-commits] CVS: llvm-gcc/gcc/llvm-expand.c Message-ID: <200509242101.QAA13131@zion.cs.uiuc.edu> Changes in directory llvm-gcc/gcc: llvm-expand.c updated: 1.114 -> 1.115 --- Log message: implement a missing case --- Diffs of the changes: (+5 -0) llvm-expand.c | 5 +++++ 1 files changed, 5 insertions(+) Index: llvm-gcc/gcc/llvm-expand.c diff -u llvm-gcc/gcc/llvm-expand.c:1.114 llvm-gcc/gcc/llvm-expand.c:1.115 --- llvm-gcc/gcc/llvm-expand.c:1.114 Sat Sep 24 03:33:56 2005 +++ llvm-gcc/gcc/llvm-expand.c Sat Sep 24 16:01:44 2005 @@ -5529,6 +5529,11 @@ Result = BB->BlockID; break; } + + case NOP_EXPR: + Result = llvm_expand_lvalue_expr(Fn, TREE_OPERAND(exp, 0), + BitStart, BitSize); + break; case PARM_DECL: if (!DECL_LLVM_SET_P (exp)) { From lattner at cs.uiuc.edu Sat Sep 24 16:42:04 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 16:42:04 -0500 Subject: [llvm-commits] CVS: llvm-gcc/gcc/llvm-expand.c Message-ID: <200509242142.QAA13284@zion.cs.uiuc.edu> Changes in directory llvm-gcc/gcc: llvm-expand.c updated: 1.115 -> 1.116 --- Log message: This optimization is bogus and broke in the presence of gotos --- Diffs of the changes: (+0 -11) llvm-expand.c | 11 ----------- 1 files changed, 11 deletions(-) Index: llvm-gcc/gcc/llvm-expand.c diff -u llvm-gcc/gcc/llvm-expand.c:1.115 llvm-gcc/gcc/llvm-expand.c:1.116 --- llvm-gcc/gcc/llvm-expand.c:1.115 Sat Sep 24 16:01:44 2005 +++ llvm-gcc/gcc/llvm-expand.c Sat Sep 24 16:41:53 2005 @@ -3400,17 +3400,6 @@ llvm_emit_label(Fn, DoneBlock); - /* If the conditional branch was folded into an unconditional branch (because - * the condition was known true or false) don't insert a PHI node, just use - * the known value instead. - */ - if (CondBr->NumOperands == 1) { - llvm_type *Ty = llvm_type_get_from_tree(TREE_TYPE(exp)); - llvm_value *Val = SecondOp; - if (CondBr->Operands[0] == D2V(FromBlock)) - Val = isAndExpr ? llvm_constant_bool_false : llvm_constant_bool_true; - return cast_if_type_not_equal(Fn, Val, Ty); - } /* Add a PHI node to merge together the two computed values */ PHI = llvm_instruction_new(BoolTy, "shortcirc_val", O_PHINode, 4); From lattner at cs.uiuc.edu Sat Sep 24 17:16:16 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 17:16:16 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/SimplifyLibCalls/SPrintF.ll Message-ID: <200509242216.RAA13909@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/SimplifyLibCalls: SPrintF.ll updated: 1.1 -> 1.2 --- Log message: Enhance this to check for a crash, add a case that crashes simplifylibcalls, and add a case that has uses. --- Diffs of the changes: (+6 -2) SPrintF.ll | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) Index: llvm/test/Regression/Transforms/SimplifyLibCalls/SPrintF.ll diff -u llvm/test/Regression/Transforms/SimplifyLibCalls/SPrintF.ll:1.1 llvm/test/Regression/Transforms/SimplifyLibCalls/SPrintF.ll:1.2 --- llvm/test/Regression/Transforms/SimplifyLibCalls/SPrintF.ll:1.1 Tue May 3 12:08:45 2005 +++ llvm/test/Regression/Transforms/SimplifyLibCalls/SPrintF.ll Sat Sep 24 17:16:04 2005 @@ -1,4 +1,5 @@ ; Test that the SPrintFOptimizer works correctly +; RUN: llvm-as < %s | opt -simplify-libcalls -disable-output && ; RUN: llvm-as < %s | opt -simplify-libcalls | llvm-dis | not grep 'call.*sprintf' declare int %sprintf(sbyte*,sbyte*,...) @@ -11,7 +12,7 @@ implementation ; Functions: -int %main () { +int %foo (sbyte* %p) { %target = alloca [1024 x sbyte] %target_p = getelementptr [1024 x sbyte]* %target, int 0, int 0 %hello_p = getelementptr [6 x sbyte]* %hello, int 0, int 0 @@ -24,9 +25,12 @@ %r2 = call int (sbyte*,sbyte*,...)* %sprintf(sbyte* %target_p, sbyte* %null_p) %r3 = call int (sbyte*,sbyte*,...)* %sprintf(sbyte* %target_p, sbyte* %nh_p) %r4 = call int (sbyte*,sbyte*,...)* %sprintf(sbyte* %target_p, sbyte* %fmt1_p, sbyte* %hello_p) + %r4.1 = call int (sbyte*,sbyte*,...)* %sprintf(sbyte* %target_p, sbyte* %fmt1_p, sbyte* %p) %r5 = call int (sbyte*,sbyte*,...)* %sprintf(sbyte* %target_p, sbyte* %fmt2_p, int 82) %r6 = add int %r1, %r2 %r7 = add int %r3, %r6 %r8 = add int %r5, %r7 - ret int %r8 + %r9 = add int %r8, %r4 + %r10 = add int %r9, %r4.1 + ret int %r10 } From lattner at cs.uiuc.edu Sat Sep 24 17:17:18 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 17:17:18 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp Message-ID: <200509242217.RAA13948@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: SimplifyLibCalls.cpp updated: 1.49 -> 1.50 --- Log message: Simplify this code a bit by relying on recursive simplification. Support sprintf("%s", P)'s that have uses. s/hasNUses(0)/use_empty()/ --- Diffs of the changes: (+43 -51) SimplifyLibCalls.cpp | 94 +++++++++++++++++++++++---------------------------- 1 files changed, 43 insertions(+), 51 deletions(-) Index: llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp diff -u llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.49 llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.50 --- llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.49 Wed Aug 24 12:22:17 2005 +++ llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp Sat Sep 24 17:17:06 2005 @@ -1282,7 +1282,7 @@ // If the result of the fprintf call is used, none of these optimizations // can be made. - if (!ci->hasNUses(0)) + if (!ci->use_empty()) return false; // All the optimizations depend on the length of the second argument and the @@ -1477,57 +1477,49 @@ // Get the second character and switch on its value ConstantInt* CI = dyn_cast(CA->getOperand(1)); - switch (CI->getRawValue()) - { - case 's': - { - uint64_t len = 0; - if (ci->hasNUses(0)) - { - // sprintf(dest,"%s",str) -> strcpy(dest,str) - Function* strcpy_func = SLC.get_strcpy(); - if (!strcpy_func) - return false; - std::vector args; - args.push_back(CastToCStr(ci->getOperand(1), *ci)); - args.push_back(CastToCStr(ci->getOperand(3), *ci)); - new CallInst(strcpy_func,args,"",ci); - } - else if (getConstantStringLength(ci->getOperand(3),len)) - { - // sprintf(dest,"%s",cstr) -> llvm.memcpy(dest,str,strlen(str),1) - len++; // get the null-terminator - Function* memcpy_func = SLC.get_memcpy(); - if (!memcpy_func) - return false; - std::vector args; - args.push_back(CastToCStr(ci->getOperand(1), *ci)); - args.push_back(CastToCStr(ci->getOperand(3), *ci)); - args.push_back(ConstantUInt::get(Type::UIntTy,len)); - args.push_back(ConstantUInt::get(Type::UIntTy,1)); - new CallInst(memcpy_func,args,"",ci); - ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,len)); - } - break; - } - case 'c': - { - // sprintf(dest,"%c",chr) -> store chr, dest - CastInst* cast = - new CastInst(ci->getOperand(3),Type::SByteTy,"char",ci); - new StoreInst(cast, ci->getOperand(1), ci); - GetElementPtrInst* gep = new GetElementPtrInst(ci->getOperand(1), - ConstantUInt::get(Type::UIntTy,1),ci->getOperand(1)->getName()+".end", - ci); - new StoreInst(ConstantInt::get(Type::SByteTy,0),gep,ci); - ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,1)); - break; - } - default: + switch (CI->getRawValue()) { + case 's': { + // sprintf(dest,"%s",str) -> llvm.memcpy(dest, str, strlen(str)+1, 1) + Function* strlen_func = SLC.get_strlen(); + Function* memcpy_func = SLC.get_memcpy(); + if (!strlen_func || !memcpy_func) return false; + + Value *Len = new CallInst(strlen_func, CastToCStr(ci->getOperand(3), *ci), + ci->getOperand(3)->getName()+".len", ci); + Value *Len1 = BinaryOperator::createAdd(Len, + ConstantInt::get(Len->getType(), 1), + Len->getName()+"1", ci); + if (Len1->getType() != Type::UIntTy) + Len1 = new CastInst(Len1, Type::UIntTy, Len1->getName(), ci); + std::vector args; + args.push_back(CastToCStr(ci->getOperand(1), *ci)); + args.push_back(CastToCStr(ci->getOperand(3), *ci)); + args.push_back(Len1); + args.push_back(ConstantUInt::get(Type::UIntTy,1)); + new CallInst(memcpy_func, args, "", ci); + + // The strlen result is the unincremented number of bytes in the string. + if (!ci->use_empty() && Len->getType() != ci->getType()) + Len = new CastInst(Len, ci->getType(), Len->getName(), ci); + ci->replaceAllUsesWith(Len); + ci->eraseFromParent(); + return true; } - ci->eraseFromParent(); - return true; + case 'c': { + // sprintf(dest,"%c",chr) -> store chr, dest + CastInst* cast = new CastInst(ci->getOperand(3),Type::SByteTy,"char",ci); + new StoreInst(cast, ci->getOperand(1), ci); + GetElementPtrInst* gep = new GetElementPtrInst(ci->getOperand(1), + ConstantUInt::get(Type::UIntTy,1),ci->getOperand(1)->getName()+".end", + ci); + new StoreInst(ConstantInt::get(Type::SByteTy,0),gep,ci); + ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,1)); + ci->eraseFromParent(); + return true; + } + } + return false; } } SPrintFOptimizer; @@ -1556,7 +1548,7 @@ virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) { // If the result is used, none of these optimizations work - if (!ci->hasNUses(0)) + if (!ci->use_empty()) return false; // All the optimizations depend on the length of the first argument and the From lattner at cs.uiuc.edu Sat Sep 24 17:57:40 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 17:57:40 -0500 Subject: [llvm-commits] CVS: llvm/include/llvm/Constants.h Message-ID: <200509242257.RAA14853@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm: Constants.h updated: 1.72 -> 1.73 --- Log message: Add long-overdue helpers for getting constants with known upper bits --- Diffs of the changes: (+14 -0) Constants.h | 14 ++++++++++++++ 1 files changed, 14 insertions(+) Index: llvm/include/llvm/Constants.h diff -u llvm/include/llvm/Constants.h:1.72 llvm/include/llvm/Constants.h:1.73 --- llvm/include/llvm/Constants.h:1.72 Wed Aug 17 15:06:22 2005 +++ llvm/include/llvm/Constants.h Sat Sep 24 17:57:28 2005 @@ -54,7 +54,21 @@ /// unsigned integer value. /// inline uint64_t getRawValue() const { return Val.Unsigned; } + + /// getZExtValue - Return the constant zero extended as appropriate for this + /// type. + inline uint64_t getZExtValue() const { + unsigned Size = getType()->getPrimitiveSizeInBits(); + return Val.Unsigned & (~0ULL >> (64-Size)); + } + /// getSExtValue - Return the constant sign extended as appropriate for this + /// type. + inline int64_t getSExtValue() const { + unsigned Size = getType()->getPrimitiveSizeInBits(); + return (Val.Signed << (64-Size)) >> (64-Size); + } + /// isNullValue - Return true if this is the value that would be returned by /// getNullValue. /// From lattner at cs.uiuc.edu Sat Sep 24 18:42:29 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 18:42:29 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/InstCombine/signext.ll Message-ID: <200509242342.SAA24840@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/InstCombine: signext.ll added (r1.1) --- Log message: All of these should turn into sign extends (e.g. extsh/extsb on PPC) --- Diffs of the changes: (+43 -0) signext.ll | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 43 insertions(+) Index: llvm/test/Regression/Transforms/InstCombine/signext.ll diff -c /dev/null llvm/test/Regression/Transforms/InstCombine/signext.ll:1.1 *** /dev/null Sat Sep 24 18:42:28 2005 --- llvm/test/Regression/Transforms/InstCombine/signext.ll Sat Sep 24 18:42:18 2005 *************** *** 0 **** --- 1,43 ---- + ; RUN: llvm-as < %s | opt -instcombine -disable-output && + ; RUN: llvm-as < %s | opt -instcombine | llvm-dis | not grep '(and\|xor\|add\|shl\|shr)' + + int %test1(int %x) { + %tmp.1 = and int %x, 65535 ; [#uses=1] + %tmp.2 = xor int %tmp.1, -32768 ; [#uses=1] + %tmp.3 = add int %tmp.2, 32768 ; [#uses=1] + ret int %tmp.3 + } + + int %test2(int %x) { + %tmp.1 = and int %x, 65535 ; [#uses=1] + %tmp.2 = xor int %tmp.1, 32768 ; [#uses=1] + %tmp.3 = add int %tmp.2, -32768 ; [#uses=1] + ret int %tmp.3 + } + + int %test3(ushort %P) { + %tmp.1 = cast ushort %P to int ; [#uses=1] + %tmp.4 = xor int %tmp.1, 32768 ; [#uses=1] + %tmp.5 = add int %tmp.4, -32768 ; [#uses=1] + ret int %tmp.5 + } + + uint %test4(ushort %P) { + %tmp.1 = cast ushort %P to uint ; [#uses=1] + %tmp.4 = xor uint %tmp.1, 32768 ; [#uses=1] + %tmp.5 = add uint %tmp.4, 4294934528 ; [#uses=1] + ret uint %tmp.5 + } + + int %test5(int %x) { + %tmp.1 = and int %x, 254 + %tmp.2 = xor int %tmp.1, 128 + %tmp.3 = add int %tmp.2, -128 + ret int %tmp.3 + } + + int %test6(int %x) { + %tmp.2 = shl int %x, ubyte 16 ; [#uses=1] + %tmp.4 = shr int %tmp.2, ubyte 16 ; [#uses=1] + ret int %tmp.4 + } From lattner at cs.uiuc.edu Sat Sep 24 18:43:44 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 18:43:44 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp Message-ID: <200509242343.SAA24879@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Scalar: InstructionCombining.cpp updated: 1.380 -> 1.381 --- Log message: Move MaskedValueIsZero up. Match a bunch of idioms for sign extensions, implementing InstCombine/signext.ll --- Diffs of the changes: (+146 -77) InstructionCombining.cpp | 223 ++++++++++++++++++++++++++++++----------------- 1 files changed, 146 insertions(+), 77 deletions(-) Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.380 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.381 --- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.380 Sun Sep 18 02:22:02 2005 +++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp Sat Sep 24 18:43:33 2005 @@ -385,6 +385,82 @@ ConstantInt::get(C->getType(), 1))); } +/// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use +/// this predicate to simplify operations downstream. V and Mask are known to +/// be the same type. +static bool MaskedValueIsZero(Value *V, ConstantIntegral *Mask) { + // Note, we cannot consider 'undef' to be "IsZero" here. The problem is that + // we cannot optimize based on the assumption that it is zero without changing + // to to an explicit zero. If we don't change it to zero, other code could + // optimized based on the contradictory assumption that it is non-zero. + // Because instcombine aggressively folds operations with undef args anyway, + // this won't lose us code quality. + if (Mask->isNullValue()) + return true; + if (ConstantIntegral *CI = dyn_cast(V)) + return ConstantExpr::getAnd(CI, Mask)->isNullValue(); + + if (Instruction *I = dyn_cast(V)) { + switch (I->getOpcode()) { + case Instruction::And: + // (X & C1) & C2 == 0 iff C1 & C2 == 0. + if (ConstantIntegral *CI = dyn_cast(I->getOperand(1))) + if (ConstantExpr::getAnd(CI, Mask)->isNullValue()) + return true; + break; + case Instruction::Or: + // If the LHS and the RHS are MaskedValueIsZero, the result is also zero. + return MaskedValueIsZero(I->getOperand(1), Mask) && + MaskedValueIsZero(I->getOperand(0), Mask); + case Instruction::Select: + // If the T and F values are MaskedValueIsZero, the result is also zero. + return MaskedValueIsZero(I->getOperand(2), Mask) && + MaskedValueIsZero(I->getOperand(1), Mask); + case Instruction::Cast: { + const Type *SrcTy = I->getOperand(0)->getType(); + if (SrcTy == Type::BoolTy) + return (Mask->getRawValue() & 1) == 0; + + if (SrcTy->isInteger()) { + // (cast X to int) & C2 == 0 iff could not have contained C2. + if (SrcTy->isUnsigned() && // Only handle zero ext. + ConstantExpr::getCast(Mask, SrcTy)->isNullValue()) + return true; + + // If this is a noop cast, recurse. + if ((SrcTy->isSigned() && SrcTy->getUnsignedVersion() == I->getType())|| + SrcTy->getSignedVersion() == I->getType()) { + Constant *NewMask = + ConstantExpr::getCast(Mask, I->getOperand(0)->getType()); + return MaskedValueIsZero(I->getOperand(0), + cast(NewMask)); + } + } + break; + } + case Instruction::Shl: + // (shl X, C1) & C2 == 0 iff (X & C2 >>u C1) == 0 + if (ConstantUInt *SA = dyn_cast(I->getOperand(1))) + return MaskedValueIsZero(I->getOperand(0), + cast(ConstantExpr::getUShr(Mask, SA))); + break; + case Instruction::Shr: + // (ushr X, C1) & C2 == 0 iff (-1 >> C1) & C2 == 0 + if (ConstantUInt *SA = dyn_cast(I->getOperand(1))) + if (I->getType()->isUnsigned()) { + Constant *C1 = ConstantIntegral::getAllOnesValue(I->getType()); + C1 = ConstantExpr::getShr(C1, SA); + C1 = ConstantExpr::getAnd(C1, Mask); + if (C1->isNullValue()) + return true; + } + break; + } + } + + return false; +} + // isTrueWhenEqual - Return true if the specified setcondinst instruction is // true when both operands are equal... // @@ -627,6 +703,58 @@ if (isa(LHS)) if (Instruction *NV = FoldOpIntoPhi(I)) return NV; + + ConstantInt *XorRHS; + Value *XorLHS; + if (match(LHS, m_Xor(m_Value(XorLHS), m_ConstantInt(XorRHS)))) { + unsigned TySizeBits = I.getType()->getPrimitiveSizeInBits(); + int64_t RHSSExt = cast(RHSC)->getSExtValue(); + uint64_t RHSZExt = cast(RHSC)->getZExtValue(); + + uint64_t C0080Val = 1ULL << 31; + int64_t CFF80Val = -C0080Val; + unsigned Size = 32; + do { + if (TySizeBits > Size) { + bool Found = false; + // If we have ADD(XOR(AND(X, 0xFF), 0x80), 0xF..F80), it's a sext. + // If we have ADD(XOR(AND(X, 0xFF), 0xF..F80), 0x80), it's a sext. + if (RHSSExt == CFF80Val) { + if (XorRHS->getZExtValue() == C0080Val) + Found = true; + } else if (RHSZExt == C0080Val) { + if (XorRHS->getSExtValue() == CFF80Val) + Found = true; + } + if (Found) { + // This is a sign extend if the top bits are known zero. + Constant *Mask = ConstantInt::getAllOnesValue(XorLHS->getType()); + Mask = ConstantExpr::getShl(Mask, + ConstantInt::get(Type::UByteTy, 64-TySizeBits-Size)); + if (!MaskedValueIsZero(XorLHS, cast(Mask))) + Size = 0; // Not a sign ext, but can't be any others either. + goto FoundSExt; + } + } + Size >>= 1; + C0080Val >>= Size; + CFF80Val >>= Size; + } while (Size >= 8); + +FoundSExt: + const Type *MiddleType = 0; + switch (Size) { + default: break; + case 32: MiddleType = Type::IntTy; break; + case 16: MiddleType = Type::ShortTy; break; + case 8: MiddleType = Type::SByteTy; break; + } + if (MiddleType) { + Instruction *NewTrunc = new CastInst(XorLHS, MiddleType, "sext"); + InsertNewInstBefore(NewTrunc, I); + return new CastInst(NewTrunc, I.getType()); + } + } } // X + X --> X << 1 @@ -1317,83 +1445,6 @@ } }; - -/// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use -/// this predicate to simplify operations downstream. V and Mask are known to -/// be the same type. -static bool MaskedValueIsZero(Value *V, ConstantIntegral *Mask) { - // Note, we cannot consider 'undef' to be "IsZero" here. The problem is that - // we cannot optimize based on the assumption that it is zero without changing - // to to an explicit zero. If we don't change it to zero, other code could - // optimized based on the contradictory assumption that it is non-zero. - // Because instcombine aggressively folds operations with undef args anyway, - // this won't lose us code quality. - if (Mask->isNullValue()) - return true; - if (ConstantIntegral *CI = dyn_cast(V)) - return ConstantExpr::getAnd(CI, Mask)->isNullValue(); - - if (Instruction *I = dyn_cast(V)) { - switch (I->getOpcode()) { - case Instruction::And: - // (X & C1) & C2 == 0 iff C1 & C2 == 0. - if (ConstantIntegral *CI = dyn_cast(I->getOperand(1))) - if (ConstantExpr::getAnd(CI, Mask)->isNullValue()) - return true; - break; - case Instruction::Or: - // If the LHS and the RHS are MaskedValueIsZero, the result is also zero. - return MaskedValueIsZero(I->getOperand(1), Mask) && - MaskedValueIsZero(I->getOperand(0), Mask); - case Instruction::Select: - // If the T and F values are MaskedValueIsZero, the result is also zero. - return MaskedValueIsZero(I->getOperand(2), Mask) && - MaskedValueIsZero(I->getOperand(1), Mask); - case Instruction::Cast: { - const Type *SrcTy = I->getOperand(0)->getType(); - if (SrcTy == Type::BoolTy) - return (Mask->getRawValue() & 1) == 0; - - if (SrcTy->isInteger()) { - // (cast X to int) & C2 == 0 iff could not have contained C2. - if (SrcTy->isUnsigned() && // Only handle zero ext. - ConstantExpr::getCast(Mask, SrcTy)->isNullValue()) - return true; - - // If this is a noop cast, recurse. - if ((SrcTy->isSigned() && SrcTy->getUnsignedVersion() == I->getType())|| - SrcTy->getSignedVersion() == I->getType()) { - Constant *NewMask = - ConstantExpr::getCast(Mask, I->getOperand(0)->getType()); - return MaskedValueIsZero(I->getOperand(0), - cast(NewMask)); - } - } - break; - } - case Instruction::Shl: - // (shl X, C1) & C2 == 0 iff (X & C2 >>u C1) == 0 - if (ConstantUInt *SA = dyn_cast(I->getOperand(1))) - return MaskedValueIsZero(I->getOperand(0), - cast(ConstantExpr::getUShr(Mask, SA))); - break; - case Instruction::Shr: - // (ushr X, C1) & C2 == 0 iff (-1 >> C1) & C2 == 0 - if (ConstantUInt *SA = dyn_cast(I->getOperand(1))) - if (I->getType()->isUnsigned()) { - Constant *C1 = ConstantIntegral::getAllOnesValue(I->getType()); - C1 = ConstantExpr::getShr(C1, SA); - C1 = ConstantExpr::getAnd(C1, Mask); - if (C1->isNullValue()) - return true; - } - break; - } - } - - return false; -} - // OptAndOp - This handles expressions of the form ((val OP C1) & C2). Where // the Op parameter is 'OP', OpRHS is 'C1', and AndRHS is 'C2'. Op is // guaranteed to be either a shift instruction or a binary operator. @@ -3566,6 +3617,24 @@ return new ShiftInst(Op0SI->getOpcode(), Mask, ConstantUInt::get(Type::UByteTy, ShiftAmt1-ShiftAmt2)); } + } else { + // We can handle signed (X << C1) >> C2 if it's a sign extend. In + // this case, C1 == C2 and C1 is 8, 16, or 32. + if (ShiftAmt1 == ShiftAmt2) { + const Type *SExtType = 0; + switch (ShiftAmt1) { + case 8 : SExtType = Type::SByteTy; break; + case 16: SExtType = Type::ShortTy; break; + case 32: SExtType = Type::IntTy; break; + } + + if (SExtType) { + Instruction *NewTrunc = new CastInst(Op0SI->getOperand(0), + SExtType, "sext"); + InsertNewInstBefore(NewTrunc, I); + return new CastInst(NewTrunc, I.getType()); + } + } } } } From lattner at cs.uiuc.edu Sat Sep 24 23:40:01 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sat, 24 Sep 2005 23:40:01 -0500 Subject: [llvm-commits] CVS: llvm-test/SingleSource/Benchmarks/Misc-C++/mandel-text.cpp Message-ID: <200509250440.XAA27026@zion.cs.uiuc.edu> Changes in directory llvm-test/SingleSource/Benchmarks/Misc-C++: mandel-text.cpp added (r1.1) --- Log message: new testcase to generate an ascii-art mandlebrot --- Diffs of the changes: (+61 -0) mandel-text.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 61 insertions(+) Index: llvm-test/SingleSource/Benchmarks/Misc-C++/mandel-text.cpp diff -c /dev/null llvm-test/SingleSource/Benchmarks/Misc-C++/mandel-text.cpp:1.1 *** /dev/null Sat Sep 24 23:40:00 2005 --- llvm-test/SingleSource/Benchmarks/Misc-C++/mandel-text.cpp Sat Sep 24 23:39:49 2005 *************** *** 0 **** --- 1,61 ---- + #include + int main() + { + // output size + int rows = 40, cols = 78; + + // number of iterations before we quit + int maxiter = 255; + + int slowdown = 2000; + + // size and position of the rect on the imaginary plane + double fViewRectReal = -2.3, fViewRectImg = -1.0; + double fMagLevel = 0.05; + + for (int y=0; y < rows; y++) + { + // imaginary component of "c" + double fCImg = fViewRectImg + y * fMagLevel; + + for (int x=0; x < cols; x++) + { + // real component of "c" + bool bInside; + int n; + + for (int SLOW = 0; SLOW < slowdown; ++SLOW) { + double fCReal = fViewRectReal + x * fMagLevel; + double fZReal = fCReal; + double fZImg = fCImg; + bInside = true; + + // apply the formula... + for (n=0; n < maxiter; n++) { + double fZRealSquared = fZReal * fZReal; + double fZImgSquared = fZImg * fZImg; + + // have we escaped? + if (fZRealSquared + fZImgSquared > 4) { + bInside = false; + break; + } + + // z = z^2 + c + fZImg = 2 * fZReal * fZImg + fCImg; + fZReal = fZRealSquared - fZImgSquared + fCReal; + } + } + + if (bInside) + putchar(' '); + else if (n > 4) + putchar('.'); + else if (n > 2) + putchar('+'); + else + putchar('*'); + } + putchar('\n'); + } + } From lattner at cs.uiuc.edu Sun Sep 25 02:06:59 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun, 25 Sep 2005 02:06:59 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp Message-ID: <200509250706.CAA27830@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: SimplifyLibCalls.cpp updated: 1.50 -> 1.51 --- Log message: Fix some logic I broke that caused a regression on SimplifyLibCalls/2005-05-20-sprintf-crash.ll --- Diffs of the changes: (+5 -3) SimplifyLibCalls.cpp | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) Index: llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp diff -u llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.50 llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.51 --- llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.50 Sat Sep 24 17:17:06 2005 +++ llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp Sun Sep 25 02:06:48 2005 @@ -1500,9 +1500,11 @@ new CallInst(memcpy_func, args, "", ci); // The strlen result is the unincremented number of bytes in the string. - if (!ci->use_empty() && Len->getType() != ci->getType()) - Len = new CastInst(Len, ci->getType(), Len->getName(), ci); - ci->replaceAllUsesWith(Len); + if (!ci->use_empty()) { + if (Len->getType() != ci->getType()) + Len = new CastInst(Len, ci->getType(), Len->getName(), ci); + ci->replaceAllUsesWith(Len); + } ci->eraseFromParent(); return true; } From jeffc at jolt-lang.org Sun Sep 25 14:04:55 2005 From: jeffc at jolt-lang.org (Jeff Cohen) Date: Sun, 25 Sep 2005 14:04:55 -0500 Subject: [llvm-commits] CVS: llvm/win32/CodeGen/CodeGen.vcproj Message-ID: <200509251904.OAA03559@zion.cs.uiuc.edu> Changes in directory llvm/win32/CodeGen: CodeGen.vcproj updated: 1.13 -> 1.14 --- Log message: Fix VC++ build errors. --- Diffs of the changes: (+2 -2) CodeGen.vcproj | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) Index: llvm/win32/CodeGen/CodeGen.vcproj diff -u llvm/win32/CodeGen/CodeGen.vcproj:1.13 llvm/win32/CodeGen/CodeGen.vcproj:1.14 --- llvm/win32/CodeGen/CodeGen.vcproj:1.13 Fri Sep 9 21:33:17 2005 +++ llvm/win32/CodeGen/CodeGen.vcproj Sun Sep 25 14:04:43 2005 @@ -212,10 +212,10 @@ RelativePath="..\..\include\llvm\CodeGen\IntrinsicLowering.h"> + RelativePath="..\..\include\llvm\CodeGen\LiveInterval.h"> + RelativePath="..\..\include\llvm\CodeGen\LiveIntervalAnalysis.h"> From jeffc at jolt-lang.org Sun Sep 25 14:04:55 2005 From: jeffc at jolt-lang.org (Jeff Cohen) Date: Sun, 25 Sep 2005 14:04:55 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/DAGISelEmitter.cpp Message-ID: <200509251904.OAA03563@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: DAGISelEmitter.cpp updated: 1.40 -> 1.41 --- Log message: Fix VC++ build errors. --- Diffs of the changes: (+2 -0) DAGISelEmitter.cpp | 2 ++ 1 files changed, 2 insertions(+) Index: llvm/utils/TableGen/DAGISelEmitter.cpp diff -u llvm/utils/TableGen/DAGISelEmitter.cpp:1.40 llvm/utils/TableGen/DAGISelEmitter.cpp:1.41 --- llvm/utils/TableGen/DAGISelEmitter.cpp:1.40 Fri Sep 23 19:50:51 2005 +++ llvm/utils/TableGen/DAGISelEmitter.cpp Sun Sep 25 14:04:43 2005 @@ -15,6 +15,7 @@ #include "Record.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Debug.h" +#include #include using namespace llvm; @@ -1128,6 +1129,7 @@ } else { N->dump(); assert(0 && "Unknown node in result pattern!"); + return ~0U; } } From lattner at cs.uiuc.edu Sun Sep 25 20:42:15 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun, 25 Sep 2005 20:42:15 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll Message-ID: <200509260142.UAA07095@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/GlobalOpt: ctor-list-opt.ll added (r1.1) --- Log message: new testcase for static ctor list optimizations --- Diffs of the changes: (+14 -0) ctor-list-opt.ll | 14 ++++++++++++++ 1 files changed, 14 insertions(+) Index: llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll diff -c /dev/null llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll:1.1 *** /dev/null Sun Sep 25 20:42:13 2005 --- llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll Sun Sep 25 20:42:03 2005 *************** *** 0 **** --- 1,14 ---- + ; RUN: llvm-as < %s | opt -globalopt -disable-output && + ; RUN: llvm-as < %s | opt -globalopt | llvm-dis | not grep CTOR + + %llvm.global_ctors = appending global [2 x { int, void ()* }] [ + { int, void ()* } { int 65535, void ()* %CTOR1 }, + { int, void ()* } { int 65535, void ()* %CTOR1 } + ] + + implementation + + internal void %CTOR1() { ;; noop ctor, remove. + ret void + } + From lattner at cs.uiuc.edu Sun Sep 25 20:43:57 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun, 25 Sep 2005 20:43:57 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/GlobalOpt.cpp Message-ID: <200509260143.UAA07155@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: GlobalOpt.cpp updated: 1.41 -> 1.42 --- Log message: Factor this code out into a few methods. Implement the start of global ctor optimization. It is currently smart enough to remove the global ctor for cases like this: struct foo { foo() {} } x; ... saving a bit of startup time for the program. --- Diffs of the changes: (+190 -33) GlobalOpt.cpp | 223 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 190 insertions(+), 33 deletions(-) Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp diff -u llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.41 llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.42 --- llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.41 Wed Jun 15 16:11:48 2005 +++ llvm/lib/Transforms/IPO/GlobalOpt.cpp Sun Sep 25 20:43:45 2005 @@ -45,6 +45,7 @@ "Number of global vars shrunk to booleans"); Statistic<> NumFastCallFns("globalopt", "Number of functions converted to fastcc"); + Statistic<> NumEmptyCtor ("globalopt", "Number of empty ctors removed"); struct GlobalOpt : public ModulePass { virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -54,6 +55,10 @@ bool runOnModule(Module &M); private: + GlobalVariable *FindGlobalCtors(Module &M); + bool OptimizeFunctions(Module &M); + bool OptimizeGlobalVars(Module &M); + bool OptimizeGlobalCtorsList(GlobalVariable *&GCL); bool ProcessInternalGlobal(GlobalVariable *GV, Module::global_iterator &GVI); }; @@ -1077,47 +1082,199 @@ } } -bool GlobalOpt::runOnModule(Module &M) { +bool GlobalOpt::OptimizeFunctions(Module &M) { bool Changed = false; + // Optimize functions. + for (Module::iterator FI = M.begin(), E = M.end(); FI != E; ) { + Function *F = FI++; + F->removeDeadConstantUsers(); + if (F->use_empty() && (F->hasInternalLinkage() || + F->hasLinkOnceLinkage())) { + M.getFunctionList().erase(F); + Changed = true; + ++NumFnDeleted; + } else if (F->hasInternalLinkage() && + F->getCallingConv() == CallingConv::C && !F->isVarArg() && + OnlyCalledDirectly(F)) { + // If this function has C calling conventions, is not a varargs + // function, and is only called directly, promote it to use the Fast + // calling convention. + F->setCallingConv(CallingConv::Fast); + ChangeCalleesToFastCall(F); + ++NumFastCallFns; + Changed = true; + } + } + return Changed; +} - // As a prepass, delete functions that are trivially dead. - bool LocalChange = true; - while (LocalChange) { - LocalChange = false; - for (Module::iterator FI = M.begin(), E = M.end(); FI != E; ) { - Function *F = FI++; - F->removeDeadConstantUsers(); - if (F->use_empty() && (F->hasInternalLinkage() || - F->hasLinkOnceLinkage())) { - M.getFunctionList().erase(F); - LocalChange = true; - ++NumFnDeleted; - } else if (F->hasInternalLinkage() && - F->getCallingConv() == CallingConv::C && !F->isVarArg() && - OnlyCalledDirectly(F)) { - // If this function has C calling conventions, is not a varargs - // function, and is only called directly, promote it to use the Fast - // calling convention. - F->setCallingConv(CallingConv::Fast); - ChangeCalleesToFastCall(F); - ++NumFastCallFns; - LocalChange = true; - } +bool GlobalOpt::OptimizeGlobalVars(Module &M) { + bool Changed = false; + for (Module::global_iterator GVI = M.global_begin(), E = M.global_end(); + GVI != E; ) { + GlobalVariable *GV = GVI++; + if (!GV->isConstant() && GV->hasInternalLinkage() && + GV->hasInitializer()) + Changed |= ProcessInternalGlobal(GV, GVI); + } + return Changed; +} + +/// FindGlobalCtors - Find the llvm.globalctors list, verifying that all +/// initializers have an init priority of 65535. +GlobalVariable *GlobalOpt::FindGlobalCtors(Module &M) { + for (Module::giterator I = M.global_begin(), E = M.global_end(); I != E; ++I) + if (I->getName() == "llvm.global_ctors") { + // Found it, verify it's an array of { int, void()* }. + const ArrayType *ATy =dyn_cast(I->getType()->getElementType()); + if (!ATy) return 0; + const StructType *STy = dyn_cast(ATy->getElementType()); + if (!STy || STy->getNumElements() != 2 || + STy->getElementType(0) != Type::IntTy) return 0; + const PointerType *PFTy = dyn_cast(STy->getElementType(1)); + if (!PFTy) return 0; + const FunctionType *FTy = dyn_cast(PFTy->getElementType()); + if (!FTy || FTy->getReturnType() != Type::VoidTy || FTy->isVarArg() || + FTy->getNumParams() != 0) + return 0; + + // Verify that the initializer is simple enough for us to handle. + if (!I->hasInitializer()) return 0; + ConstantArray *CA = dyn_cast(I->getInitializer()); + if (!CA) return 0; + for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) + if (ConstantStruct *CS = dyn_cast(CA->getOperand(i))) { + // Init priority must be standard. + ConstantInt *CI = dyn_cast(CS->getOperand(0)); + if (!CI || CI->getRawValue() != 65535) + return 0; + + // Must have a function or null ptr. + if (!isa(CS->getOperand(1)) && + !isa(CS->getOperand(1))) + return 0; + } else { + return 0; + } + + return I; + } + return 0; +} + +static std::vector ParseGlobalCtors(GlobalVariable *GV) { + ConstantArray *CA = cast(GV->getInitializer()); + std::vector Result; + Result.reserve(CA->getNumOperands()); + for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { + ConstantStruct *CS = cast(CA->getOperand(i)); + Result.push_back(dyn_cast(CS->getOperand(1))); + } + return Result; +} + +/// OptimizeGlobalCtorsList - Simplify and evaluation global ctors if possible. +/// Return true if anything changed. +bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) { + std::vector Ctors = ParseGlobalCtors(GCL); + bool MadeChange = false; + if (Ctors.empty()) return false; + + // Loop over global ctors, optimizing them when we can. + for (unsigned i = 0; i != Ctors.size(); ++i) { + Function *F = Ctors[i]; + // Found a null terminator in the middle of the list, prune off the rest of + // the list. + if (F == 0 && i != Ctors.size()-1) { + Ctors.resize(i+1); + MadeChange = true; + break; + } + + // If the function is empty, just remove it from the ctor list. + if (!F->empty() && isa(F->begin()->getTerminator()) && + &F->begin()->front() == F->begin()->getTerminator()) { + Ctors.erase(Ctors.begin()+i); + MadeChange = true; + --i; + ++NumEmptyCtor; } - Changed |= LocalChange; + } + + if (!MadeChange) return false; + + std::vector CSVals; + CSVals.push_back(ConstantSInt::get(Type::IntTy, 65535)); + CSVals.push_back(0); + + // Create the new init list. + std::vector CAList; + for (unsigned i = 0, e = Ctors.size(); i != e; ++i) { + if (Ctors[i]) + CSVals[1] = Ctors[i]; + else { + const Type *FTy = FunctionType::get(Type::VoidTy, + std::vector(), false); + const PointerType *PFTy = PointerType::get(FTy); + CSVals[1] = Constant::getNullValue(PFTy); + } + CAList.push_back(ConstantStruct::get(CSVals)); } - LocalChange = true; + // Create the array initializer. + const Type *StructTy = + cast(GCL->getType()->getElementType())->getElementType(); + Constant *CA = ConstantArray::get(ArrayType::get(StructTy, CAList.size()), + CAList); + + // Create the new global and insert it next to the existing list. + GlobalVariable *NGV = new GlobalVariable(CA->getType(), GCL->isConstant(), + GCL->getLinkage(), CA, + GCL->getName()); + GCL->setName(""); + GCL->getParent()->getGlobalList().insert(GCL, NGV); + + // Nuke the old list, replacing any uses with the new one. + if (!GCL->use_empty()) { + Constant *V = NGV; + if (V->getType() != GCL->getType()) + V = ConstantExpr::getCast(V, GCL->getType()); + GCL->replaceAllUsesWith(V); + } + GCL->eraseFromParent(); + + if (Ctors.size()) + GCL = NGV; + else + GCL = 0; + return true; +} + + +bool GlobalOpt::runOnModule(Module &M) { + bool Changed = false; + + // Try to find the llvm.globalctors list. + GlobalVariable *GlobalCtors = FindGlobalCtors(M); + + bool LocalChange = true; while (LocalChange) { LocalChange = false; - for (Module::global_iterator GVI = M.global_begin(), E = M.global_end(); - GVI != E; ) { - GlobalVariable *GV = GVI++; - if (!GV->isConstant() && GV->hasInternalLinkage() && - GV->hasInitializer()) - LocalChange |= ProcessInternalGlobal(GV, GVI); - } + + // Delete functions that are trivially dead, ccc -> fastcc + LocalChange |= OptimizeFunctions(M); + + // Optimize global_ctors list. + if (GlobalCtors) + LocalChange |= OptimizeGlobalCtorsList(GlobalCtors); + + // Optimize non-address-taken globals. + LocalChange |= OptimizeGlobalVars(M); Changed |= LocalChange; } + + // TODO: Move all global ctors functions to the end of the module for code + // layout. + return Changed; } From lattner at cs.uiuc.edu Sun Sep 25 21:19:39 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun, 25 Sep 2005 21:19:39 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/GlobalOpt.cpp Message-ID: <200509260219.VAA07328@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: GlobalOpt.cpp updated: 1.42 -> 1.43 --- Log message: Make the global opt optimizer work on modules with a null terminator, by accepting the null even with a non-65535 init prio --- Diffs of the changes: (+13 -8) GlobalOpt.cpp | 21 +++++++++++++-------- 1 files changed, 13 insertions(+), 8 deletions(-) Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp diff -u llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.42 llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.43 --- llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.42 Sun Sep 25 20:43:45 2005 +++ llvm/lib/Transforms/IPO/GlobalOpt.cpp Sun Sep 25 21:19:27 2005 @@ -1144,15 +1144,17 @@ if (!CA) return 0; for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) if (ConstantStruct *CS = dyn_cast(CA->getOperand(i))) { + if (isa(CS->getOperand(1))) + continue; + + // Must have a function or null ptr. + if (!isa(CS->getOperand(1))) + return 0; + // Init priority must be standard. ConstantInt *CI = dyn_cast(CS->getOperand(0)); if (!CI || CI->getRawValue() != 65535) return 0; - - // Must have a function or null ptr. - if (!isa(CS->getOperand(1)) && - !isa(CS->getOperand(1))) - return 0; } else { return 0; } @@ -1185,9 +1187,11 @@ Function *F = Ctors[i]; // Found a null terminator in the middle of the list, prune off the rest of // the list. - if (F == 0 && i != Ctors.size()-1) { - Ctors.resize(i+1); - MadeChange = true; + if (F == 0) { + if (i != Ctors.size()-1) { + Ctors.resize(i+1); + MadeChange = true; + } break; } @@ -1217,6 +1221,7 @@ std::vector(), false); const PointerType *PFTy = PointerType::get(FTy); CSVals[1] = Constant::getNullValue(PFTy); + CSVals[0] = ConstantSInt::get(Type::IntTy, 2147483647); } CAList.push_back(ConstantStruct::get(CSVals)); } From lattner at cs.uiuc.edu Sun Sep 25 21:31:29 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun, 25 Sep 2005 21:31:29 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/GlobalOpt.cpp Message-ID: <200509260231.VAA07453@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: GlobalOpt.cpp updated: 1.43 -> 1.44 --- Log message: factor some code into a InstallGlobalCtors method, add comments. No functionality change. --- Diffs of the changes: (+52 -35) GlobalOpt.cpp | 87 ++++++++++++++++++++++++++++++++++------------------------ 1 files changed, 52 insertions(+), 35 deletions(-) Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp diff -u llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.43 llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.44 --- llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.43 Sun Sep 25 21:19:27 2005 +++ llvm/lib/Transforms/IPO/GlobalOpt.cpp Sun Sep 25 21:31:18 2005 @@ -1164,6 +1164,8 @@ return 0; } +/// ParseGlobalCtors - Given a llvm.global_ctors list that we can understand, +/// return a list of the functions and null terminator as a vector. static std::vector ParseGlobalCtors(GlobalVariable *GV) { ConstantArray *CA = cast(GV->getInitializer()); std::vector Result; @@ -1175,38 +1177,11 @@ return Result; } -/// OptimizeGlobalCtorsList - Simplify and evaluation global ctors if possible. -/// Return true if anything changed. -bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) { - std::vector Ctors = ParseGlobalCtors(GCL); - bool MadeChange = false; - if (Ctors.empty()) return false; - - // Loop over global ctors, optimizing them when we can. - for (unsigned i = 0; i != Ctors.size(); ++i) { - Function *F = Ctors[i]; - // Found a null terminator in the middle of the list, prune off the rest of - // the list. - if (F == 0) { - if (i != Ctors.size()-1) { - Ctors.resize(i+1); - MadeChange = true; - } - break; - } - - // If the function is empty, just remove it from the ctor list. - if (!F->empty() && isa(F->begin()->getTerminator()) && - &F->begin()->front() == F->begin()->getTerminator()) { - Ctors.erase(Ctors.begin()+i); - MadeChange = true; - --i; - ++NumEmptyCtor; - } - } - - if (!MadeChange) return false; - +/// InstallGlobalCtors - Given a specified llvm.global_ctors list, install the +/// specified array, returning the new global to use. +static GlobalVariable *InstallGlobalCtors(GlobalVariable *GCL, + const std::vector &Ctors) { + // If we made a change, reassemble the initializer list. std::vector CSVals; CSVals.push_back(ConstantSInt::get(Type::IntTy, 65535)); CSVals.push_back(0); @@ -1225,13 +1200,19 @@ } CAList.push_back(ConstantStruct::get(CSVals)); } - + // Create the array initializer. const Type *StructTy = cast(GCL->getType()->getElementType())->getElementType(); Constant *CA = ConstantArray::get(ArrayType::get(StructTy, CAList.size()), CAList); + // If we didn't change the number of elements, don't create a new GV. + if (CA->getType() == GCL->getInitializer()->getType()) { + GCL->setInitializer(CA); + return GCL; + } + // Create the new global and insert it next to the existing list. GlobalVariable *NGV = new GlobalVariable(CA->getType(), GCL->isConstant(), GCL->getLinkage(), CA, @@ -1249,9 +1230,45 @@ GCL->eraseFromParent(); if (Ctors.size()) - GCL = NGV; + return NGV; else - GCL = 0; + return 0; +} + + +/// OptimizeGlobalCtorsList - Simplify and evaluation global ctors if possible. +/// Return true if anything changed. +bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) { + std::vector Ctors = ParseGlobalCtors(GCL); + bool MadeChange = false; + if (Ctors.empty()) return false; + + // Loop over global ctors, optimizing them when we can. + for (unsigned i = 0; i != Ctors.size(); ++i) { + Function *F = Ctors[i]; + // Found a null terminator in the middle of the list, prune off the rest of + // the list. + if (F == 0) { + if (i != Ctors.size()-1) { + Ctors.resize(i+1); + MadeChange = true; + } + break; + } + + // If the function is empty, just remove it from the ctor list. + if (!F->empty() && isa(F->begin()->getTerminator()) && + &F->begin()->front() == F->begin()->getTerminator()) { + Ctors.erase(Ctors.begin()+i); + MadeChange = true; + --i; + ++NumEmptyCtor; + } + } + + if (!MadeChange) return false; + + GCL = InstallGlobalCtors(GCL, Ctors); return true; } From lattner at cs.uiuc.edu Sun Sep 25 23:43:14 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun, 25 Sep 2005 23:43:14 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll Message-ID: <200509260443.XAA07901@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/GlobalOpt: ctor-list-opt.ll updated: 1.1 -> 1.2 --- Log message: make this harder: put some code into it --- Diffs of the changes: (+19 -2) ctor-list-opt.ll | 21 +++++++++++++++++++-- 1 files changed, 19 insertions(+), 2 deletions(-) Index: llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll diff -u llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll:1.1 llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll:1.2 --- llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll:1.1 Sun Sep 25 20:42:03 2005 +++ llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll Sun Sep 25 23:43:01 2005 @@ -1,14 +1,31 @@ ; RUN: llvm-as < %s | opt -globalopt -disable-output && ; RUN: llvm-as < %s | opt -globalopt | llvm-dis | not grep CTOR -%llvm.global_ctors = appending global [2 x { int, void ()* }] [ +%llvm.global_ctors = appending global [4 x { int, void ()* }] [ { int, void ()* } { int 65535, void ()* %CTOR1 }, - { int, void ()* } { int 65535, void ()* %CTOR1 } + { int, void ()* } { int 65535, void ()* %CTOR1 }, + { int, void ()* } { int 65535, void ()* %CTOR2 }, + { int, void ()* } { int 2147483647, void ()* null } ] +%G = global int 0 + +%CTORGV = internal global bool false ;; Should become constant after eval + implementation internal void %CTOR1() { ;; noop ctor, remove. ret void } +internal void %CTOR2() { ;; evaluate the store + %A = add int 1, 23 + store int %A, int* %G + store bool true, bool* %CTORGV + ret void +} + +bool %accessor() { + %V = load bool* %CTORGV ;; constant true + ret bool %V +} From lattner at cs.uiuc.edu Sun Sep 25 23:44:46 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun, 25 Sep 2005 23:44:46 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/GlobalOpt.cpp Message-ID: <200509260444.XAA07936@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: GlobalOpt.cpp updated: 1.44 -> 1.45 --- Log message: Add a simple interpreter to this code, allowing us to statically evaluate global ctors that are simple enough. This implements ctor-list-opt.ll:CTOR2. --- Diffs of the changes: (+110 -4) GlobalOpt.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 110 insertions(+), 4 deletions(-) Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp diff -u llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.44 llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.45 --- llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.44 Sun Sep 25 21:31:18 2005 +++ llvm/lib/Transforms/IPO/GlobalOpt.cpp Sun Sep 25 23:44:35 2005 @@ -46,6 +46,7 @@ Statistic<> NumFastCallFns("globalopt", "Number of functions converted to fastcc"); Statistic<> NumEmptyCtor ("globalopt", "Number of empty ctors removed"); + Statistic<> NumCtorsEvaluated("globalopt","Number of static ctors evaluated"); struct GlobalOpt : public ModulePass { virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -1189,9 +1190,9 @@ // Create the new init list. std::vector CAList; for (unsigned i = 0, e = Ctors.size(); i != e; ++i) { - if (Ctors[i]) + if (Ctors[i]) { CSVals[1] = Ctors[i]; - else { + } else { const Type *FTy = FunctionType::get(Type::VoidTy, std::vector(), false); const PointerType *PFTy = PointerType::get(FTy); @@ -1234,7 +1235,99 @@ else return 0; } - + + +static Constant *getVal(std::map &ComputedValues, + Value *V) { + if (Constant *CV = dyn_cast(V)) return CV; + Constant *R = ComputedValues[V]; + assert(R && "Reference to an uncomputed value!"); + return R; +} + +/// isSimpleEnoughPointerToCommit - Return true if this constant is simple +/// enough for us to understand. In particular, if it is a cast of something, +/// we punt. We basically just support direct accesses to globals and GEP's of +/// globals. This should be kept up to date with CommitValueTo. +static bool isSimpleEnoughPointerToCommit(Constant *C) { + if (GlobalVariable *GV = dyn_cast(C)) + return !GV->isExternal(); // reject external globals. + return false; +} + +/// CommitValueTo - We have decided that Addr (which satisfies the predicate +/// isSimpleEnoughPointerToCommit) should get Val as its value. Make it happen. +static void CommitValueTo(Constant *Val, Constant *Addr) { + GlobalVariable *GV = cast(Addr); + assert(GV->hasInitializer()); + GV->setInitializer(Val); +} + +/// EvaluateStaticConstructor - Evaluate static constructors in the function, if +/// we can. Return true if we can, false otherwise. +static bool EvaluateStaticConstructor(Function *F) { + /// Values - As we compute SSA register values, we store their contents here. + std::map Values; + + /// MutatedMemory - For each store we execute, we update this map. Loads + /// check this to get the most up-to-date value. If evaluation is successful, + /// this state is committed to the process. + std::map MutatedMemory; + + // CurInst - The current instruction we're evaluating. + BasicBlock::iterator CurInst = F->begin()->begin(); + + // This is the main evaluation loop. + while (1) { + Constant *InstResult = 0; + + if (StoreInst *SI = dyn_cast(CurInst)) { + Constant *Ptr = getVal(Values, SI->getOperand(1)); + if (!isSimpleEnoughPointerToCommit(Ptr)) + // If this is too complex for us to commit, reject it. + return false; + Constant *Val = getVal(Values, SI->getOperand(0)); + MutatedMemory[Ptr] = Val; + } else if (BinaryOperator *BO = dyn_cast(CurInst)) { + InstResult = ConstantExpr::get(BO->getOpcode(), + getVal(Values, BO->getOperand(0)), + getVal(Values, BO->getOperand(1))); + } else if (ShiftInst *SI = dyn_cast(CurInst)) { + InstResult = ConstantExpr::get(SI->getOpcode(), + getVal(Values, SI->getOperand(0)), + getVal(Values, SI->getOperand(1))); + } else if (CastInst *CI = dyn_cast(CurInst)) { + InstResult = ConstantExpr::getCast(getVal(Values, CI->getOperand(0)), + CI->getType()); + } else if (SelectInst *SI = dyn_cast(CurInst)) { + InstResult = ConstantExpr::getSelect(getVal(Values, SI->getOperand(0)), + getVal(Values, SI->getOperand(1)), + getVal(Values, SI->getOperand(2))); + } else if (ReturnInst *RI = dyn_cast(CurInst)) { + assert(RI->getNumOperands() == 0); + break; // We succeeded at evaluating this ctor! + } else { + // TODO: use ConstantFoldCall for function calls. + + // Did not know how to evaluate this! + return false; + } + + if (!CurInst->use_empty()) + Values[CurInst] = InstResult; + + // Advance program counter. + ++CurInst; + } + + // If we get here, we know that we succeeded at evaluation: commit the result. + // + for (std::map::iterator I = MutatedMemory.begin(), + E = MutatedMemory.end(); I != E; ++I) + CommitValueTo(I->second, I->first); + return true; +} + /// OptimizeGlobalCtorsList - Simplify and evaluation global ctors if possible. /// Return true if anything changed. @@ -1256,13 +1349,26 @@ break; } + // We cannot simplify external ctor functions. + if (F->empty()) continue; + + // If we can evaluate the ctor at compile time, do. + if (EvaluateStaticConstructor(F)) { + Ctors.erase(Ctors.begin()+i); + MadeChange = true; + --i; + ++NumCtorsEvaluated; + continue; + } + // If the function is empty, just remove it from the ctor list. - if (!F->empty() && isa(F->begin()->getTerminator()) && + if (isa(F->begin()->getTerminator()) && &F->begin()->front() == F->begin()->getTerminator()) { Ctors.erase(Ctors.begin()+i); MadeChange = true; --i; ++NumEmptyCtor; + continue; } } From lattner at cs.uiuc.edu Sun Sep 25 23:57:21 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun, 25 Sep 2005 23:57:21 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll Message-ID: <200509260457.XAA08053@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/GlobalOpt: ctor-list-opt.ll updated: 1.2 -> 1.3 --- Log message: add another testcase with simple control flow --- Diffs of the changes: (+15 -1) ctor-list-opt.ll | 16 +++++++++++++++- 1 files changed, 15 insertions(+), 1 deletion(-) Index: llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll diff -u llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll:1.2 llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll:1.3 --- llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll:1.2 Sun Sep 25 23:43:01 2005 +++ llvm/test/Regression/Transforms/GlobalOpt/ctor-list-opt.ll Sun Sep 25 23:57:10 2005 @@ -1,14 +1,16 @@ ; RUN: llvm-as < %s | opt -globalopt -disable-output && ; RUN: llvm-as < %s | opt -globalopt | llvm-dis | not grep CTOR -%llvm.global_ctors = appending global [4 x { int, void ()* }] [ +%llvm.global_ctors = appending global [5 x { int, void ()* }] [ { int, void ()* } { int 65535, void ()* %CTOR1 }, { int, void ()* } { int 65535, void ()* %CTOR1 }, { int, void ()* } { int 65535, void ()* %CTOR2 }, + { int, void ()* } { int 65535, void ()* %CTOR3 }, { int, void ()* } { int 2147483647, void ()* null } ] %G = global int 0 +%G2 = global int 0 %CTORGV = internal global bool false ;; Should become constant after eval @@ -25,6 +27,18 @@ ret void } +internal void %CTOR3() { + %X = or bool true, false + br label %Cont +Cont: + br bool %X, label %S, label %T +S: + store int 24, int* %G2 + ret void +T: + ret void +} + bool %accessor() { %V = load bool* %CTORGV ;; constant true ret bool %V From lattner at cs.uiuc.edu Sun Sep 25 23:57:50 2005 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun, 25 Sep 2005 23:57:50 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/GlobalOpt.cpp Message-ID: <200509260457.XAA08086@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: GlobalOpt.cpp updated: 1.45 -> 1.46 --- Log message: Add support for br/brcond/switch and phi --- Diffs of the changes: (+47 -3) GlobalOpt.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 47 insertions(+), 3 deletions(-) Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp diff -u llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.45 llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.46 --- llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.45 Sun Sep 25 23:44:35 2005 +++ llvm/lib/Transforms/IPO/GlobalOpt.cpp Sun Sep 25 23:57:38 2005 @@ -1274,8 +1274,14 @@ /// this state is committed to the process. std::map MutatedMemory; + /// ExecutedBlocks - We only handle non-looping, non-recursive code. As such, + /// we can only evaluate any one basic block at most once. This set keeps + /// track of what we have executed so we can detect recursive cases etc. + std::set ExecutedBlocks; + // CurInst - The current instruction we're evaluating. BasicBlock::iterator CurInst = F->begin()->begin(); + ExecutedBlocks.insert(F->begin()); // This is the main evaluation loop. while (1) { @@ -1303,9 +1309,47 @@ InstResult = ConstantExpr::getSelect(getVal(Values, SI->getOperand(0)), getVal(Values, SI->getOperand(1)), getVal(Values, SI->getOperand(2))); - } else if (ReturnInst *RI = dyn_cast(CurInst)) { - assert(RI->getNumOperands() == 0); - break; // We succeeded at evaluating this ctor! + } else if (TerminatorInst *TI = dyn_cast(CurInst)) { + BasicBlock *NewBB = 0; + if (BranchInst *BI = dyn_cast(CurInst)) { + if (BI->isUnconditional()) { + NewBB = BI->getSuccessor(0); + } else { + ConstantBool *Cond = + dyn_cast(getVal(Values, BI->getCondition())); + if (!Cond) return false; // Cannot determine. + NewBB = BI->getSuccessor(!Cond->getValue()); + } + } else if (SwitchInst *SI = dyn_cast(CurInst)) { + ConstantInt *Val = + dyn_cast(getVal(Values, SI->getCondition())); + if (!Val) return false; // Cannot determine. + NewBB = SI->getSuccessor(SI->findCaseValue(Val)); + } else if (ReturnInst *RI = dyn_cast(CurInst)) { + assert(RI->getNumOperands() == 0); + break; // We succeeded at evaluating this ctor! + } else { + // unwind, unreachable. + return false; // Cannot handle this terminator. + } + + // Okay, we succeeded in evaluating this control flow. See if we have + // executed the new block before. If so, we have a looping or recursive + // function, which we cannot evaluate in reasonable time. + if (!ExecutedBlocks.insert(NewBB).second) + return false; // Recursed! + + // Okay, we have never been in this block before. Check to see if there + // are any PHI nodes. If so, evaluate them with information about where + // we came from. + BasicBlock *OldBB = CurInst->getParent(); + CurInst = NewBB->begin(); + PHINode *PN; + for (; (PN = dyn_cast(CurInst)); ++CurInst) + Values[PN] = getVal(Values, PN->getIncomingValueForBlock(OldBB)); + + // Do NOT increment CurInst. We know that the terminator had no value. + continue; } else { // TODO: use ConstantFoldCall for function calls.