summaryrefslogtreecommitdiffstats
path: root/lib/Target
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-10-23 14:19:52 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-10-23 14:19:52 +0000
commit9643cca39fb9fb3b49a8912926de98acf882283c (patch)
tree22cc59e4b240d84c3a5a60531119c4eca914a256 /lib/Target
parent1adacceba9c9ee0f16e54388e56c9a249b296f75 (diff)
downloadFreeBSD-src-9643cca39fb9fb3b49a8912926de98acf882283c.zip
FreeBSD-src-9643cca39fb9fb3b49a8912926de98acf882283c.tar.gz
Update LLVM to r84949.
Diffstat (limited to 'lib/Target')
-rw-r--r--lib/Target/ARM/ARMAddressingModes.h67
-rw-r--r--lib/Target/ARM/ARMBaseRegisterInfo.cpp47
-rw-r--r--lib/Target/ARM/ARMBaseRegisterInfo.h2
-rw-r--r--lib/Target/ARM/ARMConstantIslandPass.cpp96
-rw-r--r--lib/Target/ARM/ARMISelDAGToDAG.cpp39
-rw-r--r--lib/Target/ARM/ARMISelLowering.cpp41
-rw-r--r--lib/Target/ARM/ARMInstrFormats.td35
-rw-r--r--lib/Target/ARM/ARMInstrInfo.cpp1
-rw-r--r--lib/Target/ARM/ARMInstrInfo.td14
-rw-r--r--lib/Target/ARM/ARMInstrNEON.td468
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td35
-rw-r--r--lib/Target/ARM/ARMLoadStoreOptimizer.cpp3
-rw-r--r--lib/Target/ARM/ARMRegisterInfo.td5
-rw-r--r--lib/Target/ARM/ARMSubtarget.cpp10
-rw-r--r--lib/Target/ARM/ARMSubtarget.h10
-rw-r--r--lib/Target/ARM/ARMTargetMachine.cpp1
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp232
-rw-r--r--lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp338
-rw-r--r--lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp358
-rw-r--r--lib/Target/ARM/AsmPrinter/ARMInstPrinter.h89
-rw-r--r--lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp166
-rw-r--r--lib/Target/ARM/AsmPrinter/ARMMCInstLower.h56
-rw-r--r--lib/Target/ARM/AsmPrinter/CMakeLists.txt4
-rw-r--r--lib/Target/ARM/README-Thumb.txt8
-rw-r--r--lib/Target/ARM/Thumb1RegisterInfo.cpp49
-rw-r--r--lib/Target/ARM/Thumb1RegisterInfo.h5
-rw-r--r--lib/Target/ARM/Thumb2ITBlockPass.cpp6
-rw-r--r--lib/Target/ARM/Thumb2RegisterInfo.cpp1
-rw-r--r--lib/Target/Blackfin/Blackfin.td1
-rw-r--r--lib/Target/Blackfin/BlackfinIntrinsicInfo.cpp53
-rw-r--r--lib/Target/Blackfin/BlackfinIntrinsicInfo.h28
-rw-r--r--lib/Target/Blackfin/BlackfinIntrinsics.td34
-rw-r--r--lib/Target/Blackfin/BlackfinTargetMachine.h5
-rw-r--r--lib/Target/Blackfin/CMakeLists.txt2
-rw-r--r--lib/Target/Blackfin/Makefile2
-rw-r--r--lib/Target/CBackend/CBackend.cpp7
-rw-r--r--lib/Target/CppBackend/CPPBackend.cpp14
-rw-r--r--lib/Target/MSIL/MSILWriter.cpp5
-rw-r--r--lib/Target/MSP430/AsmPrinter/CMakeLists.txt2
-rw-r--r--lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp63
-rw-r--r--lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp116
-rw-r--r--lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h46
-rw-r--r--lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp147
-rw-r--r--lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h49
-rw-r--r--lib/Target/MSP430/MSP430.h14
-rw-r--r--lib/Target/MSP430/MSP430ISelDAGToDAG.cpp292
-rw-r--r--lib/Target/MSP430/MSP430ISelLowering.cpp27
-rw-r--r--lib/Target/MSP430/MSP430InstrInfo.cpp165
-rw-r--r--lib/Target/MSP430/MSP430InstrInfo.h30
-rw-r--r--lib/Target/MSP430/MSP430InstrInfo.td4
-rw-r--r--lib/Target/MSP430/MSP430TargetMachine.cpp2
-rw-r--r--lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp229
-rw-r--r--lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h12
-rw-r--r--lib/Target/PIC16/CMakeLists.txt1
-rw-r--r--lib/Target/PIC16/Makefile2
-rw-r--r--lib/Target/PIC16/PIC16.h267
-rw-r--r--lib/Target/PIC16/PIC16ABINames.h325
-rw-r--r--lib/Target/PIC16/PIC16DebugInfo.cpp10
-rw-r--r--lib/Target/PIC16/PIC16ISelLowering.cpp1
-rw-r--r--lib/Target/PIC16/PIC16InstrInfo.cpp1
-rw-r--r--lib/Target/PIC16/PIC16MCAsmInfo.cpp1
-rw-r--r--lib/Target/PIC16/PIC16MemSelOpt.cpp1
-rw-r--r--lib/Target/PIC16/PIC16Passes/Makefile17
-rw-r--r--lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp181
-rw-r--r--lib/Target/PIC16/PIC16Passes/PIC16Overlay.h55
-rw-r--r--lib/Target/PIC16/PIC16Section.cpp96
-rw-r--r--lib/Target/PIC16/PIC16Section.h92
-rw-r--r--lib/Target/PIC16/PIC16TargetObjectFile.cpp471
-rw-r--r--lib/Target/PIC16/PIC16TargetObjectFile.h163
-rw-r--r--lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp2
-rw-r--r--lib/Target/README.txt51
-rw-r--r--lib/Target/TargetIntrinsicInfo.cpp12
-rw-r--r--lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp4
-rw-r--r--lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h3
-rw-r--r--lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp80
-rw-r--r--lib/Target/X86/AsmPrinter/X86MCInstLower.cpp15
-rw-r--r--lib/Target/X86/X86ISelLowering.cpp98
-rw-r--r--lib/Target/X86/X86ISelLowering.h16
-rw-r--r--lib/Target/X86/X86Instr64bit.td24
-rw-r--r--lib/Target/X86/X86InstrFormats.td4
-rw-r--r--lib/Target/X86/X86InstrInfo.td19
-rw-r--r--lib/Target/X86/X86InstrSSE.td33
-rw-r--r--lib/Target/X86/X86Subtarget.cpp2
-rw-r--r--lib/Target/X86/X86Subtarget.h17
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
OpenPOWER on IntegriCloud