diff options
Diffstat (limited to 'lib/Target/PowerPC/PPC32AsmPrinter.cpp')
-rw-r--r-- | lib/Target/PowerPC/PPC32AsmPrinter.cpp | 544 |
1 files changed, 382 insertions, 162 deletions
diff --git a/lib/Target/PowerPC/PPC32AsmPrinter.cpp b/lib/Target/PowerPC/PPC32AsmPrinter.cpp index cadc88a..1d2163c 100644 --- a/lib/Target/PowerPC/PPC32AsmPrinter.cpp +++ b/lib/Target/PowerPC/PPC32AsmPrinter.cpp @@ -1,4 +1,4 @@ -//===-- PPC32AsmPrinter.cpp - Print machine instrs to PowerPC assembly ----===// +//===-- PowerPCAsmPrinter.cpp - Print machine instrs to PowerPC assembly --===// // // The LLVM Compiler Infrastructure // @@ -18,7 +18,7 @@ #define DEBUG_TYPE "asmprinter" #include "PowerPC.h" -#include "PPC32TargetMachine.h" +#include "PowerPCTargetMachine.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" @@ -42,26 +42,20 @@ namespace { struct PPC32AsmPrinter : public AsmPrinter { std::set<std::string> FnStubs, GVStubs, LinkOnceStubs; std::set<std::string> Strings; - + PPC32AsmPrinter(std::ostream &O, TargetMachine &TM) - : AsmPrinter(O, TM), LabelNumber(0) { - CommentString = ";"; - GlobalPrefix = "_"; - ZeroDirective = "\t.space\t"; // ".space N" emits N zeros. - Data64bitsDirective = 0; // we can't emit a 64-bit unit - AlignmentIsInBytes = false; // Alignment is by power of 2. - } + : AsmPrinter(O, TM), LabelNumber(0) {} /// Unique incrementer for label values for referencing Global values. /// unsigned LabelNumber; virtual const char *getPassName() const { - return "PPC32 Assembly Printer"; + return "PowerPC Assembly Printer"; } - PPC32TargetMachine &getTM() { - return static_cast<PPC32TargetMachine&>(TM); + PowerPCTargetMachine &getTM() { + return static_cast<PowerPCTargetMachine&>(TM); } /// printInstruction - This method is automatically generated by tablegen @@ -72,7 +66,6 @@ namespace { void printMachineInstruction(const MachineInstr *MI); void printOp(const MachineOperand &MO, bool LoadAddrOp = false); - void printImmOp(const MachineOperand &MO, unsigned ArgType); void printOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT){ const MachineOperand &MO = MI->getOperand(OpNo); @@ -98,13 +91,24 @@ namespace { assert(value <= 63 && "Invalid u6imm argument!"); O << (unsigned int)value; } + void printS16ImmOperand(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + O << (short)MI->getOperand(OpNo).getImmedValue(); + } void printU16ImmOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT) { O << (unsigned short)MI->getOperand(OpNo).getImmedValue(); } void printBranchOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT) { - printOp(MI->getOperand(OpNo)); + + // Branches can take an immediate operand. This is used by the branch + // selection pass to print $+8, an eight byte displacement from the PC. + if (MI->getOperand(OpNo).isImmediate()) { + O << "$+" << MI->getOperand(OpNo).getImmedValue() << '\n'; + } else { + printOp(MI->getOperand(OpNo)); + } } void printPICLabel(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT) { @@ -112,80 +116,195 @@ namespace { O << "\"L0000" << LabelNumber << "$pb\"\n"; O << "\"L0000" << LabelNumber << "$pb\":"; } + void printSymbolHi(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + O << "ha16("; + printOp(MI->getOperand(OpNo), true /* LoadAddrOp */); + O << "-\"L0000" << LabelNumber << "$pb\")"; + } + void printSymbolLo(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + // FIXME: Because LFS, LFD, and LWZ can be used either with a s16imm or + // a lo16 of a global or constant pool operand, we must handle both here. + // this isn't a great design, but it works for now. + if (MI->getOperand(OpNo).isImmediate()) { + O << (short)MI->getOperand(OpNo).getImmedValue(); + } else { + O << "lo16("; + printOp(MI->getOperand(OpNo), true /* LoadAddrOp */); + O << "-\"L0000" << LabelNumber << "$pb\")"; + } + } + + virtual void printConstantPool(MachineConstantPool *MCP) = 0; + virtual bool runOnMachineFunction(MachineFunction &F) = 0; + virtual bool doFinalization(Module &M) = 0; + }; + + // + // + struct DarwinAsmPrinter : public PPC32AsmPrinter { + + DarwinAsmPrinter(std::ostream &O, TargetMachine &TM) + : PPC32AsmPrinter(O, TM) { + CommentString = ";"; + GlobalPrefix = "_"; + ZeroDirective = "\t.space\t"; // ".space N" emits N zeros. + Data64bitsDirective = 0; // we can't emit a 64-bit unit + AlignmentIsInBytes = false; // Alignment is by power of 2. + } + + virtual const char *getPassName() const { + return "Darwin PPC Assembly Printer"; + } void printConstantPool(MachineConstantPool *MCP); bool runOnMachineFunction(MachineFunction &F); bool doFinalization(Module &M); }; + + // + // + struct AIXAsmPrinter : public PPC32AsmPrinter { + /// Map for labels corresponding to global variables + /// + std::map<const GlobalVariable*,std::string> GVToLabelMap; + + AIXAsmPrinter(std::ostream &O, TargetMachine &TM) + : PPC32AsmPrinter(O, TM) { + CommentString = "#"; + GlobalPrefix = "_"; + ZeroDirective = "\t.space\t"; // ".space N" emits N zeros. + Data64bitsDirective = 0; // we can't emit a 64-bit unit + AlignmentIsInBytes = false; // Alignment is by power of 2. + } + + virtual const char *getPassName() const { + return "AIX PPC Assembly Printer"; + } + + void printConstantPool(MachineConstantPool *MCP); + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + }; } // end of anonymous namespace -/// createPPC32AsmPrinterPass - Returns a pass that prints the PPC -/// assembly code for a MachineFunction to the given output stream, -/// using the given target machine description. This should work -/// regardless of whether the function is in SSA form or not. -/// -FunctionPass *llvm::createPPC32AsmPrinter(std::ostream &o, TargetMachine &tm) { - return new PPC32AsmPrinter(o, tm); +// SwitchSection - Switch to the specified section of the executable if we are +// not already in it! +// +static void SwitchSection(std::ostream &OS, std::string &CurSection, + const char *NewSection) { + if (CurSection != NewSection) { + CurSection = NewSection; + if (!CurSection.empty()) + OS << "\t" << NewSection << "\n"; + } } -// Include the auto-generated portion of the assembly writer -#include "PowerPCGenAsmWriter.inc" +/// isStringCompatible - Can we treat the specified array as a string? +/// Only if it is an array of ubytes or non-negative sbytes. +/// +static bool isStringCompatible(const ConstantArray *CVA) { + const Type *ETy = cast<ArrayType>(CVA->getType())->getElementType(); + if (ETy == Type::UByteTy) return true; + if (ETy != Type::SByteTy) return false; -/// printConstantPool - Print to the current output stream assembly -/// representations of the constants in the constant pool MCP. This is -/// used to print out constants which have been "spilled to memory" by -/// the code generator. + for (unsigned i = 0; i < CVA->getNumOperands(); ++i) + if (cast<ConstantSInt>(CVA->getOperand(i))->getValue() < 0) + return false; + + return true; +} + +/// toOctal - Convert the low order bits of X into an octal digit. /// -void PPC32AsmPrinter::printConstantPool(MachineConstantPool *MCP) { - const std::vector<Constant*> &CP = MCP->getConstants(); - const TargetData &TD = TM.getTargetData(); - - if (CP.empty()) return; +static inline char toOctal(int X) { + return (X&7)+'0'; +} - for (unsigned i = 0, e = CP.size(); i != e; ++i) { - O << "\t.const\n"; - emitAlignment(TD.getTypeAlignmentShift(CP[i]->getType())); - O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t" << CommentString - << *CP[i] << "\n"; - emitGlobalConstant(CP[i]); +// Possible states while outputting ASCII strings +namespace { + enum StringSection { + None, + Alpha, + Numeric + }; +} + +/// SwitchStringSection - manage the changes required to output bytes as +/// characters in a string vs. numeric decimal values +/// +static inline void SwitchStringSection(std::ostream &O, StringSection NewSect, + StringSection &Current) { + if (Current == None) { + if (NewSect == Alpha) + O << "\t.byte \""; + else if (NewSect == Numeric) + O << "\t.byte "; + } else if (Current == Alpha) { + if (NewSect == None) + O << "\""; + else if (NewSect == Numeric) + O << "\"\n" + << "\t.byte "; + } else if (Current == Numeric) { + if (NewSect == Alpha) + O << '\n' + << "\t.byte \""; + else if (NewSect == Numeric) + O << ", "; } + + Current = NewSect; } -/// runOnMachineFunction - This uses the printMachineInstruction() -/// method to print assembly for each instruction. +/// getAsCString - Return the specified array as a C compatible +/// string, only if the predicate isStringCompatible is true. /// -bool PPC32AsmPrinter::runOnMachineFunction(MachineFunction &MF) { - setupMachineFunction(MF); - O << "\n\n"; - - // Print out constants referenced by the function - printConstantPool(MF.getConstantPool()); +static void printAsCString(std::ostream &O, const ConstantArray *CVA) { + assert(isStringCompatible(CVA) && "Array is not string compatible!"); - // Print out labels for the function. - O << "\t.text\n"; - emitAlignment(2); - O << "\t.globl\t" << CurrentFnName << "\n"; - O << CurrentFnName << ":\n"; + if (CVA->getNumOperands() == 0) + return; - // Print out code for the function. - for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); - I != E; ++I) { - // Print a label for the basic block. - O << ".LBB" << CurrentFnName << "_" << I->getNumber() << ":\t" - << CommentString << " " << I->getBasicBlock()->getName() << "\n"; - for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); - II != E; ++II) { - // Print the assembly for the instruction. - O << "\t"; - printMachineInstruction(II); + StringSection Current = None; + for (unsigned i = 0, e = CVA->getNumOperands(); i != e; ++i) { + unsigned char C = cast<ConstantInt>(CVA->getOperand(i))->getRawValue(); + if (C == '"') { + SwitchStringSection(O, Alpha, Current); + O << "\"\""; + } else if (isprint(C)) { + SwitchStringSection(O, Alpha, Current); + O << C; + } else { + SwitchStringSection(O, Numeric, Current); + O << utostr((unsigned)C); } } - ++LabelNumber; + SwitchStringSection(O, None, Current); + O << '\n'; +} - // We didn't modify anything. - return false; +/// createDarwinAsmPrinterPass - Returns a pass that prints the PPC assembly +/// code for a MachineFunction to the given output stream, in a format that the +/// Darwin assembler can deal with. +/// +FunctionPass *llvm::createDarwinAsmPrinter(std::ostream &o, TargetMachine &tm) { + return new DarwinAsmPrinter(o, tm); +} + +/// createAIXAsmPrinterPass - Returns a pass that prints the PPC assembly code +/// for a MachineFunction to the given output stream, in a format that the +/// AIX 5L assembler can deal with. +/// +FunctionPass *llvm::createAIXAsmPrinter(std::ostream &o, TargetMachine &tm) { + return new AIXAsmPrinter(o, tm); } +// Include the auto-generated portion of the assembly writer +#include "PowerPCGenAsmWriter.inc" + void PPC32AsmPrinter::printOp(const MachineOperand &MO, bool LoadAddrOp /* = false */) { const MRegisterInfo &RI = *TM.getRegisterInfo(); @@ -268,15 +387,6 @@ void PPC32AsmPrinter::printOp(const MachineOperand &MO, } } -void PPC32AsmPrinter::printImmOp(const MachineOperand &MO, unsigned ArgType) { - int Imm = MO.getImmedValue(); - if (ArgType == PPCII::Simm16 || ArgType == PPCII::Disimm16) { - O << (short)Imm; - } else { - O << Imm; - } -} - /// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax to /// the current output stream. /// @@ -284,100 +394,68 @@ void PPC32AsmPrinter::printMachineInstruction(const MachineInstr *MI) { ++EmittedInsts; if (printInstruction(MI)) return; // Printer was automatically generated - - unsigned Opcode = MI->getOpcode(); - const TargetInstrInfo &TII = *TM.getInstrInfo(); - const TargetInstrDescriptor &Desc = TII.get(Opcode); - unsigned i; - - unsigned ArgCount = MI->getNumOperands(); - unsigned ArgType[] = { - (Desc.TSFlags >> PPCII::Arg0TypeShift) & PPCII::ArgTypeMask, - (Desc.TSFlags >> PPCII::Arg1TypeShift) & PPCII::ArgTypeMask, - (Desc.TSFlags >> PPCII::Arg2TypeShift) & PPCII::ArgTypeMask, - (Desc.TSFlags >> PPCII::Arg3TypeShift) & PPCII::ArgTypeMask, - (Desc.TSFlags >> PPCII::Arg4TypeShift) & PPCII::ArgTypeMask - }; - assert(((Desc.TSFlags & PPCII::VMX) == 0) && - "Instruction requires VMX support"); - assert(((Desc.TSFlags & PPCII::PPC64) == 0) && - "Instruction requires 64 bit support"); - - O << TII.getName(Opcode) << " "; - if (Opcode == PPC::LOADHiAddr) { - printOp(MI->getOperand(0)); - O << ", "; - if (MI->getOperand(1).getReg() == PPC::R0) - O << "0"; - else - printOp(MI->getOperand(1)); - O << ", ha16(" ; - printOp(MI->getOperand(2), true /* LoadAddrOp */); - O << "-\"L0000" << LabelNumber << "$pb\")\n"; - } else if (ArgCount == 3 && (MI->getOperand(2).isConstantPoolIndex() - || MI->getOperand(2).isGlobalAddress())) { - printOp(MI->getOperand(0)); - O << ", lo16("; - printOp(MI->getOperand(2), true /* LoadAddrOp */); - O << "-\"L0000" << LabelNumber << "$pb\")"; - O << "("; - if (MI->getOperand(1).getReg() == PPC::R0) - O << "0"; - else - printOp(MI->getOperand(1)); - O << ")\n"; - } else if (ArgCount == 3 && ArgType[1] == PPCII::Disimm16) { - printOp(MI->getOperand(0)); - O << ", "; - printImmOp(MI->getOperand(1), ArgType[1]); - O << "("; - if (MI->getOperand(2).hasAllocatedReg() && - MI->getOperand(2).getReg() == PPC::R0) - O << "0"; - else - printOp(MI->getOperand(2)); - O << ")\n"; - } else { - for (i = 0; i < ArgCount; ++i) { - // addi and friends - if (i == 1 && ArgCount == 3 && ArgType[2] == PPCII::Simm16 && - MI->getOperand(1).hasAllocatedReg() && - MI->getOperand(1).getReg() == PPC::R0) { - O << "0"; - // for long branch support, bc $+8 - } else if (i == 1 && ArgCount == 2 && MI->getOperand(1).isImmediate() && - TII.isBranch(MI->getOpcode())) { - O << "$+8"; - assert(8 == MI->getOperand(i).getImmedValue() - && "branch off PC not to pc+8?"); - //printOp(MI->getOperand(i)); - } else if (MI->getOperand(i).isImmediate()) { - printImmOp(MI->getOperand(i), ArgType[i]); - } else { - printOp(MI->getOperand(i)); - } - if (ArgCount - 1 == i) - O << "\n"; - else - O << ", "; + + assert(0 && "Unhandled instruction in asm writer!"); + abort(); + return; +} + +/// runOnMachineFunction - This uses the printMachineInstruction() +/// method to print assembly for each instruction. +/// +bool DarwinAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + setupMachineFunction(MF); + O << "\n\n"; + + // Print out constants referenced by the function + printConstantPool(MF.getConstantPool()); + + // Print out labels for the function. + O << "\t.text\n"; + emitAlignment(2); + O << "\t.globl\t" << CurrentFnName << "\n"; + O << CurrentFnName << ":\n"; + + // Print out code for the function. + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + // Print a label for the basic block. + O << ".LBB" << CurrentFnName << "_" << I->getNumber() << ":\t" + << CommentString << " " << I->getBasicBlock()->getName() << "\n"; + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + O << "\t"; + printMachineInstruction(II); } } - return; + ++LabelNumber; + + // We didn't modify anything. + return false; } -// SwitchSection - Switch to the specified section of the executable if we are -// not already in it! -// -static void SwitchSection(std::ostream &OS, std::string &CurSection, - const char *NewSection) { - if (CurSection != NewSection) { - CurSection = NewSection; - if (!CurSection.empty()) - OS << "\t" << NewSection << "\n"; +/// printConstantPool - Print to the current output stream assembly +/// representations of the constants in the constant pool MCP. This is +/// used to print out constants which have been "spilled to memory" by +/// the code generator. +/// +void DarwinAsmPrinter::printConstantPool(MachineConstantPool *MCP) { + const std::vector<Constant*> &CP = MCP->getConstants(); + const TargetData &TD = TM.getTargetData(); + + if (CP.empty()) return; + + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + O << "\t.const\n"; + emitAlignment(TD.getTypeAlignmentShift(CP[i]->getType())); + O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t" << CommentString + << *CP[i] << "\n"; + emitGlobalConstant(CP[i]); } } -bool PPC32AsmPrinter::doFinalization(Module &M) { +bool DarwinAsmPrinter::doFinalization(Module &M) { const TargetData &TD = TM.getTargetData(); std::string CurSection; @@ -487,3 +565,145 @@ bool PPC32AsmPrinter::doFinalization(Module &M) { AsmPrinter::doFinalization(M); return false; // success } + +/// runOnMachineFunction - This uses the printMachineInstruction() +/// method to print assembly for each instruction. +/// +bool AIXAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + CurrentFnName = MF.getFunction()->getName(); + + // Print out constants referenced by the function + printConstantPool(MF.getConstantPool()); + + // Print out header for the function. + O << "\t.csect .text[PR]\n" + << "\t.align 2\n" + << "\t.globl " << CurrentFnName << '\n' + << "\t.globl ." << CurrentFnName << '\n' + << "\t.csect " << CurrentFnName << "[DS],3\n" + << CurrentFnName << ":\n" + << "\t.llong ." << CurrentFnName << ", TOC[tc0], 0\n" + << "\t.csect .text[PR]\n" + << '.' << CurrentFnName << ":\n"; + + // Print out code for the function. + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + // Print a label for the basic block. + O << "LBB" << CurrentFnName << "_" << I->getNumber() << ":\t# " + << I->getBasicBlock()->getName() << "\n"; + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + O << "\t"; + printMachineInstruction(II); + } + } + ++LabelNumber; + + O << "LT.." << CurrentFnName << ":\n" + << "\t.long 0\n" + << "\t.byte 0,0,32,65,128,0,0,0\n" + << "\t.long LT.." << CurrentFnName << "-." << CurrentFnName << '\n' + << "\t.short 3\n" + << "\t.byte \"" << CurrentFnName << "\"\n" + << "\t.align 2\n"; + + // We didn't modify anything. + return false; +} + +/// printConstantPool - Print to the current output stream assembly +/// representations of the constants in the constant pool MCP. This is +/// used to print out constants which have been "spilled to memory" by +/// the code generator. +/// +void AIXAsmPrinter::printConstantPool(MachineConstantPool *MCP) { + const std::vector<Constant*> &CP = MCP->getConstants(); + const TargetData &TD = TM.getTargetData(); + + if (CP.empty()) return; + + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + O << "\t.const\n"; + O << "\t.align " << (unsigned)TD.getTypeAlignment(CP[i]->getType()) + << "\n"; + O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t;" + << *CP[i] << "\n"; + emitGlobalConstant(CP[i]); + } +} + +bool AIXAsmPrinter::doInitialization(Module &M) { + const TargetData &TD = TM.getTargetData(); + std::string CurSection; + + O << "\t.machine \"ppc64\"\n" + << "\t.toc\n" + << "\t.csect .text[PR]\n"; + + // Print out module-level global variables + for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I) { + if (!I->hasInitializer()) + continue; + + std::string Name = I->getName(); + Constant *C = I->getInitializer(); + // N.B.: We are defaulting to writable strings + if (I->hasExternalLinkage()) { + O << "\t.globl " << Name << '\n' + << "\t.csect .data[RW],3\n"; + } else { + O << "\t.csect _global.rw_c[RW],3\n"; + } + O << Name << ":\n"; + emitGlobalConstant(C); + } + + // Output labels for globals + if (M.gbegin() != M.gend()) O << "\t.toc\n"; + for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I) { + const GlobalVariable *GV = I; + // Do not output labels for unused variables + if (GV->isExternal() && GV->use_begin() == GV->use_end()) + continue; + + std::string Name = GV->getName(); + std::string Label = "LC.." + utostr(LabelNumber++); + GVToLabelMap[GV] = Label; + O << Label << ":\n" + << "\t.tc " << Name << "[TC]," << Name; + if (GV->isExternal()) O << "[RW]"; + O << '\n'; + } + + Mang = new Mangler(M, "."); + return false; // success +} + +bool AIXAsmPrinter::doFinalization(Module &M) { + const TargetData &TD = TM.getTargetData(); + // Print out module-level global variables + for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I) { + if (I->hasInitializer() || I->hasExternalLinkage()) + continue; + + std::string Name = I->getName(); + if (I->hasInternalLinkage()) { + O << "\t.lcomm " << Name << ",16,_global.bss_c"; + } else { + O << "\t.comm " << Name << "," << TD.getTypeSize(I->getType()) + << "," << log2((unsigned)TD.getTypeAlignment(I->getType())); + } + O << "\t\t# "; + WriteAsOperand(O, I, true, true, &M); + O << "\n"; + } + + O << "_section_.text:\n" + << "\t.csect .data[RW],3\n" + << "\t.llong _section_.text\n"; + + delete Mang; + return false; // success +} |