diff --git a/lib/Target/Mips/Mips16InstrInfo.td b/lib/Target/Mips/Mips16InstrInfo.td index 4133223c1fd..b94c2edb8a4 100644 --- a/lib/Target/Mips/Mips16InstrInfo.td +++ b/lib/Target/Mips/Mips16InstrInfo.td @@ -172,6 +172,11 @@ class FEXT_RI16_B_ins _op, string asmstr, FEXT_RI16<_op, (outs), (ins CPU16Regs:$rx, brtarget:$imm), !strconcat(asmstr, "\t$rx, $imm"), [], itin>; +class FEXT_RI16_TCP_ins _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins pcrel16:$imm), + !strconcat(asmstr, "\t$rx, $imm"), [], itin>; + class FEXT_2RI16_ins _op, string asmstr, InstrItinClass itin>: FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_, simm16:$imm), @@ -455,7 +460,7 @@ def Constant32: MipsPseudo16<(outs), (ins imm32:$imm), "\t.word $imm", []>; def LwConstant32: - MipsPseudo16<(outs CPU16Regs:$rx), (ins imm32:$imm), + MipsPseudo16<(outs CPU16Regs:$rx), (ins imm32:$imm, imm32:$constid), "lw\t$rx, 1f\n\tb\t2f\n\t.align\t2\n1: \t.word\t$imm\n2:", []>; @@ -793,10 +798,11 @@ def LwRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lw", mem16, IILoad>, MayLoad{ // Purpose: Load Word (SP-Relative, Extended) // To load an SP-relative word from memory as a signed value. // -def LwRxSpImmX16: FEXT_RI16_SP_explicit_ins<0b10110, "lw", IILoad>, MayLoad{ +def LwRxSpImmX16: FEXT_RI16_SP_explicit_ins<0b10010, "lw", IILoad>, MayLoad{ let Uses = [SP]; } +def LwRxPcTcpX16: FEXT_RI16_TCP_ins<0b10110, "lw", IILoad>, MayLoad; // // Format: MOVE r32, rz MIPS16e // Purpose: Move @@ -1355,7 +1361,7 @@ def: Mips16Pat<(i32 addr16:$addr), // Large (>16 bit) immediate loads -def : Mips16Pat<(i32 imm:$imm), (LwConstant32 imm:$imm)>; +def : Mips16Pat<(i32 imm:$imm), (LwConstant32 imm:$imm, -1)>; // Carry MipsPatterns def : Mips16Pat<(subc CPU16Regs:$lhs, CPU16Regs:$rhs), @@ -1848,3 +1854,19 @@ def GotPrologue16: (outs CPU16Regs:$rh, CPU16Regs:$rl), (ins simm16:$immHi, simm16:$immLo), ".align 2\n\tli\t$rh, $immHi\n\taddiu\t$rl, $$pc, $immLo\n ",[]> ; + +// An operand for the CONSTPOOL_ENTRY pseudo-instruction. +def cpinst_operand : Operand { + // let PrintMethod = "printCPInstOperand"; +} + +// 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. +// +let neverHasSideEffects = 1, isNotDuplicable = 1 in +def CONSTPOOL_ENTRY : +MipsPseudo16<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, + i32imm:$size), "foo", []>; + diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index b6afc174e83..680edfcaf0b 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -55,6 +55,7 @@ bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { const_cast(getObjFileLowering()) .Initialize(OutContext, TM); MipsFI = MF.getInfo(); + MCP = MF.getConstantPool(); AsmPrinter::runOnMachineFunction(MF); return true; } @@ -75,6 +76,39 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { return; } + // If we just ended a constant pool, mark it as such. + if (InConstantPool && MI->getOpcode() != Mips::CONSTPOOL_ENTRY) { + OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); + InConstantPool = false; + } + if (MI->getOpcode() == Mips::CONSTPOOL_ENTRY) { + // 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. + // The required alignment is specified on the basic block holding this MI. + // + unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); + unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); + + // If this is the first entry of the pool, mark it. + if (!InConstantPool) { + OutStreamer.EmitDataRegion(MCDR_DataRegion); + InConstantPool = true; + } + + OutStreamer.EmitLabel(GetCPISymbol(LabelId)); + + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + if (MCPE.isMachineConstantPoolEntry()) + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + else + EmitGlobalConstant(MCPE.Val.ConstVal); + return; + } + + MachineBasicBlock::const_instr_iterator I = MI; MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); @@ -287,6 +321,12 @@ void MipsAsmPrinter::EmitFunctionBodyEnd() { } OutStreamer.EmitRawText("\t.end\t" + Twine(CurrentFnSym->getName())); } + // Make sure to terminate any constant pools that were at the end + // of the function. + if (!InConstantPool) + return; + InConstantPool = false; + OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); } /// isBlockOnlyReachableByFallthough - Return true if the basic block has diff --git a/lib/Target/Mips/MipsAsmPrinter.h b/lib/Target/Mips/MipsAsmPrinter.h index 5f6cac8f211..44b8b068dfa 100644 --- a/lib/Target/Mips/MipsAsmPrinter.h +++ b/lib/Target/Mips/MipsAsmPrinter.h @@ -42,6 +42,16 @@ private: // lowerOperand - Convert a MachineOperand into the equivalent MCOperand. bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp); + /// MCP - Keep a pointer to constantpool entries of the current + /// MachineFunction. + const MachineConstantPool *MCP; + + /// InConstantPool - Maintain state when emitting a sequence of constant + /// pool entries so we can properly mark them as data regions. + bool InConstantPool; + + bool UsingConstantPools; + public: const MipsSubtarget *Subtarget; @@ -49,8 +59,11 @@ public: MipsMCInstLower MCInstLowering; explicit MipsAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) - : AsmPrinter(TM, Streamer), MCInstLowering(*this) { + : AsmPrinter(TM, Streamer), MCP(0), InConstantPool(false), + MCInstLowering(*this) { Subtarget = &TM.getSubtarget(); + UsingConstantPools = + (Subtarget->inMips16Mode() && Subtarget->useConstantIslands()); } virtual const char *getPassName() const { @@ -59,6 +72,12 @@ public: virtual bool runOnMachineFunction(MachineFunction &MF); + virtual void EmitConstantPool() LLVM_OVERRIDE { + if (!UsingConstantPools) + AsmPrinter::EmitConstantPool(); + // we emit constant pools customly! + } + void EmitInstruction(const MachineInstr *MI); void printSavedRegsBitmask(raw_ostream &O); void printHex32(unsigned int Value, raw_ostream &O); diff --git a/lib/Target/Mips/MipsConstantIslandPass.cpp b/lib/Target/Mips/MipsConstantIslandPass.cpp index bda01672c09..3209c0c55f2 100644 --- a/lib/Target/Mips/MipsConstantIslandPass.cpp +++ b/lib/Target/Mips/MipsConstantIslandPass.cpp @@ -29,29 +29,69 @@ #include "MCTargetDesc/MipsBaseInfo.h" #include "MipsTargetMachine.h" #include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/IR/Function.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/InstIterator.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" +#include using namespace llvm; +STATISTIC(NumCPEs, "Number of constpool entries"); + +// FIXME: This option should be removed once it has received sufficient testing. +static cl::opt +AlignConstantIslands("mips-align-constant-islands", cl::Hidden, cl::init(true), + cl::desc("Align constant islands in code")); + namespace { typedef MachineBasicBlock::iterator Iter; typedef MachineBasicBlock::reverse_iterator ReverseIter; class MipsConstantIslands : public MachineFunctionPass { + const TargetMachine &TM; + bool IsPIC; + unsigned ABI; + const MipsSubtarget *STI; + const MipsInstrInfo *TII; + MachineFunction *MF; + MachineConstantPool *MCP; + + /// CPEntry - One per constant pool entry, keeping the machine instruction + /// pointer, the constpool index, and the number of CPUser's which + /// reference this entry. + struct CPEntry { + MachineInstr *CPEMI; + unsigned CPI; + unsigned RefCount; + CPEntry(MachineInstr *cpemi, unsigned cpi, unsigned rc = 0) + : CPEMI(cpemi), CPI(cpi), RefCount(rc) {} + }; + + /// CPEntries - Keep track of all of the constant pool entry machine + /// instructions. For each original constpool index (i.e. those that + /// existed upon entry to this pass), it keeps a vector of entries. + /// Original elements are cloned as we go along; the clones are + /// put in the vector of the original element, but have distinct CPIs. + std::vector > CPEntries; + public: static char ID; MipsConstantIslands(TargetMachine &tm) : MachineFunctionPass(ID), TM(tm), IsPIC(TM.getRelocationModel() == Reloc::PIC_), - ABI(TM.getSubtarget().getTargetABI()) {} + ABI(TM.getSubtarget().getTargetABI()), + STI(&TM.getSubtarget()), MF(0), MCP(0){} virtual const char *getPassName() const { return "Mips Constant Islands"; @@ -59,10 +99,12 @@ namespace { bool runOnMachineFunction(MachineFunction &F); + void doInitialPlacement(std::vector &CPEMIs); + + void prescanForConstants(); + private: - const TargetMachine &TM; - bool IsPIC; - unsigned ABI; + }; char MipsConstantIslands::ID = 0; @@ -74,11 +116,138 @@ FunctionPass *llvm::createMipsConstantIslandPass(MipsTargetMachine &tm) { return new MipsConstantIslands(tm); } -bool MipsConstantIslands::runOnMachineFunction(MachineFunction &F) { +bool MipsConstantIslands::runOnMachineFunction(MachineFunction &mf) { // The intention is for this to be a mips16 only pass for now // FIXME: - // if (!TM.getSubtarget().inMips16Mode()) - // return false; - return false; + MF = &mf; + MCP = mf.getConstantPool(); + DEBUG(dbgs() << "constant island machine function " << "\n"); + if (!TM.getSubtarget().inMips16Mode() || + !MipsSubtarget::useConstantIslands()) { + return false; + } + TII = (const MipsInstrInfo*)MF->getTarget().getInstrInfo(); + DEBUG(dbgs() << "constant island processing " << "\n"); + // + // will need to make predermination if there is any constants we need to + // put in constant islands. TBD. + // + prescanForConstants(); + + // This pass invalidates liveness information when it splits basic blocks. + MF->getRegInfo().invalidateLiveness(); + + // Renumber all of the machine basic blocks in the function, guaranteeing that + // the numbers agree with the position of the block in the function. + MF->RenumberBlocks(); + + // Perform the initial placement of the constant pool entries. To start with, + // we put them all at the end of the function. + std::vector CPEMIs; + if (!MCP->isEmpty()) + doInitialPlacement(CPEMIs); + + return true; } +/// doInitialPlacement - Perform the initial placement of the constant pool +/// entries. To start with, we put them all at the end of the function. +void +MipsConstantIslands::doInitialPlacement(std::vector &CPEMIs) { + // Create the basic block to hold the CPE's. + MachineBasicBlock *BB = MF->CreateMachineBasicBlock(); + MF->push_back(BB); + + + // MachineConstantPool measures alignment in bytes. We measure in log2(bytes). + unsigned MaxAlign = Log2_32(MCP->getConstantPoolAlignment()); + + // Mark the basic block as required by the const-pool. + // If AlignConstantIslands isn't set, use 4-byte alignment for everything. + BB->setAlignment(AlignConstantIslands ? MaxAlign : 2); + + // The function needs to be as aligned as the basic blocks. The linker may + // move functions around based on their alignment. + MF->ensureAlignment(BB->getAlignment()); + + // Order the entries in BB by descending alignment. That ensures correct + // alignment of all entries as long as BB is sufficiently aligned. Keep + // track of the insertion point for each alignment. We are going to bucket + // sort the entries as they are created. + SmallVector InsPoint(MaxAlign + 1, BB->end()); + + // Add all of the constants from the constant pool to the end block, use an + // identity mapping of CPI's to CPE's. + const std::vector &CPs = MCP->getConstants(); + + const DataLayout &TD = *MF->getTarget().getDataLayout(); + for (unsigned i = 0, e = CPs.size(); i != e; ++i) { + unsigned Size = TD.getTypeAllocSize(CPs[i].getType()); + assert(Size >= 4 && "Too small constant pool entry"); + unsigned Align = CPs[i].getAlignment(); + assert(isPowerOf2_32(Align) && "Invalid alignment"); + // Verify that all constant pool entries are a multiple of their alignment. + // If not, we would have to pad them out so that instructions stay aligned. + assert((Size % Align) == 0 && "CP Entry not multiple of 4 bytes!"); + + // Insert CONSTPOOL_ENTRY before entries with a smaller alignment. + unsigned LogAlign = Log2_32(Align); + MachineBasicBlock::iterator InsAt = InsPoint[LogAlign]; + + MachineInstr *CPEMI = + BuildMI(*BB, InsAt, DebugLoc(), TII->get(Mips::CONSTPOOL_ENTRY)) + .addImm(i).addConstantPoolIndex(i).addImm(Size); + + CPEMIs.push_back(CPEMI); + + // Ensure that future entries with higher alignment get inserted before + // CPEMI. This is bucket sort with iterators. + for (unsigned a = LogAlign + 1; a <= MaxAlign; ++a) + if (InsPoint[a] == InsAt) + InsPoint[a] = CPEMI; + // Add a new CPEntry, but no corresponding CPUser yet. + std::vector CPEs; + CPEs.push_back(CPEntry(CPEMI, i)); + CPEntries.push_back(CPEs); + ++NumCPEs; + DEBUG(dbgs() << "Moved CPI#" << i << " to end of function, size = " + << Size << ", align = " << Align <<'\n'); + } + DEBUG(BB->dump()); +} + + +void MipsConstantIslands::prescanForConstants() { + unsigned int J; + for (MachineFunction::iterator B = + MF->begin(), E = MF->end(); B != E; ++B) { + for (MachineBasicBlock::instr_iterator I = + B->instr_begin(), EB = B->instr_end(); I != EB; ++I) { + switch(I->getDesc().getOpcode()) { + case Mips::LwConstant32: { + DEBUG(dbgs() << "constant island constant " << *I << "\n"); + J = I->getNumOperands(); + DEBUG(dbgs() << "num operands " << J << "\n"); + MachineOperand& Literal = I->getOperand(1); + if (Literal.isImm()) { + int64_t V = Literal.getImm(); + DEBUG(dbgs() << "literal " << V << "\n"); + Type *Int32Ty = + Type::getInt32Ty(MF->getFunction()->getContext()); + const Constant *C = ConstantInt::get(Int32Ty, V); + unsigned index = MCP->getConstantPoolIndex(C, 4); + I->getOperand(2).ChangeToImmediate(index); + DEBUG(dbgs() << "constant island constant " << *I << "\n"); + I->setDesc(TII->get(Mips::LwRxPcTcpX16)); + I->RemoveOperand(1); + I->RemoveOperand(1); + I->addOperand(MachineOperand::CreateCPI(index, 0)); + } + break; + } + default: + break; + } + } + } +} diff --git a/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp index ceb8eeae9f5..7b04a9a3759 100644 --- a/lib/Target/Mips/MipsInstrInfo.cpp +++ b/lib/Target/Mips/MipsInstrInfo.cpp @@ -271,6 +271,10 @@ unsigned MipsInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { const char *AsmStr = MI->getOperand(0).getSymbolName(); return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo()); } + case Mips::CONSTPOOL_ENTRY: + // If this machine instr is a constant pool entry, its size is recorded as + // operand #2. + return MI->getOperand(2).getImm(); } } diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index 44495ff134a..34f9918c7e9 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -278,6 +278,9 @@ def uimm16 : Operand { let PrintMethod = "printUnsignedImm"; } +def pcrel16 : Operand { +} + def MipsMemAsmOperand : AsmOperandClass { let Name = "Mem"; let ParserMethod = "parseMemOperand"; diff --git a/lib/Target/Mips/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp index 3a122706aa2..0a81072b085 100644 --- a/lib/Target/Mips/MipsSubtarget.cpp +++ b/lib/Target/Mips/MipsSubtarget.cpp @@ -53,6 +53,12 @@ Mips16HardFloat("mips16-hard-float", cl::NotHidden, cl::desc("MIPS: mips16 hard float enable."), cl::init(false)); +static cl::opt +Mips16ConstantIslands( + "mips16-constant-islands", cl::Hidden, + cl::desc("MIPS: mips16 constant islands enable. experimental feature"), + cl::init(false)); + void MipsSubtarget::anchor() { } MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, @@ -163,3 +169,8 @@ void MipsSubtarget::resetSubtarget(MachineFunction *MF) { bool MipsSubtarget::mipsSEUsesSoftFloat() const { return TM->Options.UseSoftFloat && !InMips16HardFloat; } + +bool MipsSubtarget::useConstantIslands() { + DEBUG(dbgs() << "use constant islands " << Mips16ConstantIslands << "\n"); + return Mips16ConstantIslands; +} diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h index a3abc963ddd..30100656fe0 100644 --- a/lib/Target/Mips/MipsSubtarget.h +++ b/lib/Target/Mips/MipsSubtarget.h @@ -212,6 +212,10 @@ public: bool os16() const { return Os16;}; +// for now constant islands are on for the whole compilation unit but we only +// really use them if in addition we are in mips16 mode +// +static bool useConstantIslands(); // Grab MipsRegInfo object const MipsReginfo &getMReginfo() const { return MRI; } diff --git a/test/CodeGen/Mips/const1.ll b/test/CodeGen/Mips/const1.ll new file mode 100644 index 00000000000..cb2bacaf17a --- /dev/null +++ b/test/CodeGen/Mips/const1.ll @@ -0,0 +1,35 @@ +; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static -mips16-constant-islands < %s | FileCheck %s + +; ModuleID = 'const1.c' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64" +target triple = "mipsel-unknown-linux" + +@i = common global i32 0, align 4 +@j = common global i32 0, align 4 +@k = common global i32 0, align 4 +@l = common global i32 0, align 4 + +; Function Attrs: nounwind +define void @t() #0 { +entry: + store i32 -559023410, i32* @i, align 4 + store i32 -559023410, i32* @j, align 4 + store i32 -87105875, i32* @k, align 4 + store i32 262991277, i32* @l, align 4 + ret void +; CHECK: lw ${{[0-9]+}}, $CPI0_0 +; CHECK: lw ${{[0-9]+}}, $CPI0_1 +; CHECK: lw ${{[0-9]+}}, $CPI0_2 +; CHECK: $CPI0_0: +; CHECK: .4byte 3735943886 +; CHECK: $CPI0_1: +; CHECK: .4byte 4207861421 +; CHECK: $CPI0_2: +; CHECK: .4byte 262991277 +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="true" } + +!llvm.ident = !{!0} + +!0 = metadata !{metadata !"clang version 3.4 (gitosis@dmz-portal.mips.com:clang.git b754974ec32ab712ea7d8b52cd8037b24e7d6ed3) (gitosis@dmz-portal.mips.com:llvm.git 8e211187b501bc73edb938fde0019c9a20bcffd5)"}