X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FPowerPC%2FPPCAsmPrinter.cpp;h=7969d02b23e7199573fb11d5d1ad3b39eac2866f;hb=3459bfbc395914ec895aef13123f3b180242577f;hp=8119fd30940f9f2a3badf8734f4bf60a4667811b;hpb=12585baf1a086f7d54e0ac963e3b0e7b6792b80c;p=oota-llvm.git diff --git a/lib/Target/PowerPC/PPCAsmPrinter.cpp b/lib/Target/PowerPC/PPCAsmPrinter.cpp index 8119fd30940..7969d02b23e 100644 --- a/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -1,10 +1,10 @@ -//===-- PPC32AsmPrinter.cpp - Print machine instrs to PowerPC assembly ----===// -// +//===-- PPCAsmPrinter.cpp - Print machine instrs to PowerPC assembly --------=// +// // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. -// +// //===----------------------------------------------------------------------===// // // This file contains a printer that converts from our internal representation @@ -17,8 +17,9 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "asmprinter" -#include "PowerPC.h" -#include "PPC32TargetMachine.h" +#include "PPC.h" +#include "PPCTargetMachine.h" +#include "PPCSubtarget.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" @@ -29,39 +30,50 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/Support/Mangler.h" -#include "Support/CommandLine.h" -#include "Support/Debug.h" -#include "Support/Statistic.h" -#include "Support/StringExtras.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Target/MRegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" #include using namespace llvm; namespace { Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); - struct PPC32AsmPrinter : public AsmPrinter { + struct PPCAsmPrinter : public AsmPrinter { std::set FnStubs, GVStubs, LinkOnceStubs; - std::set 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. - } + PPCAsmPrinter(std::ostream &O, TargetMachine &TM) + : 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(TM); + PPCTargetMachine &getTM() { + return static_cast(TM); + } + + unsigned enumRegToMachineReg(unsigned enumReg) { + switch (enumReg) { + default: assert(0 && "Unhandled register!"); break; + case PPC::CR0: return 0; + case PPC::CR1: return 1; + case PPC::CR2: return 2; + case PPC::CR3: return 3; + case PPC::CR4: return 4; + case PPC::CR5: return 5; + case PPC::CR6: return 6; + case PPC::CR7: return 7; + } + abort(); } /// printInstruction - This method is automatically generated by tablegen @@ -71,14 +83,13 @@ namespace { bool printInstruction(const MachineInstr *MI); void printMachineInstruction(const MachineInstr *MI); - void printOp(const MachineOperand &MO, bool LoadAddrOp = false); - void printImmOp(const MachineOperand &MO, unsigned ArgType); + void printOp(const MachineOperand &MO, bool IsCallOp = false); void printOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT){ const MachineOperand &MO = MI->getOperand(OpNo); if (MO.getType() == MachineOperand::MO_MachineRegister) { assert(MRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physreg??"); - O << LowercaseString(TM.getRegisterInfo()->get(MO.getReg()).Name); + O << TM.getRegisterInfo()->get(MO.getReg()).Name; } else if (MO.isImmediate()) { O << MO.getImmedValue(); } else { @@ -92,89 +103,165 @@ namespace { assert(value <= 31 && "Invalid u5imm argument!"); O << (unsigned int)value; } + void printU6ImmOperand(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + unsigned char value = MI->getOperand(OpNo).getImmedValue(); + 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 printS16X4ImmOperand(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + O << (short)MI->getOperand(OpNo).getImmedValue()*4; + } + void printBranchOperand(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + // 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(); + } else { + printOp(MI->getOperand(OpNo), + TM.getInstrInfo()->isCall(MI->getOpcode())); + } + } + void printPICLabel(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + // FIXME: should probably be converted to cout.width and cout.fill + O << "\"L0000" << LabelNumber << "$pb\"\n"; + O << "\"L0000" << LabelNumber << "$pb\":"; + } + void printSymbolHi(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + if (MI->getOperand(OpNo).isImmediate()) { + printS16ImmOperand(MI, OpNo, VT); + } else { + O << "ha16("; + printOp(MI->getOperand(OpNo)); + if (PICEnabled) + O << "-\"L0000" << LabelNumber << "$pb\")"; + else + O << ')'; + } + } + void printSymbolLo(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + if (MI->getOperand(OpNo).isImmediate()) { + printS16ImmOperand(MI, OpNo, VT); + } else { + O << "lo16("; + printOp(MI->getOperand(OpNo)); + if (PICEnabled) + O << "-\"L0000" << LabelNumber << "$pb\")"; + else + O << ')'; + } + } + void printcrbitm(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + unsigned CCReg = MI->getOperand(OpNo).getReg(); + unsigned RegNo = enumRegToMachineReg(CCReg); + O << (0x80 >> RegNo); + } + + virtual void printConstantPool(MachineConstantPool *MCP) = 0; + virtual bool runOnMachineFunction(MachineFunction &F) = 0; + virtual bool doFinalization(Module &M) = 0; + }; + + /// DarwinAsmPrinter - PowerPC assembly printer, customized for Darwin/Mac OS + /// X + /// + struct DarwinAsmPrinter : public PPCAsmPrinter { + + DarwinAsmPrinter(std::ostream &O, TargetMachine &TM) + : PPCAsmPrinter(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 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); -} + /// AIXAsmPrinter - PowerPC assembly printer, customized for AIX + /// + struct AIXAsmPrinter : public PPCAsmPrinter { + /// Map for labels corresponding to global variables + /// + std::map GVToLabelMap; -// Include the auto-generated portion of the assembly writer -#include "PowerPCGenAsmWriter.inc" + AIXAsmPrinter(std::ostream &O, TargetMachine &TM) + : PPCAsmPrinter(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. + } -/// 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 PPC32AsmPrinter::printConstantPool(MachineConstantPool *MCP) { - const std::vector &CP = MCP->getConstants(); - const TargetData &TD = TM.getTargetData(); - - if (CP.empty()) return; + virtual const char *getPassName() const { + return "AIX PPC Assembly Printer"; + } - 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]); + void printConstantPool(MachineConstantPool *MCP); + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + }; +} // end of anonymous namespace + +// 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"; } } -/// runOnMachineFunction - This uses the printMachineInstruction() -/// method to print assembly for each instruction. +/// 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. /// -bool PPC32AsmPrinter::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); - } - } - ++LabelNumber; +FunctionPass *llvm::createDarwinAsmPrinter(std::ostream &o, TargetMachine &tm) { + return new DarwinAsmPrinter(o, tm); +} - // We didn't modify anything. - return false; +/// 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); } -void PPC32AsmPrinter::printOp(const MachineOperand &MO, - bool LoadAddrOp /* = false */) { +// Include the auto-generated portion of the assembly writer +#include "PPCGenAsmWriter.inc" + +void PPCAsmPrinter::printOp(const MachineOperand &MO, bool IsCallOp) { const MRegisterInfo &RI = *TM.getRegisterInfo(); int new_symbol; - + switch (MO.getType()) { case MachineOperand::MO_VirtualRegister: if (Value *V = MO.getVRegValueOrNull()) { @@ -184,7 +271,7 @@ void PPC32AsmPrinter::printOp(const MachineOperand &MO, // FALLTHROUGH case MachineOperand::MO_MachineRegister: case MachineOperand::MO_CCRegister: - O << LowercaseString(RI.get(MO.getReg()).Name); + O << RI.get(MO.getReg()).Name; return; case MachineOperand::MO_SignExtendedImmed: @@ -197,21 +284,27 @@ void PPC32AsmPrinter::printOp(const MachineOperand &MO, std::cerr << "Shouldn't use addPCDisp() when building PPC MachineInstrs"; abort(); return; - + case MachineOperand::MO_MachineBasicBlock: { MachineBasicBlock *MBBOp = MO.getMachineBasicBlock(); - O << ".LBB" << Mang->getValueName(MBBOp->getParent()->getFunction()) + O << "LBB" << Mang->getValueName(MBBOp->getParent()->getFunction()) << "_" << MBBOp->getNumber() << "\t; " << MBBOp->getBasicBlock()->getName(); return; } case MachineOperand::MO_ConstantPoolIndex: - O << ".CPI" << CurrentFnName << "_" << MO.getConstantPoolIndex(); + O << "LCPI" << CurrentFnName << "_" << MO.getConstantPoolIndex(); return; case MachineOperand::MO_ExternalSymbol: - O << MO.getSymbolName(); + if (IsCallOp) { + std::string Name(GlobalPrefix); Name += MO.getSymbolName(); + FnStubs.insert(Name); + O << "L" << Name << "$stub"; + return; + } + O << GlobalPrefix << MO.getSymbolName(); return; case MachineOperand::MO_GlobalAddress: { @@ -222,205 +315,163 @@ void PPC32AsmPrinter::printOp(const MachineOperand &MO, // wary however not to output $stub for external functions whose addresses // are taken. Those should be emitted as $non_lazy_ptr below. Function *F = dyn_cast(GV); - if (F && F->isExternal() && !LoadAddrOp && - getTM().CalledFunctions.count(F)) { + if (F && IsCallOp && F->isExternal()) { FnStubs.insert(Name); O << "L" << Name << "$stub"; return; } - - // External global variables need a non-lazily-resolved stub - if (GV->isExternal() && getTM().AddressTaken.count(GV)) { - GVStubs.insert(Name); - O << "L" << Name << "$non_lazy_ptr"; - return; - } - - if (F && LoadAddrOp && getTM().AddressTaken.count(GV)) { - LinkOnceStubs.insert(Name); + + // External or weakly linked global variables need non-lazily-resolved stubs + if ((GV->isExternal() || GV->hasWeakLinkage() || GV->hasLinkOnceLinkage())){ + if (GV->hasLinkOnceLinkage()) + LinkOnceStubs.insert(Name); + else + GVStubs.insert(Name); O << "L" << Name << "$non_lazy_ptr"; return; } - + O << Mang->getValueName(GV); return; } - + default: O << ""; return; } } -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. /// -void PPC32AsmPrinter::printMachineInstruction(const MachineInstr *MI) { +void PPCAsmPrinter::printMachineInstruction(const MachineInstr *MI) { ++EmittedInsts; + + // Check for slwi/srwi mnemonics. + if (MI->getOpcode() == PPC::RLWINM) { + bool FoundMnemonic = false; + unsigned char SH = MI->getOperand(2).getImmedValue(); + unsigned char MB = MI->getOperand(3).getImmedValue(); + unsigned char ME = MI->getOperand(4).getImmedValue(); + if (SH <= 31 && MB == 0 && ME == (31-SH)) { + O << "slwi "; FoundMnemonic = true; + } + if (SH <= 31 && MB == (32-SH) && ME == 31) { + O << "srwi "; FoundMnemonic = true; + SH = 32-SH; + } + if (FoundMnemonic) { + printOperand(MI, 0, MVT::i64); + O << ", "; + printOperand(MI, 1, MVT::i64); + O << ", " << (unsigned int)SH << "\n"; + return; + } + } + 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"); - - // CALLpcrel and CALLindirect are handled specially here to print only the - // appropriate number of args that the assembler expects. This is because - // may have many arguments appended to record the uses of registers that are - // holding arguments to the called function. - if (Opcode == PPC::COND_BRANCH) { - std::cerr << "Error: untranslated conditional branch psuedo instruction!\n"; - abort(); - } else if (Opcode == PPC::IMPLICIT_DEF) { - --EmittedInsts; // Not an actual machine instruction - O << "; IMPLICIT DEF "; - printOp(MI->getOperand(0)); - O << "\n"; - return; - } else if (Opcode == PPC::CALLpcrel) { - O << TII.getName(Opcode) << " "; - printOp(MI->getOperand(0)); - O << "\n"; - return; - } else if (Opcode == PPC::CALLindirect) { - O << TII.getName(Opcode) << " "; - printImmOp(MI->getOperand(0), ArgType[0]); - O << ", "; - printImmOp(MI->getOperand(1), ArgType[0]); - O << "\n"; - return; - } else if (Opcode == PPC::MovePCtoLR) { - ++EmittedInsts; // Actually two machine instructions - // FIXME: should probably be converted to cout.width and cout.fill - O << "bl \"L0000" << LabelNumber << "$pb\"\n"; - O << "\"L0000" << LabelNumber << "$pb\":\n"; - O << "\tmflr "; - printOp(MI->getOperand(0)); - O << "\n"; - return; - } - 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(4); + if (!MF.getFunction()->hasInternalLinkage()) + 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. + if (I != MF.begin()) { + O << "LBB" << CurrentFnName << "_" << I->getNumber() << ":\t"; + if (!I->getBasicBlock()->getName().empty()) + O << CommentString << " " << I->getBasicBlock()->getName(); + O << "\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 &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"; + // FIXME: force doubles to be naturally aligned. We should handle this + // more correctly in the future. + if (Type::DoubleTy == CP[i]->getType()) + emitAlignment(3); + else + emitAlignment(TD.getTypeAlignmentShift(CP[i]->getType())); + O << "LCPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t" << CommentString + << *CP[i] << "\n"; + emitGlobalConstant(CP[i]); } } -bool PPC32AsmPrinter::doFinalization(Module &M) { +bool DarwinAsmPrinter::doInitialization(Module &M) { + if (TM.getSubtarget().isGigaProcessor()) + O << "\t.machine ppc970\n"; + AsmPrinter::doInitialization(M); + return false; +} + +bool DarwinAsmPrinter::doFinalization(Module &M) { const TargetData &TD = TM.getTargetData(); std::string CurSection; // Print out module-level global variables here. - for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I) + for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) if (I->hasInitializer()) { // External global require no code - O << "\n\n"; + O << '\n'; std::string name = Mang->getValueName(I); Constant *C = I->getInitializer(); unsigned Size = TD.getTypeSize(C->getType()); unsigned Align = TD.getTypeAlignmentShift(C->getType()); if (C->isNullValue() && /* FIXME: Verify correct */ - (I->hasInternalLinkage() || I->hasWeakLinkage())) { + (I->hasInternalLinkage() || I->hasWeakLinkage() || + I->hasLinkOnceLinkage())) { SwitchSection(O, CurSection, ".data"); + if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. if (I->hasInternalLinkage()) - O << ".lcomm " << name << "," << TD.getTypeSize(C->getType()) - << "," << Align; - else - O << ".comm " << name << "," << TD.getTypeSize(C->getType()); - O << "\t\t; "; - WriteAsOperand(O, I, true, true, &M); - O << "\n"; + O << ".lcomm " << name << "," << Size << "," << Align; + else + O << ".comm " << name << "," << Size; + O << "\t\t; '" << I->getName() << "'\n"; } else { switch (I->getLinkage()) { case GlobalValue::LinkOnceLinkage: @@ -429,12 +480,10 @@ bool PPC32AsmPrinter::doFinalization(Module &M) { << ".private_extern " << name << '\n' << ".section __DATA,__datacoal_nt,coalesced,no_toc\n"; LinkOnceStubs.insert(name); - break; - case GlobalValue::WeakLinkage: // FIXME: Verify correct for weak. - // Nonnull linkonce -> weak - O << "\t.weak " << name << "\n"; - SwitchSection(O, CurSection, ""); - O << "\t.section\t.llvm.linkonce.d." << name << ",\"aw\",@progbits\n"; + break; + case GlobalValue::WeakLinkage: + O << ".weak_definition " << name << '\n' + << ".private_extern " << name << '\n'; break; case GlobalValue::AppendingLinkage: // FIXME: appending linkage variables should go into a section of @@ -446,22 +495,22 @@ bool PPC32AsmPrinter::doFinalization(Module &M) { case GlobalValue::InternalLinkage: SwitchSection(O, CurSection, ".data"); break; + case GlobalValue::GhostLinkage: + std::cerr << "Error: unmaterialized (GhostLinkage) function in asm!"; + abort(); } emitAlignment(Align); - O << name << ":\t\t\t\t; "; - WriteAsOperand(O, I, true, true, &M); - O << " = "; - WriteAsOperand(O, C, false, false, &M); - O << "\n"; + O << name << ":\t\t\t\t; '" << I->getName() << "'\n"; emitGlobalConstant(C); } } // Output stubs for dynamically-linked functions - for (std::set::iterator i = FnStubs.begin(), e = FnStubs.end(); + for (std::set::iterator i = FnStubs.begin(), e = FnStubs.end(); i != e; ++i) { + if (PICEnabled) { O << ".data\n"; O << ".section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"; emitAlignment(2); @@ -481,6 +530,20 @@ bool PPC32AsmPrinter::doFinalization(Module &M) { O << "L" << *i << "$lazy_ptr:\n"; O << "\t.indirect_symbol " << *i << "\n"; O << "\t.long dyld_stub_binding_helper\n"; + } else { + O << "\t.section __TEXT,__symbol_stub1,symbol_stubs,pure_instructions,16\n"; + emitAlignment(4); + O << "L" << *i << "$stub:\n"; + O << "\t.indirect_symbol " << *i << "\n"; + O << "\tlis r11,ha16(L" << *i << "$lazy_ptr)\n"; + O << "\tlwzu r12,lo16(L" << *i << "$lazy_ptr)(r11)\n"; + O << "\tmtctr r12\n"; + O << "\tbctr\n"; + O << "\t.lazy_symbol_pointer\n"; + O << "L" << *i << "$lazy_ptr:\n"; + O << "\t.indirect_symbol " << *i << "\n"; + O << "\t.long dyld_stub_binding_helper\n"; + } } O << "\n"; @@ -488,22 +551,173 @@ bool PPC32AsmPrinter::doFinalization(Module &M) { // Output stubs for external global variables if (GVStubs.begin() != GVStubs.end()) O << ".data\n.non_lazy_symbol_pointer\n"; - for (std::set::iterator i = GVStubs.begin(), e = GVStubs.end(); + for (std::set::iterator i = GVStubs.begin(), e = GVStubs.end(); i != e; ++i) { O << "L" << *i << "$non_lazy_ptr:\n"; O << "\t.indirect_symbol " << *i << "\n"; O << "\t.long\t0\n"; } - + // Output stubs for link-once variables if (LinkOnceStubs.begin() != LinkOnceStubs.end()) O << ".data\n.align 2\n"; - for (std::set::iterator i = LinkOnceStubs.begin(), + for (std::set::iterator i = LinkOnceStubs.begin(), e = LinkOnceStubs.end(); i != e; ++i) { O << "L" << *i << "$non_lazy_ptr:\n" << "\t.long\t" << *i << '\n'; } - + + // Funny Darwin hack: This flag tells the linker that no global symbols + // contain code that falls through to other global symbols (e.g. the obvious + // 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"; + + 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 &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 << "LCPI" << 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_global_iterator I = M.global_begin(), E = M.global_end(); + 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.global_begin() != M.global_end()) O << "\t.toc\n"; + for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); + 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'; + } + + AsmPrinter::doInitialization(M); + return false; // success +} + +bool AIXAsmPrinter::doFinalization(Module &M) { + const TargetData &TD = TM.getTargetData(); + // Print out module-level global variables + for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); + 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_32((unsigned)TD.getTypeAlignment(I->getType())); + } + O << "\t\t# "; + WriteAsOperand(O, I, false, true, &M); + O << "\n"; + } + + O << "_section_.text:\n" + << "\t.csect .data[RW],3\n" + << "\t.llong _section_.text\n"; AsmPrinter::doFinalization(M); return false; // success }