llvm-6502/lib/Target/PowerPC/PPCAsmPrinter.cpp
Reid Spencer 3ed469ccd7 For PR786:
Turn on -Wunused and -Wno-unused-parameter. Clean up most of the resulting
fall out by removing unused variables. Remaining warnings have to do with
unused functions (I didn't want to delete code without review) and unused
variables in generated code. Maintainers should clean up the remaining
issues when they see them. All changes pass DejaGnu tests and Olden.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@31380 91177308-0d34-0410-b5e6-96231b3b80d8
2006-11-02 20:25:50 +00:00

669 lines
22 KiB
C++

//===-- 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
// of machine-dependent LLVM code to PowerPC assembly language. This printer is
// the output mechanism used by `llc'.
//
// Documentation at http://developer.apple.com/documentation/DeveloperTools/
// Reference/Assembler/ASMIntroduction/chapter_1_section_1.html
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "asmprinter"
#include "PPC.h"
#include "PPCTargetMachine.h"
#include "PPCSubtarget.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineDebugInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Support/Mangler.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include <iostream>
#include <set>
using namespace llvm;
namespace {
Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed");
struct VISIBILITY_HIDDEN PPCAsmPrinter : public AsmPrinter {
std::set<std::string> FnStubs, GVStubs;
const PPCSubtarget &Subtarget;
PPCAsmPrinter(std::ostream &O, TargetMachine &TM, const TargetAsmInfo *T)
: AsmPrinter(O, TM, T), Subtarget(TM.getSubtarget<PPCSubtarget>()) {
}
virtual const char *getPassName() const {
return "PowerPC Assembly Printer";
}
PPCTargetMachine &getTM() {
return static_cast<PPCTargetMachine&>(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
/// from the instruction set description. This method returns true if the
/// machine instruction was sufficiently described to print it, otherwise it
/// returns false.
bool printInstruction(const MachineInstr *MI);
void printMachineInstruction(const MachineInstr *MI);
void printOp(const MachineOperand &MO);
void printOperand(const MachineInstr *MI, unsigned OpNo) {
const MachineOperand &MO = MI->getOperand(OpNo);
if (MO.isRegister()) {
assert(MRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physreg??");
O << TM.getRegisterInfo()->get(MO.getReg()).Name;
} else if (MO.isImmediate()) {
O << MO.getImmedValue();
} else {
printOp(MO);
}
}
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode);
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode);
void printS5ImmOperand(const MachineInstr *MI, unsigned OpNo) {
char value = MI->getOperand(OpNo).getImmedValue();
value = (value << (32-5)) >> (32-5);
O << (int)value;
}
void printU5ImmOperand(const MachineInstr *MI, unsigned OpNo) {
unsigned char value = MI->getOperand(OpNo).getImmedValue();
assert(value <= 31 && "Invalid u5imm argument!");
O << (unsigned int)value;
}
void printU6ImmOperand(const MachineInstr *MI, unsigned OpNo) {
unsigned char value = MI->getOperand(OpNo).getImmedValue();
assert(value <= 63 && "Invalid u6imm argument!");
O << (unsigned int)value;
}
void printS16ImmOperand(const MachineInstr *MI, unsigned OpNo) {
O << (short)MI->getOperand(OpNo).getImmedValue();
}
void printU16ImmOperand(const MachineInstr *MI, unsigned OpNo) {
O << (unsigned short)MI->getOperand(OpNo).getImmedValue();
}
void printS16X4ImmOperand(const MachineInstr *MI, unsigned OpNo) {
O << (short)(MI->getOperand(OpNo).getImmedValue()*4);
}
void printBranchOperand(const MachineInstr *MI, unsigned 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()*4;
} else {
printOp(MI->getOperand(OpNo));
}
}
void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
const MachineOperand &MO = MI->getOperand(OpNo);
if (TM.getRelocationModel() != Reloc::Static) {
if (MO.getType() == MachineOperand::MO_GlobalAddress) {
GlobalValue *GV = MO.getGlobal();
if (((GV->isExternal() || GV->hasWeakLinkage() ||
GV->hasLinkOnceLinkage()))) {
// Dynamically-resolved functions need a stub for the function.
std::string Name = Mang->getValueName(GV);
FnStubs.insert(Name);
O << "L" << Name << "$stub";
return;
}
}
if (MO.getType() == MachineOperand::MO_ExternalSymbol) {
std::string Name(TAI->getGlobalPrefix()); Name += MO.getSymbolName();
FnStubs.insert(Name);
O << "L" << Name << "$stub";
return;
}
}
printOp(MI->getOperand(OpNo));
}
void printAbsAddrOperand(const MachineInstr *MI, unsigned OpNo) {
O << (int)MI->getOperand(OpNo).getImmedValue()*4;
}
void printPICLabel(const MachineInstr *MI, unsigned OpNo) {
O << "\"L" << getFunctionNumber() << "$pb\"\n";
O << "\"L" << getFunctionNumber() << "$pb\":";
}
void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImmediate()) {
printS16ImmOperand(MI, OpNo);
} else {
O << "ha16(";
printOp(MI->getOperand(OpNo));
if (TM.getRelocationModel() == Reloc::PIC_)
O << "-\"L" << getFunctionNumber() << "$pb\")";
else
O << ')';
}
}
void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImmediate()) {
printS16ImmOperand(MI, OpNo);
} else {
O << "lo16(";
printOp(MI->getOperand(OpNo));
if (TM.getRelocationModel() == Reloc::PIC_)
O << "-\"L" << getFunctionNumber() << "$pb\")";
else
O << ')';
}
}
void printcrbitm(const MachineInstr *MI, unsigned OpNo) {
unsigned CCReg = MI->getOperand(OpNo).getReg();
unsigned RegNo = enumRegToMachineReg(CCReg);
O << (0x80 >> RegNo);
}
// The new addressing mode printers.
void printMemRegImm(const MachineInstr *MI, unsigned OpNo) {
printSymbolLo(MI, OpNo);
O << '(';
if (MI->getOperand(OpNo+1).isRegister() &&
MI->getOperand(OpNo+1).getReg() == PPC::R0)
O << "0";
else
printOperand(MI, OpNo+1);
O << ')';
}
void printMemRegImmShifted(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImmediate())
printS16X4ImmOperand(MI, OpNo);
else
printSymbolLo(MI, OpNo);
O << '(';
if (MI->getOperand(OpNo+1).isRegister() &&
MI->getOperand(OpNo+1).getReg() == PPC::R0)
O << "0";
else
printOperand(MI, OpNo+1);
O << ')';
}
void printMemRegReg(const MachineInstr *MI, unsigned OpNo) {
// When used as the base register, r0 reads constant zero rather than
// the value contained in the register. For this reason, the darwin
// assembler requires that we print r0 as 0 (no r) when used as the base.
const MachineOperand &MO = MI->getOperand(OpNo);
if (MO.getReg() == PPC::R0)
O << '0';
else
O << TM.getRegisterInfo()->get(MO.getReg()).Name;
O << ", ";
printOperand(MI, OpNo+1);
}
virtual bool runOnMachineFunction(MachineFunction &F) = 0;
virtual bool doFinalization(Module &M) = 0;
};
/// DarwinAsmPrinter - PowerPC assembly printer, customized for Darwin/Mac OS
/// X
struct VISIBILITY_HIDDEN DarwinAsmPrinter : public PPCAsmPrinter {
DwarfWriter DW;
DarwinAsmPrinter(std::ostream &O, PPCTargetMachine &TM,
const TargetAsmInfo *T)
: PPCAsmPrinter(O, TM, T), DW(O, this, T) {
}
virtual const char *getPassName() const {
return "Darwin PPC Assembly Printer";
}
bool runOnMachineFunction(MachineFunction &F);
bool doInitialization(Module &M);
bool doFinalization(Module &M);
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<MachineDebugInfo>();
PPCAsmPrinter::getAnalysisUsage(AU);
}
/// getSectionForFunction - Return the section that we should emit the
/// specified function body into.
virtual std::string getSectionForFunction(const Function &F) const;
};
} // end of anonymous namespace
// Include the auto-generated portion of the assembly writer
#include "PPCGenAsmWriter.inc"
void PPCAsmPrinter::printOp(const MachineOperand &MO) {
switch (MO.getType()) {
case MachineOperand::MO_Immediate:
std::cerr << "printOp() does not handle immediate values\n";
abort();
return;
case MachineOperand::MO_MachineBasicBlock:
printBasicBlockLabel(MO.getMachineBasicBlock());
return;
case MachineOperand::MO_JumpTableIndex:
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
<< '_' << MO.getJumpTableIndex();
// FIXME: PIC relocation model
return;
case MachineOperand::MO_ConstantPoolIndex:
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
<< '_' << MO.getConstantPoolIndex();
return;
case MachineOperand::MO_ExternalSymbol:
// Computing the address of an external symbol, not calling it.
if (TM.getRelocationModel() != Reloc::Static) {
std::string Name(TAI->getGlobalPrefix()); Name += MO.getSymbolName();
GVStubs.insert(Name);
O << "L" << Name << "$non_lazy_ptr";
return;
}
O << TAI->getGlobalPrefix() << MO.getSymbolName();
return;
case MachineOperand::MO_GlobalAddress: {
// Computing the address of a global symbol, not calling it.
GlobalValue *GV = MO.getGlobal();
std::string Name = Mang->getValueName(GV);
// External or weakly linked global variables need non-lazily-resolved stubs
if (TM.getRelocationModel() != Reloc::Static) {
if (((GV->isExternal() || GV->hasWeakLinkage() ||
GV->hasLinkOnceLinkage()))) {
GVStubs.insert(Name);
O << "L" << Name << "$non_lazy_ptr";
return;
}
}
O << Name;
return;
}
default:
O << "<unknown operand type: " << MO.getType() << ">";
return;
}
}
/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool PPCAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode) {
// Does this asm operand have a single letter operand modifier?
if (ExtraCode && ExtraCode[0]) {
if (ExtraCode[1] != 0) return true; // Unknown modifier.
switch (ExtraCode[0]) {
default: return true; // Unknown modifier.
case 'L': // Write second word of DImode reference.
// Verify that this operand has two consecutive registers.
if (!MI->getOperand(OpNo).isRegister() ||
OpNo+1 == MI->getNumOperands() ||
!MI->getOperand(OpNo+1).isRegister())
return true;
++OpNo; // Return the high-part.
break;
}
}
printOperand(MI, OpNo);
return false;
}
bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode) {
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier.
printMemRegReg(MI, OpNo);
return false;
}
/// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax to
/// the current output stream.
///
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);
O << ", ";
printOperand(MI, 1);
O << ", " << (unsigned int)SH << "\n";
return;
}
} else if (MI->getOpcode() == PPC::OR || MI->getOpcode() == PPC::OR8) {
if (MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) {
O << "mr ";
printOperand(MI, 0);
O << ", ";
printOperand(MI, 1);
O << "\n";
return;
}
}
if (printInstruction(MI))
return; // Printer was automatically generated
assert(0 && "Unhandled instruction in asm writer!");
abort();
return;
}
std::string DarwinAsmPrinter::getSectionForFunction(const Function &F) const {
switch (F.getLinkage()) {
default: assert(0 && "Unknown linkage type!");
case Function::ExternalLinkage:
case Function::InternalLinkage: return TAI->getTextSection();
case Function::WeakLinkage:
case Function::LinkOnceLinkage:
return ".section __TEXT,__textcoal_nt,coalesced,pure_instructions";
}
}
/// runOnMachineFunction - This uses the printMachineInstruction()
/// method to print assembly for each instruction.
///
bool DarwinAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
DW.SetDebugInfo(&getAnalysis<MachineDebugInfo>());
SetupMachineFunction(MF);
O << "\n\n";
// Print out constants referenced by the function
EmitConstantPool(MF.getConstantPool());
// Print out labels for the function.
const Function *F = MF.getFunction();
SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
switch (F->getLinkage()) {
default: assert(0 && "Unknown linkage type!");
case Function::InternalLinkage: // Symbols default to internal.
break;
case Function::ExternalLinkage:
O << "\t.globl\t" << CurrentFnName << "\n";
break;
case Function::WeakLinkage:
case Function::LinkOnceLinkage:
O << "\t.globl\t" << CurrentFnName << "\n";
O << "\t.weak_definition\t" << CurrentFnName << "\n";
break;
}
EmitAlignment(4, F);
O << CurrentFnName << ":\n";
// Emit pre-function debug information.
DW.BeginFunction(&MF);
// 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()) {
printBasicBlockLabel(I, true);
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);
}
}
// Print out jump tables referenced by the function.
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
// Emit post-function debug information.
DW.EndFunction();
// We didn't modify anything.
return false;
}
bool DarwinAsmPrinter::doInitialization(Module &M) {
if (Subtarget.isGigaProcessor())
O << "\t.machine ppc970\n";
AsmPrinter::doInitialization(M);
// Darwin wants symbols to be quoted if they have complex names.
Mang->setUseQuotes(true);
// Emit initial debug information.
DW.BeginModule(&M);
return false;
}
bool DarwinAsmPrinter::doFinalization(Module &M) {
const TargetData *TD = TM.getTargetData();
// Print out module-level global variables here.
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I) {
if (!I->hasInitializer()) continue; // External global require no code
// Check to see if this is a special global used by LLVM, if so, emit it.
if (EmitSpecialLLVMGlobal(I))
continue;
std::string name = Mang->getValueName(I);
Constant *C = I->getInitializer();
unsigned Size = TD->getTypeSize(C->getType());
unsigned Align = TD->getPreferredAlignmentLog(I);
if (C->isNullValue() && /* FIXME: Verify correct */
(I->hasInternalLinkage() || I->hasWeakLinkage() ||
I->hasLinkOnceLinkage() ||
(I->hasExternalLinkage() && !I->hasSection()))) {
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
if (I->hasExternalLinkage()) {
O << "\t.globl " << name << '\n';
O << "\t.zerofill __DATA, __common, " << name << ", "
<< Size << ", " << Align;
} else if (I->hasInternalLinkage()) {
SwitchToDataSection("\t.data", I);
O << TAI->getLCOMMDirective() << name << "," << Size << "," << Align;
} else {
SwitchToDataSection("\t.data", I);
O << ".comm " << name << "," << Size;
}
O << "\t\t; '" << I->getName() << "'\n";
} else {
switch (I->getLinkage()) {
case GlobalValue::LinkOnceLinkage:
case GlobalValue::WeakLinkage:
O << "\t.globl " << name << '\n'
<< "\t.weak_definition " << name << '\n';
SwitchToDataSection(".section __DATA,__datacoal_nt,coalesced", I);
break;
case GlobalValue::AppendingLinkage:
// FIXME: appending linkage variables should go into a section of
// their name or something. For now, just emit them as external.
case GlobalValue::ExternalLinkage:
// If external or appending, declare as a global symbol
O << "\t.globl " << name << "\n";
// FALL THROUGH
case GlobalValue::InternalLinkage:
if (I->isConstant()) {
const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
if (TAI->getCStringSection() && CVA && CVA->isCString()) {
SwitchToDataSection(TAI->getCStringSection(), I);
break;
}
}
SwitchToDataSection("\t.data", I);
break;
default:
std::cerr << "Unknown linkage type!";
abort();
}
EmitAlignment(Align, I);
O << name << ":\t\t\t\t; '" << I->getName() << "'\n";
EmitGlobalConstant(C);
O << '\n';
}
}
bool isPPC64 = TD->getPointerSizeInBits() == 64;
// Output stubs for dynamically-linked functions
if (TM.getRelocationModel() == Reloc::PIC_) {
for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
i != e; ++i) {
SwitchToTextSection(".section __TEXT,__picsymbolstub1,symbol_stubs,"
"pure_instructions,32");
EmitAlignment(4);
O << "L" << *i << "$stub:\n";
O << "\t.indirect_symbol " << *i << "\n";
O << "\tmflr r0\n";
O << "\tbcl 20,31,L0$" << *i << "\n";
O << "L0$" << *i << ":\n";
O << "\tmflr r11\n";
O << "\taddis r11,r11,ha16(L" << *i << "$lazy_ptr-L0$" << *i << ")\n";
O << "\tmtlr r0\n";
if (isPPC64)
O << "\tldu r12,lo16(L" << *i << "$lazy_ptr-L0$" << *i << ")(r11)\n";
else
O << "\tlwzu r12,lo16(L" << *i << "$lazy_ptr-L0$" << *i << ")(r11)\n";
O << "\tmtctr r12\n";
O << "\tbctr\n";
SwitchToDataSection(".lazy_symbol_pointer");
O << "L" << *i << "$lazy_ptr:\n";
O << "\t.indirect_symbol " << *i << "\n";
if (isPPC64)
O << "\t.quad dyld_stub_binding_helper\n";
else
O << "\t.long dyld_stub_binding_helper\n";
}
} else {
for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
i != e; ++i) {
SwitchToTextSection(".section __TEXT,__symbol_stub1,symbol_stubs,"
"pure_instructions,16");
EmitAlignment(4);
O << "L" << *i << "$stub:\n";
O << "\t.indirect_symbol " << *i << "\n";
O << "\tlis r11,ha16(L" << *i << "$lazy_ptr)\n";
if (isPPC64)
O << "\tldu r12,lo16(L" << *i << "$lazy_ptr)(r11)\n";
else
O << "\tlwzu r12,lo16(L" << *i << "$lazy_ptr)(r11)\n";
O << "\tmtctr r12\n";
O << "\tbctr\n";
SwitchToDataSection(".lazy_symbol_pointer");
O << "L" << *i << "$lazy_ptr:\n";
O << "\t.indirect_symbol " << *i << "\n";
if (isPPC64)
O << "\t.quad dyld_stub_binding_helper\n";
else
O << "\t.long dyld_stub_binding_helper\n";
}
}
O << "\n";
// Output stubs for external and common global variables.
if (GVStubs.begin() != GVStubs.end()) {
SwitchToDataSection(".non_lazy_symbol_pointer");
for (std::set<std::string>::iterator I = GVStubs.begin(),
E = GVStubs.end(); I != E; ++I) {
O << "L" << *I << "$non_lazy_ptr:\n";
O << "\t.indirect_symbol " << *I << "\n";
if (isPPC64)
O << "\t.quad\t0\n";
else
O << "\t.long\t0\n";
}
}
// Emit initial debug information.
DW.EndModule();
// 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
}
/// createDarwinCodePrinterPass - 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::createPPCAsmPrinterPass(std::ostream &o,
PPCTargetMachine &tm) {
return new DarwinAsmPrinter(o, tm, tm.getTargetAsmInfo());
}