diff options
Diffstat (limited to 'lib/Target')
84 files changed, 4162 insertions, 1437 deletions
diff --git a/lib/Target/ARM/ARMAddressingModes.h b/lib/Target/ARM/ARMAddressingModes.h index 1839153..c603708 100644 --- a/lib/Target/ARM/ARMAddressingModes.h +++ b/lib/Target/ARM/ARMAddressingModes.h @@ -15,7 +15,6 @@ #define LLVM_TARGET_ARM_ARMADDRESSINGMODES_H #include "llvm/CodeGen/SelectionDAGNodes.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include <cassert> @@ -38,7 +37,7 @@ namespace ARM_AM { static inline const char *getShiftOpcStr(ShiftOpc Op) { switch (Op) { - default: llvm_unreachable("Unknown shift opc!"); + default: assert(0 && "Unknown shift opc!"); case ARM_AM::asr: return "asr"; case ARM_AM::lsl: return "lsl"; case ARM_AM::lsr: return "lsr"; @@ -71,7 +70,7 @@ namespace ARM_AM { static inline const char *getAMSubModeStr(AMSubMode Mode) { switch (Mode) { - default: llvm_unreachable("Unknown addressing sub-mode!"); + default: assert(0 && "Unknown addressing sub-mode!"); case ARM_AM::ia: return "ia"; case ARM_AM::ib: return "ib"; case ARM_AM::da: return "da"; @@ -81,7 +80,7 @@ namespace ARM_AM { static inline const char *getAMSubModeAltStr(AMSubMode Mode, bool isLD) { switch (Mode) { - default: llvm_unreachable("Unknown addressing sub-mode!"); + default: assert(0 && "Unknown addressing sub-mode!"); case ARM_AM::ia: return isLD ? "fd" : "ea"; case ARM_AM::ib: return isLD ? "ed" : "fa"; case ARM_AM::da: return isLD ? "fa" : "ed"; @@ -342,6 +341,66 @@ namespace ARM_AM { return -1; } + static inline unsigned getT2SOImmValRotate(unsigned V) { + if ((V & ~255U) == 0) return 0; + // Use CTZ to compute the rotate amount. + unsigned RotAmt = CountTrailingZeros_32(V); + return (32 - RotAmt) & 31; + } + + static inline bool isT2SOImmTwoPartVal (unsigned Imm) { + unsigned V = Imm; + // Passing values can be any combination of splat values and shifter + // values. If this can be handled with a single shifter or splat, bail + // out. Those should be handled directly, not with a two-part val. + if (getT2SOImmValSplatVal(V) != -1) + return false; + V = rotr32 (~255U, getT2SOImmValRotate(V)) & V; + if (V == 0) + return false; + + // If this can be handled as an immediate, accept. + if (getT2SOImmVal(V) != -1) return true; + + // Likewise, try masking out a splat value first. + V = Imm; + if (getT2SOImmValSplatVal(V & 0xff00ff00U) != -1) + V &= ~0xff00ff00U; + else if (getT2SOImmValSplatVal(V & 0x00ff00ffU) != -1) + V &= ~0x00ff00ffU; + // If what's left can be handled as an immediate, accept. + if (getT2SOImmVal(V) != -1) return true; + + // Otherwise, do not accept. + return false; + } + + static inline unsigned getT2SOImmTwoPartFirst(unsigned Imm) { + assert (isT2SOImmTwoPartVal(Imm) && + "Immedate cannot be encoded as two part immediate!"); + // Try a shifter operand as one part + unsigned V = rotr32 (~255, getT2SOImmValRotate(Imm)) & Imm; + // If the rest is encodable as an immediate, then return it. + if (getT2SOImmVal(V) != -1) return V; + + // Try masking out a splat value first. + if (getT2SOImmValSplatVal(Imm & 0xff00ff00U) != -1) + return Imm & 0xff00ff00U; + + // The other splat is all that's left as an option. + assert (getT2SOImmValSplatVal(Imm & 0x00ff00ffU) != -1); + return Imm & 0x00ff00ffU; + } + + static inline unsigned getT2SOImmTwoPartSecond(unsigned Imm) { + // Mask out the first hunk + Imm ^= getT2SOImmTwoPartFirst(Imm); + // Return what's left + assert (getT2SOImmVal(Imm) != -1 && + "Unable to encode second part of T2 two part SO immediate"); + return Imm; + } + //===--------------------------------------------------------------------===// // Addressing Mode #2 diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp index 42ef183..00e7531 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -36,8 +36,18 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/CommandLine.h" using namespace llvm; +static cl::opt<bool> +ScavengeFrameIndexVals("arm-virtual-frame-index-vals", cl::Hidden, + cl::init(false), + cl::desc("Resolve frame index values via scavenging in PEI")); + +static cl::opt<bool> +ReuseFrameIndexVals("arm-reuse-frame-index-vals", cl::Hidden, cl::init(false), + cl::desc("Reuse repeated frame index values")); + unsigned ARMBaseRegisterInfo::getRegisterNumbering(unsigned RegEnum, bool *isSPVFP) { if (isSPVFP) @@ -740,8 +750,7 @@ unsigned ARMBaseRegisterInfo::getRegisterPairEven(unsigned Reg, case ARM::R1: return ARM::R0; case ARM::R3: - // FIXME! - return STI.isThumb1Only() ? 0 : ARM::R2; + return ARM::R2; case ARM::R5: return ARM::R4; case ARM::R7: @@ -830,8 +839,7 @@ unsigned ARMBaseRegisterInfo::getRegisterPairOdd(unsigned Reg, case ARM::R0: return ARM::R1; case ARM::R2: - // FIXME! - return STI.isThumb1Only() ? 0 : ARM::R3; + return ARM::R3; case ARM::R4: return ARM::R5; case ARM::R6: @@ -937,6 +945,11 @@ requiresRegisterScavenging(const MachineFunction &MF) const { return true; } +bool ARMBaseRegisterInfo:: +requiresFrameIndexScavenging(const MachineFunction &MF) const { + return ScavengeFrameIndexVals; +} + // hasReservedCallFrame - Under normal circumstances, when a frame pointer is // not required, we reserve argument space for call sites in the function // immediately on entry to the current function. This eliminates the need for @@ -1077,14 +1090,7 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, (MI.getDesc().TSFlags & ARMII::AddrModeMask) == ARMII::AddrMode4) && "This code isn't needed if offset already handled!"); - // Insert a set of r12 with the full address: r12 = sp + offset - // If the offset we have is too large to fit into the instruction, we need - // to form it with a series of ADDri's. Do this by taking 8-bit chunks - // out of 'Offset'. - unsigned ScratchReg = findScratchRegister(RS, ARM::GPRRegisterClass, AFI); - if (ScratchReg == 0) - // No register is "free". Scavenge a register. - ScratchReg = RS->scavengeRegister(ARM::GPRRegisterClass, II, SPAdj); + unsigned ScratchReg = 0; int PIdx = MI.findFirstPredOperandIdx(); ARMCC::CondCodes Pred = (PIdx == -1) ? ARMCC::AL : (ARMCC::CondCodes)MI.getOperand(PIdx).getImm(); @@ -1093,6 +1099,19 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, // Must be addrmode4. MI.getOperand(i).ChangeToRegister(FrameReg, false, false, false); else { + if (!ScavengeFrameIndexVals) { + // Insert a set of r12 with the full address: r12 = sp + offset + // If the offset we have is too large to fit into the instruction, we need + // to form it with a series of ADDri's. Do this by taking 8-bit chunks + // out of 'Offset'. + ScratchReg = findScratchRegister(RS, ARM::GPRRegisterClass, AFI); + if (ScratchReg == 0) + // No register is "free". Scavenge a register. + ScratchReg = RS->scavengeRegister(ARM::GPRRegisterClass, II, SPAdj); + } else { + ScratchReg = MF.getRegInfo().createVirtualRegister(ARM::GPRRegisterClass); + *Value = Offset; + } if (!AFI->isThumbFunction()) emitARMRegPlusImmediate(MBB, II, MI.getDebugLoc(), ScratchReg, FrameReg, Offset, Pred, PredReg, TII); @@ -1102,8 +1121,10 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, Offset, Pred, PredReg, TII); } MI.getOperand(i).ChangeToRegister(ScratchReg, false, false, true); + if (!ReuseFrameIndexVals || !ScavengeFrameIndexVals) + ScratchReg = 0; } - return 0; + return ScratchReg; } /// Move iterator pass the next bunch of callee save load / store ops for diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.h b/lib/Target/ARM/ARMBaseRegisterInfo.h index da703fb..f7d38e5 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.h +++ b/lib/Target/ARM/ARMBaseRegisterInfo.h @@ -122,6 +122,8 @@ public: virtual bool requiresRegisterScavenging(const MachineFunction &MF) const; + virtual bool requiresFrameIndexScavenging(const MachineFunction &MF) const; + virtual bool hasReservedCallFrame(MachineFunction &MF) const; virtual void eliminateCallFramePseudoInstr(MachineFunction &MF, diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp index b0bd04b..c995ff2 100644 --- a/lib/Target/ARM/ARMConstantIslandPass.cpp +++ b/lib/Target/ARM/ARMConstantIslandPass.cpp @@ -28,9 +28,11 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" +#include <algorithm> using namespace llvm; STATISTIC(NumCPEs, "Number of constpool entries"); @@ -70,6 +72,10 @@ namespace { /// to a return, unreachable, or unconditional branch). std::vector<MachineBasicBlock*> WaterList; + /// NewWaterList - The subset of WaterList that was created since the + /// previous iteration by inserting unconditional branches. + SmallSet<MachineBasicBlock*, 4> NewWaterList; + typedef std::vector<MachineBasicBlock*>::iterator water_iterator; /// CPUser - One user of a constant pool, keeping the machine instruction @@ -175,9 +181,7 @@ namespace { void AdjustBBOffsetsAfter(MachineBasicBlock *BB, int delta); bool DecrementOldEntry(unsigned CPI, MachineInstr* CPEMI); int LookForExistingCPEntry(CPUser& U, unsigned UserOffset); - bool LookForWater(CPUser&U, unsigned UserOffset, - MachineBasicBlock *&NewMBB); - MachineBasicBlock *AcceptWater(water_iterator IP); + bool LookForWater(CPUser&U, unsigned UserOffset, water_iterator &WaterIter); void CreateNewWater(unsigned CPUserIndex, unsigned UserOffset, MachineBasicBlock *&NewMBB); bool HandleConstantPoolUser(MachineFunction &MF, unsigned CPUserIndex); @@ -297,6 +301,10 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &MF) { if (CPChange && ++NoCPIters > 30) llvm_unreachable("Constant Island pass failed to converge!"); DEBUG(dumpBBs()); + + // Clear NewWaterList now. If we split a block for branches, it should + // appear as "new water" for the next iteration of constant pool placement. + NewWaterList.clear(); bool BRChange = false; for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i) @@ -629,7 +637,7 @@ void ARMConstantIslands::UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB) { /// Split the basic block containing MI into two blocks, which are joined by -/// an unconditional branch. Update datastructures and renumber blocks to +/// an unconditional branch. Update data structures and renumber blocks to /// account for this change and returns the newly created block. MachineBasicBlock *ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) { MachineBasicBlock *OrigBB = MI->getParent(); @@ -691,6 +699,7 @@ MachineBasicBlock *ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) { WaterList.insert(next(IP), NewBB); else WaterList.insert(IP, OrigBB); + NewWaterList.insert(OrigBB); // Figure out how large the first NewMBB is. (It cannot // contain a constpool_entry or tablejump.) @@ -941,30 +950,16 @@ static inline unsigned getUnconditionalBrDisp(int Opc) { return ((1<<23)-1)*4; } -/// AcceptWater - Small amount of common code factored out of the following. -/// -MachineBasicBlock *ARMConstantIslands::AcceptWater(water_iterator IP) { - DEBUG(errs() << "found water in range\n"); - MachineBasicBlock *WaterBB = *IP; - // Remove the original WaterList entry; we want subsequent - // insertions in this vicinity to go after the one we're - // about to insert. This considerably reduces the number - // of times we have to move the same CPE more than once. - WaterList.erase(IP); - // CPE goes before following block (NewMBB). - return next(MachineFunction::iterator(WaterBB)); -} - -/// LookForWater - look for an existing entry in the WaterList in which +/// LookForWater - Look for an existing entry in the WaterList in which /// we can place the CPE referenced from U so it's within range of U's MI. -/// Returns true if found, false if not. If it returns true, NewMBB +/// Returns true if found, false if not. If it returns true, WaterIter /// is set to the WaterList entry. For Thumb, prefer water that will not /// introduce padding to water that will. To ensure that this pass /// terminates, the CPE location for a particular CPUser is only allowed to /// move to a lower address, so search backward from the end of the list and /// prefer the first water that is in range. bool ARMConstantIslands::LookForWater(CPUser &U, unsigned UserOffset, - MachineBasicBlock *&NewMBB) { + water_iterator &WaterIter) { if (WaterList.empty()) return false; @@ -973,9 +968,17 @@ bool ARMConstantIslands::LookForWater(CPUser &U, unsigned UserOffset, for (water_iterator IP = prior(WaterList.end()), B = WaterList.begin();; --IP) { MachineBasicBlock* WaterBB = *IP; - // Check if water is in range and at a lower address than the current one. - if (WaterBB->getNumber() < U.HighWaterMark->getNumber() && - WaterIsInRange(UserOffset, WaterBB, U)) { + // Check if water is in range and is either at a lower address than the + // current "high water mark" or a new water block that was created since + // the previous iteration by inserting an unconditional branch. In the + // latter case, we want to allow resetting the high water mark back to + // this new water since we haven't seen it before. Inserting branches + // should be relatively uncommon and when it does happen, we want to be + // sure to take advantage of it for all the CPEs near that block, so that + // we don't insert more branches than necessary. + if (WaterIsInRange(UserOffset, WaterBB, U) && + (WaterBB->getNumber() < U.HighWaterMark->getNumber() || + NewWaterList.count(WaterBB))) { unsigned WBBId = WaterBB->getNumber(); if (isThumb && (BBOffsets[WBBId] + BBSizes[WBBId])%4 != 0) { @@ -986,7 +989,7 @@ bool ARMConstantIslands::LookForWater(CPUser &U, unsigned UserOffset, IPThatWouldPad = IP; } } else { - NewMBB = AcceptWater(IP); + WaterIter = IP; return true; } } @@ -994,7 +997,7 @@ bool ARMConstantIslands::LookForWater(CPUser &U, unsigned UserOffset, break; } if (FoundWaterThatWouldPad) { - NewMBB = AcceptWater(IPThatWouldPad); + WaterIter = IPThatWouldPad; return true; } return false; @@ -1107,7 +1110,6 @@ bool ARMConstantIslands::HandleConstantPoolUser(MachineFunction &MF, MachineInstr *CPEMI = U.CPEMI; unsigned CPI = CPEMI->getOperand(1).getIndex(); unsigned Size = CPEMI->getOperand(2).getImm(); - MachineBasicBlock *NewMBB; // Compute this only once, it's expensive. The 4 or 8 is the value the // hardware keeps in the PC. unsigned UserOffset = GetOffsetOf(UserMI) + (isThumb ? 4 : 8); @@ -1123,14 +1125,50 @@ bool ARMConstantIslands::HandleConstantPoolUser(MachineFunction &MF, unsigned ID = AFI->createConstPoolEntryUId(); // Look for water where we can place this CPE. - if (!LookForWater(U, UserOffset, NewMBB)) { + MachineBasicBlock *NewIsland = MF.CreateMachineBasicBlock(); + MachineBasicBlock *NewMBB; + water_iterator IP; + if (LookForWater(U, UserOffset, IP)) { + DEBUG(errs() << "found water in range\n"); + MachineBasicBlock *WaterBB = *IP; + + // If the original WaterList entry was "new water" on this iteration, + // propagate that to the new island. This is just keeping NewWaterList + // updated to match the WaterList, which will be updated below. + if (NewWaterList.count(WaterBB)) { + NewWaterList.erase(WaterBB); + NewWaterList.insert(NewIsland); + } + // The new CPE goes before the following block (NewMBB). + NewMBB = next(MachineFunction::iterator(WaterBB)); + + } else { // No water found. DEBUG(errs() << "No water found\n"); CreateNewWater(CPUserIndex, UserOffset, NewMBB); + + // SplitBlockBeforeInstr adds to WaterList, which is important when it is + // called while handling branches so that the water will be seen on the + // next iteration for constant pools, but in this context, we don't want + // it. Check for this so it will be removed from the WaterList. + // Also remove any entry from NewWaterList. + MachineBasicBlock *WaterBB = prior(MachineFunction::iterator(NewMBB)); + IP = std::find(WaterList.begin(), WaterList.end(), WaterBB); + if (IP != WaterList.end()) + NewWaterList.erase(WaterBB); + + // We are adding new water. Update NewWaterList. + NewWaterList.insert(NewIsland); } + // Remove the original WaterList entry; we want subsequent insertions in + // this vicinity to go after the one we're about to insert. This + // considerably reduces the number of times we have to move the same CPE + // more than once and is also important to ensure the algorithm terminates. + if (IP != WaterList.end()) + WaterList.erase(IP); + // Okay, we know we can put an island before NewMBB now, do it! - MachineBasicBlock *NewIsland = MF.CreateMachineBasicBlock(); MF.insert(NewMBB, NewIsland); // Update internal data structures to account for the newly inserted MBB. diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index c39de0a..5c1835b 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -1287,7 +1287,7 @@ SDNode *ARMDAGToDAGISel::SelectV6T2BitfieldExtractOp(SDValue Op, assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!"); unsigned Width = 32 - Srl_imm; int LSB = Srl_imm - Shl_imm; - if ((LSB + Width) > 32) + if (LSB < 0) return NULL; SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); SDValue Ops[] = { Op.getOperand(0).getOperand(0), @@ -1427,6 +1427,43 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) { } } break; + case ISD::AND: { + // (and (or x, c2), c1) and top 16-bits of c1 and c2 match, lower 16-bits + // of c1 are 0xffff, and lower 16-bit of c2 are 0. That is, the top 16-bits + // are entirely contributed by c2 and lower 16-bits are entirely contributed + // by x. That's equal to (or (and x, 0xffff), (and c1, 0xffff0000)). + // Select it to: "movt x, ((c1 & 0xffff) >> 16) + EVT VT = Op.getValueType(); + if (VT != MVT::i32) + break; + unsigned Opc = (Subtarget->isThumb() && Subtarget->hasThumb2()) + ? ARM::t2MOVTi16 + : (Subtarget->hasV6T2Ops() ? ARM::MOVTi16 : 0); + if (!Opc) + break; + SDValue N0 = Op.getOperand(0), N1 = Op.getOperand(1); + ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1); + if (!N1C) + break; + if (N0.getOpcode() == ISD::OR && N0.getNode()->hasOneUse()) { + SDValue N2 = N0.getOperand(1); + ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2); + if (!N2C) + break; + unsigned N1CVal = N1C->getZExtValue(); + unsigned N2CVal = N2C->getZExtValue(); + if ((N1CVal & 0xffff0000U) == (N2CVal & 0xffff0000U) && + (N1CVal & 0xffffU) == 0xffffU && + (N2CVal & 0xffffU) == 0x0U) { + SDValue Imm16 = CurDAG->getTargetConstant((N2CVal & 0xFFFF0000U) >> 16, + MVT::i32); + SDValue Ops[] = { N0.getOperand(0), Imm16, + getAL(CurDAG), CurDAG->getRegister(0, MVT::i32) }; + return CurDAG->getMachineNode(Opc, dl, VT, Ops, 4); + } + } + break; + } case ARMISD::FMRRD: return CurDAG->getMachineNode(ARM::FMRRD, dl, MVT::i32, MVT::i32, Op.getOperand(0), getAL(CurDAG), diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 426cecb..6a264fd 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -25,9 +25,10 @@ #include "llvm/CallingConv.h" #include "llvm/Constants.h" #include "llvm/Function.h" +#include "llvm/GlobalValue.h" #include "llvm/Instruction.h" #include "llvm/Intrinsics.h" -#include "llvm/GlobalValue.h" +#include "llvm/Type.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -2360,8 +2361,11 @@ static bool isVREVMask(const SmallVectorImpl<int> &M, EVT VT, assert((BlockSize==16 || BlockSize==32 || BlockSize==64) && "Only possible block sizes for VREV are: 16, 32, 64"); - unsigned NumElts = VT.getVectorNumElements(); unsigned EltSz = VT.getVectorElementType().getSizeInBits(); + if (EltSz == 64) + return false; + + unsigned NumElts = VT.getVectorNumElements(); unsigned BlockElts = M[0] + 1; if (BlockSize <= EltSz || BlockSize != BlockElts * EltSz) @@ -2378,6 +2382,10 @@ static bool isVREVMask(const SmallVectorImpl<int> &M, EVT VT, static bool isVTRNMask(const SmallVectorImpl<int> &M, EVT VT, unsigned &WhichResult) { + unsigned EltSz = VT.getVectorElementType().getSizeInBits(); + if (EltSz == 64) + return false; + unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i < NumElts; i += 2) { @@ -2390,6 +2398,10 @@ static bool isVTRNMask(const SmallVectorImpl<int> &M, EVT VT, static bool isVUZPMask(const SmallVectorImpl<int> &M, EVT VT, unsigned &WhichResult) { + unsigned EltSz = VT.getVectorElementType().getSizeInBits(); + if (EltSz == 64) + return false; + unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i != NumElts; ++i) { @@ -2398,7 +2410,7 @@ static bool isVUZPMask(const SmallVectorImpl<int> &M, EVT VT, } // VUZP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. - if (VT.is64BitVector() && VT.getVectorElementType().getSizeInBits() == 32) + if (VT.is64BitVector() && EltSz == 32) return false; return true; @@ -2406,6 +2418,10 @@ static bool isVUZPMask(const SmallVectorImpl<int> &M, EVT VT, static bool isVZIPMask(const SmallVectorImpl<int> &M, EVT VT, unsigned &WhichResult) { + unsigned EltSz = VT.getVectorElementType().getSizeInBits(); + if (EltSz == 64) + return false; + unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); unsigned Idx = WhichResult * NumElts / 2; @@ -2417,7 +2433,7 @@ static bool isVZIPMask(const SmallVectorImpl<int> &M, EVT VT, } // VZIP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. - if (VT.is64BitVector() && VT.getVectorElementType().getSizeInBits() == 32) + if (VT.is64BitVector() && EltSz == 32) return false; return true; @@ -2695,18 +2711,10 @@ static SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); SDValue Vec = Op.getOperand(0); SDValue Lane = Op.getOperand(1); - - // FIXME: This is invalid for 8 and 16-bit elements - the information about - // sign / zero extension is lost! - Op = DAG.getNode(ARMISD::VGETLANEu, dl, MVT::i32, Vec, Lane); - Op = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Op, DAG.getValueType(VT)); - - if (VT.bitsLT(MVT::i32)) - Op = DAG.getNode(ISD::TRUNCATE, dl, VT, Op); - else if (VT.bitsGT(MVT::i32)) - Op = DAG.getNode(ISD::ANY_EXTEND, dl, VT, Op); - - return Op; + assert(VT == MVT::i32 && + Vec.getValueType().getVectorElementType().getSizeInBits() < 32 && + "unexpected type for custom-lowering vector extract"); + return DAG.getNode(ARMISD::VGETLANEu, dl, MVT::i32, Vec, Lane); } static SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) { @@ -3029,7 +3037,6 @@ static SDValue PerformSUBCombine(SDNode *N, return SDValue(); } - /// PerformFMRRDCombine - Target-specific dag combine xforms for ARMISD::FMRRD. static SDValue PerformFMRRDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 3d19f23..8225fd7 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -1220,6 +1220,10 @@ class NLdSt<bit op23, bits<2> op21_20, bits<4> op11_8, bits<4> op7_4, string asm, string cstr, list<dag> pattern> : NeonI<oops, iops, AddrMode6, IndexModeNone, itin, asm, cstr, pattern> { let Inst{31-24} = 0b11110100; + let Inst{23} = op23; + let Inst{21-20} = op21_20; + let Inst{11-8} = op11_8; + let Inst{7-4} = op7_4; } class NDataI<dag oops, dag iops, InstrItinClass itin, @@ -1258,15 +1262,26 @@ class N2V<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, let Inst{4} = op4; } +// NEON Vector Duplicate (scalar). +// Inst{19-16} is specified by subclasses. +class N2VDup<bits<2> op24_23, bits<2> op21_20, bits<5> op11_7, bit op6, bit op4, + dag oops, dag iops, InstrItinClass itin, + string asm, string cstr, list<dag> pattern> + : NDataI<oops, iops, itin, asm, cstr, pattern> { + let Inst{24-23} = op24_23; + let Inst{21-20} = op21_20; + let Inst{11-7} = op11_7; + let Inst{6} = op6; + let Inst{4} = op4; +} + // NEON 2 vector register with immediate. -class N2VImm<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op6, bit op4, +class N2VImm<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4, dag oops, dag iops, InstrItinClass itin, string asm, string cstr, list<dag> pattern> : NDataI<oops, iops, itin, asm, cstr, pattern> { let Inst{24} = op24; let Inst{23} = op23; - let Inst{21-16} = op21_16; let Inst{11-8} = op11_8; let Inst{7} = op7; let Inst{6} = op6; @@ -1286,6 +1301,20 @@ class N3V<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op6, bit op4, let Inst{4} = op4; } +// NEON 3 vector register with immediate. This is only used for VEXT where +// op11_8 represents the starting byte index of the extracted result in the +// concatenation of the operands and is left unspecified. +class N3VImm<bit op24, bit op23, bits<2> op21_20, bit op6, bit op4, + dag oops, dag iops, InstrItinClass itin, + string asm, string cstr, list<dag> pattern> + : NDataI<oops, iops, itin, asm, cstr, pattern> { + let Inst{24} = op24; + let Inst{23} = op23; + let Inst{21-20} = op21_20; + let Inst{6} = op6; + let Inst{4} = op4; +} + // NEON VMOVs between scalar and core registers. class NVLaneOp<bits<8> opcod1, bits<4> opcod2, bits<2> opcod3, dag oops, dag iops, Format f, InstrItinClass itin, diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp index 4c92891..dd4123b 100644 --- a/lib/Target/ARM/ARMInstrInfo.cpp +++ b/lib/Target/ARM/ARMInstrInfo.cpp @@ -22,7 +22,6 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/MC/MCAsmInfo.h" -#include "llvm/Support/CommandLine.h" using namespace llvm; ARMInstrInfo::ARMInstrInfo(const ARMSubtarget &STI) diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 6ec78bc..384b98c 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -980,6 +980,9 @@ def MOVTi16 : AI1<0b1010, (outs GPR:$dst), (ins GPR:$src, i32imm:$imm), let Inst{25} = 1; } +def : ARMPat<(or GPR:$src, 0xffff0000), (MOVTi16 GPR:$src, 0xffff)>, + Requires<[IsARM, HasV6T2]>; + let Uses = [CPSR] in def MOVrx : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo, IIC_iMOVsi, "mov", " $dst, $src, rrx", @@ -1580,10 +1583,17 @@ def : ARMPat<(or GPR:$LHS, so_imm2part:$RHS), def : ARMPat<(xor GPR:$LHS, so_imm2part:$RHS), (EORri (EORri GPR:$LHS, (so_imm2part_1 imm:$RHS)), (so_imm2part_2 imm:$RHS))>; +def : ARMPat<(add GPR:$LHS, so_imm2part:$RHS), + (ADDri (ADDri GPR:$LHS, (so_imm2part_1 imm:$RHS)), + (so_imm2part_2 imm:$RHS))>; +def : ARMPat<(sub GPR:$LHS, so_imm2part:$RHS), + (SUBri (SUBri GPR:$LHS, (so_imm2part_1 imm:$RHS)), + (so_imm2part_2 imm:$RHS))>; // 32-bit immediate using movw + movt. -// This is a single pseudo instruction to make it re-materializable. Remove -// when we can do generalized remat. +// This is a single pseudo instruction, the benefit is that it can be remat'd +// as a single unit instead of having to handle reg inputs. +// FIXME: Remove this when we can do generalized remat. let isReMaterializable = 1 in def MOVi32imm : AI1x2<(outs GPR:$dst), (ins i32imm:$src), Pseudo, IIC_iMOVi, "movw", " $dst, ${src:lo16}\n\tmovt${p} $dst, ${src:hi16}", diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td index b34aff7..822950c 100644 --- a/lib/Target/ARM/ARMInstrNEON.td +++ b/lib/Target/ARM/ARMInstrNEON.td @@ -456,17 +456,17 @@ class VST2LN<bits<4> op11_8, string OpcodeStr> !strconcat(OpcodeStr, "\t\\{$src1[$lane],$src2[$lane]\\}, $addr"), "", []>; -def VST2LNd8 : VST2LN<0b0000, "vst2.8">; -def VST2LNd16 : VST2LN<0b0100, "vst2.16">; -def VST2LNd32 : VST2LN<0b1000, "vst2.32">; +def VST2LNd8 : VST2LN<0b0001, "vst2.8">; +def VST2LNd16 : VST2LN<0b0101, "vst2.16">; +def VST2LNd32 : VST2LN<0b1001, "vst2.32">; // vst2 to double-spaced even registers. -def VST2LNq16a: VST2LN<0b0100, "vst2.16">; -def VST2LNq32a: VST2LN<0b1000, "vst2.32">; +def VST2LNq16a: VST2LN<0b0101, "vst2.16">; +def VST2LNq32a: VST2LN<0b1001, "vst2.32">; // vst2 to double-spaced odd registers. -def VST2LNq16b: VST2LN<0b0100, "vst2.16">; -def VST2LNq32b: VST2LN<0b1000, "vst2.32">; +def VST2LNq16b: VST2LN<0b0101, "vst2.16">; +def VST2LNq32b: VST2LN<0b1001, "vst2.32">; // VST3LN : Vector Store (single 3-element structure from one lane) class VST3LN<bits<4> op11_8, string OpcodeStr> @@ -623,12 +623,12 @@ class N2VNInt<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18, (ins QPR:$src), itin, !strconcat(OpcodeStr, "\t$dst, $src"), "", [(set DPR:$dst, (TyD (IntOp (TyQ QPR:$src))))]>; -// Long 2-register intrinsics. (This is currently only used for VMOVL and is -// derived from N2VImm instead of N2V because of the way the size is encoded.) -class N2VLInt<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op6, bit op4, InstrItinClass itin, string OpcodeStr, +// Long 2-register intrinsics (currently only used for VMOVL). +class N2VLInt<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18, + bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, ValueType TyQ, ValueType TyD, Intrinsic IntOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, op6, op4, (outs QPR:$dst), + : N2V<op24_23, op21_20, op19_18, op17_16, op11_7, op6, op4, (outs QPR:$dst), (ins DPR:$src), itin, !strconcat(OpcodeStr, "\t$dst, $src"), "", [(set QPR:$dst, (TyQ (IntOp (TyD DPR:$src))))]>; @@ -1016,36 +1016,33 @@ class N2VQPLInt2<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18, // Shift by immediate, // both double- and quad-register. -class N2VDSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, InstrItinClass itin, string OpcodeStr, - ValueType Ty, SDNode OpNode> - : N2VImm<op24, op23, op21_16, op11_8, op7, 0, op4, +class N2VDSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + InstrItinClass itin, string OpcodeStr, ValueType Ty, SDNode OpNode> + : N2VImm<op24, op23, op11_8, op7, 0, op4, (outs DPR:$dst), (ins DPR:$src, i32imm:$SIMM), itin, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set DPR:$dst, (Ty (OpNode (Ty DPR:$src), (i32 imm:$SIMM))))]>; -class N2VQSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, InstrItinClass itin, string OpcodeStr, - ValueType Ty, SDNode OpNode> - : N2VImm<op24, op23, op21_16, op11_8, op7, 1, op4, +class N2VQSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + InstrItinClass itin, string OpcodeStr, ValueType Ty, SDNode OpNode> + : N2VImm<op24, op23, op11_8, op7, 1, op4, (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), itin, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>; // Long shift by immediate. -class N2VLSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op6, bit op4, string OpcodeStr, ValueType ResTy, - ValueType OpTy, SDNode OpNode> - : N2VImm<op24, op23, op21_16, op11_8, op7, op6, op4, +class N2VLSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4, + string OpcodeStr, ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VImm<op24, op23, op11_8, op7, op6, op4, (outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src), (i32 imm:$SIMM))))]>; // Narrow shift by immediate. -class N2VNSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op6, bit op4, InstrItinClass itin, string OpcodeStr, +class N2VNSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VImm<op24, op23, op21_16, op11_8, op7, op6, op4, + : N2VImm<op24, op23, op11_8, op7, op6, op4, (outs DPR:$dst), (ins QPR:$src, i32imm:$SIMM), itin, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set DPR:$dst, (ResTy (OpNode (OpTy QPR:$src), @@ -1053,53 +1050,49 @@ class N2VNSh<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, // Shift right by immediate and accumulate, // both double- and quad-register. -class N2VDShAdd<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType Ty, SDNode ShOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 0, op4, - (outs DPR:$dst), (ins DPR:$src1, DPR:$src2, i32imm:$SIMM), - IIC_VPALiD, +class N2VDShAdd<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType Ty, SDNode ShOp> + : N2VImm<op24, op23, op11_8, op7, 0, op4, (outs DPR:$dst), + (ins DPR:$src1, DPR:$src2, i32imm:$SIMM), IIC_VPALiD, !strconcat(OpcodeStr, "\t$dst, $src2, $SIMM"), "$src1 = $dst", [(set DPR:$dst, (Ty (add DPR:$src1, (Ty (ShOp DPR:$src2, (i32 imm:$SIMM))))))]>; -class N2VQShAdd<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType Ty, SDNode ShOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 1, op4, - (outs QPR:$dst), (ins QPR:$src1, QPR:$src2, i32imm:$SIMM), - IIC_VPALiD, +class N2VQShAdd<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType Ty, SDNode ShOp> + : N2VImm<op24, op23, op11_8, op7, 1, op4, (outs QPR:$dst), + (ins QPR:$src1, QPR:$src2, i32imm:$SIMM), IIC_VPALiD, !strconcat(OpcodeStr, "\t$dst, $src2, $SIMM"), "$src1 = $dst", [(set QPR:$dst, (Ty (add QPR:$src1, (Ty (ShOp QPR:$src2, (i32 imm:$SIMM))))))]>; // Shift by immediate and insert, // both double- and quad-register. -class N2VDShIns<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType Ty, SDNode ShOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 0, op4, - (outs DPR:$dst), (ins DPR:$src1, DPR:$src2, i32imm:$SIMM), - IIC_VSHLiD, +class N2VDShIns<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType Ty, SDNode ShOp> + : N2VImm<op24, op23, op11_8, op7, 0, op4, (outs DPR:$dst), + (ins DPR:$src1, DPR:$src2, i32imm:$SIMM), IIC_VSHLiD, !strconcat(OpcodeStr, "\t$dst, $src2, $SIMM"), "$src1 = $dst", [(set DPR:$dst, (Ty (ShOp DPR:$src1, DPR:$src2, (i32 imm:$SIMM))))]>; -class N2VQShIns<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType Ty, SDNode ShOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 1, op4, - (outs QPR:$dst), (ins QPR:$src1, QPR:$src2, i32imm:$SIMM), - IIC_VSHLiQ, +class N2VQShIns<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType Ty, SDNode ShOp> + : N2VImm<op24, op23, op11_8, op7, 1, op4, (outs QPR:$dst), + (ins QPR:$src1, QPR:$src2, i32imm:$SIMM), IIC_VSHLiQ, !strconcat(OpcodeStr, "\t$dst, $src2, $SIMM"), "$src1 = $dst", [(set QPR:$dst, (Ty (ShOp QPR:$src1, QPR:$src2, (i32 imm:$SIMM))))]>; // Convert, with fractional bits immediate, // both double- and quad-register. -class N2VCvtD<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType ResTy, ValueType OpTy, +class N2VCvtD<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 0, op4, + : N2VImm<op24, op23, op11_8, op7, 0, op4, (outs DPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VUNAD, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set DPR:$dst, (ResTy (IntOp (OpTy DPR:$src), (i32 imm:$SIMM))))]>; -class N2VCvtQ<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, - bit op4, string OpcodeStr, ValueType ResTy, ValueType OpTy, +class N2VCvtQ<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4, + string OpcodeStr, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> - : N2VImm<op24, op23, op21_16, op11_8, op7, 1, op4, + : N2VImm<op24, op23, op11_8, op7, 1, op4, (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), IIC_VUNAQ, !strconcat(OpcodeStr, "\t$dst, $src, $SIMM"), "", [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src), (i32 imm:$SIMM))))]>; @@ -1175,14 +1168,14 @@ multiclass N2VNInt_HSD<bits<2> op24_23, bits<2> op21_20, bits<2> op17_16, // Neon Lengthening 2-register vector intrinsic (currently specific to VMOVL). // source operand element sizes of 16, 32 and 64 bits: -multiclass N2VLInt_QHS<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, - bit op4, string OpcodeStr, Intrinsic IntOp> { - def v8i16 : N2VLInt<op24, op23, 0b001000, op11_8, op7, op6, op4, - IIC_VQUNAiD, !strconcat(OpcodeStr, "8"), v8i16, v8i8, IntOp>; - def v4i32 : N2VLInt<op24, op23, 0b010000, op11_8, op7, op6, op4, - IIC_VQUNAiD, !strconcat(OpcodeStr, "16"), v4i32, v4i16, IntOp>; - def v2i64 : N2VLInt<op24, op23, 0b100000, op11_8, op7, op6, op4, - IIC_VQUNAiD, !strconcat(OpcodeStr, "32"), v2i64, v2i32, IntOp>; +multiclass N2VLInt_QHS<bits<2> op24_23, bits<5> op11_7, bit op6, bit op4, + string OpcodeStr, Intrinsic IntOp> { + def v8i16 : N2VLInt<op24_23, 0b00, 0b10, 0b00, op11_7, op6, op4, IIC_VQUNAiD, + !strconcat(OpcodeStr, "8"), v8i16, v8i8, IntOp>; + def v4i32 : N2VLInt<op24_23, 0b01, 0b00, 0b00, op11_7, op6, op4, IIC_VQUNAiD, + !strconcat(OpcodeStr, "16"), v4i32, v4i16, IntOp>; + def v2i64 : N2VLInt<op24_23, 0b10, 0b00, 0b00, op11_7, op6, op4, IIC_VQUNAiD, + !strconcat(OpcodeStr, "32"), v2i64, v2i32, IntOp>; } @@ -1381,7 +1374,7 @@ multiclass N3VLInt3SL_HS<bit op24, bits<4> op11_8, multiclass N3VLInt3_QHS<bit op24, bit op23, bits<4> op11_8, bit op4, string OpcodeStr, Intrinsic IntOp> : N3VLInt3_HS<op24, op23, op11_8, op4, OpcodeStr, IntOp> { - def v8i16 : N3VLInt3<op24, op23, 0b01, op11_8, op4, IIC_VMACi16D, + def v8i16 : N3VLInt3<op24, op23, 0b00, op11_8, op4, IIC_VMACi16D, !strconcat(OpcodeStr, "8"), v8i16, v8i8, IntOp>; } @@ -1461,24 +1454,38 @@ multiclass N2VPLInt2_QHS<bits<2> op24_23, bits<2> op21_20, bits<2> op17_16, multiclass N2VSh_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, SDNode OpNode> { // 64-bit vector types. - def v8i8 : N2VDSh<op24, op23, 0b001000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "8"), v8i8, OpNode>; - def v4i16 : N2VDSh<op24, op23, 0b010000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "16"), v4i16, OpNode>; - def v2i32 : N2VDSh<op24, op23, 0b100000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "32"), v2i32, OpNode>; - def v1i64 : N2VDSh<op24, op23, 0b000000, op11_8, 1, op4, itin, + def v8i8 : N2VDSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "8"), v8i8, OpNode> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "16"), v4i16, OpNode> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "32"), v2i32, OpNode> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDSh<op24, op23, op11_8, 1, op4, itin, !strconcat(OpcodeStr, "64"), v1i64, OpNode>; + // imm6 = xxxxxx // 128-bit vector types. - def v16i8 : N2VQSh<op24, op23, 0b001000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "8"), v16i8, OpNode>; - def v8i16 : N2VQSh<op24, op23, 0b010000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "16"), v8i16, OpNode>; - def v4i32 : N2VQSh<op24, op23, 0b100000, op11_8, 0, op4, itin, - !strconcat(OpcodeStr, "32"), v4i32, OpNode>; - def v2i64 : N2VQSh<op24, op23, 0b000000, op11_8, 1, op4, itin, + def v16i8 : N2VQSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "8"), v16i8, OpNode> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "16"), v8i16, OpNode> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQSh<op24, op23, op11_8, 0, op4, itin, + !strconcat(OpcodeStr, "32"), v4i32, OpNode> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQSh<op24, op23, op11_8, 1, op4, itin, !strconcat(OpcodeStr, "64"), v2i64, OpNode>; + // imm6 = xxxxxx } @@ -1487,24 +1494,38 @@ multiclass N2VSh_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, multiclass N2VShAdd_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, string OpcodeStr, SDNode ShOp> { // 64-bit vector types. - def v8i8 : N2VDShAdd<op24, op23, 0b001000, op11_8, 0, op4, - !strconcat(OpcodeStr, "8"), v8i8, ShOp>; - def v4i16 : N2VDShAdd<op24, op23, 0b010000, op11_8, 0, op4, - !strconcat(OpcodeStr, "16"), v4i16, ShOp>; - def v2i32 : N2VDShAdd<op24, op23, 0b100000, op11_8, 0, op4, - !strconcat(OpcodeStr, "32"), v2i32, ShOp>; - def v1i64 : N2VDShAdd<op24, op23, 0b000000, op11_8, 1, op4, + def v8i8 : N2VDShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "8"), v8i8, ShOp> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "16"), v4i16, ShOp> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "32"), v2i32, ShOp> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDShAdd<op24, op23, op11_8, 1, op4, !strconcat(OpcodeStr, "64"), v1i64, ShOp>; + // imm6 = xxxxxx // 128-bit vector types. - def v16i8 : N2VQShAdd<op24, op23, 0b001000, op11_8, 0, op4, - !strconcat(OpcodeStr, "8"), v16i8, ShOp>; - def v8i16 : N2VQShAdd<op24, op23, 0b010000, op11_8, 0, op4, - !strconcat(OpcodeStr, "16"), v8i16, ShOp>; - def v4i32 : N2VQShAdd<op24, op23, 0b100000, op11_8, 0, op4, - !strconcat(OpcodeStr, "32"), v4i32, ShOp>; - def v2i64 : N2VQShAdd<op24, op23, 0b000000, op11_8, 1, op4, + def v16i8 : N2VQShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "8"), v16i8, ShOp> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "16"), v8i16, ShOp> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQShAdd<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "32"), v4i32, ShOp> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQShAdd<op24, op23, op11_8, 1, op4, !strconcat(OpcodeStr, "64"), v2i64, ShOp>; + // imm6 = xxxxxx } @@ -1513,24 +1534,75 @@ multiclass N2VShAdd_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, multiclass N2VShIns_QHSD<bit op24, bit op23, bits<4> op11_8, bit op4, string OpcodeStr, SDNode ShOp> { // 64-bit vector types. - def v8i8 : N2VDShIns<op24, op23, 0b001000, op11_8, 0, op4, - !strconcat(OpcodeStr, "8"), v8i8, ShOp>; - def v4i16 : N2VDShIns<op24, op23, 0b010000, op11_8, 0, op4, - !strconcat(OpcodeStr, "16"), v4i16, ShOp>; - def v2i32 : N2VDShIns<op24, op23, 0b100000, op11_8, 0, op4, - !strconcat(OpcodeStr, "32"), v2i32, ShOp>; - def v1i64 : N2VDShIns<op24, op23, 0b000000, op11_8, 1, op4, + def v8i8 : N2VDShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "8"), v8i8, ShOp> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "16"), v4i16, ShOp> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "32"), v2i32, ShOp> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDShIns<op24, op23, op11_8, 1, op4, !strconcat(OpcodeStr, "64"), v1i64, ShOp>; + // imm6 = xxxxxx // 128-bit vector types. - def v16i8 : N2VQShIns<op24, op23, 0b001000, op11_8, 0, op4, - !strconcat(OpcodeStr, "8"), v16i8, ShOp>; - def v8i16 : N2VQShIns<op24, op23, 0b010000, op11_8, 0, op4, - !strconcat(OpcodeStr, "16"), v8i16, ShOp>; - def v4i32 : N2VQShIns<op24, op23, 0b100000, op11_8, 0, op4, - !strconcat(OpcodeStr, "32"), v4i32, ShOp>; - def v2i64 : N2VQShIns<op24, op23, 0b000000, op11_8, 1, op4, + def v16i8 : N2VQShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "8"), v16i8, ShOp> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "16"), v8i16, ShOp> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQShIns<op24, op23, op11_8, 0, op4, + !strconcat(OpcodeStr, "32"), v4i32, ShOp> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQShIns<op24, op23, op11_8, 1, op4, !strconcat(OpcodeStr, "64"), v2i64, ShOp>; + // imm6 = xxxxxx +} + +// Neon Shift Long operations, +// element sizes of 8, 16, 32 bits: +multiclass N2VLSh_QHS<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, + bit op4, string OpcodeStr, SDNode OpNode> { + def v8i16 : N2VLSh<op24, op23, op11_8, op7, op6, op4, + !strconcat(OpcodeStr, "8"), v8i16, v8i8, OpNode> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i32 : N2VLSh<op24, op23, op11_8, op7, op6, op4, + !strconcat(OpcodeStr, "16"), v4i32, v4i16, OpNode> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i64 : N2VLSh<op24, op23, op11_8, op7, op6, op4, + !strconcat(OpcodeStr, "32"), v2i64, v2i32, OpNode> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } +} + +// Neon Shift Narrow operations, +// element sizes of 16, 32, 64 bits: +multiclass N2VNSh_HSD<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, + bit op4, InstrItinClass itin, string OpcodeStr, + SDNode OpNode> { + def v8i8 : N2VNSh<op24, op23, op11_8, op7, op6, op4, itin, + !strconcat(OpcodeStr, "16"), v8i8, v8i16, OpNode> { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VNSh<op24, op23, op11_8, op7, op6, op4, itin, + !strconcat(OpcodeStr, "32"), v4i16, v4i32, OpNode> { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VNSh<op24, op23, op11_8, op7, op6, op4, itin, + !strconcat(OpcodeStr, "64"), v2i32, v2i64, OpNode> { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } } //===----------------------------------------------------------------------===// @@ -1903,8 +1975,8 @@ defm VABDLs : N3VLInt_QHS<0,1,0b0111,0, IIC_VBINi4Q, "vabdl.s", int_arm_neon_v defm VABDLu : N3VLInt_QHS<1,1,0b0111,0, IIC_VBINi4Q, "vabdl.u", int_arm_neon_vabdlu, 0>; // VABA : Vector Absolute Difference and Accumulate -defm VABAs : N3VInt3_QHS<0,1,0b0101,0, "vaba.s", int_arm_neon_vabas>; -defm VABAu : N3VInt3_QHS<1,1,0b0101,0, "vaba.u", int_arm_neon_vabau>; +defm VABAs : N3VInt3_QHS<0,0,0b0111,1, "vaba.s", int_arm_neon_vabas>; +defm VABAu : N3VInt3_QHS<1,0,0b0111,1, "vaba.u", int_arm_neon_vabau>; // VABAL : Vector Absolute Difference and Accumulate Long (Q += | D - D |) defm VABALs : N3VLInt3_QHS<0,1,0b0101,0, "vabal.s", int_arm_neon_vabals>; @@ -2044,34 +2116,25 @@ defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr.s", NEONvshrs>; defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr.u", NEONvshru>; // VSHLL : Vector Shift Left Long -def VSHLLs8 : N2VLSh<0, 1, 0b001000, 0b1010, 0, 0, 1, "vshll.s8", - v8i16, v8i8, NEONvshlls>; -def VSHLLs16 : N2VLSh<0, 1, 0b010000, 0b1010, 0, 0, 1, "vshll.s16", - v4i32, v4i16, NEONvshlls>; -def VSHLLs32 : N2VLSh<0, 1, 0b100000, 0b1010, 0, 0, 1, "vshll.s32", - v2i64, v2i32, NEONvshlls>; -def VSHLLu8 : N2VLSh<1, 1, 0b001000, 0b1010, 0, 0, 1, "vshll.u8", - v8i16, v8i8, NEONvshllu>; -def VSHLLu16 : N2VLSh<1, 1, 0b010000, 0b1010, 0, 0, 1, "vshll.u16", - v4i32, v4i16, NEONvshllu>; -def VSHLLu32 : N2VLSh<1, 1, 0b100000, 0b1010, 0, 0, 1, "vshll.u32", - v2i64, v2i32, NEONvshllu>; +defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll.s", NEONvshlls>; +defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll.u", NEONvshllu>; // VSHLL : Vector Shift Left Long (with maximum shift count) -def VSHLLi8 : N2VLSh<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll.i8", - v8i16, v8i8, NEONvshlli>; -def VSHLLi16 : N2VLSh<1, 1, 0b110110, 0b0011, 0, 0, 0, "vshll.i16", - v4i32, v4i16, NEONvshlli>; -def VSHLLi32 : N2VLSh<1, 1, 0b111010, 0b0011, 0, 0, 0, "vshll.i32", - v2i64, v2i32, NEONvshlli>; +class N2VLShMax<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7, + bit op6, bit op4, string OpcodeStr, ValueType ResTy, + ValueType OpTy, SDNode OpNode> + : N2VLSh<op24, op23, op11_8, op7, op6, op4, OpcodeStr, ResTy, OpTy, OpNode> { + let Inst{21-16} = op21_16; +} +def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll.i8", + v8i16, v8i8, NEONvshlli>; +def VSHLLi16 : N2VLShMax<1, 1, 0b110110, 0b0011, 0, 0, 0, "vshll.i16", + v4i32, v4i16, NEONvshlli>; +def VSHLLi32 : N2VLShMax<1, 1, 0b111010, 0b0011, 0, 0, 0, "vshll.i32", + v2i64, v2i32, NEONvshlli>; // VSHRN : Vector Shift Right and Narrow -def VSHRN16 : N2VNSh<0, 1, 0b001000, 0b1000, 0, 0, 1, - IIC_VSHLiD, "vshrn.i16", v8i8, v8i16, NEONvshrn>; -def VSHRN32 : N2VNSh<0, 1, 0b010000, 0b1000, 0, 0, 1, - IIC_VSHLiD, "vshrn.i32", v4i16, v4i32, NEONvshrn>; -def VSHRN64 : N2VNSh<0, 1, 0b100000, 0b1000, 0, 0, 1, - IIC_VSHLiD, "vshrn.i64", v2i32, v2i64, NEONvshrn>; +defm VSHRN : N2VNSh_HSD<0,1,0b1000,0,0,1, IIC_VSHLiD, "vshrn.i", NEONvshrn>; // VRSHL : Vector Rounding Shift defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, @@ -2083,12 +2146,8 @@ defm VRSHRs : N2VSh_QHSD<0, 1, 0b0010, 1, IIC_VSHLi4D, "vrshr.s", NEONvrshrs>; defm VRSHRu : N2VSh_QHSD<1, 1, 0b0010, 1, IIC_VSHLi4D, "vrshr.u", NEONvrshru>; // VRSHRN : Vector Rounding Shift Right and Narrow -def VRSHRN16 : N2VNSh<0, 1, 0b001000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vrshrn.i16", v8i8, v8i16, NEONvrshrn>; -def VRSHRN32 : N2VNSh<0, 1, 0b010000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vrshrn.i32", v4i16, v4i32, NEONvrshrn>; -def VRSHRN64 : N2VNSh<0, 1, 0b100000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vrshrn.i64", v2i32, v2i64, NEONvrshrn>; +defm VRSHRN : N2VNSh_HSD<0, 1, 0b1000, 0, 1, 1, IIC_VSHLi4D, "vrshrn.i", + NEONvrshrn>; // VQSHL : Vector Saturating Shift defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, @@ -2102,26 +2161,14 @@ defm VQSHLui : N2VSh_QHSD<1, 1, 0b0111, 1, IIC_VSHLi4D, "vqshl.u", NEONvqshlu>; defm VQSHLsu : N2VSh_QHSD<1, 1, 0b0110, 1, IIC_VSHLi4D, "vqshlu.s", NEONvqshlsu>; // VQSHRN : Vector Saturating Shift Right and Narrow -def VQSHRNs16 : N2VNSh<0, 1, 0b001000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.s16", v8i8, v8i16, NEONvqshrns>; -def VQSHRNs32 : N2VNSh<0, 1, 0b010000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.s32", v4i16, v4i32, NEONvqshrns>; -def VQSHRNs64 : N2VNSh<0, 1, 0b100000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.s64", v2i32, v2i64, NEONvqshrns>; -def VQSHRNu16 : N2VNSh<1, 1, 0b001000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.u16", v8i8, v8i16, NEONvqshrnu>; -def VQSHRNu32 : N2VNSh<1, 1, 0b010000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.u32", v4i16, v4i32, NEONvqshrnu>; -def VQSHRNu64 : N2VNSh<1, 1, 0b100000, 0b1001, 0, 0, 1, - IIC_VSHLi4D, "vqshrn.u64", v2i32, v2i64, NEONvqshrnu>; +defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn.s", + NEONvqshrns>; +defm VQSHRNu : N2VNSh_HSD<1, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn.u", + NEONvqshrnu>; // VQSHRUN : Vector Saturating Shift Right and Narrow (Unsigned) -def VQSHRUN16 : N2VNSh<1, 1, 0b001000, 0b1000, 0, 0, 1, - IIC_VSHLi4D, "vqshrun.s16", v8i8, v8i16, NEONvqshrnsu>; -def VQSHRUN32 : N2VNSh<1, 1, 0b010000, 0b1000, 0, 0, 1, - IIC_VSHLi4D, "vqshrun.s32", v4i16, v4i32, NEONvqshrnsu>; -def VQSHRUN64 : N2VNSh<1, 1, 0b100000, 0b1000, 0, 0, 1, - IIC_VSHLi4D, "vqshrun.s64", v2i32, v2i64, NEONvqshrnsu>; +defm VQSHRUN : N2VNSh_HSD<1, 1, 0b1000, 0, 0, 1, IIC_VSHLi4D, "vqshrun.s", + NEONvqshrnsu>; // VQRSHL : Vector Saturating Rounding Shift defm VQRSHLs : N3VInt_QHSD<0, 0, 0b0101, 1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, @@ -2130,26 +2177,14 @@ defm VQRSHLu : N3VInt_QHSD<1, 0, 0b0101, 1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi IIC_VSHLi4Q, "vqrshl.u", int_arm_neon_vqrshiftu, 0>; // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow -def VQRSHRNs16: N2VNSh<0, 1, 0b001000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.s16", v8i8, v8i16, NEONvqrshrns>; -def VQRSHRNs32: N2VNSh<0, 1, 0b010000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.s32", v4i16, v4i32, NEONvqrshrns>; -def VQRSHRNs64: N2VNSh<0, 1, 0b100000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.s64", v2i32, v2i64, NEONvqrshrns>; -def VQRSHRNu16: N2VNSh<1, 1, 0b001000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.u16", v8i8, v8i16, NEONvqrshrnu>; -def VQRSHRNu32: N2VNSh<1, 1, 0b010000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.u32", v4i16, v4i32, NEONvqrshrnu>; -def VQRSHRNu64: N2VNSh<1, 1, 0b100000, 0b1001, 0, 1, 1, - IIC_VSHLi4D, "vqrshrn.u64", v2i32, v2i64, NEONvqrshrnu>; +defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn.s", + NEONvqrshrns>; +defm VQRSHRNu : N2VNSh_HSD<1, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn.u", + NEONvqrshrnu>; // VQRSHRUN : Vector Saturating Rounding Shift Right and Narrow (Unsigned) -def VQRSHRUN16: N2VNSh<1, 1, 0b001000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vqrshrun.s16", v8i8, v8i16, NEONvqrshrnsu>; -def VQRSHRUN32: N2VNSh<1, 1, 0b010000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vqrshrun.s32", v4i16, v4i32, NEONvqrshrnsu>; -def VQRSHRUN64: N2VNSh<1, 1, 0b100000, 0b1000, 0, 1, 1, - IIC_VSHLi4D, "vqrshrun.s64", v2i32, v2i64, NEONvqrshrnsu>; +defm VQRSHRUN : N2VNSh_HSD<1, 1, 0b1000, 0, 1, 1, IIC_VSHLi4D, "vqrshrun.s", + NEONvqrshrnsu>; // VSRA : Vector Shift Right and Accumulate defm VSRAs : N2VShAdd_QHSD<0, 1, 0b0001, 1, "vsra.s", NEONvshrs>; @@ -2491,27 +2526,28 @@ def VDUPfq : NVDup<0b11101010, 0b1011, 0b00, (outs QPR:$dst), (ins GPR:$src), // VDUP : Vector Duplicate Lane (from scalar to all elements) -class VDUPLND<bits<2> op19_18, bits<2> op17_16, string OpcodeStr, ValueType Ty> - : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0, +class VDUPLND<string OpcodeStr, ValueType Ty> + : N2VDup<0b11, 0b11, 0b11000, 0, 0, (outs DPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, !strconcat(OpcodeStr, "\t$dst, $src[$lane]"), "", [(set DPR:$dst, (Ty (NEONvduplane (Ty DPR:$src), imm:$lane)))]>; -class VDUPLNQ<bits<2> op19_18, bits<2> op17_16, string OpcodeStr, - ValueType ResTy, ValueType OpTy> - : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 1, 0, +class VDUPLNQ<string OpcodeStr, ValueType ResTy, ValueType OpTy> + : N2VDup<0b11, 0b11, 0b11000, 1, 0, (outs QPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, !strconcat(OpcodeStr, "\t$dst, $src[$lane]"), "", [(set QPR:$dst, (ResTy (NEONvduplane (OpTy DPR:$src), imm:$lane)))]>; -def VDUPLN8d : VDUPLND<0b00, 0b01, "vdup.8", v8i8>; -def VDUPLN16d : VDUPLND<0b00, 0b10, "vdup.16", v4i16>; -def VDUPLN32d : VDUPLND<0b01, 0b00, "vdup.32", v2i32>; -def VDUPLNfd : VDUPLND<0b01, 0b00, "vdup.32", v2f32>; -def VDUPLN8q : VDUPLNQ<0b00, 0b01, "vdup.8", v16i8, v8i8>; -def VDUPLN16q : VDUPLNQ<0b00, 0b10, "vdup.16", v8i16, v4i16>; -def VDUPLN32q : VDUPLNQ<0b01, 0b00, "vdup.32", v4i32, v2i32>; -def VDUPLNfq : VDUPLNQ<0b01, 0b00, "vdup.32", v4f32, v2f32>; +// Inst{19-16} is partially specified depending on the element size. + +def VDUPLN8d : VDUPLND<"vdup.8", v8i8> { let Inst{16} = 1; } +def VDUPLN16d : VDUPLND<"vdup.16", v4i16> { let Inst{17-16} = 0b10; } +def VDUPLN32d : VDUPLND<"vdup.32", v2i32> { let Inst{18-16} = 0b100; } +def VDUPLNfd : VDUPLND<"vdup.32", v2f32> { let Inst{18-16} = 0b100; } +def VDUPLN8q : VDUPLNQ<"vdup.8", v16i8, v8i8> { let Inst{16} = 1; } +def VDUPLN16q : VDUPLNQ<"vdup.16", v8i16, v4i16> { let Inst{17-16} = 0b10; } +def VDUPLN32q : VDUPLNQ<"vdup.32", v4i32, v2i32> { let Inst{18-16} = 0b100; } +def VDUPLNfq : VDUPLNQ<"vdup.32", v4f32, v2f32> { let Inst{18-16} = 0b100; } def : Pat<(v16i8 (NEONvduplane (v16i8 QPR:$src), imm:$lane)), (v16i8 (VDUPLN8q (v8i8 (EXTRACT_SUBREG QPR:$src, @@ -2530,15 +2566,19 @@ def : Pat<(v4f32 (NEONvduplane (v4f32 QPR:$src), imm:$lane)), (DSubReg_i32_reg imm:$lane))), (SubReg_i32_lane imm:$lane)))>; -def VDUPfdf : N2V<0b11, 0b11, 0b01, 0b00, 0b11000, 0, 0, - (outs DPR:$dst), (ins SPR:$src), - IIC_VMOVD, "vdup.32\t$dst, ${src:lane}", "", - [(set DPR:$dst, (v2f32 (NEONvdup (f32 SPR:$src))))]>; +def VDUPfdf : N2VDup<0b11, 0b11, 0b11000, 0, 0, + (outs DPR:$dst), (ins SPR:$src), + IIC_VMOVD, "vdup.32\t$dst, ${src:lane}", "", + [(set DPR:$dst, (v2f32 (NEONvdup (f32 SPR:$src))))]> { + let Inst{18-16} = 0b100; +} -def VDUPfqf : N2V<0b11, 0b11, 0b01, 0b00, 0b11000, 1, 0, - (outs QPR:$dst), (ins SPR:$src), - IIC_VMOVD, "vdup.32\t$dst, ${src:lane}", "", - [(set QPR:$dst, (v4f32 (NEONvdup (f32 SPR:$src))))]>; +def VDUPfqf : N2VDup<0b11, 0b11, 0b11000, 1, 0, + (outs QPR:$dst), (ins SPR:$src), + IIC_VMOVD, "vdup.32\t$dst, ${src:lane}", "", + [(set QPR:$dst, (v4f32 (NEONvdup (f32 SPR:$src))))]> { + let Inst{18-16} = 0b100; +} def : Pat<(v2i64 (NEONvduplane (v2i64 QPR:$src), imm:$lane)), (INSERT_SUBREG QPR:$src, @@ -2560,8 +2600,8 @@ defm VQMOVNu : N2VNInt_HSD<0b11,0b11,0b10,0b00101,1,0, IIC_VQUNAiD, "vqmovn.u", defm VQMOVNsu : N2VNInt_HSD<0b11,0b11,0b10,0b00100,1,0, IIC_VQUNAiD, "vqmovun.s", int_arm_neon_vqmovnsu>; // VMOVL : Vector Lengthening Move -defm VMOVLs : N2VLInt_QHS<0,1,0b1010,0,0,1, "vmovl.s", int_arm_neon_vmovls>; -defm VMOVLu : N2VLInt_QHS<1,1,0b1010,0,0,1, "vmovl.u", int_arm_neon_vmovlu>; +defm VMOVLs : N2VLInt_QHS<0b01,0b10100,0,1, "vmovl.s", int_arm_neon_vmovls>; +defm VMOVLu : N2VLInt_QHS<0b11,0b10100,0,1, "vmovl.u", int_arm_neon_vmovlu>; // Vector Conversions. @@ -2585,24 +2625,22 @@ def VCVTu2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt.f32.u32", v4f32, v4i32, uint_to_fp>; // VCVT : Vector Convert Between Floating-Point and Fixed-Point. -// Note: Some of the opcode bits in the following VCVT instructions need to -// be encoded based on the immed values. -def VCVTf2xsd : N2VCvtD<0, 1, 0b000000, 0b1111, 0, 1, "vcvt.s32.f32", +def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt.s32.f32", v2i32, v2f32, int_arm_neon_vcvtfp2fxs>; -def VCVTf2xud : N2VCvtD<1, 1, 0b000000, 0b1111, 0, 1, "vcvt.u32.f32", +def VCVTf2xud : N2VCvtD<1, 1, 0b1111, 0, 1, "vcvt.u32.f32", v2i32, v2f32, int_arm_neon_vcvtfp2fxu>; -def VCVTxs2fd : N2VCvtD<0, 1, 0b000000, 0b1110, 0, 1, "vcvt.f32.s32", +def VCVTxs2fd : N2VCvtD<0, 1, 0b1110, 0, 1, "vcvt.f32.s32", v2f32, v2i32, int_arm_neon_vcvtfxs2fp>; -def VCVTxu2fd : N2VCvtD<1, 1, 0b000000, 0b1110, 0, 1, "vcvt.f32.u32", +def VCVTxu2fd : N2VCvtD<1, 1, 0b1110, 0, 1, "vcvt.f32.u32", v2f32, v2i32, int_arm_neon_vcvtfxu2fp>; -def VCVTf2xsq : N2VCvtQ<0, 1, 0b000000, 0b1111, 0, 1, "vcvt.s32.f32", +def VCVTf2xsq : N2VCvtQ<0, 1, 0b1111, 0, 1, "vcvt.s32.f32", v4i32, v4f32, int_arm_neon_vcvtfp2fxs>; -def VCVTf2xuq : N2VCvtQ<1, 1, 0b000000, 0b1111, 0, 1, "vcvt.u32.f32", +def VCVTf2xuq : N2VCvtQ<1, 1, 0b1111, 0, 1, "vcvt.u32.f32", v4i32, v4f32, int_arm_neon_vcvtfp2fxu>; -def VCVTxs2fq : N2VCvtQ<0, 1, 0b000000, 0b1110, 0, 1, "vcvt.f32.s32", +def VCVTxs2fq : N2VCvtQ<0, 1, 0b1110, 0, 1, "vcvt.f32.s32", v4f32, v4i32, int_arm_neon_vcvtfxs2fp>; -def VCVTxu2fq : N2VCvtQ<1, 1, 0b000000, 0b1110, 0, 1, "vcvt.f32.u32", +def VCVTxu2fq : N2VCvtQ<1, 1, 0b1110, 0, 1, "vcvt.f32.u32", v4f32, v4i32, int_arm_neon_vcvtfxu2fp>; // Vector Reverse. @@ -2670,18 +2708,18 @@ def VREV16q8 : VREV16Q<0b00, "vrev16.8", v16i8>; // VEXT : Vector Extract class VEXTd<string OpcodeStr, ValueType Ty> - : N3V<0,1,0b11,0b0000,0,0, (outs DPR:$dst), - (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, - !strconcat(OpcodeStr, "\t$dst, $lhs, $rhs, $index"), "", - [(set DPR:$dst, (Ty (NEONvext (Ty DPR:$lhs), - (Ty DPR:$rhs), imm:$index)))]>; + : N3VImm<0,1,0b11,0,0, (outs DPR:$dst), + (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, + !strconcat(OpcodeStr, "\t$dst, $lhs, $rhs, $index"), "", + [(set DPR:$dst, (Ty (NEONvext (Ty DPR:$lhs), + (Ty DPR:$rhs), imm:$index)))]>; class VEXTq<string OpcodeStr, ValueType Ty> - : N3V<0,1,0b11,0b0000,1,0, (outs QPR:$dst), - (ins QPR:$lhs, QPR:$rhs, i32imm:$index), IIC_VEXTQ, - !strconcat(OpcodeStr, "\t$dst, $lhs, $rhs, $index"), "", - [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), - (Ty QPR:$rhs), imm:$index)))]>; + : N3VImm<0,1,0b11,1,0, (outs QPR:$dst), + (ins QPR:$lhs, QPR:$rhs, i32imm:$index), IIC_VEXTQ, + !strconcat(OpcodeStr, "\t$dst, $lhs, $rhs, $index"), "", + [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), + (Ty QPR:$rhs), imm:$index)))]>; def VEXTd8 : VEXTd<"vext.8", v8i8>; def VEXTd16 : VEXTd<"vext.16", v4i16>; diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 0750dcc..2b6fa98 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -69,6 +69,25 @@ def t2_so_imm_neg : Operand<i32>, return ARM_AM::getT2SOImmVal(-((int)N->getZExtValue())) != -1; }], t2_so_imm_neg_XFORM>; +// Break t2_so_imm's up into two pieces. This handles immediates with up to 16 +// bits set in them. This uses t2_so_imm2part to match and t2_so_imm2part_[12] +// to get the first/second pieces. +def t2_so_imm2part : Operand<i32>, + PatLeaf<(imm), [{ + return ARM_AM::isT2SOImmTwoPartVal((unsigned)N->getZExtValue()); + }]> { +} + +def t2_so_imm2part_1 : SDNodeXForm<imm, [{ + unsigned V = ARM_AM::getT2SOImmTwoPartFirst((unsigned)N->getZExtValue()); + return CurDAG->getTargetConstant(V, MVT::i32); +}]>; + +def t2_so_imm2part_2 : SDNodeXForm<imm, [{ + unsigned V = ARM_AM::getT2SOImmTwoPartSecond((unsigned)N->getZExtValue()); + return CurDAG->getTargetConstant(V, MVT::i32); +}]>; + /// imm1_31 predicate - True if the 32-bit immediate is in the range [1,31]. def imm1_31 : PatLeaf<(i32 imm), [{ return (int32_t)N->getZExtValue() >= 1 && (int32_t)N->getZExtValue() < 32; @@ -666,6 +685,8 @@ def t2MOVTi16 : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm), IIC_iMOVi, [(set GPR:$dst, (or (and GPR:$src, 0xffff), lo16AllZero:$imm))]>; +def : T2Pat<(or GPR:$src, 0xffff0000), (t2MOVTi16 GPR:$src, 0xffff)>; + //===----------------------------------------------------------------------===// // Extend Instructions. // @@ -1129,6 +1150,20 @@ def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask), // Non-Instruction Patterns // +// Two piece so_imms. +def : T2Pat<(or GPR:$LHS, t2_so_imm2part:$RHS), + (t2ORRri (t2ORRri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), + (t2_so_imm2part_2 imm:$RHS))>; +def : T2Pat<(xor GPR:$LHS, t2_so_imm2part:$RHS), + (t2EORri (t2EORri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), + (t2_so_imm2part_2 imm:$RHS))>; +def : T2Pat<(add GPR:$LHS, t2_so_imm2part:$RHS), + (t2ADDri (t2ADDri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), + (t2_so_imm2part_2 imm:$RHS))>; +def : T2Pat<(sub GPR:$LHS, t2_so_imm2part:$RHS), + (t2SUBri (t2SUBri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), + (t2_so_imm2part_2 imm:$RHS))>; + // ConstantPool, GlobalAddress, and JumpTable def : T2Pat<(ARMWrapper tglobaladdr :$dst), (t2LEApcrel tglobaladdr :$dst)>; def : T2Pat<(ARMWrapper tconstpool :$dst), (t2LEApcrel tconstpool :$dst)>; diff --git a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp index d2ec9ee..c9b9e84 100644 --- a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp +++ b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp @@ -974,6 +974,9 @@ bool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) { if (Advance) { ++Position; ++MBBI; + if (MBBI == E) + // Reach the end of the block, try merging the memory instructions. + TryMerge = true; } else TryMerge = true; diff --git a/lib/Target/ARM/ARMRegisterInfo.td b/lib/Target/ARM/ARMRegisterInfo.td index 20a7355..e0be784 100644 --- a/lib/Target/ARM/ARMRegisterInfo.td +++ b/lib/Target/ARM/ARMRegisterInfo.td @@ -222,12 +222,9 @@ def tGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, R7]> { iterator allocation_order_begin(const MachineFunction &MF) const; iterator allocation_order_end(const MachineFunction &MF) const; }]; - // FIXME: We are reserving r3 in Thumb mode in case the PEI needs to use it - // to generate large stack offset. Make it available once we have register - // scavenging. let MethodBodies = [{ static const unsigned THUMB_tGPR_AO[] = { - ARM::R0, ARM::R1, ARM::R2, + ARM::R0, ARM::R1, ARM::R2, ARM::R3, ARM::R4, ARM::R5, ARM::R6, ARM::R7 }; // FP is R7, only low registers available. diff --git a/lib/Target/ARM/ARMSubtarget.cpp b/lib/Target/ARM/ARMSubtarget.cpp index cf1ee3f..5af95c3 100644 --- a/lib/Target/ARM/ARMSubtarget.cpp +++ b/lib/Target/ARM/ARMSubtarget.cpp @@ -27,11 +27,11 @@ UseNEONFP("arm-use-neon-fp", cl::init(false), cl::Hidden); ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &FS, - bool isThumb) + bool isT) : ARMArchVersion(V4T) , ARMFPUType(None) , UseNEONForSinglePrecisionFP(UseNEONFP) - , IsThumb(isThumb) + , IsThumb(isT) , ThumbMode(Thumb1) , PostRAScheduler(false) , IsR9Reserved(ReserveR9) @@ -98,9 +98,13 @@ ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &FS, if (isTargetDarwin()) IsR9Reserved = ReserveR9 | (ARMArchVersion < V6); + if (!isThumb() || hasThumb2()) + PostRAScheduler = true; + // Set CPU specific features. if (CPUString == "cortex-a8") { - PostRAScheduler = true; + // On Cortex-a8, it's faster to perform some single-precision FP + // operations with NEON instructions. if (UseNEONFP.getPosition() == 0) UseNEONForSinglePrecisionFP = true; } diff --git a/lib/Target/ARM/ARMSubtarget.h b/lib/Target/ARM/ARMSubtarget.h index 7098fd4..7478159 100644 --- a/lib/Target/ARM/ARMSubtarget.h +++ b/lib/Target/ARM/ARMSubtarget.h @@ -126,9 +126,13 @@ protected: const std::string & getCPUString() const { return CPUString; } - /// enablePostRAScheduler - From TargetSubtarget, return true to - /// enable post-RA scheduler. - bool enablePostRAScheduler() const { return PostRAScheduler; } + /// enablePostRAScheduler - True at 'More' optimization except + /// for Thumb1. + bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, + TargetSubtarget::AntiDepBreakMode& mode) const { + mode = TargetSubtarget::ANTIDEP_NONE; + return PostRAScheduler && OptLevel >= CodeGenOpt::Default; + } /// getInstrItins - Return the instruction itineraies based on subtarget /// selection. diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp index 32ddc20..c1da6ce 100644 --- a/lib/Target/ARM/ARMTargetMachine.cpp +++ b/lib/Target/ARM/ARMTargetMachine.cpp @@ -16,7 +16,6 @@ #include "ARM.h" #include "llvm/PassManager.h" #include "llvm/CodeGen/Passes.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegistry.h" diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 7438ea9..403f96c 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -56,6 +56,14 @@ private: bool ParseDirectiveWord(unsigned Size, SMLoc L); + bool ParseDirectiveThumb(SMLoc L); + + bool ParseDirectiveThumbFunc(SMLoc L); + + bool ParseDirectiveCode(SMLoc L); + + bool ParseDirectiveSyntax(SMLoc L); + // TODO - For now hacked versions of the next two are in here in this file to // allow some parser testing until the table gen versions are implemented. @@ -230,8 +238,8 @@ bool ARMAsmParser::ParseRegister(ARMOperand &Op) { return false; } -// Try to parse a register list. The first token must be a '{' when called -// for now. +// Parse a register list, return false if successful else return true or an +// error. The first token must be a '{' when called. bool ARMAsmParser::ParseRegisterList(ARMOperand &Op) { assert(getLexer().getTok().is(AsmToken::LCurly) && "Token is not an Left Curly Brace"); @@ -277,7 +285,8 @@ bool ARMAsmParser::ParseRegisterList(ARMOperand &Op) { return false; } -// Try to parse an arm memory expression. It must start with a '[' token. +// Parse an arm memory expression, return false if successful else return true +// or an error. The first token must be a '[' when called. // TODO Only preindexing and postindexing addressing are started, unindexed // with option, etc are still to do. bool ARMAsmParser::ParseMemory(ARMOperand &Op) { @@ -374,50 +383,55 @@ bool ARMAsmParser::ParseMemory(ARMOperand &Op) { Writeback = true; getLexer().Lex(); // Eat right bracket token. - const AsmToken &CommaTok = getLexer().getTok(); - if (CommaTok.isNot(AsmToken::Comma)) - return Error(CommaTok.getLoc(), "',' expected"); - getLexer().Lex(); // Eat comma token. - - const AsmToken &NextTok = getLexer().getTok(); - if (NextTok.is(AsmToken::Plus)) - getLexer().Lex(); // Eat plus token. - else if (NextTok.is(AsmToken::Minus)) { - Negative = true; - getLexer().Lex(); // Eat minus token - } - - // See if there is a register following the "[Rn]," we have so far. - const AsmToken &OffsetRegTok = getLexer().getTok(); - int OffsetRegNum = MatchRegisterName(OffsetRegTok.getString()); + int OffsetRegNum = 0; bool OffsetRegShifted = false; enum ShiftType ShiftType; const MCExpr *ShiftAmount; const MCExpr *Offset; - if (OffsetRegNum != -1) { - OffsetIsReg = true; - getLexer().Lex(); // Eat identifier token for the offset register. - // Look for a comma then a shift - const AsmToken &Tok = getLexer().getTok(); - if (Tok.is(AsmToken::Comma)) { - getLexer().Lex(); // Eat comma token. - const AsmToken &Tok = getLexer().getTok(); - if (ParseShift(&ShiftType, ShiftAmount)) - return Error(Tok.getLoc(), "shift expected"); - OffsetRegShifted = true; + const AsmToken &NextTok = getLexer().getTok(); + if (NextTok.isNot(AsmToken::EndOfStatement)) { + if (NextTok.isNot(AsmToken::Comma)) + return Error(NextTok.getLoc(), "',' expected"); + getLexer().Lex(); // Eat comma token. + + const AsmToken &PlusMinusTok = getLexer().getTok(); + if (PlusMinusTok.is(AsmToken::Plus)) + getLexer().Lex(); // Eat plus token. + else if (PlusMinusTok.is(AsmToken::Minus)) { + Negative = true; + getLexer().Lex(); // Eat minus token } - } - else { // "[Rn]," we have so far was not followed by "Rm" - // Look for #offset following the "[Rn]," - const AsmToken &HashTok = getLexer().getTok(); - if (HashTok.isNot(AsmToken::Hash)) - return Error(HashTok.getLoc(), "'#' expected"); - getLexer().Lex(); // Eat hash token. - if (getParser().ParseExpression(Offset)) - return true; + // See if there is a register following the "[Rn]," we have so far. + const AsmToken &OffsetRegTok = getLexer().getTok(); + OffsetRegNum = MatchRegisterName(OffsetRegTok.getString()); + if (OffsetRegNum != -1) { + OffsetIsReg = true; + getLexer().Lex(); // Eat identifier token for the offset register. + // Look for a comma then a shift + const AsmToken &Tok = getLexer().getTok(); + if (Tok.is(AsmToken::Comma)) { + getLexer().Lex(); // Eat comma token. + + const AsmToken &Tok = getLexer().getTok(); + if (ParseShift(&ShiftType, ShiftAmount)) + return Error(Tok.getLoc(), "shift expected"); + OffsetRegShifted = true; + } + } + else { // "[Rn]," we have so far was not followed by "Rm" + // Look for #offset following the "[Rn]," + const AsmToken &HashTok = getLexer().getTok(); + if (HashTok.isNot(AsmToken::Hash)) + return Error(HashTok.getLoc(), "'#' expected"); + getLexer().Lex(); // Eat hash token. + + if (getParser().ParseExpression(Offset)) + return true; + } } + Op = ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, OffsetRegShifted, ShiftType, ShiftAmount, Preindexed, Postindexed, Negative, Writeback); @@ -465,7 +479,7 @@ bool ARMAsmParser::ParseShift(ShiftType *St, const MCExpr *&ShiftAmount) { return false; } -// A hack to allow some testing +// A hack to allow some testing, to be replaced by a real table gen version. int ARMAsmParser::MatchRegisterName(const StringRef &Name) { if (Name == "r0" || Name == "R0") return 0; @@ -504,7 +518,7 @@ int ARMAsmParser::MatchRegisterName(const StringRef &Name) { return -1; } -// A hack to allow some testing +// A hack to allow some testing, to be replaced by a real table gen version. bool ARMAsmParser::MatchInstruction(SmallVectorImpl<ARMOperand> &Operands, MCInst &Inst) { struct ARMOperand Op0 = Operands[0]; @@ -516,40 +530,58 @@ bool ARMAsmParser::MatchInstruction(SmallVectorImpl<ARMOperand> &Operands, Mnemonic == "ldmfd" || Mnemonic == "ldr" || Mnemonic == "mov" || - Mnemonic == "sub") + Mnemonic == "sub" || + Mnemonic == "bl" || + Mnemonic == "push" || + Mnemonic == "blx" || + Mnemonic == "pop") { + // Hard-coded to a valid instruction, till we have a real matcher. + Inst = MCInst(); + Inst.setOpcode(ARM::MOVr); + Inst.addOperand(MCOperand::CreateReg(2)); + Inst.addOperand(MCOperand::CreateReg(2)); + Inst.addOperand(MCOperand::CreateImm(0)); + Inst.addOperand(MCOperand::CreateImm(0)); + Inst.addOperand(MCOperand::CreateReg(0)); return false; + } return true; } -// TODO - this is a work in progress +// Parse a arm instruction operand. For now this parses the operand regardless +// of the mnemonic. bool ARMAsmParser::ParseOperand(ARMOperand &Op) { switch (getLexer().getKind()) { case AsmToken::Identifier: if (!ParseRegister(Op)) return false; - // TODO parse other operands that start with an identifier like labels - return Error(getLexer().getTok().getLoc(), "labels not yet supported"); + // This was not a register so parse other operands that start with an + // identifier (like labels) as expressions and create them as immediates. + const MCExpr *IdVal; + if (getParser().ParseExpression(IdVal)) + return true; + Op = ARMOperand::CreateImm(IdVal); + return false; case AsmToken::LBrac: - if (!ParseMemory(Op)) - return false; + return ParseMemory(Op); case AsmToken::LCurly: - if (!ParseRegisterList(Op)) - return false; + return ParseRegisterList(Op); case AsmToken::Hash: // #42 -> immediate. // TODO: ":lower16:" and ":upper16:" modifiers after # before immediate getLexer().Lex(); - const MCExpr *Val; - if (getParser().ParseExpression(Val)) + const MCExpr *ImmVal; + if (getParser().ParseExpression(ImmVal)) return true; - Op = ARMOperand::CreateImm(Val); + Op = ARMOperand::CreateImm(ImmVal); return false; default: return Error(getLexer().getTok().getLoc(), "unexpected token in operand"); } } +// Parse an arm instruction mnemonic followed by its operands. bool ARMAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) { SmallVector<ARMOperand, 7> Operands; @@ -579,10 +611,19 @@ bool ARMAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) { return true; } +/// ParseDirective parses the arm specific directives bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getIdentifier(); if (IDVal == ".word") return ParseDirectiveWord(4, DirectiveID.getLoc()); + else if (IDVal == ".thumb") + return ParseDirectiveThumb(DirectiveID.getLoc()); + else if (IDVal == ".thumb_func") + return ParseDirectiveThumbFunc(DirectiveID.getLoc()); + else if (IDVal == ".code") + return ParseDirectiveCode(DirectiveID.getLoc()); + else if (IDVal == ".syntax") + return ParseDirectiveSyntax(DirectiveID.getLoc()); return true; } @@ -611,6 +652,93 @@ bool ARMAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) { return false; } +/// ParseDirectiveThumb +/// ::= .thumb +bool ARMAsmParser::ParseDirectiveThumb(SMLoc L) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(L, "unexpected token in directive"); + getLexer().Lex(); + + // TODO: set thumb mode + // TODO: tell the MC streamer the mode + // getParser().getStreamer().Emit???(); + return false; +} + +/// ParseDirectiveThumbFunc +/// ::= .thumbfunc symbol_name +bool ARMAsmParser::ParseDirectiveThumbFunc(SMLoc L) { + const AsmToken &Tok = getLexer().getTok(); + if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) + return Error(L, "unexpected token in .syntax directive"); + StringRef SymbolName = getLexer().getTok().getIdentifier(); + getLexer().Lex(); // Consume the identifier token. + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(L, "unexpected token in directive"); + getLexer().Lex(); + + // TODO: mark symbol as a thumb symbol + // getParser().getStreamer().Emit???(); + return false; +} + +/// ParseDirectiveSyntax +/// ::= .syntax unified | divided +bool ARMAsmParser::ParseDirectiveSyntax(SMLoc L) { + const AsmToken &Tok = getLexer().getTok(); + if (Tok.isNot(AsmToken::Identifier)) + return Error(L, "unexpected token in .syntax directive"); + const StringRef &Mode = Tok.getString(); + bool unified_syntax; + if (Mode == "unified" || Mode == "UNIFIED") { + getLexer().Lex(); + unified_syntax = true; + } + else if (Mode == "divided" || Mode == "DIVIDED") { + getLexer().Lex(); + unified_syntax = false; + } + else + return Error(L, "unrecognized syntax mode in .syntax directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getTok().getLoc(), "unexpected token in directive"); + getLexer().Lex(); + + // TODO tell the MC streamer the mode + // getParser().getStreamer().Emit???(); + return false; +} + +/// ParseDirectiveCode +/// ::= .code 16 | 32 +bool ARMAsmParser::ParseDirectiveCode(SMLoc L) { + const AsmToken &Tok = getLexer().getTok(); + if (Tok.isNot(AsmToken::Integer)) + return Error(L, "unexpected token in .code directive"); + int64_t Val = getLexer().getTok().getIntVal(); + bool thumb_mode; + if (Val == 16) { + getLexer().Lex(); + thumb_mode = true; + } + else if (Val == 32) { + getLexer().Lex(); + thumb_mode = false; + } + else + return Error(L, "invalid operand to .code directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getTok().getLoc(), "unexpected token in directive"); + getLexer().Lex(); + + // TODO tell the MC streamer the mode + // getParser().getStreamer().Emit???(); + return false; +} + // Force static initialization. extern "C" void LLVMInitializeARMAsmParser() { RegisterAsmParser<ARMAsmParser> X(TheARMTarget); diff --git a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp index 546731b..8719e4c 100644 --- a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp @@ -1,3 +1,5 @@ +//===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -13,21 +15,25 @@ #define DEBUG_TYPE "asm-printer" #include "ARM.h" #include "ARMBuildAttrs.h" -#include "ARMTargetMachine.h" #include "ARMAddressingModes.h" #include "ARMConstantPoolValue.h" +#include "ARMInstPrinter.h" #include "ARMMachineFunctionInfo.h" +#include "ARMMCInstLower.h" +#include "ARMTargetMachine.h" #include "llvm/Constants.h" #include "llvm/Module.h" #include "llvm/Assembly/Writer.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DwarfWriter.h" -#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" @@ -38,18 +44,22 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSet.h" -#include "llvm/Support/Compiler.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/Mangler.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Support/FormattedStream.h" #include <cctype> using namespace llvm; STATISTIC(EmittedInsts, "Number of machine instrs printed"); +static cl::opt<bool> +EnableMCInst("enable-arm-mcinst-printer", cl::Hidden, + cl::desc("enable experimental asmprinter gunk in the arm backend")); + namespace { - class VISIBILITY_HIDDEN ARMAsmPrinter : public AsmPrinter { + class ARMAsmPrinter : public AsmPrinter { /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can /// make the right decision when printing asm code for different targets. @@ -63,34 +73,23 @@ namespace { /// MachineFunction. const MachineConstantPool *MCP; - /// We name each basic block in a Function with a unique number, so - /// that we can consistently refer to them later. This is cleared - /// at the beginning of each call to runOnMachineFunction(). - /// - typedef std::map<const Value *, unsigned> ValueMapTy; - ValueMapTy NumberForBB; - - /// GVNonLazyPtrs - Keeps the set of GlobalValues that require - /// non-lazy-pointers for indirect access. - StringMap<std::string> GVNonLazyPtrs; - - /// HiddenGVNonLazyPtrs - Keeps the set of GlobalValues with hidden - /// visibility that require non-lazy-pointers for indirect access. - StringMap<std::string> HiddenGVNonLazyPtrs; - - /// True if asm printer is printing a series of CONSTPOOL_ENTRY. - bool InCPMode; public: explicit ARMAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, const MCAsmInfo *T, bool V) - : AsmPrinter(O, TM, T, V), AFI(NULL), MCP(NULL), - InCPMode(false) { + : AsmPrinter(O, TM, T, V), AFI(NULL), MCP(NULL) { Subtarget = &TM.getSubtarget<ARMSubtarget>(); } virtual const char *getPassName() const { return "ARM Assembly Printer"; } + + void printMCInst(const MCInst *MI) { + ARMInstPrinter(O, *MAI, VerboseAsm).printInstruction(MI); + } + + void printInstructionThroughMCStreamer(const MachineInstr *MI); + void printOperand(const MachineInstr *MI, int OpNum, const char *Modifier = 0); @@ -149,8 +148,8 @@ namespace { void printMachineInstruction(const MachineInstr *MI); bool runOnMachineFunction(MachineFunction &F); - bool doFinalization(Module &M); void EmitStartOfAsmFile(Module &M); + void EmitEndOfAsmFile(Module &M); /// EmitMachineConstantPoolValue - Print a machine constantpool value to /// the .s file. @@ -173,12 +172,19 @@ namespace { Name = Mang->getMangledName(GV); else { // FIXME: Remove this when Darwin transition to @GOT like syntax. - std::string SymName = Mang->getMangledName(GV); Name = Mang->getMangledName(GV, "$non_lazy_ptr", true); - if (GV->hasHiddenVisibility()) - HiddenGVNonLazyPtrs[SymName] = Name; - else - GVNonLazyPtrs[SymName] = Name; + MCSymbol *Sym = OutContext.GetOrCreateSymbol(StringRef(Name)); + + MachineModuleInfoMachO &MMIMachO = + MMI->getObjFileInfo<MachineModuleInfoMachO>(); + const MCSymbol *&StubSym = + GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) : + MMIMachO.getGVStubEntry(Sym); + if (StubSym == 0) { + SmallString<128> NameStr; + Mang->getNameWithPrefix(NameStr, GV, false); + StubSym = OutContext.GetOrCreateSymbol(NameStr.str()); + } } } else Name = Mang->makeNameProper(ACPV->getSymbol()); @@ -260,7 +266,6 @@ bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { if (Subtarget->isTargetDarwin()) O << "\t" << CurrentFnName; O << "\n"; - InCPMode = false; } else { EmitAlignment(FnAlign, F); } @@ -283,14 +288,13 @@ bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); I != E; ++I) { // Print a label for the basic block. - if (I != MF.begin()) { + if (I != MF.begin()) EmitBasicBlockStart(I); - } + + // Print the assembly for the instruction. for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); - II != E; ++II) { - // Print the assembly for the instruction. + II != E; ++II) printMachineInstruction(II); - } } if (MAI->hasDotTypeDotSizeDirective()) @@ -306,25 +310,25 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, const char *Modifier) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { + default: + assert(0 && "<unknown operand type>"); case MachineOperand::MO_Register: { unsigned Reg = MO.getReg(); - if (TargetRegisterInfo::isPhysicalRegister(Reg)) { - if (Modifier && strcmp(Modifier, "dregpair") == 0) { - unsigned DRegLo = TRI->getSubReg(Reg, 5); // arm_dsubreg_0 - unsigned DRegHi = TRI->getSubReg(Reg, 6); // arm_dsubreg_1 - O << '{' - << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) - << '}'; - } else if (Modifier && strcmp(Modifier, "lane") == 0) { - unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); - unsigned DReg = TRI->getMatchingSuperReg(Reg, RegNum & 1 ? 2 : 1, - &ARM::DPR_VFP2RegClass); - O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; - } else { - O << getRegisterName(Reg); - } - } else - llvm_unreachable("not implemented"); + assert(TargetRegisterInfo::isPhysicalRegister(Reg)); + if (Modifier && strcmp(Modifier, "dregpair") == 0) { + unsigned DRegLo = TRI->getSubReg(Reg, 5); // arm_dsubreg_0 + unsigned DRegHi = TRI->getSubReg(Reg, 6); // arm_dsubreg_1 + O << '{' + << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) + << '}'; + } else if (Modifier && strcmp(Modifier, "lane") == 0) { + unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); + unsigned DReg = TRI->getMatchingSuperReg(Reg, RegNum & 1 ? 2 : 1, + &ARM::DPR_VFP2RegClass); + O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; + } else { + O << getRegisterName(Reg); + } break; } case MachineOperand::MO_Immediate: { @@ -372,8 +376,6 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_' << MO.getIndex(); break; - default: - O << "<unknown operand type>"; abort (); break; } } @@ -1027,22 +1029,19 @@ bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, void ARMAsmPrinter::printMachineInstruction(const MachineInstr *MI) { ++EmittedInsts; - int Opc = MI->getOpcode(); - switch (Opc) { - case ARM::CONSTPOOL_ENTRY: - if (!InCPMode && AFI->isThumbFunction()) { - EmitAlignment(2); - InCPMode = true; - } - break; - default: { - if (InCPMode && AFI->isThumbFunction()) - InCPMode = false; - }} - // Call the autogenerated instruction printer routines. processDebugLoc(MI, true); - printInstruction(MI); + + if (EnableMCInst) { + printInstructionThroughMCStreamer(MI); + } else { + int Opc = MI->getOpcode(); + if (Opc == ARM::CONSTPOOL_ENTRY) + EmitAlignment(2); + + printInstruction(MI); + } + if (VerboseAsm && !MI->getDebugLoc().isUnknown()) EmitComments(*MI); O << '\n'; @@ -1256,34 +1255,40 @@ void ARMAsmPrinter::PrintGlobalVariable(const GlobalVariable* GVar) { } -bool ARMAsmPrinter::doFinalization(Module &M) { +void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { if (Subtarget->isTargetDarwin()) { // All darwin targets use mach-o. TargetLoweringObjectFileMachO &TLOFMacho = static_cast<TargetLoweringObjectFileMachO &>(getObjFileLowering()); + MachineModuleInfoMachO &MMIMacho = + MMI->getObjFileInfo<MachineModuleInfoMachO>(); O << '\n'; // Output non-lazy-pointers for external and common global variables. - if (!GVNonLazyPtrs.empty()) { + MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList(); + + if (!Stubs.empty()) { // Switch with ".non_lazy_symbol_pointer" directive. OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); EmitAlignment(2); - for (StringMap<std::string>::iterator I = GVNonLazyPtrs.begin(), - E = GVNonLazyPtrs.end(); I != E; ++I) { - O << I->second << ":\n"; - O << "\t.indirect_symbol " << I->getKeyData() << "\n"; - O << "\t.long\t0\n"; + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + Stubs[i].first->print(O, MAI); + O << ":\n\t.indirect_symbol "; + Stubs[i].second->print(O, MAI); + O << "\n\t.long\t0\n"; } } - if (!HiddenGVNonLazyPtrs.empty()) { + Stubs = MMIMacho.GetHiddenGVStubList(); + if (!Stubs.empty()) { OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); EmitAlignment(2); - for (StringMap<std::string>::iterator I = HiddenGVNonLazyPtrs.begin(), - E = HiddenGVNonLazyPtrs.end(); I != E; ++I) { - O << I->second << ":\n"; - O << "\t.long " << I->getKeyData() << "\n"; + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + Stubs[i].first->print(O, MAI); + O << ":\n\t.long "; + Stubs[i].second->print(O, MAI); + O << "\n"; } } @@ -1292,14 +1297,179 @@ bool ARMAsmPrinter::doFinalization(Module &M) { // implementation of multiple entry points). If this doesn't occur, the // linker can safely perform dead code stripping. Since LLVM never // generates code that does this, it is always safe to set. - O << "\t.subsections_via_symbols\n"; + OutStreamer.EmitAssemblerFlag(MCStreamer::SubsectionsViaSymbols); + } +} + +//===----------------------------------------------------------------------===// + +void ARMAsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) { + ARMMCInstLower MCInstLowering(OutContext, *Mang, *this); + switch (MI->getOpcode()) { + case ARM::t2MOVi32imm: + assert(0 && "Should be lowered by thumb2it pass"); + default: break; + case TargetInstrInfo::DBG_LABEL: + case TargetInstrInfo::EH_LABEL: + case TargetInstrInfo::GC_LABEL: + printLabel(MI); + return; + case TargetInstrInfo::KILL: + return; + case TargetInstrInfo::INLINEASM: + O << '\t'; + printInlineAsm(MI); + return; + case TargetInstrInfo::IMPLICIT_DEF: + printImplicitDef(MI); + return; + case ARM::PICADD: { // FIXME: Remove asm string from td file. + // This is a pseudo op for a label + instruction sequence, which looks like: + // LPC0: + // add r0, pc, r0 + // This adds the address of LPC0 to r0. + + // Emit the label. + // FIXME: MOVE TO SHARED PLACE. + unsigned Id = (unsigned)MI->getOperand(2).getImm(); + const char *Prefix = MAI->getPrivateGlobalPrefix(); + MCSymbol *Label =OutContext.GetOrCreateSymbol(Twine(Prefix)+"PC"+Twine(Id)); + OutStreamer.EmitLabel(Label); + + + // Form and emit tha dd. + MCInst AddInst; + AddInst.setOpcode(ARM::ADDrr); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + AddInst.addOperand(MCOperand::CreateReg(ARM::PC)); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + printMCInst(&AddInst); + return; + } + case ARM::CONSTPOOL_ENTRY: { // FIXME: Remove asm string from td file. + /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool + /// in the function. The first operand is the ID# for this instruction, the + /// second is the index into the MachineConstantPool that this is, the third + /// is the size in bytes of this constant pool entry. + unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); + unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); + + EmitAlignment(2); + + const char *Prefix = MAI->getPrivateGlobalPrefix(); + MCSymbol *Label = OutContext.GetOrCreateSymbol(Twine(Prefix)+"CPI"+ + Twine(getFunctionNumber())+ + "_"+ Twine(LabelId)); + OutStreamer.EmitLabel(Label); + + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + if (MCPE.isMachineConstantPoolEntry()) + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + else + EmitGlobalConstant(MCPE.Val.ConstVal); + + return; } + case ARM::MOVi2pieces: { // FIXME: Remove asmstring from td file. + // This is a hack that lowers as a two instruction sequence. + unsigned DstReg = MI->getOperand(0).getReg(); + unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); + + unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal); + unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal); + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); + TmpInst.addOperand(MCOperand::CreateImm(SOImmValV1)); + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + printMCInst(&TmpInst); + O << '\n'; + } - return AsmPrinter::doFinalization(M); + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::ORRri); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // inreg + TmpInst.addOperand(MCOperand::CreateImm(SOImmValV2)); // so_imm + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + printMCInst(&TmpInst); + } + return; + } + case ARM::MOVi32imm: { // FIXME: Remove asmstring from td file. + // This is a hack that lowers as a two instruction sequence. + unsigned DstReg = MI->getOperand(0).getReg(); + unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi16); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateImm(ImmVal & 65535)); // lower16(imm) + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + printMCInst(&TmpInst); + O << '\n'; + } + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVTi16); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // srcreg + TmpInst.addOperand(MCOperand::CreateImm(ImmVal >> 16)); // upper16(imm) + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + printMCInst(&TmpInst); + } + + return; + } + } + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + + printMCInst(&TmpInst); +} + +//===----------------------------------------------------------------------===// +// Target Registry Stuff +//===----------------------------------------------------------------------===// + +static MCInstPrinter *createARMMCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + raw_ostream &O) { + if (SyntaxVariant == 0) + return new ARMInstPrinter(O, MAI, false); + return 0; } // Force static initialization. extern "C" void LLVMInitializeARMAsmPrinter() { RegisterAsmPrinter<ARMAsmPrinter> X(TheARMTarget); RegisterAsmPrinter<ARMAsmPrinter> Y(TheThumbTarget); + + TargetRegistry::RegisterMCInstPrinter(TheARMTarget, createARMMCInstPrinter); + TargetRegistry::RegisterMCInstPrinter(TheThumbTarget, createARMMCInstPrinter); } + diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp new file mode 100644 index 0000000..f422798 --- /dev/null +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp @@ -0,0 +1,358 @@ +//===-- ARMInstPrinter.cpp - Convert ARM MCInst to assembly syntax --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an ARM MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "ARM.h" // FIXME: FACTOR ENUMS BETTER. +#include "ARMInstPrinter.h" +#include "ARMAddressingModes.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +// Include the auto-generated portion of the assembly writer. +#define MachineInstr MCInst +#define ARMAsmPrinter ARMInstPrinter // FIXME: REMOVE. +#define NO_ASM_WRITER_BOILERPLATE +#include "ARMGenAsmWriter.inc" +#undef MachineInstr +#undef ARMAsmPrinter + +void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); } + +void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + unsigned Reg = Op.getReg(); + if (Modifier && strcmp(Modifier, "dregpair") == 0) { + // FIXME: Breaks e.g. ARM/vmul.ll. + assert(0); + /* + unsigned DRegLo = TRI->getSubReg(Reg, 5); // arm_dsubreg_0 + unsigned DRegHi = TRI->getSubReg(Reg, 6); // arm_dsubreg_1 + O << '{' + << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) + << '}';*/ + } else if (Modifier && strcmp(Modifier, "lane") == 0) { + assert(0); + /* + unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); + unsigned DReg = TRI->getMatchingSuperReg(Reg, RegNum & 1 ? 2 : 1, + &ARM::DPR_VFP2RegClass); + O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; + */ + } else { + O << getRegisterName(Reg); + } + } else if (Op.isImm()) { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + O << '#' << Op.getImm(); + } else { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + assert(Op.isExpr() && "unknown operand kind in printOperand"); + Op.getExpr()->print(O, &MAI); + } +} + +static void printSOImm(raw_ostream &O, int64_t V, bool VerboseAsm, + const MCAsmInfo *MAI) { + // Break it up into two parts that make up a shifter immediate. + V = ARM_AM::getSOImmVal(V); + assert(V != -1 && "Not a valid so_imm value!"); + + unsigned Imm = ARM_AM::getSOImmValImm(V); + unsigned Rot = ARM_AM::getSOImmValRot(V); + + // Print low-level immediate formation info, per + // A5.1.3: "Data-processing operands - Immediate". + if (Rot) { + O << "#" << Imm << ", " << Rot; + // Pretty printed version. + if (VerboseAsm) + O << ' ' << MAI->getCommentString() + << ' ' << (int)ARM_AM::rotr32(Imm, Rot); + } else { + O << "#" << Imm; + } +} + + +/// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit +/// immediate in bits 0-7. +void ARMInstPrinter::printSOImmOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO = MI->getOperand(OpNum); + assert(MO.isImm() && "Not a valid so_imm value!"); + printSOImm(O, MO.getImm(), VerboseAsm, &MAI); +} + +/// printSOImm2PartOperand - SOImm is broken into two pieces using a 'mov' +/// followed by an 'orr' to materialize. +void ARMInstPrinter::printSOImm2PartOperand(const MCInst *MI, unsigned OpNum) { + // FIXME: REMOVE this method. + abort(); +} + +// so_reg is a 4-operand unit corresponding to register forms of the A5.1 +// "Addressing Mode 1 - Data-processing operands" forms. This includes: +// REG 0 0 - e.g. R5 +// REG REG 0,SH_OPC - e.g. R5, ROR R3 +// REG 0 IMM,SH_OPC - e.g. R5, LSL #3 +void ARMInstPrinter::printSORegOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + const MCOperand &MO3 = MI->getOperand(OpNum+2); + + O << getRegisterName(MO1.getReg()); + + // Print the shift opc. + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())) + << ' '; + + if (MO2.getReg()) { + O << getRegisterName(MO2.getReg()); + assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); + } else { + O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); + } +} + + +void ARMInstPrinter::printAddrMode2Operand(const MCInst *MI, unsigned Op) { + const MCOperand &MO1 = MI->getOperand(Op); + const MCOperand &MO2 = MI->getOperand(Op+1); + const MCOperand &MO3 = MI->getOperand(Op+2); + + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op); + return; + } + + O << "[" << getRegisterName(MO1.getReg()); + + if (!MO2.getReg()) { + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + O << ", #" + << (char)ARM_AM::getAM2Op(MO3.getImm()) + << ARM_AM::getAM2Offset(MO3.getImm()); + O << "]"; + return; + } + + O << ", " + << (char)ARM_AM::getAM2Op(MO3.getImm()) + << getRegisterName(MO2.getReg()); + + if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm())) + << " #" << ShImm; + O << "]"; +} + +void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + if (!MO1.getReg()) { + unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); + assert(ImmOffs && "Malformed indexed load / store!"); + O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; + return; + } + + O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); + + if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm())) + << " #" << ShImm; +} + +void ARMInstPrinter::printAddrMode3Operand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + const MCOperand &MO3 = MI->getOperand(OpNum+2); + + O << '[' << getRegisterName(MO1.getReg()); + + if (MO2.getReg()) { + O << ", " << (char)ARM_AM::getAM3Op(MO3.getImm()) + << getRegisterName(MO2.getReg()) << ']'; + return; + } + + if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) + O << ", #" + << (char)ARM_AM::getAM3Op(MO3.getImm()) + << ImmOffs; + O << ']'; +} + +void ARMInstPrinter::printAddrMode3OffsetOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + if (MO1.getReg()) { + O << (char)ARM_AM::getAM3Op(MO2.getImm()) + << getRegisterName(MO1.getReg()); + return; + } + + unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); + assert(ImmOffs && "Malformed indexed load / store!"); + O << "#" + << (char)ARM_AM::getAM3Op(MO2.getImm()) + << ImmOffs; +} + + +void ARMInstPrinter::printAddrMode4Operand(const MCInst *MI, unsigned OpNum, + const char *Modifier) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); + if (Modifier && strcmp(Modifier, "submode") == 0) { + if (MO1.getReg() == ARM::SP) { + // FIXME + bool isLDM = (MI->getOpcode() == ARM::LDM || + MI->getOpcode() == ARM::LDM_RET || + MI->getOpcode() == ARM::t2LDM || + MI->getOpcode() == ARM::t2LDM_RET); + O << ARM_AM::getAMSubModeAltStr(Mode, isLDM); + } else + O << ARM_AM::getAMSubModeStr(Mode); + } else if (Modifier && strcmp(Modifier, "wide") == 0) { + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); + if (Mode == ARM_AM::ia) + O << ".w"; + } else { + printOperand(MI, OpNum); + if (ARM_AM::getAM4WBFlag(MO2.getImm())) + O << "!"; + } +} + +void ARMInstPrinter::printAddrMode5Operand(const MCInst *MI, unsigned OpNum, + const char *Modifier) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, OpNum); + return; + } + + if (Modifier && strcmp(Modifier, "submode") == 0) { + ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MO2.getImm()); + if (MO1.getReg() == ARM::SP) { + bool isFLDM = (MI->getOpcode() == ARM::FLDMD || + MI->getOpcode() == ARM::FLDMS); + O << ARM_AM::getAMSubModeAltStr(Mode, isFLDM); + } else + O << ARM_AM::getAMSubModeStr(Mode); + return; + } else if (Modifier && strcmp(Modifier, "base") == 0) { + // Used for FSTM{D|S} and LSTM{D|S} operations. + O << getRegisterName(MO1.getReg()); + if (ARM_AM::getAM5WBFlag(MO2.getImm())) + O << "!"; + return; + } + + O << "[" << getRegisterName(MO1.getReg()); + + if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { + O << ", #" + << (char)ARM_AM::getAM5Op(MO2.getImm()) + << ImmOffs*4; + } + O << "]"; +} + +void ARMInstPrinter::printAddrMode6Operand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + const MCOperand &MO3 = MI->getOperand(OpNum+2); + + // FIXME: No support yet for specifying alignment. + O << '[' << getRegisterName(MO1.getReg()) << ']'; + + if (ARM_AM::getAM6WBFlag(MO3.getImm())) { + if (MO2.getReg() == 0) + O << '!'; + else + O << ", " << getRegisterName(MO2.getReg()); + } +} + +void ARMInstPrinter::printAddrModePCOperand(const MCInst *MI, unsigned OpNum, + const char *Modifier) { + assert(0 && "FIXME: Implement printAddrModePCOperand"); +} + +void ARMInstPrinter::printBitfieldInvMaskImmOperand (const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO = MI->getOperand(OpNum); + uint32_t v = ~MO.getImm(); + int32_t lsb = CountTrailingZeros_32(v); + int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb; + assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!"); + O << '#' << lsb << ", #" << width; +} + +void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) { + O << "{"; + // Always skip the first operand, it's the optional (and implicit writeback). + for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) { + if (i != OpNum+1) O << ", "; + O << getRegisterName(MI->getOperand(i).getReg()); + } + O << "}"; +} + +void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) { + ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); + if (CC != ARMCC::AL) + O << ARMCondCodeToString(CC); +} + +void ARMInstPrinter::printSBitModifierOperand(const MCInst *MI, unsigned OpNum){ + if (MI->getOperand(OpNum).getReg()) { + assert(MI->getOperand(OpNum).getReg() == ARM::CPSR && + "Expect ARM CPSR register!"); + O << 's'; + } +} + + + +void ARMInstPrinter::printCPInstOperand(const MCInst *MI, unsigned OpNum, + const char *Modifier) { + // FIXME: remove this. + abort(); +} + +void ARMInstPrinter::printNoHashImmediate(const MCInst *MI, unsigned OpNum) { + O << MI->getOperand(OpNum).getImm(); +} + + +void ARMInstPrinter::printPCLabel(const MCInst *MI, unsigned OpNum) { + // FIXME: remove this. + abort(); +} diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h new file mode 100644 index 0000000..4925137 --- /dev/null +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h @@ -0,0 +1,89 @@ +//===-- ARMInstPrinter.h - Convert ARM MCInst to assembly syntax ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an ARM MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef ARMINSTPRINTER_H +#define ARMINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { + class MCOperand; + +class ARMInstPrinter : public MCInstPrinter { + bool VerboseAsm; +public: + ARMInstPrinter(raw_ostream &O, const MCAsmInfo &MAI, bool verboseAsm) + : MCInstPrinter(O, MAI), VerboseAsm(verboseAsm) {} + + virtual void printInst(const MCInst *MI); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI); + static const char *getRegisterName(unsigned RegNo); + + + void printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier = 0); + + void printSOImmOperand(const MCInst *MI, unsigned OpNum); + void printSOImm2PartOperand(const MCInst *MI, unsigned OpNum); + + void printSORegOperand(const MCInst *MI, unsigned OpNum); + void printAddrMode2Operand(const MCInst *MI, unsigned OpNum); + void printAddrMode2OffsetOperand(const MCInst *MI, unsigned OpNum); + void printAddrMode3Operand(const MCInst *MI, unsigned OpNum); + void printAddrMode3OffsetOperand(const MCInst *MI, unsigned OpNum); + void printAddrMode4Operand(const MCInst *MI, unsigned OpNum, + const char *Modifier = 0); + void printAddrMode5Operand(const MCInst *MI, unsigned OpNum, + const char *Modifier = 0); + void printAddrMode6Operand(const MCInst *MI, unsigned OpNum); + void printAddrModePCOperand(const MCInst *MI, unsigned OpNum, + const char *Modifier = 0); + + void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum); + + void printThumbITMask(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeRI5Operand(const MCInst *MI, unsigned OpNum, + unsigned Scale) {} + void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum) {} + + void printT2SOOperand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum) {} + + void printPredicateOperand(const MCInst *MI, unsigned OpNum); + void printSBitModifierOperand(const MCInst *MI, unsigned OpNum); + void printRegisterList(const MCInst *MI, unsigned OpNum); + void printCPInstOperand(const MCInst *MI, unsigned OpNum, + const char *Modifier); + void printJTBlockOperand(const MCInst *MI, unsigned OpNum) {} + void printJT2BlockOperand(const MCInst *MI, unsigned OpNum) {} + void printTBAddrMode(const MCInst *MI, unsigned OpNum) {} + void printNoHashImmediate(const MCInst *MI, unsigned OpNum); + + void printPCLabel(const MCInst *MI, unsigned OpNum); + // FIXME: Implement. + void PrintSpecial(const MCInst *MI, const char *Kind) {} +}; + +} + +#endif diff --git a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp new file mode 100644 index 0000000..757164e --- /dev/null +++ b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp @@ -0,0 +1,166 @@ +//===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower ARM MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "ARMMCInstLower.h" +//#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +//#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Mangler.h" +#include "llvm/ADT/SmallString.h" +using namespace llvm; + + +#if 0 +const ARMSubtarget &ARMMCInstLower::getSubtarget() const { + return AsmPrinter.getSubtarget(); +} + +MachineModuleInfoMachO &ARMMCInstLower::getMachOMMI() const { + assert(getSubtarget().isTargetDarwin() &&"Can only get MachO info on darwin"); + return AsmPrinter.MMI->getObjFileInfo<MachineModuleInfoMachO>(); +} +#endif + +MCSymbol *ARMMCInstLower:: +GetGlobalAddressSymbol(const MachineOperand &MO) const { + const GlobalValue *GV = MO.getGlobal(); + + SmallString<128> Name; + Mang.getNameWithPrefix(Name, GV, false); + + // FIXME: HANDLE PLT references how?? + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *ARMMCInstLower:: +GetExternalSymbolSymbol(const MachineOperand &MO) const { + SmallString<128> Name; + Name += Printer.MAI->getGlobalPrefix(); + Name += MO.getSymbolName(); + + // FIXME: HANDLE PLT references how?? + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + + + +MCSymbol *ARMMCInstLower:: +GetJumpTableSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' << MO.getIndex(); + +#if 0 + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + } +#endif + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *ARMMCInstLower:: +GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' << MO.getIndex(); + +#if 0 + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + } +#endif + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCOperand ARMMCInstLower:: +LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + +#if 0 + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + } +#endif + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), Ctx), + Ctx); + return MCOperand::CreateExpr(Expr); +} + + +void ARMMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->dump(); + assert(0 && "unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + Printer.GetMBBSymbol(MO.getMBB()->getNumber()), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + } + + OutMI.addOperand(MCOp); + } + +} diff --git a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.h b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.h new file mode 100644 index 0000000..383d30d --- /dev/null +++ b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.h @@ -0,0 +1,56 @@ +//===-- ARMMCInstLower.h - Lower MachineInstr to MCInst -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef ARM_MCINSTLOWER_H +#define ARM_MCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { + class AsmPrinter; + class MCAsmInfo; + class MCContext; + class MCInst; + class MCOperand; + class MCSymbol; + class MachineInstr; + class MachineModuleInfoMachO; + class MachineOperand; + class Mangler; + //class ARMSubtarget; + +/// ARMMCInstLower - This class is used to lower an MachineInstr into an MCInst. +class VISIBILITY_HIDDEN ARMMCInstLower { + MCContext &Ctx; + Mangler &Mang; + AsmPrinter &Printer; + + //const ARMSubtarget &getSubtarget() const; +public: + ARMMCInstLower(MCContext &ctx, Mangler &mang, AsmPrinter &printer) + : Ctx(ctx), Mang(mang), Printer(printer) {} + + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + //MCSymbol *GetPICBaseSymbol() const; + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + +/* +private: + MachineModuleInfoMachO &getMachOMMI() const; + */ +}; + +} + +#endif diff --git a/lib/Target/ARM/AsmPrinter/CMakeLists.txt b/lib/Target/ARM/AsmPrinter/CMakeLists.txt index a67fc84..4e299f8 100644 --- a/lib/Target/ARM/AsmPrinter/CMakeLists.txt +++ b/lib/Target/ARM/AsmPrinter/CMakeLists.txt @@ -2,5 +2,7 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/ add_llvm_library(LLVMARMAsmPrinter ARMAsmPrinter.cpp + ARMInstPrinter.cpp + ARMMCInstLower.cpp ) -add_dependencies(LLVMARMAsmPrinter ARMCodeGenTable_gen)
\ No newline at end of file +add_dependencies(LLVMARMAsmPrinter ARMCodeGenTable_gen) diff --git a/lib/Target/ARM/README-Thumb.txt b/lib/Target/ARM/README-Thumb.txt index a961a57..e7770b2 100644 --- a/lib/Target/ARM/README-Thumb.txt +++ b/lib/Target/ARM/README-Thumb.txt @@ -196,14 +196,6 @@ This is especially bad when dynamic alloca is used. The all fixed size stack objects are referenced off the frame pointer with negative offsets. See oggenc for an example. -//===---------------------------------------------------------------------===// - -We are reserving R3 as a scratch register under thumb mode. So if it is live in -to the function, we save / restore R3 to / from R12. Until register scavenging -is done, we should save R3 to a high callee saved reg at emitPrologue time -(when hasFP is true or stack size is large) and restore R3 from that register -instead. This allows us to at least get rid of the save to r12 everytime it is -used. //===---------------------------------------------------------------------===// diff --git a/lib/Target/ARM/Thumb1RegisterInfo.cpp b/lib/Target/ARM/Thumb1RegisterInfo.cpp index 3c896da..6207177 100644 --- a/lib/Target/ARM/Thumb1RegisterInfo.cpp +++ b/lib/Target/ARM/Thumb1RegisterInfo.cpp @@ -32,7 +32,6 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -394,31 +393,48 @@ rewriteFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, return 0; } -/// saveScavengerRegister - Save the register so it can be used by the +/// saveScavengerRegister - Spill the register so it can be used by the /// register scavenger. Return true. -bool Thumb1RegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - const TargetRegisterClass *RC, - unsigned Reg) const { +bool +Thumb1RegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, + const TargetRegisterClass *RC, + unsigned Reg) const { // Thumb1 can't use the emergency spill slot on the stack because // ldr/str immediate offsets must be positive, and if we're referencing // off the frame pointer (if, for example, there are alloca() calls in // the function, the offset will be negative. Use R12 instead since that's // a call clobbered register that we know won't be used in Thumb1 mode. + DebugLoc DL = DebugLoc::getUnknownLoc(); + BuildMI(MBB, I, DL, TII.get(ARM::tMOVtgpr2gpr)). + addReg(ARM::R12, RegState::Define).addReg(Reg, RegState::Kill); + + // The UseMI is where we would like to restore the register. If there's + // interference with R12 before then, however, we'll need to restore it + // before that instead and adjust the UseMI. + bool done = false; + for (MachineBasicBlock::iterator II = I; !done && II != UseMI ; ++II) { + // If this instruction affects R12, adjust our restore point. + for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = II->getOperand(i); + if (!MO.isReg() || MO.isUndef() || !MO.getReg() || + TargetRegisterInfo::isVirtualRegister(MO.getReg())) + continue; + if (MO.getReg() == ARM::R12) { + UseMI = II; + done = true; + break; + } + } + } + // Restore the register from R12 + BuildMI(MBB, UseMI, DL, TII.get(ARM::tMOVgpr2tgpr)). + addReg(Reg, RegState::Define).addReg(ARM::R12, RegState::Kill); - TII.copyRegToReg(MBB, I, ARM::R12, Reg, ARM::GPRRegisterClass, RC); return true; } -/// restoreScavengerRegister - restore a registers saved by -// saveScavengerRegister(). -void Thumb1RegisterInfo::restoreScavengerRegister(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - const TargetRegisterClass *RC, - unsigned Reg) const { - TII.copyRegToReg(MBB, I, Reg, ARM::R12, RC, ARM::GPRRegisterClass); -} - unsigned Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, int *Value, @@ -828,7 +844,6 @@ void Thumb1RegisterInfo::emitEpilogue(MachineFunction &MF, if (VARegSaveSize) { // Epilogue for vararg functions: pop LR to R3 and branch off it. - // FIXME: Verify this is still ok when R3 is no longer being reserved. AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tPOP))) .addReg(0) // No write back. .addReg(ARM::R3, RegState::Define); diff --git a/lib/Target/ARM/Thumb1RegisterInfo.h b/lib/Target/ARM/Thumb1RegisterInfo.h index bb7a619..570a5bc 100644 --- a/lib/Target/ARM/Thumb1RegisterInfo.h +++ b/lib/Target/ARM/Thumb1RegisterInfo.h @@ -57,12 +57,9 @@ public: bool saveScavengerRegister(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, const TargetRegisterClass *RC, unsigned Reg) const; - void restoreScavengerRegister(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - const TargetRegisterClass *RC, - unsigned Reg) const; unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, int *Value = NULL, RegScavenger *RS = NULL) const; diff --git a/lib/Target/ARM/Thumb2ITBlockPass.cpp b/lib/Target/ARM/Thumb2ITBlockPass.cpp index 98b5cbd..427c0bb 100644 --- a/lib/Target/ARM/Thumb2ITBlockPass.cpp +++ b/lib/Target/ARM/Thumb2ITBlockPass.cpp @@ -107,8 +107,12 @@ bool Thumb2ITBlockPass::InsertITBlocks(MachineBasicBlock &MBB) { // Finalize IT mask. ARMCC::CondCodes OCC = ARMCC::getOppositeCondition(CC); unsigned Mask = 0, Pos = 3; - while (MBBI != E && Pos) { + // Branches, including tricky ones like LDM_RET, need to end an IT + // block so check the instruction we just put in the block. + while (MBBI != E && Pos && + (!MI->getDesc().isBranch() && !MI->getDesc().isReturn())) { MachineInstr *NMI = &*MBBI; + MI = NMI; DebugLoc ndl = NMI->getDebugLoc(); unsigned NPredReg = 0; ARMCC::CondCodes NCC = getPredicate(NMI, NPredReg); diff --git a/lib/Target/ARM/Thumb2RegisterInfo.cpp b/lib/Target/ARM/Thumb2RegisterInfo.cpp index 6c4c15d..f217e0e 100644 --- a/lib/Target/ARM/Thumb2RegisterInfo.cpp +++ b/lib/Target/ARM/Thumb2RegisterInfo.cpp @@ -32,7 +32,6 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; diff --git a/lib/Target/Blackfin/Blackfin.td b/lib/Target/Blackfin/Blackfin.td index b904638..cd90962 100644 --- a/lib/Target/Blackfin/Blackfin.td +++ b/lib/Target/Blackfin/Blackfin.td @@ -74,6 +74,7 @@ def WA_IND_CALL : SubtargetFeature<"ind-call-anomaly", "wa_ind_call", "true", include "BlackfinRegisterInfo.td" include "BlackfinCallingConv.td" +include "BlackfinIntrinsics.td" include "BlackfinInstrInfo.td" def BlackfinInstrInfo : InstrInfo {} diff --git a/lib/Target/Blackfin/BlackfinIntrinsicInfo.cpp b/lib/Target/Blackfin/BlackfinIntrinsicInfo.cpp new file mode 100644 index 0000000..544dc68 --- /dev/null +++ b/lib/Target/Blackfin/BlackfinIntrinsicInfo.cpp @@ -0,0 +1,53 @@ +//===- BlackfinIntrinsicInfo.cpp - Intrinsic Information --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Blackfin implementation of TargetIntrinsicInfo. +// +//===----------------------------------------------------------------------===// + +#include "BlackfinIntrinsicInfo.h" +#include "llvm/Intrinsics.h" +#include "llvm/Support/raw_ostream.h" +#include <cstring> + +using namespace llvm; + +namespace bfinIntrinsic { + + enum ID { + last_non_bfin_intrinsic = Intrinsic::num_intrinsics-1, +#define GET_INTRINSIC_ENUM_VALUES +#include "BlackfinGenIntrinsics.inc" +#undef GET_INTRINSIC_ENUM_VALUES + , num_bfin_intrinsics + }; + +} + +const char *BlackfinIntrinsicInfo::getName(unsigned IntrID) const { + static const char *const names[] = { +#define GET_INTRINSIC_NAME_TABLE +#include "BlackfinGenIntrinsics.inc" +#undef GET_INTRINSIC_NAME_TABLE + }; + + if (IntrID < Intrinsic::num_intrinsics) + return 0; + assert(IntrID < bfinIntrinsic::num_bfin_intrinsics && "Invalid intrinsic ID"); + + return names[IntrID - Intrinsic::num_intrinsics]; +} + +unsigned +BlackfinIntrinsicInfo::lookupName(const char *Name, unsigned Len) const { +#define GET_FUNCTION_RECOGNIZER +#include "BlackfinGenIntrinsics.inc" +#undef GET_FUNCTION_RECOGNIZER + return 0; +} diff --git a/lib/Target/Blackfin/BlackfinIntrinsicInfo.h b/lib/Target/Blackfin/BlackfinIntrinsicInfo.h new file mode 100644 index 0000000..3b59a60 --- /dev/null +++ b/lib/Target/Blackfin/BlackfinIntrinsicInfo.h @@ -0,0 +1,28 @@ +//===- BlackfinIntrinsicInfo.h - Blackfin Intrinsic Information -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Blackfin implementation of TargetIntrinsicInfo. +// +//===----------------------------------------------------------------------===// +#ifndef BLACKFININTRINSICS_H +#define BLACKFININTRINSICS_H + +#include "llvm/Target/TargetIntrinsicInfo.h" + +namespace llvm { + + class BlackfinIntrinsicInfo : public TargetIntrinsicInfo { + public: + const char *getName(unsigned IntrID) const; + unsigned lookupName(const char *Name, unsigned Len) const; + }; + +} + +#endif diff --git a/lib/Target/Blackfin/BlackfinIntrinsics.td b/lib/Target/Blackfin/BlackfinIntrinsics.td new file mode 100644 index 0000000..bf02cfe --- /dev/null +++ b/lib/Target/Blackfin/BlackfinIntrinsics.td @@ -0,0 +1,34 @@ +//===- BlackfinIntrinsics.td - Defines Blackfin intrinsics -*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines all of the blackfin-specific intrinsics. +// +//===----------------------------------------------------------------------===// + +let TargetPrefix = "bfin", isTarget = 1 in { + +//===----------------------------------------------------------------------===// +// Core synchronisation etc. +// +// These intrinsics have sideeffects. Each represent a single instruction, but +// workarounds are sometimes required depending on the cpu. + +// Execute csync instruction with workarounds +def int_bfin_csync : GCCBuiltin<"__builtin_bfin_csync">, + Intrinsic<[llvm_void_ty]>; + +// Execute ssync instruction with workarounds +def int_bfin_ssync : GCCBuiltin<"__builtin_bfin_ssync">, + Intrinsic<[llvm_void_ty]>; + +// Execute idle instruction with workarounds +def int_bfin_idle : GCCBuiltin<"__builtin_bfin_idle">, + Intrinsic<[llvm_void_ty]>; + +} diff --git a/lib/Target/Blackfin/BlackfinTargetMachine.h b/lib/Target/Blackfin/BlackfinTargetMachine.h index 73ed314..a14052b 100644 --- a/lib/Target/Blackfin/BlackfinTargetMachine.h +++ b/lib/Target/Blackfin/BlackfinTargetMachine.h @@ -20,6 +20,7 @@ #include "BlackfinInstrInfo.h" #include "BlackfinSubtarget.h" #include "BlackfinISelLowering.h" +#include "BlackfinIntrinsicInfo.h" namespace llvm { @@ -29,6 +30,7 @@ namespace llvm { BlackfinTargetLowering TLInfo; BlackfinInstrInfo InstrInfo; TargetFrameInfo FrameInfo; + BlackfinIntrinsicInfo IntrinsicInfo; public: BlackfinTargetMachine(const Target &T, const std::string &TT, const std::string &FS); @@ -47,6 +49,9 @@ namespace llvm { virtual const TargetData *getTargetData() const { return &DataLayout; } virtual bool addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel); + const TargetIntrinsicInfo *getIntrinsicInfo() const { + return &IntrinsicInfo; + } }; } // end namespace llvm diff --git a/lib/Target/Blackfin/CMakeLists.txt b/lib/Target/Blackfin/CMakeLists.txt index 6c3b244..deb005d 100644 --- a/lib/Target/Blackfin/CMakeLists.txt +++ b/lib/Target/Blackfin/CMakeLists.txt @@ -9,9 +9,11 @@ tablegen(BlackfinGenAsmWriter.inc -gen-asm-writer) tablegen(BlackfinGenDAGISel.inc -gen-dag-isel) tablegen(BlackfinGenSubtarget.inc -gen-subtarget) tablegen(BlackfinGenCallingConv.inc -gen-callingconv) +tablegen(BlackfinGenIntrinsics.inc -gen-tgt-intrinsic) add_llvm_target(BlackfinCodeGen BlackfinInstrInfo.cpp + BlackfinIntrinsicInfo.cpp BlackfinISelDAGToDAG.cpp BlackfinISelLowering.cpp BlackfinMCAsmInfo.cpp diff --git a/lib/Target/Blackfin/Makefile b/lib/Target/Blackfin/Makefile index c0c1bce..c68760b 100644 --- a/lib/Target/Blackfin/Makefile +++ b/lib/Target/Blackfin/Makefile @@ -15,7 +15,7 @@ BUILT_SOURCES = BlackfinGenRegisterInfo.h.inc BlackfinGenRegisterNames.inc \ BlackfinGenRegisterInfo.inc BlackfinGenInstrNames.inc \ BlackfinGenInstrInfo.inc BlackfinGenAsmWriter.inc \ BlackfinGenDAGISel.inc BlackfinGenSubtarget.inc \ - BlackfinGenCallingConv.inc + BlackfinGenCallingConv.inc BlackfinGenIntrinsics.inc DIRS = AsmPrinter TargetInfo diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index fe63edf..cbf769b 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -302,7 +302,6 @@ namespace { void visitInlineAsm(CallInst &I); bool visitBuiltinCall(CallInst &I, Intrinsic::ID ID, bool &WroteCallee); - void visitMallocInst(MallocInst &I); void visitAllocaInst(AllocaInst &I); void visitFreeInst (FreeInst &I); void visitLoadInst (LoadInst &I); @@ -3405,10 +3404,6 @@ void CWriter::visitInlineAsm(CallInst &CI) { Out << ")"; } -void CWriter::visitMallocInst(MallocInst &I) { - llvm_unreachable("lowerallocations pass didn't work!"); -} - void CWriter::visitAllocaInst(AllocaInst &I) { Out << '('; printType(Out, I.getType()); @@ -3690,7 +3685,7 @@ bool CTargetMachine::addPassesToEmitWholeFile(PassManager &PM, if (FileType != TargetMachine::AssemblyFile) return true; PM.add(createGCLoweringPass()); - PM.add(createLowerAllocationsPass(true)); + PM.add(createLowerAllocationsPass()); PM.add(createLowerInvokePass()); PM.add(createCFGSimplificationPass()); // clean up after lower invoke. PM.add(new CBackendNameAllUsedStructsAndMergeFunctions()); diff --git a/lib/Target/CppBackend/CPPBackend.cpp b/lib/Target/CppBackend/CPPBackend.cpp index 14ad451..45c2a7b 100644 --- a/lib/Target/CppBackend/CPPBackend.cpp +++ b/lib/Target/CppBackend/CPPBackend.cpp @@ -1258,20 +1258,6 @@ namespace { Out << "\");"; break; } - case Instruction::Malloc: { - const MallocInst* mallocI = cast<MallocInst>(I); - Out << "MallocInst* " << iName << " = new MallocInst(" - << getCppName(mallocI->getAllocatedType()) << ", "; - if (mallocI->isArrayAllocation()) - Out << opNames[0] << ", " ; - Out << "\""; - printEscapedString(mallocI->getName()); - Out << "\", " << bbname << ");"; - if (mallocI->getAlignment()) - nl(Out) << iName << "->setAlignment(" - << mallocI->getAlignment() << ");"; - break; - } case Instruction::Free: { Out << "FreeInst* " << iName << " = new FreeInst(" << getCppName(I->getOperand(0)) << ", " << bbname << ");"; diff --git a/lib/Target/MSIL/MSILWriter.cpp b/lib/Target/MSIL/MSILWriter.cpp index 26d637b..cf08a97 100644 --- a/lib/Target/MSIL/MSILWriter.cpp +++ b/lib/Target/MSIL/MSILWriter.cpp @@ -1191,9 +1191,6 @@ void MSILWriter::printInstruction(const Instruction* Inst) { case Instruction::Alloca: printAllocaInstruction(cast<AllocaInst>(Inst)); break; - case Instruction::Malloc: - llvm_unreachable("LowerAllocationsPass used"); - break; case Instruction::Free: llvm_unreachable("LowerAllocationsPass used"); break; @@ -1702,7 +1699,7 @@ bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM, if (FileType != TargetMachine::AssemblyFile) return true; MSILWriter* Writer = new MSILWriter(o); PM.add(createGCLoweringPass()); - PM.add(createLowerAllocationsPass(true)); + PM.add(createLowerAllocationsPass()); // FIXME: Handle switch trougth native IL instruction "switch" PM.add(createLowerSwitchPass()); PM.add(createCFGSimplificationPass()); diff --git a/lib/Target/MSP430/AsmPrinter/CMakeLists.txt b/lib/Target/MSP430/AsmPrinter/CMakeLists.txt index 6e66887..f1eb885 100644 --- a/lib/Target/MSP430/AsmPrinter/CMakeLists.txt +++ b/lib/Target/MSP430/AsmPrinter/CMakeLists.txt @@ -1,6 +1,8 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) add_llvm_library(LLVMMSP430AsmPrinter + MSP430InstPrinter.cpp MSP430AsmPrinter.cpp + MSP430MCInstLower.cpp ) add_dependencies(LLVMMSP430AsmPrinter MSP430CodeGenTable_gen) diff --git a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp index 852019f..ace358e 100644 --- a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp +++ b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp @@ -15,7 +15,9 @@ #define DEBUG_TYPE "asm-printer" #include "MSP430.h" #include "MSP430InstrInfo.h" +#include "MSP430InstPrinter.h" #include "MSP430MCAsmInfo.h" +#include "MSP430MCInstLower.h" #include "MSP430TargetMachine.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" @@ -26,12 +28,14 @@ #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Mangler.h" @@ -41,6 +45,10 @@ using namespace llvm; STATISTIC(EmittedInsts, "Number of machine instrs printed"); +static cl::opt<bool> +EnableMCInst("enable-msp430-mcinst-printer", cl::Hidden, + cl::desc("enable experimental mcinst gunk in the msp430 backend")); + namespace { class VISIBILITY_HIDDEN MSP430AsmPrinter : public AsmPrinter { public: @@ -52,8 +60,14 @@ namespace { return "MSP430 Assembly Printer"; } + void printMCInst(const MCInst *MI) { + MSP430InstPrinter(O, *MAI).printInstruction(MI); + } void printOperand(const MachineInstr *MI, int OpNum, const char* Modifier = 0); + void printPCRelImmOperand(const MachineInstr *MI, int OpNum) { + printOperand(MI, OpNum); + } void printSrcMemOperand(const MachineInstr *MI, int OpNum, const char* Modifier = 0); void printCCOperand(const MachineInstr *MI, int OpNum); @@ -67,6 +81,7 @@ namespace { bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode); + void printInstructionThroughMCStreamer(const MachineInstr *MI); void emitFunctionHeader(const MachineFunction &MF); bool runOnMachineFunction(MachineFunction &F); @@ -148,7 +163,11 @@ void MSP430AsmPrinter::printMachineInstruction(const MachineInstr *MI) { processDebugLoc(MI, true); // Call the autogenerated instruction printer routines. - printInstruction(MI); + if (EnableMCInst) { + printInstructionThroughMCStreamer(MI); + } else { + printInstruction(MI); + } if (VerboseAsm && !MI->getDebugLoc().isUnknown()) EmitComments(*MI); @@ -231,22 +250,22 @@ void MSP430AsmPrinter::printCCOperand(const MachineInstr *MI, int OpNum) { default: llvm_unreachable("Unsupported CC code"); break; - case MSP430::COND_E: + case MSP430CC::COND_E: O << "eq"; break; - case MSP430::COND_NE: + case MSP430CC::COND_NE: O << "ne"; break; - case MSP430::COND_HS: + case MSP430CC::COND_HS: O << "hs"; break; - case MSP430::COND_LO: + case MSP430CC::COND_LO: O << "lo"; break; - case MSP430::COND_GE: + case MSP430CC::COND_GE: O << "ge"; break; - case MSP430::COND_L: + case MSP430CC::COND_L: O << 'l'; break; } @@ -275,6 +294,36 @@ bool MSP430AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, return false; } +//===----------------------------------------------------------------------===// +void MSP430AsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) +{ + + MSP430MCInstLower MCInstLowering(OutContext, *Mang, *this); + + switch (MI->getOpcode()) { + case TargetInstrInfo::DBG_LABEL: + case TargetInstrInfo::EH_LABEL: + case TargetInstrInfo::GC_LABEL: + printLabel(MI); + return; + case TargetInstrInfo::KILL: + return; + case TargetInstrInfo::INLINEASM: + O << '\t'; + printInlineAsm(MI); + return; + case TargetInstrInfo::IMPLICIT_DEF: + printImplicitDef(MI); + return; + default: break; + } + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + + printMCInst(&TmpInst); +} + // Force static initialization. extern "C" void LLVMInitializeMSP430AsmPrinter() { RegisterAsmPrinter<MSP430AsmPrinter> X(TheMSP430Target); diff --git a/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp new file mode 100644 index 0000000..a3ecc67 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp @@ -0,0 +1,116 @@ +//===-- MSP430InstPrinter.cpp - Convert MSP430 MCInst to assembly syntax --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an MSP430 MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "MSP430.h" +#include "MSP430InstrInfo.h" +#include "MSP430InstPrinter.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + + +// Include the auto-generated portion of the assembly writer. +#define MachineInstr MCInst +#define MSP430AsmPrinter MSP430InstPrinter // FIXME: REMOVE. +#define NO_ASM_WRITER_BOILERPLATE +#include "MSP430GenAsmWriter.inc" +#undef MachineInstr +#undef MSP430AsmPrinter + +void MSP430InstPrinter::printInst(const MCInst *MI) { + printInstruction(MI); +} + +void MSP430InstPrinter::printPCRelImmOperand(const MCInst *MI, unsigned OpNo) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isImm()) + O << Op.getImm(); + else { + assert(Op.isExpr() && "unknown pcrel immediate operand"); + Op.getExpr()->print(O, &MAI); + } +} + +void MSP430InstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier) { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + O << getRegisterName(Op.getReg()); + } else if (Op.isImm()) { + O << '#' << Op.getImm(); + } else { + assert(Op.isExpr() && "unknown operand kind in printOperand"); + O << '#'; + Op.getExpr()->print(O, &MAI); + } +} + +void MSP430InstPrinter::printSrcMemOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier) { + const MCOperand &Base = MI->getOperand(OpNo); + const MCOperand &Disp = MI->getOperand(OpNo+1); + + // FIXME: move global to displacement field! + if (Base.isExpr()) { + O << '&'; + Base.getExpr()->print(O, &MAI); + } else if (Disp.isImm() && !Base.isReg()) + printOperand(MI, OpNo); + else if (Base.isReg()) { + if (Disp.getImm()) { + O << Disp.getImm() << '('; + printOperand(MI, OpNo); + O << ')'; + } else { + O << '@'; + printOperand(MI, OpNo); + } + } else { + Base.dump(); + Disp.dump(); + llvm_unreachable("Unsupported memory operand"); + } +} + +void MSP430InstPrinter::printCCOperand(const MCInst *MI, unsigned OpNo) { + unsigned CC = MI->getOperand(OpNo).getImm(); + + switch (CC) { + default: + llvm_unreachable("Unsupported CC code"); + break; + case MSP430CC::COND_E: + O << "eq"; + break; + case MSP430CC::COND_NE: + O << "ne"; + break; + case MSP430CC::COND_HS: + O << "hs"; + break; + case MSP430CC::COND_LO: + O << "lo"; + break; + case MSP430CC::COND_GE: + O << "ge"; + break; + case MSP430CC::COND_L: + O << 'l'; + break; + } +} diff --git a/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h new file mode 100644 index 0000000..2fac800 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h @@ -0,0 +1,46 @@ +//===-- MSP430InstPrinter.h - Convert MSP430 MCInst to assembly syntax ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints a MSP430 MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430INSTPRINTER_H +#define MSP430INSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm +{ + + class MCOperand; + + class MSP430InstPrinter : public MCInstPrinter { + public: + MSP430InstPrinter(raw_ostream &O, const MCAsmInfo &MAI) : + MCInstPrinter(O, MAI){ + } + + virtual void printInst(const MCInst *MI); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI); + static const char *getRegisterName(unsigned RegNo); + + void printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier = 0); + void printPCRelImmOperand(const MCInst *MI, unsigned OpNo); + void printSrcMemOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier = 0); + void printCCOperand(const MCInst *MI, unsigned OpNo); + + }; +} + +#endif diff --git a/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp new file mode 100644 index 0000000..f505b23 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp @@ -0,0 +1,147 @@ +//===-- MSP430MCInstLower.cpp - Convert MSP430 MachineInstr to an MCInst---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower MSP430 MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "MSP430MCInstLower.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Mangler.h" +#include "llvm/ADT/SmallString.h" +using namespace llvm; + +MCSymbol *MSP430MCInstLower:: +GetGlobalAddressSymbol(const MachineOperand &MO) const { + const GlobalValue *GV = MO.getGlobal(); + + SmallString<128> Name; + Mang.getNameWithPrefix(Name, GV, false); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetExternalSymbolSymbol(const MachineOperand &MO) const { + SmallString<128> Name; + Name += Printer.MAI->getGlobalPrefix(); + Name += MO.getSymbolName(); + + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetJumpTableSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCOperand MSP430MCInstLower:: +LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), Ctx), + Ctx); + return MCOperand::CreateExpr(Expr); +} + +void MSP430MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->dump(); + assert(0 && "unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + Printer.GetMBBSymbol(MO.getMBB()->getNumber()), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + } + + OutMI.addOperand(MCOp); + } +} diff --git a/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h new file mode 100644 index 0000000..a2b99ae --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h @@ -0,0 +1,49 @@ +//===-- MSP430MCInstLower.h - Lower MachineInstr to MCInst ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430_MCINSTLOWER_H +#define MSP430_MCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { + class AsmPrinter; + class MCAsmInfo; + class MCContext; + class MCInst; + class MCOperand; + class MCSymbol; + class MachineInstr; + class MachineModuleInfoMachO; + class MachineOperand; + class Mangler; + + /// MSP430MCInstLower - This class is used to lower an MachineInstr + /// into an MCInst. +class VISIBILITY_HIDDEN MSP430MCInstLower { + MCContext &Ctx; + Mangler &Mang; + + AsmPrinter &Printer; +public: + MSP430MCInstLower(MCContext &ctx, Mangler &mang, AsmPrinter &printer) + : Ctx(ctx), Mang(mang), Printer(printer) {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; +}; + +} + +#endif diff --git a/lib/Target/MSP430/MSP430.h b/lib/Target/MSP430/MSP430.h index d9f5f86..1ff178d 100644 --- a/lib/Target/MSP430/MSP430.h +++ b/lib/Target/MSP430/MSP430.h @@ -17,6 +17,20 @@ #include "llvm/Target/TargetMachine.h" +namespace MSP430CC { + // MSP430 specific condition code. + enum CondCodes { + COND_E = 0, // aka COND_Z + COND_NE = 1, // aka COND_NZ + COND_HS = 2, // aka COND_C + COND_LO = 3, // aka COND_NC + COND_GE = 4, + COND_L = 5, + + COND_INVALID = -1 + }; +} + namespace llvm { class MSP430TargetMachine; class FunctionPass; diff --git a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp index 4195a88..b7d9282 100644 --- a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp +++ b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp @@ -26,6 +26,7 @@ #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -34,6 +35,14 @@ using namespace llvm; +#ifndef NDEBUG +static cl::opt<bool> +ViewRMWDAGs("view-msp430-rmw-dags", cl::Hidden, + cl::desc("Pop up a window to show isel dags after RMW preprocess")); +#else +static const bool ViewRMWDAGs = false; +#endif + STATISTIC(NumLoadMoved, "Number of loads moved below TokenFactor"); /// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine @@ -56,6 +65,9 @@ namespace { return "MSP430 DAG->DAG Pattern Instruction Selection"; } + bool IsLegalAndProfitableToFold(SDNode *N, SDNode *U, + SDNode *Root) const; + virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, std::vector<SDValue> &OutOps); @@ -64,6 +76,7 @@ namespace { #include "MSP430GenDAGISel.inc" private: + DenseMap<SDNode*, SDNode*> RMWStores; void PreprocessForRMW(); SDNode *Select(SDValue Op); bool SelectAddr(SDValue Op, SDValue Addr, SDValue &Base, SDValue &Disp); @@ -130,7 +143,6 @@ bool MSP430DAGToDAGISel::SelectAddr(SDValue Op, SDValue Addr, return true; } - bool MSP430DAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, std::vector<SDValue> &OutOps) { @@ -148,31 +160,54 @@ SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, return false; } +bool MSP430DAGToDAGISel::IsLegalAndProfitableToFold(SDNode *N, SDNode *U, + SDNode *Root) const { + if (OptLevel == CodeGenOpt::None) return false; + + /// RMW preprocessing creates the following code: + /// [Load1] + /// ^ ^ + /// / | + /// / | + /// [Load2] | + /// ^ ^ | + /// | | | + /// | \-| + /// | | + /// | [Op] + /// | ^ + /// | | + /// \ / + /// \ / + /// [Store] + /// + /// The path Store => Load2 => Load1 is via chain. Note that in general it is + /// not allowed to fold Load1 into Op (and Store) since it will creates a + /// cycle. However, this is perfectly legal for the loads moved below the + /// TokenFactor by PreprocessForRMW. Query the map Store => Load1 (created + /// during preprocessing) to determine whether it's legal to introduce such + /// "cycle" for a moment. + DenseMap<SDNode*, SDNode*>::iterator I = RMWStores.find(Root); + if (I != RMWStores.end() && I->second == N) + return true; + + // Proceed to 'generic' cycle finder code + return SelectionDAGISel::IsLegalAndProfitableToFold(N, U, Root); +} + + /// MoveBelowTokenFactor - Replace TokenFactor operand with load's chain operand /// and move load below the TokenFactor. Replace store's chain operand with /// load's chain result. -/// Shamelessly stolen from X86. static void MoveBelowTokenFactor(SelectionDAG *CurDAG, SDValue Load, SDValue Store, SDValue TF) { SmallVector<SDValue, 4> Ops; - bool isRMW = false; - SDValue TF0, TF1, NewTF; for (unsigned i = 0, e = TF.getNode()->getNumOperands(); i != e; ++i) - if (Load.getNode() == TF.getOperand(i).getNode()) { - TF0 = Load.getOperand(0); - Ops.push_back(TF0); - } else { - TF1 = TF.getOperand(i); - Ops.push_back(TF1); - if (LoadSDNode* LD = dyn_cast<LoadSDNode>(TF1)) - isRMW = !LD->isVolatile(); - } - - if (isRMW && TF1.getOperand(0).getNode() == TF0.getNode()) - NewTF = TF0; - else - NewTF = CurDAG->UpdateNodeOperands(TF, &Ops[0], Ops.size()); - + if (Load.getNode() == TF.getOperand(i).getNode()) + Ops.push_back(Load.getOperand(0)); + else + Ops.push_back(TF.getOperand(i)); + SDValue NewTF = CurDAG->UpdateNodeOperands(TF, &Ops[0], Ops.size()); SDValue NewLoad = CurDAG->UpdateNodeOperands(Load, NewTF, Load.getOperand(1), Load.getOperand(2)); @@ -180,12 +215,43 @@ static void MoveBelowTokenFactor(SelectionDAG *CurDAG, SDValue Load, Store.getOperand(2), Store.getOperand(3)); } -/// isRMWLoad - Return true if N is a load that's part of RMW sub-DAG. The chain -/// produced by the load must only be used by the store's chain operand, -/// otherwise this may produce a cycle in the DAG. -/// Shamelessly stolen from X86. FIXME: Should we make this function common? -static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, - SDValue &Load) { +/// MoveBelowTokenFactor2 - Replace TokenFactor operand with load's chain operand +/// and move load below the TokenFactor. Replace store's chain operand with +/// load's chain result. This a version which sinks two loads below token factor. +/// Look into PreprocessForRMW comments for explanation of transform. +static void MoveBelowTokenFactor2(SelectionDAG *CurDAG, + SDValue Load1, SDValue Load2, + SDValue Store, SDValue TF) { + SmallVector<SDValue, 4> Ops; + for (unsigned i = 0, e = TF.getNode()->getNumOperands(); i != e; ++i) { + SDNode* N = TF.getOperand(i).getNode(); + if (Load2.getNode() == N) + Ops.push_back(Load2.getOperand(0)); + else if (Load1.getNode() != N) + Ops.push_back(TF.getOperand(i)); + } + + SDValue NewTF = SDValue(CurDAG->MorphNodeTo(TF.getNode(), + TF.getOpcode(), + TF.getNode()->getVTList(), + &Ops[0], Ops.size()), TF.getResNo()); + SDValue NewLoad2 = CurDAG->UpdateNodeOperands(Load2, NewTF, + Load2.getOperand(1), + Load2.getOperand(2)); + + SDValue NewLoad1 = CurDAG->UpdateNodeOperands(Load1, NewLoad2.getValue(1), + Load1.getOperand(1), + Load1.getOperand(2)); + + CurDAG->UpdateNodeOperands(Store, + NewLoad1.getValue(1), + Store.getOperand(1), + Store.getOperand(2), Store.getOperand(3)); +} + +/// isAllowedToSink - return true if N a load which can be moved below token +/// factor. Basically, the load should be non-volatile and has single use. +static bool isLoadAllowedToSink(SDValue N, SDValue Chain) { if (N.getOpcode() == ISD::BIT_CONVERT) N = N.getOperand(0); @@ -199,10 +265,19 @@ static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, if (ExtType != ISD::NON_EXTLOAD && ExtType != ISD::EXTLOAD) return false; - if (N.hasOneUse() && - LD->hasNUsesOfValue(1, 1) && - N.getOperand(1) == Address && - LD->isOperandOf(Chain.getNode())) { + return (N.hasOneUse() && + LD->hasNUsesOfValue(1, 1) && + LD->isOperandOf(Chain.getNode())); +} + + +/// isRMWLoad - Return true if N is a load that's part of RMW sub-DAG. +/// The chain produced by the load must only be used by the store's chain +/// operand, otherwise this may produce a cycle in the DAG. +static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, + SDValue &Load) { + if (isLoadAllowedToSink(N, Chain) && + N.getOperand(1) == Address) { Load = N; return true; } @@ -210,57 +285,140 @@ static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, } /// PreprocessForRMW - Preprocess the DAG to make instruction selection better. -/// Shamelessly stolen from X86. +/// This is only run if not in -O0 mode. +/// This allows the instruction selector to pick more read-modify-write +/// instructions. This is a common case: +/// +/// [Load chain] +/// ^ +/// | +/// [Load] +/// ^ ^ +/// | | +/// / \- +/// / | +/// [TokenFactor] [Op] +/// ^ ^ +/// | | +/// \ / +/// \ / +/// [Store] +/// +/// The fact the store's chain operand != load's chain will prevent the +/// (store (op (load))) instruction from being selected. We can transform it to: +/// +/// [Load chain] +/// ^ +/// | +/// [TokenFactor] +/// ^ +/// | +/// [Load] +/// ^ ^ +/// | | +/// | \- +/// | | +/// | [Op] +/// | ^ +/// | | +/// \ / +/// \ / +/// [Store] +/// +/// We also recognize the case where second operand of Op is load as well and +/// move it below token factor as well creating DAG as follows: +/// +/// [Load chain] +/// ^ +/// | +/// [TokenFactor] +/// ^ +/// | +/// [Load1] +/// ^ ^ +/// / | +/// / | +/// [Load2] | +/// ^ ^ | +/// | | | +/// | \-| +/// | | +/// | [Op] +/// | ^ +/// | | +/// \ / +/// \ / +/// [Store] +/// +/// This allows selection of mem-mem instructions. Yay! + void MSP430DAGToDAGISel::PreprocessForRMW() { for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(), E = CurDAG->allnodes_end(); I != E; ++I) { if (!ISD::isNON_TRUNCStore(I)) continue; - SDValue Chain = I->getOperand(0); + if (Chain.getNode()->getOpcode() != ISD::TokenFactor) continue; - SDValue N1 = I->getOperand(1); // Value to store - SDValue N2 = I->getOperand(2); // Address of store - - if (!N1.hasOneUse()) + SDValue N1 = I->getOperand(1); + SDValue N2 = I->getOperand(2); + if ((N1.getValueType().isFloatingPoint() && + !N1.getValueType().isVector()) || + !N1.hasOneUse()) continue; - bool RModW = false; - SDValue Load; + unsigned RModW = 0; + SDValue Load1, Load2; unsigned Opcode = N1.getNode()->getOpcode(); switch (Opcode) { - case ISD::ADD: - case ISD::AND: - case ISD::OR: - case ISD::XOR: - case ISD::ADDC: - case ISD::ADDE: { - SDValue N10 = N1.getOperand(0); - SDValue N11 = N1.getOperand(1); - RModW = isRMWLoad(N10, Chain, N2, Load); - - if (!RModW && isRMWLoad(N11, Chain, N2, Load)) { - // Swap the operands, making the RMW load the first operand seems - // to help selection and prevent token chain loops. - N1 = CurDAG->UpdateNodeOperands(N1, N11, N10); - RModW = true; - } - break; + case ISD::ADD: + case ISD::AND: + case ISD::OR: + case ISD::XOR: + case ISD::ADDC: + case ISD::ADDE: { + SDValue N10 = N1.getOperand(0); + SDValue N11 = N1.getOperand(1); + if (isRMWLoad(N10, Chain, N2, Load1)) { + if (isLoadAllowedToSink(N11, Chain)) { + Load2 = N11; + RModW = 2; + } else + RModW = 1; + } else if (isRMWLoad(N11, Chain, N2, Load1)) { + if (isLoadAllowedToSink(N10, Chain)) { + Load2 = N10; + RModW = 2; + } else + RModW = 1; } - case ISD::SUB: - case ISD::SUBC: - case ISD::SUBE: { - SDValue N10 = N1.getOperand(0); - RModW = isRMWLoad(N10, Chain, N2, Load); - break; + break; + } + case ISD::SUB: + case ISD::SUBC: + case ISD::SUBE: { + SDValue N10 = N1.getOperand(0); + SDValue N11 = N1.getOperand(1); + if (isRMWLoad(N10, Chain, N2, Load1)) { + if (isLoadAllowedToSink(N11, Chain)) { + Load2 = N11; + RModW = 2; + } else + RModW = 1; } + break; + } } - if (RModW) { - MoveBelowTokenFactor(CurDAG, Load, SDValue(I, 0), Chain); - ++NumLoadMoved; + NumLoadMoved += RModW; + if (RModW == 1) + MoveBelowTokenFactor(CurDAG, Load1, SDValue(I, 0), Chain); + else if (RModW == 2) { + MoveBelowTokenFactor2(CurDAG, Load1, Load2, SDValue(I, 0), Chain); + SDNode* Store = I; + RMWStores[Store] = Load2.getNode(); } } } @@ -268,8 +426,15 @@ void MSP430DAGToDAGISel::PreprocessForRMW() { /// InstructionSelect - This callback is invoked by /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. void MSP430DAGToDAGISel::InstructionSelect() { + std::string BlockName; + if (ViewRMWDAGs) + BlockName = MF->getFunction()->getNameStr() + ":" + + BB->getBasicBlock()->getNameStr(); + PreprocessForRMW(); + if (ViewRMWDAGs) CurDAG->viewGraph("RMW preprocessed:" + BlockName); + DEBUG(errs() << "Selection DAG after RMW preprocessing:\n"); DEBUG(CurDAG->dump()); @@ -282,6 +447,7 @@ void MSP430DAGToDAGISel::InstructionSelect() { DEBUG(errs() << "===== Instruction selection ends:\n"); CurDAG->RemoveDeadNodes(); + RMWStores.clear(); } SDNode *MSP430DAGToDAGISel::Select(SDValue Op) { diff --git a/lib/Target/MSP430/MSP430ISelLowering.cpp b/lib/Target/MSP430/MSP430ISelLowering.cpp index b56f069..34e6d2c 100644 --- a/lib/Target/MSP430/MSP430ISelLowering.cpp +++ b/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -567,44 +567,45 @@ SDValue MSP430TargetLowering::LowerExternalSymbol(SDValue Op, return DAG.getNode(MSP430ISD::Wrapper, dl, getPointerTy(), Result);; } -static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, unsigned &TargetCC, +static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC, ISD::CondCode CC, DebugLoc dl, SelectionDAG &DAG) { // FIXME: Handle bittests someday assert(!LHS.getValueType().isFloatingPoint() && "We don't handle FP yet"); // FIXME: Handle jump negative someday - TargetCC = MSP430::COND_INVALID; + MSP430CC::CondCodes TCC = MSP430CC::COND_INVALID; switch (CC) { default: llvm_unreachable("Invalid integer condition!"); case ISD::SETEQ: - TargetCC = MSP430::COND_E; // aka COND_Z + TCC = MSP430CC::COND_E; // aka COND_Z break; case ISD::SETNE: - TargetCC = MSP430::COND_NE; // aka COND_NZ + TCC = MSP430CC::COND_NE; // aka COND_NZ break; case ISD::SETULE: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETUGE: - TargetCC = MSP430::COND_HS; // aka COND_C + TCC = MSP430CC::COND_HS; // aka COND_C break; case ISD::SETUGT: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETULT: - TargetCC = MSP430::COND_LO; // aka COND_NC + TCC = MSP430CC::COND_LO; // aka COND_NC break; case ISD::SETLE: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETGE: - TargetCC = MSP430::COND_GE; + TCC = MSP430CC::COND_GE; break; case ISD::SETGT: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETLT: - TargetCC = MSP430::COND_L; + TCC = MSP430CC::COND_L; break; } + TargetCC = DAG.getConstant(TCC, MVT::i8); return DAG.getNode(MSP430ISD::CMP, dl, MVT::Flag, LHS, RHS); } @@ -617,13 +618,11 @@ SDValue MSP430TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) { SDValue Dest = Op.getOperand(4); DebugLoc dl = Op.getDebugLoc(); - unsigned TargetCC = MSP430::COND_INVALID; + SDValue TargetCC; SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); return DAG.getNode(MSP430ISD::BR_CC, dl, Op.getValueType(), - Chain, - Dest, DAG.getConstant(TargetCC, MVT::i8), - Flag); + Chain, Dest, TargetCC, Flag); } SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { @@ -634,14 +633,14 @@ SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); DebugLoc dl = Op.getDebugLoc(); - unsigned TargetCC = MSP430::COND_INVALID; + SDValue TargetCC; SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag); SmallVector<SDValue, 4> Ops; Ops.push_back(TrueV); Ops.push_back(FalseV); - Ops.push_back(DAG.getConstant(TargetCC, MVT::i8)); + Ops.push_back(TargetCC); Ops.push_back(Flag); return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size()); diff --git a/lib/Target/MSP430/MSP430InstrInfo.cpp b/lib/Target/MSP430/MSP430InstrInfo.cpp index 37fbb6d..a6d9638 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.cpp +++ b/lib/Target/MSP430/MSP430InstrInfo.cpp @@ -151,6 +151,163 @@ MSP430InstrInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, return true; } +unsigned MSP430InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator I = MBB.end(); + unsigned Count = 0; + + while (I != MBB.begin()) { + --I; + if (I->getOpcode() != MSP430::JMP && + I->getOpcode() != MSP430::JCC) + break; + // Remove the branch. + I->eraseFromParent(); + I = MBB.end(); + ++Count; + } + + return Count; +} + +bool MSP430InstrInfo:: +ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { + assert(Cond.size() == 1 && "Invalid Xbranch condition!"); + + MSP430CC::CondCodes CC = static_cast<MSP430CC::CondCodes>(Cond[0].getImm()); + + switch (CC) { + default: + assert(0 && "Invalid branch condition!"); + break; + case MSP430CC::COND_E: + CC = MSP430CC::COND_NE; + break; + case MSP430CC::COND_NE: + CC = MSP430CC::COND_E; + break; + case MSP430CC::COND_L: + CC = MSP430CC::COND_GE; + break; + case MSP430CC::COND_GE: + CC = MSP430CC::COND_L; + break; + case MSP430CC::COND_HS: + CC = MSP430CC::COND_LO; + break; + case MSP430CC::COND_LO: + CC = MSP430CC::COND_HS; + break; + } + + Cond[0].setImm(CC); + return false; +} + +bool MSP430InstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB)const{ + if (MBB.empty()) return false; + + switch (MBB.back().getOpcode()) { + case MSP430::RET: // Return. + case MSP430::JMP: // Uncond branch. + return true; + default: return false; + } +} + +bool MSP430InstrInfo::isUnpredicatedTerminator(const MachineInstr *MI) const { + const TargetInstrDesc &TID = MI->getDesc(); + if (!TID.isTerminator()) return false; + + // Conditional branch is a special case. + if (TID.isBranch() && !TID.isBarrier()) + return true; + if (!TID.isPredicable()) + return true; + return !isPredicated(MI); +} + +bool MSP430InstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + // Start from the bottom of the block and work up, examining the + // terminator instructions. + MachineBasicBlock::iterator I = MBB.end(); + while (I != MBB.begin()) { + --I; + // Working from the bottom, when we see a non-terminator + // instruction, we're done. + if (!isUnpredicatedTerminator(I)) + break; + + // A terminator that isn't a branch can't easily be handled + // by this analysis. + if (!I->getDesc().isBranch()) + return true; + + // Handle unconditional branches. + if (I->getOpcode() == MSP430::JMP) { + if (!AllowModify) { + TBB = I->getOperand(0).getMBB(); + continue; + } + + // If the block has any instructions after a JMP, delete them. + while (next(I) != MBB.end()) + next(I)->eraseFromParent(); + Cond.clear(); + FBB = 0; + + // Delete the JMP if it's equivalent to a fall-through. + if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { + TBB = 0; + I->eraseFromParent(); + I = MBB.end(); + continue; + } + + // TBB is used to indicate the unconditinal destination. + TBB = I->getOperand(0).getMBB(); + continue; + } + + // Handle conditional branches. + assert(I->getOpcode() == MSP430::JCC && "Invalid conditional branch"); + MSP430CC::CondCodes BranchCode = + static_cast<MSP430CC::CondCodes>(I->getOperand(1).getImm()); + if (BranchCode == MSP430CC::COND_INVALID) + return true; // Can't handle weird stuff. + + // Working from the bottom, handle the first conditional branch. + if (Cond.empty()) { + FBB = TBB; + TBB = I->getOperand(0).getMBB(); + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + continue; + } + + // Handle subsequent conditional branches. Only handle the case where all + // conditional branches branch to the same destination. + assert(Cond.size() == 1); + assert(TBB); + + // Only handle the case where all conditional branches branch to + // the same destination. + if (TBB != I->getOperand(0).getMBB()) + return true; + + MSP430CC::CondCodes OldBranchCode = (MSP430CC::CondCodes)Cond[0].getImm(); + // If the conditions are the same, we can leave them alone. + if (OldBranchCode == BranchCode) + continue; + + return true; + } + + return false; +} + unsigned MSP430InstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, @@ -172,7 +329,13 @@ MSP430InstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, // Conditional branch. unsigned Count = 0; - llvm_unreachable("Implement conditional branches!"); + BuildMI(&MBB, dl, get(MSP430::JCC)).addMBB(TBB).addImm(Cond[0].getImm()); + ++Count; + if (FBB) { + // Two-way Conditional branch. Insert the second branch. + BuildMI(&MBB, dl, get(MSP430::JMP)).addMBB(FBB); + ++Count; + } return Count; } diff --git a/lib/Target/MSP430/MSP430InstrInfo.h b/lib/Target/MSP430/MSP430InstrInfo.h index e07aaca..35e35db 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.h +++ b/lib/Target/MSP430/MSP430InstrInfo.h @@ -21,20 +21,6 @@ namespace llvm { class MSP430TargetMachine; -namespace MSP430 { - // MSP430 specific condition code. - enum CondCode { - COND_E = 0, // aka COND_Z - COND_NE = 1, // aka COND_NZ - COND_HS = 2, // aka COND_C - COND_LO = 3, // aka COND_NC - COND_GE = 4, - COND_L = 5, - - COND_INVALID - }; -} - class MSP430InstrInfo : public TargetInstrInfoImpl { const MSP430RegisterInfo RI; MSP430TargetMachine &TM; @@ -73,9 +59,19 @@ public: MachineBasicBlock::iterator MI, const std::vector<CalleeSavedInfo> &CSI) const; - virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, - MachineBasicBlock *FBB, - const SmallVectorImpl<MachineOperand> &Cond) const; + // Branch folding goodness + bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; + bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const; + bool isUnpredicatedTerminator(const MachineInstr *MI) const; + bool AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + + unsigned RemoveBranch(MachineBasicBlock &MBB) const; + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const; }; diff --git a/lib/Target/MSP430/MSP430InstrInfo.td b/lib/Target/MSP430/MSP430InstrInfo.td index f7e0d2b..e202175 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.td +++ b/lib/Target/MSP430/MSP430InstrInfo.td @@ -71,7 +71,9 @@ def memdst : Operand<i16> { } // Branch targets have OtherVT type. -def brtarget : Operand<OtherVT>; +def brtarget : Operand<OtherVT> { + let PrintMethod = "printPCRelImmOperand"; +} // Operand for printing out a condition code. def cc : Operand<i8> { diff --git a/lib/Target/MSP430/MSP430TargetMachine.cpp b/lib/Target/MSP430/MSP430TargetMachine.cpp index 5e21f8e..da54507 100644 --- a/lib/Target/MSP430/MSP430TargetMachine.cpp +++ b/lib/Target/MSP430/MSP430TargetMachine.cpp @@ -32,7 +32,7 @@ MSP430TargetMachine::MSP430TargetMachine(const Target &T, LLVMTargetMachine(T, TT), Subtarget(TT, FS), // FIXME: Check TargetData string. - DataLayout("e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8"), + DataLayout("e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32"), InstrInfo(*this), TLInfo(*this), FrameInfo(TargetFrameInfo::StackGrowsDown, 2, -2) { } diff --git a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp index 3f415af..ea0f494 100644 --- a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp +++ b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp @@ -12,8 +12,9 @@ // //===----------------------------------------------------------------------===// +#include "PIC16ABINames.h" #include "PIC16AsmPrinter.h" -#include "MCSectionPIC16.h" +#include "PIC16Section.h" #include "PIC16MCAsmInfo.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" @@ -39,7 +40,7 @@ PIC16AsmPrinter::PIC16AsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, : AsmPrinter(O, TM, T, V), DbgInfo(O, T) { PTLI = static_cast<PIC16TargetLowering*>(TM.getTargetLowering()); PMAI = static_cast<const PIC16MCAsmInfo*>(T); - PTOF = (PIC16TargetObjectFile*)&PTLI->getObjFileLowering(); + PTOF = (PIC16TargetObjectFile *)&PTLI->getObjFileLowering(); } bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) { @@ -52,6 +53,45 @@ bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) { return true; } +static int getFunctionColor(const Function *F) { + if (F->hasSection()) { + std::string Sectn = F->getSection(); + std::string StrToFind = "Overlay="; + std::string::size_type Pos = Sectn.find(StrToFind); + + // Retreive the color number if the key is found. + if (Pos != std::string::npos) { + Pos += StrToFind.length(); + std::string Color = ""; + char c = Sectn.at(Pos); + // A Color can only consist of digits. + while (c >= '0' && c<= '9') { + Color.append(1,c); + Pos++; + if (Pos >= Sectn.length()) + break; + c = Sectn.at(Pos); + } + return atoi(Color.c_str()); + } + } + + // Color was not set for function, so return -1. + return -1; +} + +// Color the Auto section of the given function. +void PIC16AsmPrinter::ColorAutoSection(const Function *F) { + std::string SectionName = PAN::getAutosSectionName(CurrentFnName); + PIC16Section* Section = PTOF->findPIC16Section(SectionName); + if (Section != NULL) { + int Color = getFunctionColor(F); + if (Color >= 0) + Section->setColor(Color); + } +} + + /// runOnMachineFunction - This emits the frame section, autos section and /// assembly for each instruction. Also takes care of function begin debug /// directive and file begin debug directive (if required) for the function. @@ -67,17 +107,18 @@ bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) { const Function *F = MF.getFunction(); CurrentFnName = Mang->getMangledName(F); + // Put the color information from function to its auto section. + ColorAutoSection(F); + // Emit the function frame (args and temps). EmitFunctionFrame(MF); DbgInfo.BeginFunction(MF); - // Emit the autos section of function. - EmitAutos(CurrentFnName); - // Now emit the instructions of function in its code section. - const MCSection *fCodeSection = - getObjFileLowering().getSectionForFunction(CurrentFnName); + const MCSection *fCodeSection + = getObjFileLowering().SectionForCode(CurrentFnName); + // Start the Code Section. O << "\n"; OutStreamer.SwitchSection(fCodeSection); @@ -229,12 +270,26 @@ bool PIC16AsmPrinter::doInitialization(Module &M) { // Set the section names for all globals. for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) - if (!I->isDeclaration() && !I->hasAvailableExternallyLinkage()) { + I != E; ++I) { + + // Record External Var Decls. + if (I->isDeclaration()) { + ExternalVarDecls.push_back(I); + continue; + } + + // Record Exteranl Var Defs. + if (I->hasExternalLinkage() || I->hasCommonLinkage()) { + ExternalVarDefs.push_back(I); + } + + // Sectionify actual data. + if (!I->hasAvailableExternallyLinkage()) { const MCSection *S = getObjFileLowering().SectionForGlobal(I, Mang, TM); - I->setSection(((const MCSectionPIC16*)S)->getName()); + I->setSection(((const PIC16Section *)S)->getName()); } + } DbgInfo.BeginModule(M); EmitFunctionDecls(M); @@ -243,6 +298,7 @@ bool PIC16AsmPrinter::doInitialization(Module &M) { EmitIData(M); EmitUData(M); EmitRomData(M); + EmitUserSections(M); return Result; } @@ -287,7 +343,7 @@ void PIC16AsmPrinter::EmitFunctionDecls(Module &M) { // Emit variables imported from other Modules. void PIC16AsmPrinter::EmitUndefinedVars(Module &M) { - std::vector<const GlobalVariable*> Items = PTOF->ExternalVarDecls->Items; + std::vector<const GlobalVariable*> Items = ExternalVarDecls; if (!Items.size()) return; O << "\n" << MAI->getCommentString() << "Imported Variables - BEGIN" << "\n"; @@ -299,7 +355,7 @@ void PIC16AsmPrinter::EmitUndefinedVars(Module &M) { // Emit variables defined in this module and are available to other modules. void PIC16AsmPrinter::EmitDefinedVars(Module &M) { - std::vector<const GlobalVariable*> Items = PTOF->ExternalVarDefs->Items; + std::vector<const GlobalVariable*> Items = ExternalVarDefs; if (!Items.size()) return; O << "\n" << MAI->getCommentString() << "Exported Variables - BEGIN" << "\n"; @@ -311,25 +367,12 @@ void PIC16AsmPrinter::EmitDefinedVars(Module &M) { // Emit initialized data placed in ROM. void PIC16AsmPrinter::EmitRomData(Module &M) { - // Print ROM Data section. - const std::vector<PIC16Section*> &ROSections = PTOF->ROSections; - for (unsigned i = 0; i < ROSections.size(); i++) { - const std::vector<const GlobalVariable*> &Items = ROSections[i]->Items; - if (!Items.size()) continue; - O << "\n"; - OutStreamer.SwitchSection(PTOF->ROSections[i]->S_); - for (unsigned j = 0; j < Items.size(); j++) { - O << Mang->getMangledName(Items[j]); - Constant *C = Items[j]->getInitializer(); - int AddrSpace = Items[j]->getType()->getAddressSpace(); - EmitGlobalConstant(C, AddrSpace); - } - } + EmitSingleSection(PTOF->ROMDATASection()); } bool PIC16AsmPrinter::doFinalization(Module &M) { + EmitAllAutos(M); printLibcallDecls(); - EmitRemainingAutos(); DbgInfo.EndModule(M); O << "\n\t" << "END\n"; return AsmPrinter::doFinalization(M); @@ -342,8 +385,10 @@ void PIC16AsmPrinter::EmitFunctionFrame(MachineFunction &MF) { // Emit the data section name. O << "\n"; - const MCSection *fPDataSection = - getObjFileLowering().getSectionForFunctionFrame(CurrentFnName); + PIC16Section *fPDataSection = const_cast<PIC16Section *>(getObjFileLowering(). + SectionForFrame(CurrentFnName)); + + fPDataSection->setColor(getFunctionColor(F)); OutStreamer.SwitchSection(fPDataSection); // Emit function frame label @@ -379,106 +424,86 @@ void PIC16AsmPrinter::EmitFunctionFrame(MachineFunction &MF) { O << PAN::getTempdataLabel(CurrentFnName) << " RES " << TempSize << '\n'; } -void PIC16AsmPrinter::EmitIData(Module &M) { - // Print all IDATA sections. - const std::vector<PIC16Section*> &IDATASections = PTOF->IDATASections; - for (unsigned i = 0; i < IDATASections.size(); i++) { - O << "\n"; - if (IDATASections[i]->S_->getName().find("llvm.") != std::string::npos) - continue; - OutStreamer.SwitchSection(IDATASections[i]->S_); - std::vector<const GlobalVariable*> Items = IDATASections[i]->Items; +void PIC16AsmPrinter::EmitInitializedDataSection(const PIC16Section *S) { + /// Emit Section header. + OutStreamer.SwitchSection(S); + + std::vector<const GlobalVariable*> Items = S->Items; for (unsigned j = 0; j < Items.size(); j++) { std::string Name = Mang->getMangledName(Items[j]); Constant *C = Items[j]->getInitializer(); int AddrSpace = Items[j]->getType()->getAddressSpace(); O << Name; EmitGlobalConstant(C, AddrSpace); - } - } + } } -void PIC16AsmPrinter::EmitUData(Module &M) { - const TargetData *TD = TM.getTargetData(); +// Print all IDATA sections. +void PIC16AsmPrinter::EmitIData(Module &M) { + EmitSectionList (M, PTOF->IDATASections()); +} - // Print all BSS sections. - const std::vector<PIC16Section*> &BSSSections = PTOF->BSSSections; - for (unsigned i = 0; i < BSSSections.size(); i++) { - O << "\n"; - OutStreamer.SwitchSection(BSSSections[i]->S_); - std::vector<const GlobalVariable*> Items = BSSSections[i]->Items; +void PIC16AsmPrinter:: +EmitUninitializedDataSection(const PIC16Section *S) { + const TargetData *TD = TM.getTargetData(); + OutStreamer.SwitchSection(S); + std::vector<const GlobalVariable*> Items = S->Items; for (unsigned j = 0; j < Items.size(); j++) { std::string Name = Mang->getMangledName(Items[j]); Constant *C = Items[j]->getInitializer(); const Type *Ty = C->getType(); unsigned Size = TD->getTypeAllocSize(Ty); - O << Name << " RES " << Size << "\n"; } - } } -void PIC16AsmPrinter::EmitAutos(std::string FunctName) { - // Section names for all globals are already set. - const TargetData *TD = TM.getTargetData(); +// Print all UDATA sections. +void PIC16AsmPrinter::EmitUData(Module &M) { + EmitSectionList (M, PTOF->UDATASections()); +} - // Now print Autos section for this function. - std::string SectionName = PAN::getAutosSectionName(FunctName); - const std::vector<PIC16Section*> &AutosSections = PTOF->AutosSections; - for (unsigned i = 0; i < AutosSections.size(); i++) { - O << "\n"; - if (AutosSections[i]->S_->getName() == SectionName) { - // Set the printing status to true - AutosSections[i]->setPrintedStatus(true); - OutStreamer.SwitchSection(AutosSections[i]->S_); - const std::vector<const GlobalVariable*> &Items = AutosSections[i]->Items; - for (unsigned j = 0; j < Items.size(); j++) { - std::string VarName = Mang->getMangledName(Items[j]); - Constant *C = Items[j]->getInitializer(); - const Type *Ty = C->getType(); - unsigned Size = TD->getTypeAllocSize(Ty); - // Emit memory reserve directive. - O << VarName << " RES " << Size << "\n"; - } - break; - } - } +// Print all USER sections. +void PIC16AsmPrinter::EmitUserSections(Module &M) { + EmitSectionList (M, PTOF->USERSections()); } -// Print autos that were not printed during the code printing of functions. -// As the functions might themselves would have got deleted by the optimizer. -void PIC16AsmPrinter::EmitRemainingAutos() { - const TargetData *TD = TM.getTargetData(); +// Print all AUTO sections. +void PIC16AsmPrinter::EmitAllAutos(Module &M) { + EmitSectionList (M, PTOF->AUTOSections()); +} - // Now print Autos section for this function. - std::vector <PIC16Section *>AutosSections = PTOF->AutosSections; - for (unsigned i = 0; i < AutosSections.size(); i++) { - - // if the section is already printed then don't print again - if (AutosSections[i]->isPrinted()) - continue; +extern "C" void LLVMInitializePIC16AsmPrinter() { + RegisterAsmPrinter<PIC16AsmPrinter> X(ThePIC16Target); +} - // Set status as printed - AutosSections[i]->setPrintedStatus(true); +// Emit one data section using correct section emitter based on section type. +void PIC16AsmPrinter::EmitSingleSection(const PIC16Section *S) { + if (S == NULL) return; - O << "\n"; - OutStreamer.SwitchSection(AutosSections[i]->S_); - const std::vector<const GlobalVariable*> &Items = AutosSections[i]->Items; - for (unsigned j = 0; j < Items.size(); j++) { - std::string VarName = Mang->getMangledName(Items[j]); - Constant *C = Items[j]->getInitializer(); - const Type *Ty = C->getType(); - unsigned Size = TD->getTypeAllocSize(Ty); - // Emit memory reserve directive. - O << VarName << " RES " << Size << "\n"; - } + switch (S->getType()) { + default: llvm_unreachable ("unknow user section type"); + case UDATA: + case UDATA_SHR: + case UDATA_OVR: + EmitUninitializedDataSection(S); + break; + case IDATA: + case ROMDATA: + EmitInitializedDataSection(S); + break; } } - -extern "C" void LLVMInitializePIC16AsmPrinter() { - RegisterAsmPrinter<PIC16AsmPrinter> X(ThePIC16Target); +// Emit a list of sections. +void PIC16AsmPrinter:: +EmitSectionList(Module &M, const std::vector<PIC16Section *> &SList) { + for (unsigned i = 0; i < SList.size(); i++) { + // Exclude llvm specific metadata sections. + if (SList[i]->getName().find("llvm.") != std::string::npos) + continue; + O << "\n"; + EmitSingleSection(SList[i]); + } } - diff --git a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h index 2dd4600..b13d9ce 100644 --- a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h +++ b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h @@ -53,11 +53,17 @@ namespace llvm { void EmitDefinedVars (Module &M); void EmitIData (Module &M); void EmitUData (Module &M); - void EmitAutos (std::string FunctName); - void EmitRemainingAutos (); + void EmitAllAutos (Module &M); void EmitRomData (Module &M); + void EmitUserSections (Module &M); void EmitFunctionFrame(MachineFunction &MF); void printLibcallDecls(); + void EmitUninitializedDataSection(const PIC16Section *S); + void EmitInitializedDataSection(const PIC16Section *S); + void EmitSingleSection(const PIC16Section *S); + void EmitSectionList(Module &M, + const std::vector< PIC16Section *> &SList); + void ColorAutoSection(const Function *F); protected: bool doInitialization(Module &M); bool doFinalization(Module &M); @@ -74,6 +80,8 @@ namespace llvm { PIC16DbgInfo DbgInfo; const PIC16MCAsmInfo *PMAI; std::list<const char *> LibcallDecls; // List of extern decls. + std::vector<const GlobalVariable *> ExternalVarDecls; + std::vector<const GlobalVariable *> ExternalVarDefs; }; } // end of namespace diff --git a/lib/Target/PIC16/CMakeLists.txt b/lib/Target/PIC16/CMakeLists.txt index 0ee88f9..208b067 100644 --- a/lib/Target/PIC16/CMakeLists.txt +++ b/lib/Target/PIC16/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_target(PIC16 PIC16MemSelOpt.cpp PIC16MCAsmInfo.cpp PIC16RegisterInfo.cpp + PIC16Section.cpp PIC16Subtarget.cpp PIC16TargetMachine.cpp PIC16TargetObjectFile.cpp diff --git a/lib/Target/PIC16/Makefile b/lib/Target/PIC16/Makefile index f913675..4382eba7 100644 --- a/lib/Target/PIC16/Makefile +++ b/lib/Target/PIC16/Makefile @@ -17,7 +17,7 @@ BUILT_SOURCES = PIC16GenRegisterInfo.h.inc PIC16GenRegisterNames.inc \ PIC16GenDAGISel.inc PIC16GenCallingConv.inc \ PIC16GenSubtarget.inc -DIRS = AsmPrinter TargetInfo +DIRS = AsmPrinter TargetInfo PIC16Passes include $(LEVEL)/Makefile.common diff --git a/lib/Target/PIC16/PIC16.h b/lib/Target/PIC16/PIC16.h index 8a3704d..e46c9b2 100644 --- a/lib/Target/PIC16/PIC16.h +++ b/lib/Target/PIC16/PIC16.h @@ -42,266 +42,15 @@ namespace PIC16CC { UGE }; } - // A Central class to manage all ABI naming conventions. - // PAN - [P]ic16 [A]BI [N]ames - class PAN { - public: - // Map the name of the symbol to its section name. - // Current ABI: - // ----------------------------------------------------- - // ALL Names are prefixed with the symobl '@'. - // ------------------------------------------------------ - // Global variables do not have any '.' in their names. - // These are maily function names and global variable names. - // Example - @foo, @i - // ------------------------------------------------------- - // Functions and auto variables. - // Names are mangled as <prefix><funcname>.<tag>.<varname> - // Where <prefix> is '@' and <tag> is any one of - // the following - // .auto. - an automatic var of a function. - // .temp. - temproray data of a function. - // .ret. - return value label for a function. - // .frame. - Frame label for a function where retval, args - // and temps are stored. - // .args. - Label used to pass arguments to a direct call. - // Example - Function name: @foo - // Its frame: @foo.frame. - // Its retval: @foo.ret. - // Its local vars: @foo.auto.a - // Its temp data: @foo.temp. - // Its arg passing: @foo.args. - //---------------------------------------------- - // Libcall - compiler generated libcall names must start with .lib. - // This id will be used to emit extern decls for libcalls. - // Example - libcall name: @.lib.sra.i8 - // To pass args: @.lib.sra.i8.args. - // To return val: @.lib.sra.i8.ret. - //---------------------------------------------- - // SECTION Names - // uninitialized globals - @udata.<num>.# - // initialized globals - @idata.<num>.# - // Function frame - @<func>.frame_section. - // Function autos - @<func>.autos_section. - // Declarations - Enclosed in comments. No section for them. - //---------------------------------------------------------- - - // Tags used to mangle different names. - enum TAGS { - PREFIX_SYMBOL, - GLOBAL, - STATIC_LOCAL, - AUTOS_LABEL, - FRAME_LABEL, - RET_LABEL, - ARGS_LABEL, - TEMPS_LABEL, - - LIBCALL, - - FRAME_SECTION, - AUTOS_SECTION, - CODE_SECTION - }; - - // Textual names of the tags. - inline static const char *getTagName(TAGS tag) { - switch (tag) { - default: return ""; - case PREFIX_SYMBOL: return "@"; - case AUTOS_LABEL: return ".auto."; - case FRAME_LABEL: return ".frame."; - case TEMPS_LABEL: return ".temp."; - case ARGS_LABEL: return ".args."; - case RET_LABEL: return ".ret."; - case LIBCALL: return ".lib."; - case FRAME_SECTION: return ".frame_section."; - case AUTOS_SECTION: return ".autos_section."; - case CODE_SECTION: return ".code_section."; - } - } - - // Get tag type for the Symbol. - inline static TAGS getSymbolTag(const std::string &Sym) { - if (Sym.find(getTagName(TEMPS_LABEL)) != std::string::npos) - return TEMPS_LABEL; - - if (Sym.find(getTagName(FRAME_LABEL)) != std::string::npos) - return FRAME_LABEL; - - if (Sym.find(getTagName(RET_LABEL)) != std::string::npos) - return RET_LABEL; - - if (Sym.find(getTagName(ARGS_LABEL)) != std::string::npos) - return ARGS_LABEL; - - if (Sym.find(getTagName(AUTOS_LABEL)) != std::string::npos) - return AUTOS_LABEL; - - if (Sym.find(getTagName(LIBCALL)) != std::string::npos) - return LIBCALL; - - // It does not have any Tag. So its a true global or static local. - if (Sym.find(".") == std::string::npos) - return GLOBAL; - - // If a . is there, then it may be static local. - // We should mangle these as well in clang. - if (Sym.find(".") != std::string::npos) - return STATIC_LOCAL; - - assert (0 && "Could not determine Symbol's tag"); - return PREFIX_SYMBOL; // Silence warning when assertions are turned off. - } - - // addPrefix - add prefix symbol to a name if there isn't one already. - inline static std::string addPrefix (const std::string &Name) { - std::string prefix = getTagName (PREFIX_SYMBOL); - - // If this name already has a prefix, nothing to do. - if (Name.compare(0, prefix.size(), prefix) == 0) - return Name; - - return prefix + Name; - } - - // Get mangled func name from a mangled sym name. - // In all cases func name is the first component before a '.'. - static inline std::string getFuncNameForSym(const std::string &Sym1) { - assert (getSymbolTag(Sym1) != GLOBAL && "not belongs to a function"); - - std::string Sym = addPrefix(Sym1); - - // Position of the . after func name. That's where func name ends. - size_t func_name_end = Sym.find ('.'); - - return Sym.substr (0, func_name_end); - } - - // Get Frame start label for a func. - static std::string getFrameLabel(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(FRAME_LABEL); - return Func1 + tag; - } - - static std::string getRetvalLabel(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(RET_LABEL); - return Func1 + tag; - } - - static std::string getArgsLabel(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(ARGS_LABEL); - return Func1 + tag; - } - - static std::string getTempdataLabel(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(TEMPS_LABEL); - return Func1 + tag; - } - static std::string getFrameSectionName(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(FRAME_SECTION); - return Func1 + tag + "# UDATA_OVR"; - } - - static std::string getAutosSectionName(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(AUTOS_SECTION); - return Func1 + tag + "# UDATA_OVR"; - } - - static std::string getCodeSectionName(const std::string &Func) { - std::string Func1 = addPrefix(Func); - std::string tag = getTagName(CODE_SECTION); - return Func1 + tag + "# CODE"; - } - - // udata, romdata and idata section names are generated by a given number. - // @udata.<num>.# - static std::string getUdataSectionName(unsigned num, - std::string prefix = "") { - std::ostringstream o; - o << getTagName(PREFIX_SYMBOL) << prefix << "udata." << num - << ".# UDATA"; - return o.str(); - } - - static std::string getRomdataSectionName(unsigned num, - std::string prefix = "") { - std::ostringstream o; - o << getTagName(PREFIX_SYMBOL) << prefix << "romdata." << num - << ".# ROMDATA"; - return o.str(); - } - - static std::string getIdataSectionName(unsigned num, - std::string prefix = "") { - std::ostringstream o; - o << getTagName(PREFIX_SYMBOL) << prefix << "idata." << num - << ".# IDATA"; - return o.str(); - } - - inline static bool isLocalName (const std::string &Name) { - if (getSymbolTag(Name) == AUTOS_LABEL) - return true; - - return false; - } - - inline static bool isMemIntrinsic (const std::string &Name) { - if (Name.compare("@memcpy") == 0 || Name.compare("@memset") == 0 || - Name.compare("@memmove") == 0) { - return true; - } - - return false; - } - - inline static bool isLocalToFunc (std::string &Func, std::string &Var) { - if (! isLocalName(Var)) return false; - - std::string Func1 = addPrefix(Func); - // Extract func name of the varilable. - const std::string &fname = getFuncNameForSym(Var); - - if (fname.compare(Func1) == 0) - return true; - - return false; - } - - - // Get the section for the given external symbol names. - // This tries to find the type (Tag) of the symbol from its mangled name - // and return appropriate section name for it. - static inline std::string getSectionNameForSym(const std::string &Sym1) { - std::string Sym = addPrefix(Sym1); - - std::string SectionName; - - std::string Fname = getFuncNameForSym (Sym); - TAGS id = getSymbolTag (Sym); - - switch (id) { - default : assert (0 && "Could not determine external symbol type"); - case FRAME_LABEL: - case RET_LABEL: - case TEMPS_LABEL: - case ARGS_LABEL: { - return getFrameSectionName(Fname); - } - case AUTOS_LABEL: { - return getAutosSectionName(Fname); - } - } - } - }; // class PAN. + enum PIC16SectionType { + CODE, + UDATA, + IDATA, + ROMDATA, + UDATA_OVR, + UDATA_SHR + }; // External symbol names require memory to live till the program end. diff --git a/lib/Target/PIC16/PIC16ABINames.h b/lib/Target/PIC16/PIC16ABINames.h new file mode 100644 index 0000000..7f4c2f1 --- /dev/null +++ b/lib/Target/PIC16/PIC16ABINames.h @@ -0,0 +1,325 @@ +//===-- PIC16ABINames.h - PIC16 Naming conventios for ABI----- --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the functions to manage ABI Naming conventions for PIC16. +// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_PIC16ABINAMES_H +#define LLVM_TARGET_PIC16ABINAMES_H + +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetMachine.h" +#include <cassert> +#include <sstream> +#include <cstring> +#include <string> + +namespace llvm { + class PIC16TargetMachine; + class FunctionPass; + class MachineCodeEmitter; + class formatted_raw_ostream; + + // A Central class to manage all ABI naming conventions. + // PAN - [P]ic16 [A]BI [N]ames + class PAN { + public: + // Map the name of the symbol to its section name. + // Current ABI: + // ----------------------------------------------------- + // ALL Names are prefixed with the symobl '@'. + // ------------------------------------------------------ + // Global variables do not have any '.' in their names. + // These are maily function names and global variable names. + // Example - @foo, @i + // Static local variables - @<func>.<var> + // ------------------------------------------------------- + // Functions and auto variables. + // Names are mangled as <prefix><funcname>.<tag>.<varname> + // Where <prefix> is '@' and <tag> is any one of + // the following + // .auto. - an automatic var of a function. + // .temp. - temproray data of a function. + // .ret. - return value label for a function. + // .frame. - Frame label for a function where retval, args + // and temps are stored. + // .args. - Label used to pass arguments to a direct call. + // Example - Function name: @foo + // Its frame: @foo.frame. + // Its retval: @foo.ret. + // Its local vars: @foo.auto.a + // Its temp data: @foo.temp. + // Its arg passing: @foo.args. + //---------------------------------------------- + // Libcall - compiler generated libcall names must start with .lib. + // This id will be used to emit extern decls for libcalls. + // Example - libcall name: @.lib.sra.i8 + // To pass args: @.lib.sra.i8.args. + // To return val: @.lib.sra.i8.ret. + //---------------------------------------------- + // SECTION Names + // uninitialized globals - @udata.<num>.# + // initialized globals - @idata.<num>.# + // Program memory data - @romdata.# + // Variables with user defined section name - <user_defined_section> + // Variables with user defined address - @<var>.user_section.<address>.# + // Function frame - @<func>.frame_section. + // Function autos - @<func>.autos_section. + // Overlay sections - @<color>.## + // Declarations - Enclosed in comments. No section for them. + //---------------------------------------------------------- + + // Tags used to mangle different names. + enum TAGS { + PREFIX_SYMBOL, + GLOBAL, + STATIC_LOCAL, + AUTOS_LABEL, + FRAME_LABEL, + RET_LABEL, + ARGS_LABEL, + TEMPS_LABEL, + + LIBCALL, + + FRAME_SECTION, + AUTOS_SECTION, + CODE_SECTION, + USER_SECTION + }; + + // Textual names of the tags. + inline static const char *getTagName(TAGS tag) { + switch (tag) { + default: return ""; + case PREFIX_SYMBOL: return "@"; + case AUTOS_LABEL: return ".auto."; + case FRAME_LABEL: return ".frame."; + case TEMPS_LABEL: return ".temp."; + case ARGS_LABEL: return ".args."; + case RET_LABEL: return ".ret."; + case LIBCALL: return ".lib."; + case FRAME_SECTION: return ".frame_section."; + case AUTOS_SECTION: return ".autos_section."; + case CODE_SECTION: return ".code_section."; + case USER_SECTION: return ".user_section."; + } + } + + // Get tag type for the Symbol. + inline static TAGS getSymbolTag(const std::string &Sym) { + if (Sym.find(getTagName(TEMPS_LABEL)) != std::string::npos) + return TEMPS_LABEL; + + if (Sym.find(getTagName(FRAME_LABEL)) != std::string::npos) + return FRAME_LABEL; + + if (Sym.find(getTagName(RET_LABEL)) != std::string::npos) + return RET_LABEL; + + if (Sym.find(getTagName(ARGS_LABEL)) != std::string::npos) + return ARGS_LABEL; + + if (Sym.find(getTagName(AUTOS_LABEL)) != std::string::npos) + return AUTOS_LABEL; + + if (Sym.find(getTagName(LIBCALL)) != std::string::npos) + return LIBCALL; + + // It does not have any Tag. So its a true global or static local. + if (Sym.find(".") == std::string::npos) + return GLOBAL; + + // If a . is there, then it may be static local. + // We should mangle these as well in clang. + if (Sym.find(".") != std::string::npos) + return STATIC_LOCAL; + + assert (0 && "Could not determine Symbol's tag"); + return PREFIX_SYMBOL; // Silence warning when assertions are turned off. + } + + // addPrefix - add prefix symbol to a name if there isn't one already. + inline static std::string addPrefix (const std::string &Name) { + std::string prefix = getTagName (PREFIX_SYMBOL); + + // If this name already has a prefix, nothing to do. + if (Name.compare(0, prefix.size(), prefix) == 0) + return Name; + + return prefix + Name; + } + + // Get mangled func name from a mangled sym name. + // In all cases func name is the first component before a '.'. + static inline std::string getFuncNameForSym(const std::string &Sym1) { + assert (getSymbolTag(Sym1) != GLOBAL && "not belongs to a function"); + + std::string Sym = addPrefix(Sym1); + + // Position of the . after func name. That's where func name ends. + size_t func_name_end = Sym.find ('.'); + + return Sym.substr (0, func_name_end); + } + + // Get Frame start label for a func. + static std::string getFrameLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(FRAME_LABEL); + return Func1 + tag; + } + + static std::string getRetvalLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(RET_LABEL); + return Func1 + tag; + } + + static std::string getArgsLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(ARGS_LABEL); + return Func1 + tag; + } + + static std::string getTempdataLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(TEMPS_LABEL); + return Func1 + tag; + } + + static std::string getFrameSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(FRAME_SECTION); + return Func1 + tag + "#"; + } + + static std::string getAutosSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(AUTOS_SECTION); + return Func1 + tag + "#"; + } + + static std::string getCodeSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(CODE_SECTION); + return Func1 + tag + "#"; + } + + static std::string getUserSectionName(const std::string &Name) { + std::string sname = addPrefix(Name);; + std::string tag = getTagName(USER_SECTION); + return sname + tag + "#"; + } + + // udata, romdata and idata section names are generated by a given number. + // @udata.<num>.# + static std::string getUdataSectionName(unsigned num, + std::string prefix = "") { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << prefix << "udata." << num + << ".#"; + return o.str(); + } + + static std::string getRomdataSectionName() { + return "romdata.#"; + } + + static std::string getRomdataSectionName(unsigned num, + std::string prefix = "") { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << prefix << "romdata." << num + << ".#"; + return o.str(); + } + + static std::string getIdataSectionName(unsigned num, + std::string prefix = "") { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << prefix << "idata." << num + << ".#"; + return o.str(); + } + + inline static bool isLocalName (const std::string &Name) { + if (getSymbolTag(Name) == AUTOS_LABEL) + return true; + + return false; + } + + inline static bool isMemIntrinsic (const std::string &Name) { + if (Name.compare("@memcpy") == 0 || Name.compare("@memset") == 0 || + Name.compare("@memmove") == 0) { + return true; + } + + return false; + } + + inline static bool isLocalToFunc (std::string &Func, std::string &Var) { + if (! isLocalName(Var)) return false; + + std::string Func1 = addPrefix(Func); + // Extract func name of the varilable. + const std::string &fname = getFuncNameForSym(Var); + + if (fname.compare(Func1) == 0) + return true; + + return false; + } + + + // Get the section for the given external symbol names. + // This tries to find the type (Tag) of the symbol from its mangled name + // and return appropriate section name for it. + static inline std::string getSectionNameForSym(const std::string &Sym1) { + std::string Sym = addPrefix(Sym1); + + std::string SectionName; + + std::string Fname = getFuncNameForSym (Sym); + TAGS id = getSymbolTag (Sym); + + switch (id) { + default : assert (0 && "Could not determine external symbol type"); + case FRAME_LABEL: + case RET_LABEL: + case TEMPS_LABEL: + case ARGS_LABEL: { + return getFrameSectionName(Fname); + } + case AUTOS_LABEL: { + return getAutosSectionName(Fname); + } + } + } + + /// Return Overlay Name for the section. + /// The ABI Convention is: @<Color>.##.<section_tag> + /// The section_tag is retrieved from the SectName parameter and + /// and Color is passed in parameter. + static inline std::string getOverlayName(std::string SectName, int Color) { + // FIXME: Only autos_section and frame_section are colored. + // So check and assert if the passed SectName does not have AUTOS_SECTION + // or FRAME_SECTION tag in it. + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << Color << ".##" + << SectName.substr(SectName.find(".")); + + return o.str(); + } + }; // class PAN. +} // end namespace llvm; + +#endif diff --git a/lib/Target/PIC16/PIC16DebugInfo.cpp b/lib/Target/PIC16/PIC16DebugInfo.cpp index 961caed..0ed44d2 100644 --- a/lib/Target/PIC16/PIC16DebugInfo.cpp +++ b/lib/Target/PIC16/PIC16DebugInfo.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "PIC16.h" +#include "PIC16ABINames.h" #include "PIC16DebugInfo.h" #include "llvm/GlobalVariable.h" #include "llvm/CodeGen/MachineFunction.h" @@ -30,10 +31,10 @@ void PIC16DbgInfo::PopulateDebugInfo (DIType Ty, unsigned short &TypeNo, std::string &TagName) { if (Ty.isBasicType()) PopulateBasicTypeInfo (Ty, TypeNo); - else if (Ty.isDerivedType()) - PopulateDerivedTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); else if (Ty.isCompositeType()) PopulateCompositeTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); + else if (Ty.isDerivedType()) + PopulateDerivedTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); else { TypeNo = PIC16Dbg::T_NULL; HasAux = false; @@ -190,7 +191,7 @@ unsigned PIC16DbgInfo::GetTypeDebugNumber(std::string &type) { /// short PIC16DbgInfo::getStorageClass(DIGlobalVariable DIGV) { short ClassNo; - if (PAN::isLocalName(DIGV.getGlobal()->getName())) { + if (PAN::isLocalName(DIGV.getName())) { // Generating C_AUTO here fails due to error in linker. Change it once // linker is fixed. ClassNo = PIC16Dbg::C_STAT; @@ -446,7 +447,8 @@ void PIC16DbgInfo::EmitVarDebugInfo(Module &M) { bool HasAux = false; int Aux[PIC16Dbg::AuxSize] = { 0 }; std::string TagName = ""; - std::string VarName = MAI->getGlobalPrefix()+DIGV.getGlobal()->getNameStr(); + std::string VarName = DIGV.getName(); + VarName = MAI->getGlobalPrefix() + VarName; PopulateDebugInfo(Ty, TypeNo, HasAux, Aux, TagName); // Emit debug info only if type information is availaible. if (TypeNo != PIC16Dbg::T_NULL) { diff --git a/lib/Target/PIC16/PIC16ISelLowering.cpp b/lib/Target/PIC16/PIC16ISelLowering.cpp index bf986b1..635befe 100644 --- a/lib/Target/PIC16/PIC16ISelLowering.cpp +++ b/lib/Target/PIC16/PIC16ISelLowering.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "pic16-lower" +#include "PIC16ABINames.h" #include "PIC16ISelLowering.h" #include "PIC16TargetObjectFile.h" #include "PIC16TargetMachine.h" diff --git a/lib/Target/PIC16/PIC16InstrInfo.cpp b/lib/Target/PIC16/PIC16InstrInfo.cpp index cb0c41b..87bd3d9 100644 --- a/lib/Target/PIC16/PIC16InstrInfo.cpp +++ b/lib/Target/PIC16/PIC16InstrInfo.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "PIC16.h" +#include "PIC16ABINames.h" #include "PIC16InstrInfo.h" #include "PIC16TargetMachine.h" #include "PIC16GenInstrInfo.inc" diff --git a/lib/Target/PIC16/PIC16MCAsmInfo.cpp b/lib/Target/PIC16/PIC16MCAsmInfo.cpp index a17d1a8..827315e 100644 --- a/lib/Target/PIC16/PIC16MCAsmInfo.cpp +++ b/lib/Target/PIC16/PIC16MCAsmInfo.cpp @@ -16,6 +16,7 @@ // FIXME: Layering violation to get enums and static function, should be moved // to separate headers. #include "PIC16.h" +#include "PIC16ABINames.h" #include "PIC16ISelLowering.h" using namespace llvm; diff --git a/lib/Target/PIC16/PIC16MemSelOpt.cpp b/lib/Target/PIC16/PIC16MemSelOpt.cpp index c9ebb57..a97dc35 100644 --- a/lib/Target/PIC16/PIC16MemSelOpt.cpp +++ b/lib/Target/PIC16/PIC16MemSelOpt.cpp @@ -21,6 +21,7 @@ #define DEBUG_TYPE "pic16-codegen" #include "PIC16.h" +#include "PIC16ABINames.h" #include "PIC16InstrInfo.h" #include "PIC16MCAsmInfo.h" #include "PIC16TargetMachine.h" diff --git a/lib/Target/PIC16/PIC16Passes/Makefile b/lib/Target/PIC16/PIC16Passes/Makefile new file mode 100644 index 0000000..cbb34b3 --- /dev/null +++ b/lib/Target/PIC16/PIC16Passes/Makefile @@ -0,0 +1,17 @@ +##===- lib/Target/PIC16/PIC16Passes/Makefile -----------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +TARGET = PIC16 +LIBRARYNAME = LLVMpic16passes +BUILD_ARCHIVE = 1 + + + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp new file mode 100644 index 0000000..197c398 --- /dev/null +++ b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp @@ -0,0 +1,181 @@ +//===-- PIC16Overlay.cpp - Implementation for PIC16 Frame Overlay===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 Frame Overlay implementation. +// +//===----------------------------------------------------------------------===// + + +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Pass.h" +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/Value.h" +#include "PIC16Overlay.h" +#include "llvm/Function.h" +#include <cstdlib> +#include <sstream> +using namespace llvm; + +namespace llvm { + char PIC16FrameOverlay::ID = 0; + ModulePass *createPIC16OverlayPass() { return new PIC16FrameOverlay(); } +} + +void PIC16FrameOverlay::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired<CallGraph>(); +} + +void PIC16FrameOverlay::DFSTraverse(CallGraphNode *CGN, unsigned Depth) { + // Do not set any color for external calling node. + if (Depth != 0 && CGN->getFunction()) { + unsigned Color = getColor(CGN->getFunction()); + + // Handle indirectly called functions + if (Color >= PIC16Overlay::StartIndirectCallColor || + Depth >= PIC16Overlay::StartIndirectCallColor) { + // All functions called from an indirectly called function are given + // an unique color. + if (Color < PIC16Overlay::StartIndirectCallColor && + Depth >= PIC16Overlay::StartIndirectCallColor) + setColor(CGN->getFunction(), Depth); + + for (unsigned int i = 0; i < CGN->size(); i++) + DFSTraverse((*CGN)[i], ++IndirectCallColor); + return; + } + // Just return if the node already has a color greater than the current + // depth. A node must be colored with the maximum depth that it has. + if (Color >= Depth) + return; + + Depth = ModifyDepthForInterrupt(CGN, Depth); + setColor(CGN->getFunction(), Depth); + } + + // Color all children of this node with color depth+1. + for (unsigned int i = 0; i < CGN->size(); i++) + DFSTraverse((*CGN)[i], Depth+1); +} + +unsigned PIC16FrameOverlay::ModifyDepthForInterrupt(CallGraphNode *CGN, + unsigned Depth) { + Function *Fn = CGN->getFunction(); + + // Return original Depth if function or section for function do not exist. + if (!Fn || !Fn->hasSection()) + return Depth; + + // Return original Depth if this function is not marked as interrupt. + if (Fn->getSection().find("interrupt") == string::npos) + return Depth; + + Depth = Depth + InterruptDepth; + return Depth; +} + +void PIC16FrameOverlay::setColor(Function *Fn, unsigned Color) { + std::string Section = ""; + if (Fn->hasSection()) + Section = Fn->getSection(); + + size_t Pos = Section.find(OverlayStr); + + // Convert Color to string. + std::stringstream ss; + ss << Color; + std::string ColorString = ss.str(); + + // If color is already set then reset it with the new value. Else append + // the Color string to section. + if (Pos != std::string::npos) { + Pos += OverlayStr.length(); + char c = Section.at(Pos); + unsigned OldColorLength = 0; + while (c >= '0' && c<= '9') { + OldColorLength++; + if (Pos < Section.length() - 1) + Pos++; + else + break; + c = Section.at(Pos); + } + // Replace old color with new one. + Section.replace(Pos-OldColorLength +1, OldColorLength, ColorString); + } + else { + // Append Color information to section string. + if (Fn->hasSection()) + Section.append(" "); + Section.append(OverlayStr + ColorString); + } + Fn->setSection(Section); +} + +unsigned PIC16FrameOverlay::getColor(Function *Fn) { + int Color = 0; + if (!Fn->hasSection()) + return 0; + + std::string Section = Fn->getSection(); + size_t Pos = Section.find(OverlayStr); + + // Return 0 if Color is not set. + if (Pos == std::string::npos) + return 0; + + // Set Pos to after "Overlay=". + Pos += OverlayStr.length(); + char c = Section.at(Pos); + std::string ColorString = ""; + + // Find the string representing Color. A Color can only consist of digits. + while (c >= '0' && c<= '9') { + ColorString.append(1,c); + if (Pos < Section.length() - 1) + Pos++; + else + break; + c = Section.at(Pos); + } + Color = atoi(ColorString.c_str()); + + return Color; +} + +bool PIC16FrameOverlay::runOnModule(Module &M) { + CallGraph &CG = getAnalysis<CallGraph>(); + CallGraphNode *ECN = CG.getExternalCallingNode(); + + MarkIndirectlyCalledFunctions(M); + // Since External Calling Node is the base function, do a depth first + // traversal of CallGraph with ECN as root. Each node with be marked with + // a color that is max(color(callers)) + 1. + if(ECN) { + DFSTraverse(ECN, 0); + } + return false; +} + +void PIC16FrameOverlay::MarkIndirectlyCalledFunctions(Module &M) { + // If the use of a function is not a call instruction then this + // function might be called indirectly. In that case give it + // an unique color. + for (Module::iterator MI = M.begin(), E = M.end(); MI != E; ++MI) { + for (Value::use_iterator I = MI->use_begin(), E = MI->use_end(); I != E; + ++I) { + if ((!isa<CallInst>(I) && !isa<InvokeInst>(I)) + || !CallSite(cast<Instruction>(I)).isCallee(I)) { + setColor(MI, ++IndirectCallColor); + break; + } + } + } +} diff --git a/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h new file mode 100644 index 0000000..d70c4e7 --- /dev/null +++ b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h @@ -0,0 +1,55 @@ +//===-- PIC16FrameOverlay.h - Interface for PIC16 Frame Overlay -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 Overlay infrastructure. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16FRAMEOVERLAY_H +#define PIC16FRAMEOVERLAY_H + +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Pass.h" +#include "llvm/CallGraphSCCPass.h" + +using std::string; +using namespace llvm; + +namespace llvm { + namespace PIC16Overlay { + enum OverlayConsts { + StartInterruptColor = 200, + StartIndirectCallColor = 300 + }; + } + class PIC16FrameOverlay : public ModulePass { + std::string OverlayStr; + unsigned InterruptDepth; + unsigned IndirectCallColor; + public: + static char ID; // Class identification + PIC16FrameOverlay() : ModulePass(&ID) { + OverlayStr = "Overlay="; + InterruptDepth = PIC16Overlay::StartInterruptColor; + IndirectCallColor = PIC16Overlay::StartIndirectCallColor; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + virtual bool runOnModule(Module &M); + + private: + unsigned getColor(Function *Fn); + void setColor(Function *Fn, unsigned Color); + unsigned ModifyDepthForInterrupt(CallGraphNode *CGN, unsigned Depth); + void MarkIndirectlyCalledFunctions(Module &M); + void DFSTraverse(CallGraphNode *CGN, unsigned Depth); + }; +} // End of namespace + +#endif diff --git a/lib/Target/PIC16/PIC16Section.cpp b/lib/Target/PIC16/PIC16Section.cpp new file mode 100644 index 0000000..a96ebb8 --- /dev/null +++ b/lib/Target/PIC16/PIC16Section.cpp @@ -0,0 +1,96 @@ +//===-- PIC16Section.cpp - PIC16 Section ----------- --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PIC16.h" +#include "PIC16ABINames.h" +#include "PIC16Section.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + + +// This is the only way to create a PIC16Section. Sections created here +// do not need to be explicitly deleted as they are managed by auto_ptrs. +PIC16Section *PIC16Section::Create(const StringRef &Name, + PIC16SectionType Ty, + const std::string &Address, + int Color, MCContext &Ctx) { + + /// Determine the internal SectionKind info. + /// Users of PIC16Section class should not need to know the internal + /// SectionKind. They should work only with PIC16SectionType. + /// + /// PIC16 Terminology for section kinds is as below. + /// UDATA - BSS + /// IDATA - initialized data (equiv to Metadata) + /// ROMDATA - ReadOnly. + /// UDATA_OVR - Sections that can be overlaid. Section of such type is + /// used to contain function autos an frame. We can think of + /// it as equiv to llvm ThreadBSS) + /// UDATA_SHR - Shared RAM. Memory area that is mapped to all banks. + + SectionKind K; + switch (Ty) { + default: llvm_unreachable ("can not create unknown section type"); + case UDATA_OVR: { + K = SectionKind::getThreadBSS(); + break; + } + case UDATA_SHR: + case UDATA: { + K = SectionKind::getBSS(); + break; + } + case ROMDATA: + case IDATA: { + K = SectionKind::getMetadata(); + break; + } + case CODE: { + K = SectionKind::getText(); + break; + } + + } + + // Create the Section. + PIC16Section *S = new (Ctx) PIC16Section(Name, K, Address, Color); + S->T = Ty; + return S; +} + +// A generic way to print all types of sections. +void PIC16Section::PrintSwitchToSection(const MCAsmInfo &MAI, + raw_ostream &OS) const { + + // If the section is overlaid(i.e. it has a color), print overlay name for + // it. Otherwise print its normal name. + if (Color != -1) + OS << PAN::getOverlayName(getName(), Color) << '\t'; + else + OS << getName() << '\t'; + + // Print type. + switch (getType()) { + default : llvm_unreachable ("unknown section type"); + case UDATA: OS << "UDATA"; break; + case IDATA: OS << "IDATA"; break; + case ROMDATA: OS << "ROMDATA"; break; + case UDATA_SHR: OS << "UDATA_SHR"; break; + case UDATA_OVR: OS << "UDATA_OVR"; break; + case CODE: OS << "CODE"; break; + } + + OS << '\t'; + + // Print Address. + OS << Address; + + OS << '\n'; +} diff --git a/lib/Target/PIC16/PIC16Section.h b/lib/Target/PIC16/PIC16Section.h new file mode 100644 index 0000000..3a8bbfb --- /dev/null +++ b/lib/Target/PIC16/PIC16Section.h @@ -0,0 +1,92 @@ +//===- PIC16Section.h - PIC16-specific section representation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the PIC16Section class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PIC16SECTION_H +#define LLVM_PIC16SECTION_H + +#include "llvm/MC/MCSection.h" +#include "llvm/GlobalVariable.h" +#include <vector> + +namespace llvm { + /// PIC16Section - Represents a physical section in PIC16 COFF. + /// Contains data objects. + /// + class PIC16Section : public MCSection { + /// PIC16 Sections does not really use the SectionKind class to + /// to distinguish between various types of sections. PIC16 maintain + /// its own Section Type info. See the PIC16SectionType enum in PIC16.h + /// for various section types. + PIC16SectionType T; + + /// Name of the section to uniquely identify it. + std::string Name; + + /// User can specify an address at which a section should be placed. + /// Negative value here means user hasn't specified any. + std::string Address; + + /// Overlay information - Sections with same color can be overlaid on + /// one another. + int Color; + + /// Total size of all data objects contained here. + unsigned Size; + + PIC16Section(const StringRef &name, SectionKind K, const std::string &addr, + int color) + : MCSection(K), Name(name), Address(addr), Color(color) { + } + + public: + /// Return the name of the section. + const std::string &getName() const { return Name; } + + /// Return the Address of the section. + const std::string &getAddress() const { return Address; } + + /// Return the Color of the section. + int getColor() const { return Color; } + void setColor(int color) { Color = color; } + + /// Return the size of the section. + unsigned getSize() const { return Size; } + void setSize(unsigned size) { Size = size; } + + /// Conatined data objects. + std::vector<const GlobalVariable *>Items; + + /// Check section type. + bool isUDATA_Type() const { return T == UDATA; } + bool isIDATA_Type() const { return T == IDATA; } + bool isROMDATA_Type() const { return T == ROMDATA; } + bool isUDATA_OVR_Type() const { return T == UDATA_OVR; } + bool isUDATA_SHR_Type() const { return T == UDATA_SHR; } + bool isCODE_Type() const { return T == CODE; } + + PIC16SectionType getType() const { return T; } + + /// This would be the only way to create a section. + static PIC16Section *Create(const StringRef &Name, PIC16SectionType Ty, + const std::string &Address, int Color, + MCContext &Ctx); + + /// Override this as PIC16 has its own way of printing switching + /// to a section. + virtual void PrintSwitchToSection(const MCAsmInfo &MAI, + raw_ostream &OS) const; + }; + +} // end namespace llvm + +#endif diff --git a/lib/Target/PIC16/PIC16TargetObjectFile.cpp b/lib/Target/PIC16/PIC16TargetObjectFile.cpp index a2a4c09..7eedf7f 100644 --- a/lib/Target/PIC16/PIC16TargetObjectFile.cpp +++ b/lib/Target/PIC16/PIC16TargetObjectFile.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "PIC16TargetObjectFile.h" -#include "MCSectionPIC16.h" #include "PIC16ISelLowering.h" #include "PIC16TargetMachine.h" +#include "PIC16Section.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" #include "llvm/MC/MCSection.h" @@ -19,75 +19,118 @@ using namespace llvm; -MCSectionPIC16 *MCSectionPIC16::Create(const StringRef &Name, SectionKind K, - int Address, int Color, MCContext &Ctx) { - return new (Ctx) MCSectionPIC16(Name, K, Address, Color); +PIC16TargetObjectFile::PIC16TargetObjectFile() { } +PIC16TargetObjectFile::~PIC16TargetObjectFile() { +} -void MCSectionPIC16::PrintSwitchToSection(const MCAsmInfo &MAI, - raw_ostream &OS) const { - OS << getName() << '\n'; +/// Find a pic16 section. Return null if not found. Do not create one. +PIC16Section *PIC16TargetObjectFile:: +findPIC16Section(const std::string &Name) { + /// Return if we have an already existing one. + PIC16Section *Entry = SectionsByName[Name]; + if (Entry) + return Entry; + + return NULL; } +/// Find a pic16 section. If not found, create one. +PIC16Section *PIC16TargetObjectFile:: +getPIC16Section(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; -PIC16TargetObjectFile::PIC16TargetObjectFile() - : ExternalVarDecls(0), ExternalVarDefs(0) { + + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + return Entry; } -const MCSectionPIC16 *PIC16TargetObjectFile:: -getPIC16Section(const char *Name, SectionKind Kind, - int Address, int Color) const { - MCSectionPIC16 *&Entry = SectionsByName[Name]; +/// Find a standard pic16 data section. If not found, create one and keep +/// track of it by adding it to appropriate std section list. +PIC16Section *PIC16TargetObjectFile:: +getPIC16DataSection(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; if (Entry) return Entry; - return Entry = MCSectionPIC16::Create(Name, Kind, Address, Color, - getContext()); -} + /// Else create a new one and add it to appropriate section list. + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); -void PIC16TargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &tm){ - TargetLoweringObjectFile::Initialize(Ctx, tm); - TM = &tm; - - BSSSection = getPIC16Section("udata.# UDATA", MCSectionPIC16::UDATA_Kind()); - ReadOnlySection = getPIC16Section("romdata.# ROMDATA", - MCSectionPIC16::ROMDATA_Kind()); - DataSection = getPIC16Section("idata.# IDATA", MCSectionPIC16::IDATA_Kind()); - - // Need because otherwise a .text symbol is emitted by DwarfWriter - // in BeginModule, and gpasm cribbs for that .text symbol. - TextSection = getPIC16Section("", SectionKind::getText()); + switch (Ty) { + default: llvm_unreachable ("unknow standard section type."); + case UDATA: UDATASections_.push_back(Entry); break; + case IDATA: IDATASections_.push_back(Entry); break; + case ROMDATA: ROMDATASection_ = Entry; break; + } - ROSections.push_back(new PIC16Section((MCSectionPIC16*)ReadOnlySection)); - - // FIXME: I don't know what the classification of these sections really is. - // These aren't really objects belonging to any section. Just emit them - // in AsmPrinter and remove this code from here. - ExternalVarDecls = new PIC16Section(getPIC16Section("ExternalVarDecls", - SectionKind::getMetadata())); - ExternalVarDefs = new PIC16Section(getPIC16Section("ExternalVarDefs", - SectionKind::getMetadata())); + return Entry; } + -const MCSection *PIC16TargetObjectFile:: -getSectionForFunction(const std::string &FnName) const { - std::string T = PAN::getCodeSectionName(FnName); - return getPIC16Section(T.c_str(), SectionKind::getText()); +/// Find a standard pic16 autos section. If not found, create one and keep +/// track of it by adding it to appropriate std section list. +PIC16Section *PIC16TargetObjectFile:: +getPIC16AutoSection(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; + + + /// Else create a new one and add it to appropriate section list. + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + + assert (Ty == UDATA_OVR && "incorrect section type for autos"); + AUTOSections_.push_back(Entry); + + return Entry; } + +/// Find a pic16 user section. If not found, create one and keep +/// track of it by adding it to appropriate std section list. +PIC16Section *PIC16TargetObjectFile:: +getPIC16UserSection(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; -const MCSection *PIC16TargetObjectFile:: -getSectionForFunctionFrame(const std::string &FnName) const { - std::string T = PAN::getFrameSectionName(FnName); - return getPIC16Section(T.c_str(), SectionKind::getDataRel()); + /// Else create a new one and add it to appropriate section list. + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + + USERSections_.push_back(Entry); + + return Entry; } +/// Do some standard initialization. +void PIC16TargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &tm){ + TargetLoweringObjectFile::Initialize(Ctx, tm); + TM = &tm; + + ROMDATASection_ = NULL; +} + +/// allocateUDATA - Allocate a un-initialized global to an existing or new UDATA +/// section and return that section. const MCSection * -PIC16TargetObjectFile::getBSSSectionForGlobal(const GlobalVariable *GV) const { +PIC16TargetObjectFile::allocateUDATA(const GlobalVariable *GV) const { assert(GV->hasInitializer() && "This global doesn't need space"); Constant *C = GV->getInitializer(); assert(C->isNullValue() && "Unitialized globals has non-zero initializer"); @@ -97,41 +140,37 @@ PIC16TargetObjectFile::getBSSSectionForGlobal(const GlobalVariable *GV) const { const Type *Ty = C->getType(); unsigned ValSize = TD->getTypeAllocSize(Ty); - // Go through all BSS Sections and assign this variable + // Go through all UDATA Sections and assign this variable // to the first available section having enough space. - PIC16Section *FoundBSS = NULL; - for (unsigned i = 0; i < BSSSections.size(); i++) { - if (DataBankSize - BSSSections[i]->Size >= ValSize) { - FoundBSS = BSSSections[i]; + PIC16Section *Found = NULL; + for (unsigned i = 0; i < UDATASections_.size(); i++) { + if (DataBankSize - UDATASections_[i]->getSize() >= ValSize) { + Found = UDATASections_[i]; break; } } - // No BSS section spacious enough was found. Crate a new one. - if (!FoundBSS) { - std::string name = PAN::getUdataSectionName(BSSSections.size()); - const MCSectionPIC16 *NewSection - = getPIC16Section(name.c_str(), MCSectionPIC16::UDATA_Kind()); - - FoundBSS = new PIC16Section(NewSection); - - // Add this newly created BSS section to the list of BSSSections. - BSSSections.push_back(FoundBSS); + // No UDATA section spacious enough was found. Crate a new one. + if (!Found) { + std::string name = PAN::getUdataSectionName(UDATASections_.size()); + Found = getPIC16DataSection(name.c_str(), UDATA); } - // Insert the GV into this BSS. - FoundBSS->Items.push_back(GV); - FoundBSS->Size += ValSize; - return FoundBSS->S_; + // Insert the GV into this UDATA section. + Found->Items.push_back(GV); + Found->setSize(Found->getSize() + ValSize); + return Found; } +/// allocateIDATA - allocate an initialized global into an existing +/// or new section and return that section. const MCSection * -PIC16TargetObjectFile::getIDATASectionForGlobal(const GlobalVariable *GV) const{ +PIC16TargetObjectFile::allocateIDATA(const GlobalVariable *GV) const{ assert(GV->hasInitializer() && "This global doesn't need space"); Constant *C = GV->getInitializer(); assert(!C->isNullValue() && "initialized globals has zero initializer"); assert(GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE && - "can split initialized RAM data only"); + "can allocate initialized RAM data only"); // Find how much space this global needs. const TargetData *TD = TM->getTargetData(); @@ -140,64 +179,47 @@ PIC16TargetObjectFile::getIDATASectionForGlobal(const GlobalVariable *GV) const{ // Go through all IDATA Sections and assign this variable // to the first available section having enough space. - PIC16Section *FoundIDATA = NULL; - for (unsigned i = 0; i < IDATASections.size(); i++) { - if (DataBankSize - IDATASections[i]->Size >= ValSize) { - FoundIDATA = IDATASections[i]; + PIC16Section *Found = NULL; + for (unsigned i = 0; i < IDATASections_.size(); i++) { + if (DataBankSize - IDATASections_[i]->getSize() >= ValSize) { + Found = IDATASections_[i]; break; } } // No IDATA section spacious enough was found. Crate a new one. - if (!FoundIDATA) { - std::string name = PAN::getIdataSectionName(IDATASections.size()); - const MCSectionPIC16 *NewSection = - getPIC16Section(name.c_str(), MCSectionPIC16::IDATA_Kind()); - - FoundIDATA = new PIC16Section(NewSection); - - // Add this newly created IDATA section to the list of IDATASections. - IDATASections.push_back(FoundIDATA); + if (!Found) { + std::string name = PAN::getIdataSectionName(IDATASections_.size()); + Found = getPIC16DataSection(name.c_str(), IDATA); } // Insert the GV into this IDATA. - FoundIDATA->Items.push_back(GV); - FoundIDATA->Size += ValSize; - return FoundIDATA->S_; + Found->Items.push_back(GV); + Found->setSize(Found->getSize() + ValSize); + return Found; } -// Get the section for an automatic variable of a function. -// For PIC16 they are globals only with mangled names. +// Allocate a program memory variable into ROMDATA section. const MCSection * -PIC16TargetObjectFile::getSectionForAuto(const GlobalVariable *GV) const { +PIC16TargetObjectFile::allocateROMDATA(const GlobalVariable *GV) const { - const std::string name = PAN::getSectionNameForSym(GV->getName()); + std::string name = PAN::getRomdataSectionName(); + PIC16Section *S = getPIC16DataSection(name.c_str(), ROMDATA); - // Go through all Auto Sections and assign this variable - // to the appropriate section. - PIC16Section *FoundAutoSec = NULL; - for (unsigned i = 0; i < AutosSections.size(); i++) { - if (AutosSections[i]->S_->getName() == name) { - FoundAutoSec = AutosSections[i]; - break; - } - } - - // No Auto section was found. Crate a new one. - if (!FoundAutoSec) { - const MCSectionPIC16 *NewSection = - getPIC16Section(name.c_str(), MCSectionPIC16::UDATA_OVR_Kind()); - - FoundAutoSec = new PIC16Section(NewSection); + S->Items.push_back(GV); + return S; +} - // Add this newly created autos section to the list of AutosSections. - AutosSections.push_back(FoundAutoSec); - } +// Get the section for an automatic variable of a function. +// For PIC16 they are globals only with mangled names. +const MCSection * +PIC16TargetObjectFile::allocateAUTO(const GlobalVariable *GV) const { - // Insert the auto into this section. - FoundAutoSec->Items.push_back(GV); + const std::string name = PAN::getSectionNameForSym(GV->getName()); + PIC16Section *S = getPIC16AutoSection(name.c_str()); - return FoundAutoSec->S_; + S->Items.push_back(GV); + return S; } @@ -214,56 +236,35 @@ PIC16TargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV1, if (!GV) return TargetLoweringObjectFile::SelectSectionForGlobal(GV1, Kind, Mang,TM); - // Record External Var Decls. - if (GV->isDeclaration()) { - ExternalVarDecls->Items.push_back(GV); - return ExternalVarDecls->S_; - } - assert(GV->hasInitializer() && "A def without initializer?"); // First, if this is an automatic variable for a function, get the section // name for it and return. std::string name = GV->getName(); if (PAN::isLocalName(name)) - return getSectionForAuto(GV); - - // Record Exteranl Var Defs. - if (GV->hasExternalLinkage() || GV->hasCommonLinkage()) - ExternalVarDefs->Items.push_back(GV); + return allocateAUTO(GV); // See if this is an uninitialized global. const Constant *C = GV->getInitializer(); if (C->isNullValue()) - return getBSSSectionForGlobal(GV); + return allocateUDATA(GV); // If this is initialized data in RAM. Put it in the correct IDATA section. if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) - return getIDATASectionForGlobal(GV); + return allocateIDATA(GV); // This is initialized data in rom, put it in the readonly section. if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) - return getROSectionForGlobal(GV); + return allocateROMDATA(GV); // Else let the default implementation take care of it. return TargetLoweringObjectFile::SelectSectionForGlobal(GV, Kind, Mang,TM); } -PIC16TargetObjectFile::~PIC16TargetObjectFile() { - for (unsigned i = 0; i < BSSSections.size(); i++) - delete BSSSections[i]; - for (unsigned i = 0; i < IDATASections.size(); i++) - delete IDATASections[i]; - for (unsigned i = 0; i < AutosSections.size(); i++) - delete AutosSections[i]; - for (unsigned i = 0; i < ROSections.size(); i++) - delete ROSections[i]; - delete ExternalVarDecls; - delete ExternalVarDefs; -} -/// getSpecialCasedSectionGlobals - Allow the target to completely override + +/// getExplicitSectionGlobal - Allow the target to completely override /// section assignment of a global. const MCSection *PIC16TargetObjectFile:: getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, @@ -274,167 +275,83 @@ getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, std::string SectName = GVar->getSection(); // If address for a variable is specified, get the address and create // section. + // FIXME: move this attribute checking in PAN. std::string AddrStr = "Address="; if (SectName.compare(0, AddrStr.length(), AddrStr) == 0) { std::string SectAddr = SectName.substr(AddrStr.length()); - return CreateSectionForGlobal(GVar, Mang, SectAddr); + return allocateAtGivenAddress(GVar, SectAddr); } // Create the section specified with section attribute. - return CreateSectionForGlobal(GVar, Mang); + return allocateInGivenSection(GVar); } - return getPIC16Section(GV->getSection().c_str(), Kind); + return getPIC16DataSection(GV->getSection().c_str(), UDATA); +} + +// Interface used by AsmPrinter to get a code section for a function. +const PIC16Section * +PIC16TargetObjectFile::SectionForCode(const std::string &FnName) const { + const std::string &sec_name = PAN::getCodeSectionName(FnName); + return getPIC16Section(sec_name, CODE); +} + +// Interface used by AsmPrinter to get a frame section for a function. +const PIC16Section * +PIC16TargetObjectFile::SectionForFrame(const std::string &FnName) const { + const std::string &sec_name = PAN::getFrameSectionName(FnName); + return getPIC16Section(sec_name, UDATA_OVR); } -// Create a new section for global variable. If Addr is given then create -// section at that address else create by name. +// Allocate a global var in existing or new section of given name. const MCSection * -PIC16TargetObjectFile::CreateSectionForGlobal(const GlobalVariable *GV, - Mangler *Mang, - const std::string &Addr) const { +PIC16TargetObjectFile::allocateInGivenSection(const GlobalVariable *GV) const { + // Determine the type of section that we need to create. + PIC16SectionType SecTy; + // See if this is an uninitialized global. const Constant *C = GV->getInitializer(); if (C->isNullValue()) - return CreateBSSSectionForGlobal(GV, Addr); - + SecTy = UDATA; // If this is initialized data in RAM. Put it in the correct IDATA section. - if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) - return CreateIDATASectionForGlobal(GV, Addr); - + else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) + SecTy = IDATA; // This is initialized data in rom, put it in the readonly section. - if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) - return CreateROSectionForGlobal(GV, Addr); - - // Else let the default implementation take care of it. - return TargetLoweringObjectFile::SectionForGlobal(GV, Mang, *TM); + else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) + SecTy = ROMDATA; + else + llvm_unreachable ("Could not determine section type for global"); + + PIC16Section *S = getPIC16UserSection(GV->getSection().c_str(), SecTy); + S->Items.push_back(GV); + return S; } -// Create uninitialized section for a variable. +// Allocate a global var in a new absolute sections at given address. const MCSection * -PIC16TargetObjectFile::CreateBSSSectionForGlobal(const GlobalVariable *GV, - std::string Addr) const { - assert(GV->hasInitializer() && "This global doesn't need space"); - assert(GV->getInitializer()->isNullValue() && - "Unitialized global has non-zero initializer"); - std::string Name; - // If address is given then create a section at that address else create a - // section by section name specified in GV. - PIC16Section *FoundBSS = NULL; - if (Addr.empty()) { - Name = GV->getSection() + " UDATA"; - for (unsigned i = 0; i < BSSSections.size(); i++) { - if (BSSSections[i]->S_->getName() == Name) { - FoundBSS = BSSSections[i]; - break; - } - } - } else { - std::string Prefix = GV->getNameStr() + "." + Addr + "."; - Name = PAN::getUdataSectionName(BSSSections.size(), Prefix) + " " + Addr; - } - - PIC16Section *NewBSS = FoundBSS; - if (NewBSS == NULL) { - const MCSectionPIC16 *NewSection = - getPIC16Section(Name.c_str(), MCSectionPIC16::UDATA_Kind()); - NewBSS = new PIC16Section(NewSection); - BSSSections.push_back(NewBSS); - } +PIC16TargetObjectFile::allocateAtGivenAddress(const GlobalVariable *GV, + const std::string &Addr) const { + // Determine the type of section that we need to create. + PIC16SectionType SecTy; - // Insert the GV into this BSS. - NewBSS->Items.push_back(GV); - - // We do not want to put any GV without explicit section into this section - // so set its size to DatabankSize. - NewBSS->Size = DataBankSize; - return NewBSS->S_; -} - -// Get rom section for a variable. Currently there can be only one rom section -// unless a variable explicitly requests a section. -const MCSection * -PIC16TargetObjectFile::getROSectionForGlobal(const GlobalVariable *GV) const { - ROSections[0]->Items.push_back(GV); - return ROSections[0]->S_; -} - -// Create initialized data section for a variable. -const MCSection * -PIC16TargetObjectFile::CreateIDATASectionForGlobal(const GlobalVariable *GV, - std::string Addr) const { - assert(GV->hasInitializer() && "This global doesn't need space"); - assert(!GV->getInitializer()->isNullValue() && - "initialized global has zero initializer"); - assert(GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE && - "can be used for initialized RAM data only"); - - std::string Name; - // If address is given then create a section at that address else create a - // section by section name specified in GV. - PIC16Section *FoundIDATASec = NULL; - if (Addr.empty()) { - Name = GV->getSection() + " IDATA"; - for (unsigned i = 0; i < IDATASections.size(); i++) { - if (IDATASections[i]->S_->getName() == Name) { - FoundIDATASec = IDATASections[i]; - break; - } - } - } else { - std::string Prefix = GV->getNameStr() + "." + Addr + "."; - Name = PAN::getIdataSectionName(IDATASections.size(), Prefix) + " " + Addr; - } - - PIC16Section *NewIDATASec = FoundIDATASec; - if (NewIDATASec == NULL) { - const MCSectionPIC16 *NewSection = - getPIC16Section(Name.c_str(), MCSectionPIC16::IDATA_Kind()); - NewIDATASec = new PIC16Section(NewSection); - IDATASections.push_back(NewIDATASec); - } - // Insert the GV into this IDATA Section. - NewIDATASec->Items.push_back(GV); - // We do not want to put any GV without explicit section into this section - // so set its size to DatabankSize. - NewIDATASec->Size = DataBankSize; - return NewIDATASec->S_; + // See if this is an uninitialized global. + const Constant *C = GV->getInitializer(); + if (C->isNullValue()) + SecTy = UDATA; + // If this is initialized data in RAM. Put it in the correct IDATA section. + else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) + SecTy = IDATA; + // This is initialized data in rom, put it in the readonly section. + else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) + SecTy = ROMDATA; + else + llvm_unreachable ("Could not determine section type for global"); + + std::string Prefix = GV->getNameStr() + "." + Addr + "."; + std::string SName = PAN::getUserSectionName(Prefix); + PIC16Section *S = getPIC16UserSection(SName.c_str(), SecTy, Addr.c_str()); + S->Items.push_back(GV); + return S; } -// Create a section in rom for a variable. -const MCSection * -PIC16TargetObjectFile::CreateROSectionForGlobal(const GlobalVariable *GV, - std::string Addr) const { - assert(GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE && - "can be used for ROM data only"); - - std::string Name; - // If address is given then create a section at that address else create a - // section by section name specified in GV. - PIC16Section *FoundROSec = NULL; - if (Addr.empty()) { - Name = GV->getSection() + " ROMDATA"; - for (unsigned i = 1; i < ROSections.size(); i++) { - if (ROSections[i]->S_->getName() == Name) { - FoundROSec = ROSections[i]; - break; - } - } - } else { - std::string Prefix = GV->getNameStr() + "." + Addr + "."; - Name = PAN::getRomdataSectionName(ROSections.size(), Prefix) + " " + Addr; - } - - PIC16Section *NewRomSec = FoundROSec; - if (NewRomSec == NULL) { - const MCSectionPIC16 *NewSection = - getPIC16Section(Name.c_str(), MCSectionPIC16::ROMDATA_Kind()); - NewRomSec = new PIC16Section(NewSection); - ROSections.push_back(NewRomSec); - } - - // Insert the GV into this ROM Section. - NewRomSec->Items.push_back(GV); - return NewRomSec->S_; -} diff --git a/lib/Target/PIC16/PIC16TargetObjectFile.h b/lib/Target/PIC16/PIC16TargetObjectFile.h index 75f6cce..ca07bed 100644 --- a/lib/Target/PIC16/PIC16TargetObjectFile.h +++ b/lib/Target/PIC16/PIC16TargetObjectFile.h @@ -10,6 +10,8 @@ #ifndef LLVM_TARGET_PIC16_TARGETOBJECTFILE_H #define LLVM_TARGET_PIC16_TARGETOBJECTFILE_H +#include "PIC16.h" +#include "PIC16ABINames.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/ADT/StringMap.h" #include <vector> @@ -19,7 +21,7 @@ namespace llvm { class GlobalVariable; class Module; class PIC16TargetMachine; - class MCSectionPIC16; + class PIC16Section; enum { DataBankSize = 80 }; @@ -29,91 +31,128 @@ namespace llvm { /// again and printing only those that match the current section. /// Keeping values inside the sections make printing a section much easier. /// - /// FIXME: MOVE ALL THIS STUFF TO MCSectionPIC16. + /// FIXME: MOVE ALL THIS STUFF TO PIC16Section. /// - struct PIC16Section { - const MCSectionPIC16 *S_; // Connection to actual Section. - unsigned Size; // Total size of the objects contained. - bool SectionPrinted; - std::vector<const GlobalVariable*> Items; - - PIC16Section(const MCSectionPIC16 *s) { - S_ = s; - Size = 0; - SectionPrinted = false; - } - bool isPrinted() const { return SectionPrinted; } - void setPrintedStatus(bool status) { SectionPrinted = status; } - }; - + + /// PIC16TargetObjectFile - PIC16 Object file. Contains data and code + /// sections. + // PIC16 Object File has two types of sections. + // 1. Standard Sections + // 1.1 un-initialized global data + // 1.2 initialized global data + // 1.3 program memory data + // 1.4 local variables of functions. + // 2. User defined sections + // 2.1 Objects placed in a specific section. (By _Section() macro) + // 2.2 Objects placed at a specific address. (By _Address() macro) class PIC16TargetObjectFile : public TargetLoweringObjectFile { /// SectionsByName - Bindings of names to allocated sections. - mutable StringMap<MCSectionPIC16*> SectionsByName; + mutable StringMap<PIC16Section*> SectionsByName; const TargetMachine *TM; - const MCSectionPIC16 *getPIC16Section(const char *Name, - SectionKind K, - int Address = -1, - int Color = -1) const; - public: - mutable std::vector<PIC16Section*> BSSSections; - mutable std::vector<PIC16Section*> IDATASections; - mutable std::vector<PIC16Section*> AutosSections; - mutable std::vector<PIC16Section*> ROSections; - mutable PIC16Section *ExternalVarDecls; - mutable PIC16Section *ExternalVarDefs; + /// Lists of sections. + /// Standard Data Sections. + mutable std::vector<PIC16Section *> UDATASections_; + mutable std::vector<PIC16Section *> IDATASections_; + mutable PIC16Section * ROMDATASection_; + + /// Standard Auto Sections. + mutable std::vector<PIC16Section *> AUTOSections_; + + /// User specified sections. + mutable std::vector<PIC16Section *> USERSections_; + + + /// Find or Create a PIC16 Section, without adding it to any + /// section list. + PIC16Section *getPIC16Section(const std::string &Name, + PIC16SectionType Ty, + const std::string &Address = "", + int Color = -1) const; + + /// Convenience functions. These wrappers also take care of adding + /// the newly created section to the appropriate sections list. + + /// Find or Create PIC16 Standard Data Section. + PIC16Section *getPIC16DataSection(const std::string &Name, + PIC16SectionType Ty, + const std::string &Address = "", + int Color = -1) const; + + /// Find or Create PIC16 Standard Auto Section. + PIC16Section *getPIC16AutoSection(const std::string &Name, + PIC16SectionType Ty = UDATA_OVR, + const std::string &Address = "", + int Color = -1) const; + + /// Find or Create PIC16 Standard Auto Section. + PIC16Section *getPIC16UserSection(const std::string &Name, + PIC16SectionType Ty, + const std::string &Address = "", + int Color = -1) const; + + /// Allocate Un-initialized data to a standard UDATA section. + const MCSection *allocateUDATA(const GlobalVariable *GV) const; + + /// Allocate Initialized data to a standard IDATA section. + const MCSection *allocateIDATA(const GlobalVariable *GV) const; + /// Allocate ROM data to the standard ROMDATA section. + const MCSection *allocateROMDATA(const GlobalVariable *GV) const; + + /// Allocate an AUTO variable to an AUTO section. + const MCSection *allocateAUTO(const GlobalVariable *GV) const; + + /// Allocate DATA in user specified section. + const MCSection *allocateInGivenSection(const GlobalVariable *GV) const; + + /// Allocate DATA at user specified address. + const MCSection *allocateAtGivenAddress(const GlobalVariable *GV, + const std::string &Addr) const; + + public: PIC16TargetObjectFile(); ~PIC16TargetObjectFile(); - void Initialize(MCContext &Ctx, const TargetMachine &TM); - + /// Return the section with the given Name. Null if not found. + PIC16Section *findPIC16Section(const std::string &Name); + + /// Override section allocations for user specified sections. virtual const MCSection * getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const; + /// Select sections for Data and Auto variables(globals). virtual const MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine&) const; - const MCSection *getSectionForFunction(const std::string &FnName) const; - const MCSection *getSectionForFunctionFrame(const std::string &FnName)const; - - - private: - std::string getSectionNameForSym(const std::string &Sym) const; - - const MCSection *getBSSSectionForGlobal(const GlobalVariable *GV) const; - const MCSection *getIDATASectionForGlobal(const GlobalVariable *GV) const; - const MCSection *getSectionForAuto(const GlobalVariable *GV) const; - const MCSection *CreateBSSSectionForGlobal(const GlobalVariable *GV, - std::string Addr = "") const; - const MCSection *CreateIDATASectionForGlobal(const GlobalVariable *GV, - std::string Addr = "") const; - const MCSection *getROSectionForGlobal(const GlobalVariable *GV) const; - const MCSection *CreateROSectionForGlobal(const GlobalVariable *GV, - std::string Addr = "") const; - const MCSection *CreateSectionForGlobal(const GlobalVariable *GV, - Mangler *Mang, - const std::string &Addr = "") const; - public: - void SetSectionForGVs(Module &M); - const std::vector<PIC16Section*> &getBSSSections() const { - return BSSSections; + + /// Return a code section for a function. + const PIC16Section *SectionForCode (const std::string &FnName) const; + + /// Return a frame section for a function. + const PIC16Section *SectionForFrame (const std::string &FnName) const; + + /// Accessors for various section lists. + const std::vector<PIC16Section *> &UDATASections() const { + return UDATASections_; } - const std::vector<PIC16Section*> &getIDATASections() const { - return IDATASections; + const std::vector<PIC16Section *> &IDATASections() const { + return IDATASections_; } - const std::vector<PIC16Section*> &getAutosSections() const { - return AutosSections; + const PIC16Section *ROMDATASection() const { + return ROMDATASection_; } - const std::vector<PIC16Section*> &getROSections() const { - return ROSections; + const std::vector<PIC16Section *> &AUTOSections() const { + return AUTOSections_; + } + const std::vector<PIC16Section *> &USERSections() const { + return USERSections_; } - }; } // end namespace llvm diff --git a/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp b/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp index a0fba86..dc6b852 100644 --- a/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp @@ -1129,7 +1129,7 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { // implementation of multiple entry points). If this doesn't occur, the // linker can safely perform dead code stripping. Since LLVM never generates // code that does this, it is always safe to set. - O << "\t.subsections_via_symbols\n"; + OutStreamer.EmitAssemblerFlag(MCStreamer::SubsectionsViaSymbols); return AsmPrinter::doFinalization(M); } diff --git a/lib/Target/README.txt b/lib/Target/README.txt index 89ea9d0..2740387 100644 --- a/lib/Target/README.txt +++ b/lib/Target/README.txt @@ -1594,23 +1594,8 @@ int int_char(char m) {if(m>7) return 0; return m;} //===---------------------------------------------------------------------===// -Instcombine should replace the load with a constant in: - - static const char x[4] = {'a', 'b', 'c', 'd'}; - - unsigned int y(void) { - return *(unsigned int *)x; - } - -It currently only does this transformation when the size of the constant -is the same as the size of the integer (so, try x[5]) and the last byte -is a null (making it a C string). There's no need for these restrictions. - -//===---------------------------------------------------------------------===// - -InstCombine's "turn load from constant into constant" optimization should be -more aggressive in the presence of bitcasts. For example, because of unions, -this code: +libanalysis is not aggressively folding vector bitcasts. For example, the +constant expressions generated when compiling this code: union vec2d { double e[2]; @@ -1624,23 +1609,29 @@ vec2d foo () { return (vec2d){ .v = a.v + b.v * (vec2d){{5,5}}.v }; } -Compiles into: +in X86-32 end up being: -@a = internal constant %0 { [2 x double] - [double 1.000000e+00, double 2.000000e+00] }, align 16 -@b = internal constant %0 { [2 x double] - [double 3.000000e+00, double 4.000000e+00] }, align 16 -... -define void @foo(%struct.vec2d* noalias nocapture sret %agg.result) nounwind { +define void @foo(%union.vec2d* noalias nocapture sret %agg.result) nounwind ssp { entry: - %0 = load <2 x double>* getelementptr (%struct.vec2d* - bitcast (%0* @a to %struct.vec2d*), i32 0, i32 0), align 16 - %1 = load <2 x double>* getelementptr (%struct.vec2d* - bitcast (%0* @b to %struct.vec2d*), i32 0, i32 0), align 16 + %agg.result.0 = getelementptr %union.vec2d* %agg.result, i32 0, i32 0 ; <<2 x double>*> [#uses=1] + store <2 x double> fadd (<2 x double> bitcast (<1 x i128> <i128 85070591730234615870450834276742070272> to <2 x double>), <2 x double> fmul (<2 x double> bitcast (<1 x i128> <i128 85153668479971173112514077617450647552> to <2 x double>), <2 x double> <double 5.000000e+00, double 5.000000e+00>)), <2 x double>* %agg.result.0, align 16 + ret void +} +and in X86-64 mode: -Instcombine should be able to optimize away the loads (and thus the globals). +define %0 @foo() nounwind readnone ssp { +entry: + %mrv5 = insertvalue %0 undef, double extractelement (<2 x double> fadd (<2 x double> bitcast (<1 x i128> <i128 85070591730234615870450834276742070272> to <2 x double>), <2 x double> fmul (<2 x double> bitcast (<1 x i128> <i128 85153668479971173112514077617450647552> to <2 x double>), <2 x double> bitcast (<1 x i128> <i128 85174437667405312423031577302488055808> to <2 x double>))), i32 0), 0 ; <%0> [#uses=1] + %mrv6 = insertvalue %0 %mrv5, double extractelement (<2 x double> fadd (<2 x double> bitcast (<1 x i128> <i128 85070591730234615870450834276742070272> to <2 x double>), <2 x double> fmul (<2 x double> bitcast (<1 x i128> <i128 85153668479971173112514077617450647552> to <2 x double>), <2 x double> bitcast (<1 x i128> <i128 85174437667405312423031577302488055808> to <2 x double>))), i32 1), 1 ; <%0> [#uses=1] + ret %0 %mrv6 +} -See also PR4973 +//===---------------------------------------------------------------------===// + +IPSCCP is propagating elements of first class aggregates, but is not propagating +the entire aggregate itself. This leads it to miss opportunities, for example +in test/Transforms/SCCP/ipsccp-basic.ll:test5b. //===---------------------------------------------------------------------===// + diff --git a/lib/Target/TargetIntrinsicInfo.cpp b/lib/Target/TargetIntrinsicInfo.cpp index d8da08e..e049a1d 100644 --- a/lib/Target/TargetIntrinsicInfo.cpp +++ b/lib/Target/TargetIntrinsicInfo.cpp @@ -12,11 +12,19 @@ //===----------------------------------------------------------------------===// #include "llvm/Target/TargetIntrinsicInfo.h" +#include "llvm/Function.h" +#include "llvm/ADT/StringMap.h" using namespace llvm; -TargetIntrinsicInfo::TargetIntrinsicInfo(const char **desc, unsigned count) - : Intrinsics(desc), NumIntrinsics(count) { +TargetIntrinsicInfo::TargetIntrinsicInfo() { } TargetIntrinsicInfo::~TargetIntrinsicInfo() { } + +unsigned TargetIntrinsicInfo::getIntrinsicID(Function *F) const { + const ValueName *ValName = F->getValueName(); + if (!ValName) + return 0; + return lookupName(ValName->getKeyData(), ValName->getKeyLength()); +} diff --git a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp index bc70ffe..8ec5b62 100644 --- a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp +++ b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp @@ -57,9 +57,7 @@ void X86ATTInstPrinter::print_pcrel_imm(const MCInst *MI, unsigned OpNo) { } } -void X86ATTInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, - const char *Modifier) { - assert(Modifier == 0 && "Modifiers should not be used"); +void X86ATTInstPrinter::printOperand(const MCInst *MI, unsigned OpNo) { const MCOperand &Op = MI->getOperand(OpNo); if (Op.isReg()) { diff --git a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h index 5f28fa4..3180618 100644 --- a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h +++ b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h @@ -32,8 +32,7 @@ public: static const char *getRegisterName(unsigned RegNo); - void printOperand(const MCInst *MI, unsigned OpNo, - const char *Modifier = 0); + void printOperand(const MCInst *MI, unsigned OpNo); void printMemReference(const MCInst *MI, unsigned Op); void printLeaMemReference(const MCInst *MI, unsigned Op); void printSSECC(const MCInst *MI, unsigned Op); diff --git a/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp b/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp index 2a0290d..ae8e6d3 100644 --- a/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp +++ b/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp @@ -225,7 +225,7 @@ void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO) { std::string Name = Mang->getMangledName(GV, Suffix, Suffix[0] != '\0'); if (Subtarget->isTargetCygMing()) { - X86COFFMachineModuleInfo &COFFMMI = + X86COFFMachineModuleInfo &COFFMMI = MMI->getObjFileInfo<X86COFFMachineModuleInfo>(); COFFMMI.DecorateCygMingName(Name, GV, *TM.getTargetData()); } @@ -288,12 +288,12 @@ void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO) { std::string Name = Mang->makeNameProper(MO.getSymbolName()); if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) { Name += "$stub"; - MCSymbol *Sym = OutContext.GetOrCreateSymbol(Name); + MCSymbol *Sym = OutContext.GetOrCreateSymbol(StringRef(Name)); const MCSymbol *&StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>().getFnStubEntry(Sym); if (StubSym == 0) { Name.erase(Name.end()-5, Name.end()); - StubSym = OutContext.GetOrCreateSymbol(Name); + StubSym = OutContext.GetOrCreateSymbol(StringRef(Name)); } } @@ -870,49 +870,55 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { // implementation of multiple entry points). If this doesn't occur, the // linker can safely perform dead code stripping. Since LLVM never // generates code that does this, it is always safe to set. - O << "\t.subsections_via_symbols\n"; - } - - if (Subtarget->isTargetCOFF()) { - // Necessary for dllexport support - std::vector<std::string> DLLExportedFns, DLLExportedGlobals; + OutStreamer.EmitAssemblerFlag(MCStreamer::SubsectionsViaSymbols); + } - X86COFFMachineModuleInfo &COFFMMI = + if (Subtarget->isTargetCOFF()) { + X86COFFMachineModuleInfo &COFFMMI = MMI->getObjFileInfo<X86COFFMachineModuleInfo>(); - TargetLoweringObjectFileCOFF &TLOFCOFF = - static_cast<TargetLoweringObjectFileCOFF&>(getObjFileLowering()); - for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) - if (I->hasDLLExportLinkage()) - DLLExportedFns.push_back(Mang->getMangledName(I)); - - for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) - if (I->hasDLLExportLinkage()) - DLLExportedGlobals.push_back(Mang->getMangledName(I)); - - if (Subtarget->isTargetCygMing()) { - // Emit type information for external functions - for (X86COFFMachineModuleInfo::stub_iterator I = COFFMMI.stub_begin(), + // Emit type information for external functions + for (X86COFFMachineModuleInfo::stub_iterator I = COFFMMI.stub_begin(), E = COFFMMI.stub_end(); I != E; ++I) { - O << "\t.def\t " << I->getKeyData() + O << "\t.def\t " << I->getKeyData() << ";\t.scl\t" << COFF::C_EXT << ";\t.type\t" << (COFF::DT_FCN << COFF::N_BTSHFT) << ";\t.endef\n"; - } } - - // Output linker support code for dllexported globals on windows. - if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { - OutStreamer.SwitchSection(TLOFCOFF.getCOFFSection(".section .drectve", - true, + + if (Subtarget->isTargetCygMing()) { + // Necessary for dllexport support + std::vector<std::string> DLLExportedFns, DLLExportedGlobals; + + TargetLoweringObjectFileCOFF &TLOFCOFF = + static_cast<TargetLoweringObjectFileCOFF&>(getObjFileLowering()); + + for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) + if (I->hasDLLExportLinkage()) { + std::string Name = Mang->getMangledName(I); + COFFMMI.DecorateCygMingName(Name, I, *TM.getTargetData()); + DLLExportedFns.push_back(Name); + } + + for (Module::const_global_iterator I = M.global_begin(), + E = M.global_end(); I != E; ++I) + if (I->hasDLLExportLinkage()) { + std::string Name = Mang->getMangledName(I); + COFFMMI.DecorateCygMingName(Name, I, *TM.getTargetData()); + DLLExportedGlobals.push_back(Mang->getMangledName(I)); + } + + // Output linker support code for dllexported globals on windows. + if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { + OutStreamer.SwitchSection(TLOFCOFF.getCOFFSection(".section .drectve", + true, SectionKind::getMetadata())); - - for (unsigned i = 0, e = DLLExportedGlobals.size(); i != e; ++i) - O << "\t.ascii \" -export:" << DLLExportedGlobals[i] << ",data\"\n"; - - for (unsigned i = 0, e = DLLExportedFns.size(); i != e; ++i) - O << "\t.ascii \" -export:" << DLLExportedFns[i] << "\"\n"; + for (unsigned i = 0, e = DLLExportedGlobals.size(); i != e; ++i) + O << "\t.ascii \" -export:" << DLLExportedGlobals[i] << ",data\"\n"; + + for (unsigned i = 0, e = DLLExportedFns.size(); i != e; ++i) + O << "\t.ascii \" -export:" << DLLExportedFns[i] << "\"\n"; + } } } } diff --git a/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp b/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp index 5ccddf5..d498c57 100644 --- a/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp +++ b/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp @@ -38,10 +38,8 @@ MachineModuleInfoMachO &X86MCInstLower::getMachOMMI() const { MCSymbol *X86MCInstLower::GetPICBaseSymbol() const { - SmallString<60> Name; - raw_svector_ostream(Name) << AsmPrinter.MAI->getPrivateGlobalPrefix() - << AsmPrinter.getFunctionNumber() << "$pb"; - return Ctx.GetOrCreateSymbol(Name.str()); + return Ctx.GetOrCreateSymbol(Twine(AsmPrinter.MAI->getPrivateGlobalPrefix())+ + Twine(AsmPrinter.getFunctionNumber())+"$pb"); } @@ -308,6 +306,8 @@ void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { MI->dump(); llvm_unreachable("unknown operand type"); case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; MCOp = MCOperand::CreateReg(MO.getReg()); break; case MachineOperand::MO_Immediate: @@ -449,10 +449,9 @@ void X86AsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) { // MYGLOBAL + (. - PICBASE) // However, we can't generate a ".", so just emit a new label here and refer // to it. We know that this operand flag occurs at most once per function. - SmallString<64> Name; - raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() - << "picbaseref" << getFunctionNumber(); - MCSymbol *DotSym = OutContext.GetOrCreateSymbol(Name.str()); + const char *Prefix = MAI->getPrivateGlobalPrefix(); + MCSymbol *DotSym = OutContext.GetOrCreateSymbol(Twine(Prefix)+"picbaseref"+ + Twine(getFunctionNumber())); OutStreamer.EmitLabel(DotSym); // Now that we have emitted the label, lower the complex operand expression. diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index fadc818..e5e7bc8 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -2286,6 +2286,8 @@ static unsigned TranslateX86CC(ISD::CondCode SetCCOpcode, bool isFP, case ISD::SETNE: return X86::COND_NE; case ISD::SETUO: return X86::COND_P; case ISD::SETO: return X86::COND_NP; + case ISD::SETOEQ: + case ISD::SETUNE: return X86::COND_INVALID; } } @@ -2389,6 +2391,56 @@ bool X86::isPSHUFLWMask(ShuffleVectorSDNode *N) { return ::isPSHUFLWMask(M, N->getValueType(0)); } +/// isPALIGNRMask - Return true if the node specifies a shuffle of elements that +/// is suitable for input to PALIGNR. +static bool isPALIGNRMask(const SmallVectorImpl<int> &Mask, EVT VT, + bool hasSSSE3) { + int i, e = VT.getVectorNumElements(); + + // Do not handle v2i64 / v2f64 shuffles with palignr. + if (e < 4 || !hasSSSE3) + return false; + + for (i = 0; i != e; ++i) + if (Mask[i] >= 0) + break; + + // All undef, not a palignr. + if (i == e) + return false; + + // Determine if it's ok to perform a palignr with only the LHS, since we + // don't have access to the actual shuffle elements to see if RHS is undef. + bool Unary = Mask[i] < (int)e; + bool NeedsUnary = false; + + int s = Mask[i] - i; + + // Check the rest of the elements to see if they are consecutive. + for (++i; i != e; ++i) { + int m = Mask[i]; + if (m < 0) + continue; + + Unary = Unary && (m < (int)e); + NeedsUnary = NeedsUnary || (m < s); + + if (NeedsUnary && !Unary) + return false; + if (Unary && m != ((s+i) & (e-1))) + return false; + if (!Unary && m != (s+i)) + return false; + } + return true; +} + +bool X86::isPALIGNRMask(ShuffleVectorSDNode *N) { + SmallVector<int, 8> M; + N->getMask(M); + return ::isPALIGNRMask(M, N->getValueType(0), true); +} + /// isSHUFPMask - Return true if the specified VECTOR_SHUFFLE operand /// specifies a shuffle of elements that is suitable for input to SHUFP*. static bool isSHUFPMask(const SmallVectorImpl<int> &Mask, EVT VT) { @@ -2733,8 +2785,7 @@ bool X86::isMOVDDUPMask(ShuffleVectorSDNode *N) { } /// getShuffleSHUFImmediate - Return the appropriate immediate to shuffle -/// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUF* and SHUFP* -/// instructions. +/// the specified VECTOR_SHUFFLE mask with PSHUF* and SHUFP* instructions. unsigned X86::getShuffleSHUFImmediate(SDNode *N) { ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); int NumOperands = SVOp->getValueType(0).getVectorNumElements(); @@ -2753,8 +2804,7 @@ unsigned X86::getShuffleSHUFImmediate(SDNode *N) { } /// getShufflePSHUFHWImmediate - Return the appropriate immediate to shuffle -/// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFHW -/// instructions. +/// the specified VECTOR_SHUFFLE mask with the PSHUFHW instruction. unsigned X86::getShufflePSHUFHWImmediate(SDNode *N) { ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); unsigned Mask = 0; @@ -2770,8 +2820,7 @@ unsigned X86::getShufflePSHUFHWImmediate(SDNode *N) { } /// getShufflePSHUFLWImmediate - Return the appropriate immediate to shuffle -/// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFLW -/// instructions. +/// the specified VECTOR_SHUFFLE mask with the PSHUFLW instruction. unsigned X86::getShufflePSHUFLWImmediate(SDNode *N) { ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); unsigned Mask = 0; @@ -2786,6 +2835,23 @@ unsigned X86::getShufflePSHUFLWImmediate(SDNode *N) { return Mask; } +/// getShufflePALIGNRImmediate - Return the appropriate immediate to shuffle +/// the specified VECTOR_SHUFFLE mask with the PALIGNR instruction. +unsigned X86::getShufflePALIGNRImmediate(SDNode *N) { + ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); + EVT VVT = N->getValueType(0); + unsigned EltSize = VVT.getVectorElementType().getSizeInBits() >> 3; + int Val = 0; + + unsigned i, e; + for (i = 0, e = VVT.getVectorNumElements(); i != e; ++i) { + Val = SVOp->getMaskElt(i); + if (Val >= 0) + break; + } + return (Val - i) * EltSize; +} + /// isZeroNode - Returns true if Elt is a constant zero or a floating point /// constant +0.0. bool X86::isZeroNode(SDValue Elt) { @@ -5502,6 +5568,8 @@ SDValue X86TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) { bool isFP = Op.getOperand(1).getValueType().isFloatingPoint(); unsigned X86CC = TranslateX86CC(CC, isFP, Op0, Op1, DAG); + if (X86CC == X86::COND_INVALID) + return SDValue(); SDValue Cond = EmitCmp(Op0, Op1, X86CC, DAG); return DAG.getNode(X86ISD::SETCC, dl, MVT::i8, @@ -5650,8 +5718,11 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); SDValue CC; - if (Cond.getOpcode() == ISD::SETCC) - Cond = LowerSETCC(Cond, DAG); + if (Cond.getOpcode() == ISD::SETCC) { + SDValue NewCond = LowerSETCC(Cond, DAG); + if (NewCond.getNode()) + Cond = NewCond; + } // If condition flag is set by a X86ISD::CMP, then use it as the condition // setting operand in place of the X86ISD::SETCC. @@ -5724,8 +5795,11 @@ SDValue X86TargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); SDValue CC; - if (Cond.getOpcode() == ISD::SETCC) - Cond = LowerSETCC(Cond, DAG); + if (Cond.getOpcode() == ISD::SETCC) { + SDValue NewCond = LowerSETCC(Cond, DAG); + if (NewCond.getNode()) + Cond = NewCond; + } #if 0 // FIXME: LowerXALUO doesn't handle these!! else if (Cond.getOpcode() == X86ISD::ADD || @@ -6274,6 +6348,7 @@ X86TargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) { SDValue LHS = Op.getOperand(1); SDValue RHS = Op.getOperand(2); unsigned X86CC = TranslateX86CC(CC, true, LHS, RHS, DAG); + assert(X86CC != X86::COND_INVALID && "Unexpected illegal condition!"); SDValue Cond = DAG.getNode(Opc, dl, MVT::i32, LHS, RHS); SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8, DAG.getConstant(X86CC, MVT::i8), Cond); @@ -7274,7 +7349,7 @@ X86TargetLowering::isShuffleMaskLegal(const SmallVectorImpl<int> &M, if (VT.getSizeInBits() == 64) return false; - // FIXME: pshufb, blends, palignr, shifts. + // FIXME: pshufb, blends, shifts. return (VT.getVectorNumElements() == 2 || ShuffleVectorSDNode::isSplatMask(&M[0], VT) || isMOVLMask(M, VT) || @@ -7282,6 +7357,7 @@ X86TargetLowering::isShuffleMaskLegal(const SmallVectorImpl<int> &M, isPSHUFDMask(M, VT) || isPSHUFHWMask(M, VT) || isPSHUFLWMask(M, VT) || + isPALIGNRMask(M, VT, Subtarget->hasSSSE3()) || isUNPCKLMask(M, VT) || isUNPCKHMask(M, VT) || isUNPCKL_v_undef_Mask(M, VT) || diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 2f7b8ba..66a9107 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -323,21 +323,27 @@ namespace llvm { /// specifies a shuffle of elements that is suitable for input to MOVDDUP. bool isMOVDDUPMask(ShuffleVectorSDNode *N); + /// isPALIGNRMask - Return true if the specified VECTOR_SHUFFLE operand + /// specifies a shuffle of elements that is suitable for input to PALIGNR. + bool isPALIGNRMask(ShuffleVectorSDNode *N); + /// getShuffleSHUFImmediate - Return the appropriate immediate to shuffle /// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUF* and SHUFP* /// instructions. unsigned getShuffleSHUFImmediate(SDNode *N); /// getShufflePSHUFHWImmediate - Return the appropriate immediate to shuffle - /// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFHW - /// instructions. + /// the specified VECTOR_SHUFFLE mask with PSHUFHW instruction. unsigned getShufflePSHUFHWImmediate(SDNode *N); - /// getShufflePSHUFKWImmediate - Return the appropriate immediate to shuffle - /// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFLW - /// instructions. + /// getShufflePSHUFLWImmediate - Return the appropriate immediate to shuffle + /// the specified VECTOR_SHUFFLE mask with PSHUFLW instruction. unsigned getShufflePSHUFLWImmediate(SDNode *N); + /// getShufflePALIGNRImmediate - Return the appropriate immediate to shuffle + /// the specified VECTOR_SHUFFLE mask with the PALIGNR instruction. + unsigned getShufflePALIGNRImmediate(SDNode *N); + /// isZeroNode - Returns true if Elt is a constant zero or a floating point /// constant +0.0. bool isZeroNode(SDValue Elt); diff --git a/lib/Target/X86/X86Instr64bit.td b/lib/Target/X86/X86Instr64bit.td index ef19823..c1b7b8f 100644 --- a/lib/Target/X86/X86Instr64bit.td +++ b/lib/Target/X86/X86Instr64bit.td @@ -368,19 +368,15 @@ def MOVSX64rm32: RI<0x63, MRMSrcMem, (outs GR64:$dst), (ins i32mem:$src), // Use movzbl instead of movzbq when the destination is a register; it's // equivalent due to implicit zero-extending, and it has a smaller encoding. def MOVZX64rr8 : I<0xB6, MRMSrcReg, (outs GR64:$dst), (ins GR8 :$src), - "movz{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zext GR8:$src))]>, TB; + "", [(set GR64:$dst, (zext GR8:$src))]>, TB; def MOVZX64rm8 : I<0xB6, MRMSrcMem, (outs GR64:$dst), (ins i8mem :$src), - "movz{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zextloadi64i8 addr:$src))]>, TB; + "", [(set GR64:$dst, (zextloadi64i8 addr:$src))]>, TB; // Use movzwl instead of movzwq when the destination is a register; it's // equivalent due to implicit zero-extending, and it has a smaller encoding. def MOVZX64rr16: I<0xB7, MRMSrcReg, (outs GR64:$dst), (ins GR16:$src), - "movz{wl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zext GR16:$src))]>, TB; + "", [(set GR64:$dst, (zext GR16:$src))]>, TB; def MOVZX64rm16: I<0xB7, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src), - "movz{wl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zextloadi64i16 addr:$src))]>, TB; + "", [(set GR64:$dst, (zextloadi64i16 addr:$src))]>, TB; // There's no movzlq instruction, but movl can be used for this purpose, using // implicit zero-extension. The preferred way to do 32-bit-to-64-bit zero @@ -390,11 +386,9 @@ def MOVZX64rm16: I<0xB7, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src), // necessarily all zero. In such cases, we fall back to these explicit zext // instructions. def MOVZX64rr32 : I<0x89, MRMDestReg, (outs GR64:$dst), (ins GR32:$src), - "mov{l}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zext GR32:$src))]>; + "", [(set GR64:$dst, (zext GR32:$src))]>; def MOVZX64rm32 : I<0x8B, MRMSrcMem, (outs GR64:$dst), (ins i32mem:$src), - "mov{l}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, (zextloadi64i32 addr:$src))]>; + "", [(set GR64:$dst, (zextloadi64i32 addr:$src))]>; // Any instruction that defines a 32-bit result leaves the high half of the // register. Truncate can be lowered to EXTRACT_SUBREG. CopyFromReg may @@ -1455,8 +1449,7 @@ def : Pat<(i64 0), // Materialize i64 constant where top 32-bits are zero. let AddedComplexity = 1, isReMaterializable = 1, isAsCheapAsAMove = 1 in def MOV64ri64i32 : Ii32<0xB8, AddRegFrm, (outs GR64:$dst), (ins i64i32imm:$src), - "mov{l}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR64:$dst, i64immZExt32:$src)]>; + "", [(set GR64:$dst, i64immZExt32:$src)]>; //===----------------------------------------------------------------------===// // Thread Local Storage Instructions @@ -1515,6 +1508,7 @@ def XCHG64rm : RI<0x87, MRMSrcMem, (outs GR64:$dst), (ins i64mem:$ptr,GR64:$val) } // Optimized codegen when the non-memory output is not used. +let Defs = [EFLAGS] in { // FIXME: Use normal add / sub instructions and add lock prefix dynamically. def LOCK_ADD64mr : RI<0x03, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src2), "lock\n\t" @@ -1544,7 +1538,7 @@ def LOCK_INC64m : RI<0xFF, MRM0m, (outs), (ins i64mem:$dst), def LOCK_DEC64m : RI<0xFF, MRM1m, (outs), (ins i64mem:$dst), "lock\n\t" "dec{q}\t$dst", []>, LOCK; - +} // Atomic exchange, and, or, xor let Constraints = "$val = $dst", Defs = [EFLAGS], usesCustomDAGSchedInserter = 1 in { diff --git a/lib/Target/X86/X86InstrFormats.td b/lib/Target/X86/X86InstrFormats.td index abdb313..2f14bb0 100644 --- a/lib/Target/X86/X86InstrFormats.td +++ b/lib/Target/X86/X86InstrFormats.td @@ -224,10 +224,10 @@ class S3I<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern> class SS38I<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern> - : I<o, F, outs, ins, asm, pattern>, T8, Requires<[HasSSSE3]>; + : Ii8<o, F, outs, ins, asm, pattern>, T8, Requires<[HasSSSE3]>; class SS3AI<bits<8> o, Format F, dag outs, dag ins, string asm, list<dag> pattern> - : I<o, F, outs, ins, asm, pattern>, TA, Requires<[HasSSSE3]>; + : Ii8<o, F, outs, ins, asm, pattern>, TA, Requires<[HasSSSE3]>; // SSE4.1 Instruction Templates: // diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 30b57d8..16b2af7 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -3392,11 +3392,9 @@ def BT32mi8 : Ii8<0xBA, MRM4m, (outs), (ins i32mem:$src1, i32i8imm:$src2), // of the register here. This has a smaller encoding and avoids a // partial-register update. def MOVSX16rr8 : I<0xBE, MRMSrcReg, (outs GR16:$dst), (ins GR8 :$src), - "movs{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR16:$dst, (sext GR8:$src))]>, TB; + "", [(set GR16:$dst, (sext GR8:$src))]>, TB; def MOVSX16rm8 : I<0xBE, MRMSrcMem, (outs GR16:$dst), (ins i8mem :$src), - "movs{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR16:$dst, (sextloadi16i8 addr:$src))]>, TB; + "", [(set GR16:$dst, (sextloadi16i8 addr:$src))]>, TB; def MOVSX32rr8 : I<0xBE, MRMSrcReg, (outs GR32:$dst), (ins GR8 :$src), "movs{bl|x}\t{$src, $dst|$dst, $src}", [(set GR32:$dst, (sext GR8:$src))]>, TB; @@ -3414,11 +3412,9 @@ def MOVSX32rm16: I<0xBF, MRMSrcMem, (outs GR32:$dst), (ins i16mem:$src), // of the register here. This has a smaller encoding and avoids a // partial-register update. def MOVZX16rr8 : I<0xB6, MRMSrcReg, (outs GR16:$dst), (ins GR8 :$src), - "movz{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR16:$dst, (zext GR8:$src))]>, TB; + "", [(set GR16:$dst, (zext GR8:$src))]>, TB; def MOVZX16rm8 : I<0xB6, MRMSrcMem, (outs GR16:$dst), (ins i8mem :$src), - "movz{bl|x}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}", - [(set GR16:$dst, (zextloadi16i8 addr:$src))]>, TB; + "", [(set GR16:$dst, (zextloadi16i8 addr:$src))]>, TB; def MOVZX32rr8 : I<0xB6, MRMSrcReg, (outs GR32:$dst), (ins GR8 :$src), "movz{bl|x}\t{$src, $dst|$dst, $src}", [(set GR32:$dst, (zext GR8:$src))]>, TB; @@ -3474,9 +3470,8 @@ def MOV8r0 : I<0x30, MRMInitReg, (outs GR8 :$dst), (ins), [(set GR8:$dst, 0)]>; // Use xorl instead of xorw since we don't care about the high 16 bits, // it's smaller, and it avoids a partial-register update. -def MOV16r0 : I<0x31, MRMInitReg, (outs GR16:$dst), (ins), - "xor{l}\t${dst:subreg32}, ${dst:subreg32}", - [(set GR16:$dst, 0)]>; +def MOV16r0 : I<0x31, MRMInitReg, (outs GR16:$dst), (ins), + "", [(set GR16:$dst, 0)]>; def MOV32r0 : I<0x31, MRMInitReg, (outs GR32:$dst), (ins), "xor{l}\t$dst, $dst", [(set GR32:$dst, 0)]>; @@ -3598,6 +3593,7 @@ def LXADD8 : I<0xC0, MRMSrcMem, (outs GR8:$dst), (ins i8mem:$ptr, GR8:$val), // Optimized codegen when the non-memory output is not used. // FIXME: Use normal add / sub instructions and add lock prefix dynamically. +let Defs = [EFLAGS] in { def LOCK_ADD8mr : I<0x00, MRMDestMem, (outs), (ins i8mem:$dst, GR8:$src2), "lock\n\t" "add{b}\t{$src2, $dst|$dst, $src2}", []>, LOCK; @@ -3667,6 +3663,7 @@ def LOCK_DEC16m : I<0xFF, MRM1m, (outs), (ins i16mem:$dst), def LOCK_DEC32m : I<0xFF, MRM1m, (outs), (ins i32mem:$dst), "lock\n\t" "dec{l}\t$dst", []>, LOCK; +} // Atomic exchange, and, or, xor let Constraints = "$val = $dst", Defs = [EFLAGS], diff --git a/lib/Target/X86/X86InstrSSE.td b/lib/Target/X86/X86InstrSSE.td index 96fc932..f4e97c9 100644 --- a/lib/Target/X86/X86InstrSSE.td +++ b/lib/Target/X86/X86InstrSSE.td @@ -197,6 +197,12 @@ def SHUFFLE_get_pshuflw_imm : SDNodeXForm<vector_shuffle, [{ return getI8Imm(X86::getShufflePSHUFLWImmediate(N)); }]>; +// SHUFFLE_get_palign_imm xform function: convert vector_shuffle mask to +// a PALIGNR imm. +def SHUFFLE_get_palign_imm : SDNodeXForm<vector_shuffle, [{ + return getI8Imm(X86::getShufflePALIGNRImmediate(N)); +}]>; + def splat_lo : PatFrag<(ops node:$lhs, node:$rhs), (vector_shuffle node:$lhs, node:$rhs), [{ ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); @@ -283,6 +289,11 @@ def pshuflw : PatFrag<(ops node:$lhs, node:$rhs), return X86::isPSHUFLWMask(cast<ShuffleVectorSDNode>(N)); }], SHUFFLE_get_pshuflw_imm>; +def palign : PatFrag<(ops node:$lhs, node:$rhs), + (vector_shuffle node:$lhs, node:$rhs), [{ + return X86::isPALIGNRMask(cast<ShuffleVectorSDNode>(N)); +}], SHUFFLE_get_palign_imm>; + //===----------------------------------------------------------------------===// // SSE scalar FP Instructions //===----------------------------------------------------------------------===// @@ -2062,6 +2073,7 @@ defm PACKSSDW : PDI_binop_rm_int<0x6B, "packssdw", int_x86_sse2_packssdw_128>; defm PACKUSWB : PDI_binop_rm_int<0x67, "packuswb", int_x86_sse2_packuswb_128>; // Shuffle and unpack instructions +let AddedComplexity = 5 in { def PSHUFDri : PDIi8<0x70, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, i8imm:$src2), "pshufd\t{$src2, $src1, $dst|$dst, $src1, $src2}", @@ -2073,6 +2085,7 @@ def PSHUFDmi : PDIi8<0x70, MRMSrcMem, [(set VR128:$dst, (v4i32 (pshufd:$src2 (bc_v4i32(memopv2i64 addr:$src1)), (undef))))]>; +} // SSE2 with ImmT == Imm8 and XS prefix. def PSHUFHWri : Ii8<0x70, MRMSrcReg, @@ -2839,6 +2852,26 @@ let Constraints = "$src1 = $dst" in { imm:$src3))]>, OpSize; } +// palignr patterns. +let AddedComplexity = 5 in { +def : Pat<(v4i32 (palign:$src3 VR128:$src1, VR128:$src2)), + (PALIGNR128rr VR128:$src2, VR128:$src1, + (SHUFFLE_get_palign_imm VR128:$src3))>, + Requires<[HasSSSE3]>; +def : Pat<(v4f32 (palign:$src3 VR128:$src1, VR128:$src2)), + (PALIGNR128rr VR128:$src2, VR128:$src1, + (SHUFFLE_get_palign_imm VR128:$src3))>, + Requires<[HasSSSE3]>; +def : Pat<(v8i16 (palign:$src3 VR128:$src1, VR128:$src2)), + (PALIGNR128rr VR128:$src2, VR128:$src1, + (SHUFFLE_get_palign_imm VR128:$src3))>, + Requires<[HasSSSE3]>; +def : Pat<(v16i8 (palign:$src3 VR128:$src1, VR128:$src2)), + (PALIGNR128rr VR128:$src2, VR128:$src1, + (SHUFFLE_get_palign_imm VR128:$src3))>, + Requires<[HasSSSE3]>; +} + def : Pat<(X86pshufb VR128:$src, VR128:$mask), (PSHUFBrr128 VR128:$src, VR128:$mask)>, Requires<[HasSSSE3]>; def : Pat<(X86pshufb VR128:$src, (bc_v16i8 (memopv2i64 addr:$mask))), diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index fb76aeb..9525f04 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -382,7 +382,6 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &FS, , HasFMA4(false) , IsBTMemSlow(false) , DarwinVers(0) - , IsLinux(false) , stackAlignment(8) // FIXME: this is a known good value for Yonah. How about others? , MaxInlineSizeThreshold(128) @@ -434,7 +433,6 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &FS, } else if (TT.find("linux") != std::string::npos) { // Linux doesn't imply ELF, but we don't currently support anything else. TargetType = isELF; - IsLinux = true; } else if (TT.find("cygwin") != std::string::npos) { TargetType = isCygwin; } else if (TT.find("mingw") != std::string::npos) { diff --git a/lib/Target/X86/X86Subtarget.h b/lib/Target/X86/X86Subtarget.h index a2e368d..e64b854 100644 --- a/lib/Target/X86/X86Subtarget.h +++ b/lib/Target/X86/X86Subtarget.h @@ -82,9 +82,6 @@ protected: /// version of the platform, e.g. 8 = 10.4 (Tiger), 9 = 10.5 (Leopard), etc. unsigned char DarwinVers; // Is any darwin-x86 platform. - /// isLinux - true if this is a "linux" platform. - bool IsLinux; - /// stackAlignment - The minimum alignment known to hold of the stack frame on /// entry to the function and which must be maintained by every function. unsigned stackAlignment; @@ -195,11 +192,7 @@ public: /// getDarwinVers - Return the darwin version number, 8 = Tiger, 9 = Leopard, /// 10 = Snow Leopard, etc. unsigned getDarwinVers() const { return DarwinVers; } - - /// isLinux - Return true if the target is "Linux". - bool isLinux() const { return IsLinux; } - - + /// ClassifyGlobalReference - Classify a global variable reference for the /// current subtarget according to how we should reference it in a non-pcrel /// context. @@ -222,6 +215,14 @@ public: /// indicating the number of scheduling cycles of backscheduling that /// should be attempted. unsigned getSpecialAddressLatency() const; + + /// enablePostRAScheduler - X86 target is enabling post-alloc scheduling + /// at 'More' optimization level. + bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, + TargetSubtarget::AntiDepBreakMode& mode) const { + mode = TargetSubtarget::ANTIDEP_CRITICAL; + return OptLevel >= CodeGenOpt::Default; + } }; } // End llvm namespace |