#define DEBUG_TYPE "asmprinter"
#include "PPC.h"
-#include "PPCPredicates.h"
#include "PPCTargetMachine.h"
#include "PPCSubtarget.h"
+#include "MCTargetDesc/PPCPredicates.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetOptions.h"
-#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/SmallString.h"
+#include "InstPrinter/PPCInstPrinter.h"
using namespace llvm;
namespace {
protected:
DenseMap<MCSymbol*, MCSymbol*> TOC;
const PPCSubtarget &Subtarget;
- uint64_t LabelID;
+ uint64_t TOCLabelID;
public:
explicit PPCAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
: AsmPrinter(TM, Streamer),
- Subtarget(TM.getSubtarget<PPCSubtarget>()), LabelID(0) {}
+ Subtarget(TM.getSubtarget<PPCSubtarget>()), TOCLabelID(0) {}
virtual const char *getPassName() const {
return "PowerPC Assembly Printer";
}
- unsigned enumRegToMachineReg(unsigned enumReg) {
- switch (enumReg) {
- default: llvm_unreachable("Unhandled register!");
- 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;
- }
- llvm_unreachable(0);
- }
-
- /// 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.
- void printInstruction(const MachineInstr *MI, raw_ostream &O);
- static const char *getRegisterName(unsigned RegNo);
-
virtual void EmitInstruction(const MachineInstr *MI);
- void printOp(const MachineOperand &MO, raw_ostream &O);
-
- /// stripRegisterPrefix - This method strips the character prefix from a
- /// register name so that only the number is left. Used by for linux asm.
- const char *stripRegisterPrefix(const char *RegName) {
- switch (RegName[0]) {
- case 'r':
- case 'f':
- case 'v': return RegName + 1;
- case 'c': if (RegName[1] == 'r') return RegName + 2;
- }
-
- return RegName;
- }
-
- /// printRegister - Print register according to target requirements.
- ///
- void printRegister(const MachineOperand &MO, bool R0AsZero, raw_ostream &O){
- unsigned RegNo = MO.getReg();
- assert(TargetRegisterInfo::isPhysicalRegister(RegNo) && "Not physreg??");
-
- // If we should use 0 for R0.
- if (R0AsZero && RegNo == PPC::R0) {
- O << "0";
- return;
- }
- const char *RegName = getRegisterName(RegNo);
- // Linux assembler (Others?) does not take register mnemonics.
- // FIXME - What about special registers used in mfspr/mtspr?
- if (!Subtarget.isDarwin()) RegName = stripRegisterPrefix(RegName);
- O << RegName;
- }
-
- void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
- const MachineOperand &MO = MI->getOperand(OpNo);
- if (MO.isReg()) {
- printRegister(MO, false, O);
- } else if (MO.isImm()) {
- O << MO.getImm();
- } else {
- printOp(MO, O);
- }
- }
+ void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O);
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O);
-
- void printS5ImmOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- char value = MI->getOperand(OpNo).getImm();
- value = (value << (32-5)) >> (32-5);
- O << (int)value;
- }
- void printU5ImmOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- unsigned char value = MI->getOperand(OpNo).getImm();
- assert(value <= 31 && "Invalid u5imm argument!");
- O << (unsigned int)value;
- }
- void printU6ImmOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- unsigned char value = MI->getOperand(OpNo).getImm();
- assert(value <= 63 && "Invalid u6imm argument!");
- O << (unsigned int)value;
- }
- void printS16ImmOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- O << (short)MI->getOperand(OpNo).getImm();
- }
- void printU16ImmOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- O << (unsigned short)MI->getOperand(OpNo).getImm();
- }
- void printS16X4ImmOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- if (MI->getOperand(OpNo).isImm()) {
- O << (short)(MI->getOperand(OpNo).getImm()*4);
- } else {
- O << "lo16(";
- printOp(MI->getOperand(OpNo), O);
- if (TM.getRelocationModel() == Reloc::PIC_)
- O << "-\"L" << getFunctionNumber() << "$pb\")";
- else
- O << ')';
- }
- }
- void printBranchOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- // 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).isImm()) {
- O << "$+" << MI->getOperand(OpNo).getImm()*4;
- } else {
- printOp(MI->getOperand(OpNo), O);
- }
- }
- void printCallOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- const MachineOperand &MO = MI->getOperand(OpNo);
- if (TM.getRelocationModel() != Reloc::Static) {
- if (MO.isGlobal()) {
- const GlobalValue *GV = MO.getGlobal();
- if (GV->isDeclaration() || GV->isWeakForLinker()) {
- // Dynamically-resolved functions need a stub for the function.
- MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$stub");
- MachineModuleInfoImpl::StubValueTy &StubSym =
- MMI->getObjFileInfo<MachineModuleInfoMachO>().getFnStubEntry(Sym);
- if (StubSym.getPointer() == 0)
- StubSym = MachineModuleInfoImpl::
- StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage());
- O << *Sym;
- return;
- }
- }
- if (MO.isSymbol()) {
- SmallString<128> TempNameStr;
- TempNameStr += StringRef(MO.getSymbolName());
- TempNameStr += StringRef("$stub");
-
- MCSymbol *Sym = GetExternalSymbolSymbol(TempNameStr.str());
- MachineModuleInfoImpl::StubValueTy &StubSym =
- MMI->getObjFileInfo<MachineModuleInfoMachO>().getFnStubEntry(Sym);
- if (StubSym.getPointer() == 0)
- StubSym = MachineModuleInfoImpl::
- StubValueTy(GetExternalSymbolSymbol(MO.getSymbolName()), true);
- O << *Sym;
- return;
- }
- }
-
- printOp(MI->getOperand(OpNo), O);
- }
- void printAbsAddrOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- O << (int)MI->getOperand(OpNo).getImm()*4;
- }
- void printPICLabel(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
- O << "\"L" << getFunctionNumber() << "$pb\"\n";
- O << "\"L" << getFunctionNumber() << "$pb\":";
- }
- void printSymbolHi(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
- if (MI->getOperand(OpNo).isImm()) {
- printS16ImmOperand(MI, OpNo, O);
- } else {
- if (Subtarget.isDarwin()) O << "ha16(";
- printOp(MI->getOperand(OpNo), O);
- if (TM.getRelocationModel() == Reloc::PIC_)
- O << "-\"L" << getFunctionNumber() << "$pb\"";
- if (Subtarget.isDarwin())
- O << ')';
- else
- O << "@ha";
- }
- }
- void printSymbolLo(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
- if (MI->getOperand(OpNo).isImm()) {
- printS16ImmOperand(MI, OpNo, O);
- } else {
- if (Subtarget.isDarwin()) O << "lo16(";
- printOp(MI->getOperand(OpNo), O);
- if (TM.getRelocationModel() == Reloc::PIC_)
- O << "-\"L" << getFunctionNumber() << "$pb\"";
- if (Subtarget.isDarwin())
- O << ')';
- else
- O << "@l";
- }
- }
- void printcrbitm(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
- 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, raw_ostream &O) {
- printSymbolLo(MI, OpNo, O);
- O << '(';
- if (MI->getOperand(OpNo+1).isReg() &&
- MI->getOperand(OpNo+1).getReg() == PPC::R0)
- O << "0";
- else
- printOperand(MI, OpNo+1, O);
- O << ')';
- }
- void printMemRegImmShifted(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- if (MI->getOperand(OpNo).isImm())
- printS16X4ImmOperand(MI, OpNo, O);
- else
- printSymbolLo(MI, OpNo, O);
- O << '(';
- if (MI->getOperand(OpNo+1).isReg() &&
- MI->getOperand(OpNo+1).getReg() == PPC::R0)
- O << "0";
- else
- printOperand(MI, OpNo+1, O);
- O << ')';
- }
-
- void printMemRegReg(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
- // 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);
- printRegister(MO, true, O);
- O << ", ";
- printOperand(MI, OpNo+1, O);
- }
-
- void printTOCEntryLabel(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
- const MachineOperand &MO = MI->getOperand(OpNo);
- assert(MO.isGlobal());
- MCSymbol *Sym = Mang->getSymbol(MO.getGlobal());
-
- // Map symbol -> label of TOC entry.
- MCSymbol *&TOCEntry = TOC[Sym];
- if (TOCEntry == 0)
- TOCEntry = OutContext.
- GetOrCreateSymbol(StringRef(MAI->getPrivateGlobalPrefix()) +
- "C" + Twine(LabelID++));
-
- O << *TOCEntry << "@toc";
- }
-
- void printPredicateOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O, const char *Modifier);
-
MachineLocation getDebugValueLocation(const MachineInstr *MI) const {
-
MachineLocation Location;
- assert (MI->getNumOperands() == 4 && "Invalid no. of machine operands!");
+ assert(MI->getNumOperands() == 4 && "Invalid no. of machine operands!");
// Frame address. Currently handles register +- offset only.
if (MI->getOperand(0).isReg() && MI->getOperand(2).isImm())
Location.set(MI->getOperand(0).getReg(), MI->getOperand(2).getImm());
};
} // end of anonymous namespace
-// Include the auto-generated portion of the assembly writer
-#include "PPCGenAsmWriter.inc"
+/// stripRegisterPrefix - This method strips the character prefix from a
+/// register name so that only the number is left. Used by for linux asm.
+static const char *stripRegisterPrefix(const char *RegName) {
+ switch (RegName[0]) {
+ case 'r':
+ case 'f':
+ case 'v': return RegName + 1;
+ case 'c': if (RegName[1] == 'r') return RegName + 2;
+ }
+
+ return RegName;
+}
-void PPCAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) {
+void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
+ raw_ostream &O) {
+ const MachineOperand &MO = MI->getOperand(OpNo);
+
switch (MO.getType()) {
+ case MachineOperand::MO_Register: {
+ const char *RegName = PPCInstPrinter::getRegisterName(MO.getReg());
+ // Linux assembler (Others?) does not take register mnemonics.
+ // FIXME - What about special registers used in mfspr/mtspr?
+ if (!Subtarget.isDarwin()) RegName = stripRegisterPrefix(RegName);
+ O << RegName;
+ return;
+ }
case MachineOperand::MO_Immediate:
- llvm_unreachable("printOp() does not handle immediate values");
+ O << MO.getImm();
+ return;
case MachineOperand::MO_MachineBasicBlock:
O << *MO.getMBB()->getSymbol();
switch (ExtraCode[0]) {
default: return true; // Unknown modifier.
case 'c': // Don't print "$" before a global var name or constant.
- // PPC never has a prefix.
- printOperand(MI, OpNo, O);
- return false;
+ break; // PPC never has a prefix.
case 'L': // Write second word of DImode reference.
// Verify that this operand has two consecutive registers.
if (!MI->getOperand(OpNo).isReg() ||
raw_ostream &O) {
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier.
- assert (MI->getOperand(OpNo).isReg());
+ assert(MI->getOperand(OpNo).isReg());
O << "0(";
printOperand(MI, OpNo, O);
O << ")";
return false;
}
-void PPCAsmPrinter::printPredicateOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O, const char *Modifier){
- assert(Modifier && "Must specify 'cc' or 'reg' as predicate op modifier!");
- unsigned Code = MI->getOperand(OpNo).getImm();
- if (!strcmp(Modifier, "cc")) {
- switch ((PPC::Predicate)Code) {
- case PPC::PRED_ALWAYS: return; // Don't print anything for always.
- case PPC::PRED_LT: O << "lt"; return;
- case PPC::PRED_LE: O << "le"; return;
- case PPC::PRED_EQ: O << "eq"; return;
- case PPC::PRED_GE: O << "ge"; return;
- case PPC::PRED_GT: O << "gt"; return;
- case PPC::PRED_NE: O << "ne"; return;
- case PPC::PRED_UN: O << "un"; return;
- case PPC::PRED_NU: O << "nu"; return;
- }
-
- } else {
- assert(!strcmp(Modifier, "reg") &&
- "Need to specify 'cc' or 'reg' as predicate op modifier!");
- // Don't print the register for 'always'.
- if (Code == PPC::PRED_ALWAYS) return;
- printOperand(MI, OpNo+1, O);
- }
-}
-
/// EmitInstruction -- Print out a single PowerPC MI in Darwin syntax to
/// the current output stream.
///
void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
- SmallString<128> Str;
- raw_svector_ostream O(Str);
-
- if (MI->getOpcode() == TargetOpcode::DBG_VALUE) {
+ MCInst TmpInst;
+
+ // Lower multi-instruction pseudo operations.
+ switch (MI->getOpcode()) {
+ default: break;
+ case TargetOpcode::DBG_VALUE: {
+ if (!isVerbose() || !OutStreamer.hasRawTextSupport()) return;
+
+ SmallString<32> Str;
+ raw_svector_ostream O(Str);
unsigned NOps = MI->getNumOperands();
assert(NOps==4);
O << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
OutStreamer.EmitRawText(O.str());
return;
}
- // Check for slwi/srwi mnemonics.
- if (MI->getOpcode() == PPC::RLWINM) {
- unsigned char SH = MI->getOperand(2).getImm();
- unsigned char MB = MI->getOperand(3).getImm();
- unsigned char ME = MI->getOperand(4).getImm();
- bool useSubstituteMnemonic = false;
- if (SH <= 31 && MB == 0 && ME == (31-SH)) {
- O << "\tslwi "; useSubstituteMnemonic = true;
- }
- if (SH <= 31 && MB == (32-SH) && ME == 31) {
- O << "\tsrwi "; useSubstituteMnemonic = true;
- SH = 32-SH;
- }
- if (useSubstituteMnemonic) {
- printOperand(MI, 0, O);
- O << ", ";
- printOperand(MI, 1, O);
- O << ", " << (unsigned int)SH;
- OutStreamer.EmitRawText(O.str());
- return;
- }
+
+ case PPC::MovePCtoLR:
+ case PPC::MovePCtoLR8: {
+ // Transform %LR = MovePCtoLR
+ // Into this, where the label is the PIC base:
+ // bl L1$pb
+ // L1$pb:
+ MCSymbol *PICBase = MF->getPICBaseSymbol();
+
+ // Emit the 'bl'.
+ TmpInst.setOpcode(PPC::BL_Darwin); // Darwin vs SVR4 doesn't matter here.
+
+
+ // FIXME: We would like an efficient form for this, so we don't have to do
+ // a lot of extra uniquing.
+ TmpInst.addOperand(MCOperand::CreateExpr(MCSymbolRefExpr::
+ Create(PICBase, OutContext)));
+ OutStreamer.EmitInstruction(TmpInst);
+
+ // Emit the label.
+ OutStreamer.EmitLabel(PICBase);
+ return;
}
-
- if ((MI->getOpcode() == PPC::OR || MI->getOpcode() == PPC::OR8) &&
- MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) {
- O << "\tmr ";
- printOperand(MI, 0, O);
- O << ", ";
- printOperand(MI, 1, O);
- OutStreamer.EmitRawText(O.str());
+ case PPC::LDtoc: {
+ // Transform %X3 = LDtoc <ga:@min1>, %X2
+ LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin());
+
+ // Change the opcode to LD, and the global address operand to be a
+ // reference to the TOC entry we will synthesize later.
+ TmpInst.setOpcode(PPC::LD);
+ const MachineOperand &MO = MI->getOperand(1);
+ assert(MO.isGlobal());
+
+ // Map symbol -> label of TOC entry.
+ MCSymbol *&TOCEntry = TOC[Mang->getSymbol(MO.getGlobal())];
+ if (TOCEntry == 0)
+ TOCEntry = GetTempSymbol("C", TOCLabelID++);
+
+ const MCExpr *Exp =
+ MCSymbolRefExpr::Create(TOCEntry, MCSymbolRefExpr::VK_PPC_TOC,
+ OutContext);
+ TmpInst.getOperand(1) = MCOperand::CreateExpr(Exp);
+ OutStreamer.EmitInstruction(TmpInst);
return;
}
-
- if (MI->getOpcode() == PPC::RLDICR) {
- unsigned char SH = MI->getOperand(2).getImm();
- unsigned char ME = MI->getOperand(3).getImm();
- // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
- if (63-SH == ME) {
- O << "\tsldi ";
- printOperand(MI, 0, O);
- O << ", ";
- printOperand(MI, 1, O);
- O << ", " << (unsigned int)SH;
- OutStreamer.EmitRawText(O.str());
+
+ case PPC::MFCRpseud:
+ // Transform: %R3 = MFCRpseud %CR7
+ // Into: %R3 = MFCR ;; cr7
+ OutStreamer.AddComment(PPCInstPrinter::
+ getRegisterName(MI->getOperand(1).getReg()));
+ TmpInst.setOpcode(PPC::MFCR);
+ TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
+ OutStreamer.EmitInstruction(TmpInst);
+ return;
+ case PPC::SYNC:
+ // In Book E sync is called msync, handle this special case here...
+ if (Subtarget.isBookE()) {
+ OutStreamer.EmitRawText(StringRef("\tmsync"));
return;
}
}
- printInstruction(MI, O);
- OutStreamer.EmitRawText(O.str());
+ LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin());
+ OutStreamer.EmitInstruction(TmpInst);
}
void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() {
static const char *const CPUDirectives[] = {
"",
"ppc",
+ "ppc440",
"ppc601",
"ppc602",
"ppc603",
Directive = PPC::DIR_970;
if (Subtarget.hasAltivec() && Directive < PPC::DIR_7400)
Directive = PPC::DIR_7400;
- if (Subtarget.isPPC64() && Directive < PPC::DIR_970)
+ if (Subtarget.isPPC64() && Directive < PPC::DIR_64)
Directive = PPC::DIR_64;
assert(Directive <= PPC::DIR_64 && "Directive out of range.");
- OutStreamer.EmitRawText("\t.machine " + Twine(CPUDirectives[Directive]));
+
+ // FIXME: This is a total hack, finish mc'izing the PPC backend.
+ if (OutStreamer.hasRawTextSupport())
+ OutStreamer.EmitRawText("\t.machine " + Twine(CPUDirectives[Directive]));
// Prime text sections so they are adjacent. This reduces the likelihood a
// large data or debug section causes a branch to exceed 16M limit.