//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "asm-printer"
+#include "X86ATTInstPrinter.h"
#include "llvm/MC/MCInst.h"
-#include "X86ATTAsmPrinter.h"
-#include "llvm/Target/TargetAsmInfo.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormattedStream.h"
+#include "X86GenInstrNames.inc"
using namespace llvm;
// Include the auto-generated portion of the assembly writer.
#define MachineInstr MCInst
-#define NO_ASM_WRITER_BOILERPLATE
+#define GET_INSTRUCTION_NAME
#include "X86GenAsmWriter.inc"
#undef MachineInstr
-void X86ATTAsmPrinter::printSSECC(const MCInst *MI, unsigned Op) {
+void X86ATTInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); }
+StringRef X86ATTInstPrinter::getOpcodeName(unsigned Opcode) const {
+ return getInstructionName(Opcode);
+}
+
+
+void X86ATTInstPrinter::printSSECC(const MCInst *MI, unsigned Op) {
switch (MI->getOperand(Op).getImm()) {
- default: assert(0 && "Invalid ssecc argument!");
+ default: llvm_unreachable("Invalid ssecc argument!");
case 0: O << "eq"; break;
case 1: O << "lt"; break;
case 2: O << "le"; break;
}
}
-
-void X86ATTAsmPrinter::printPICLabel(const MCInst *MI, unsigned Op) {
- assert(0 &&
- "This is only used for MOVPC32r, should lower before asm printing!");
+/// print_pcrel_imm - This is used to print an immediate value that ends up
+/// being encoded as a pc-relative value (e.g. for jumps and calls). These
+/// print slightly differently than normal immediates. For example, a $ is not
+/// emitted.
+void X86ATTInstPrinter::print_pcrel_imm(const MCInst *MI, unsigned OpNo) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+ if (Op.isImm())
+ // Print this as a signed 32-bit value.
+ O << (int)Op.getImm();
+ else {
+ assert(Op.isExpr() && "unknown pcrel immediate operand");
+ O << *Op.getExpr();
+ }
}
-
-void X86ATTAsmPrinter::printOperand(const MCInst *MI, unsigned OpNo,
- const char *Modifier, bool NotRIPRel) {
- assert(Modifier == 0 && "Modifiers should not be used");
+void X86ATTInstPrinter::printOperand(const MCInst *MI, unsigned OpNo) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isReg()) {
- O << '%';
- unsigned Reg = Op.getReg();
-#if 0
- if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) {
- MVT VT = (strcmp(Modifier+6,"64") == 0) ?
- MVT::i64 : ((strcmp(Modifier+6, "32") == 0) ? MVT::i32 :
- ((strcmp(Modifier+6,"16") == 0) ? MVT::i16 : MVT::i8));
- Reg = getX86SubSuperRegister(Reg, VT);
- }
-#endif
- O << TRI->getAsmName(Reg);
- return;
+ O << '%' << getRegisterName(Op.getReg());
} else if (Op.isImm()) {
- //if (!Modifier || (strcmp(Modifier, "debug") && strcmp(Modifier, "mem") &&
- // strcmp(Modifier, "call")))
- O << '$';
- O << Op.getImm();
- return;
- } else if (Op.isMBBLabel()) {
- // FIXME: Keep in sync with printBasicBlockLabel. printBasicBlockLabel
- // should eventually call into this code, not the other way around.
+ O << '$' << Op.getImm();
- O << TAI->getPrivateGlobalPrefix() << "BB" << Op.getMBBLabelFunction()
- << '_' << Op.getMBBLabelBlock();
+ if (CommentStream && (Op.getImm() > 255 || Op.getImm() < -256))
+ *CommentStream << format("imm = 0x%llX\n", (long long)Op.getImm());
- // FIXME: with verbose asm print llvm bb name, add to operand.
- return;
- }
-
- O << "<<UNKNOWN OPERAND KIND>>";
-
-
-#if 0
- const MachineOperand &MO = MI->getOperand(OpNo);
- switch (MO.getType()) {
- case MachineOperand::MO_Register: {
- assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
- "Virtual registers should not make it this far!");
- O << '%';
- unsigned Reg = MO.getReg();
- if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) {
- MVT VT = (strcmp(Modifier+6,"64") == 0) ?
- MVT::i64 : ((strcmp(Modifier+6, "32") == 0) ? MVT::i32 :
- ((strcmp(Modifier+6,"16") == 0) ? MVT::i16 : MVT::i8));
- Reg = getX86SubSuperRegister(Reg, VT);
- }
- O << TRI->getAsmName(Reg);
- return;
- }
-
- case MachineOperand::MO_Immediate:
- if (!Modifier || (strcmp(Modifier, "debug") &&
- strcmp(Modifier, "mem") &&
- strcmp(Modifier, "call")))
- O << '$';
- O << MO.getImm();
- return;
- case MachineOperand::MO_MachineBasicBlock:
- printBasicBlockLabel(MO.getMBB(), false, false, VerboseAsm);
- return;
- case MachineOperand::MO_JumpTableIndex: {
- bool isMemOp = Modifier && !strcmp(Modifier, "mem");
- if (!isMemOp) O << '$';
- O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_'
- << MO.getIndex();
-
- if (TM.getRelocationModel() == Reloc::PIC_) {
- if (Subtarget->isPICStyleStub())
- O << "-\"" << TAI->getPrivateGlobalPrefix() << getFunctionNumber()
- << "$pb\"";
- else if (Subtarget->isPICStyleGOT())
- O << "@GOTOFF";
- }
-
- if (isMemOp && Subtarget->isPICStyleRIPRel() && !NotRIPRel)
- O << "(%rip)";
- return;
- }
- case MachineOperand::MO_ConstantPoolIndex: {
- bool isMemOp = Modifier && !strcmp(Modifier, "mem");
- if (!isMemOp) O << '$';
- O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_'
- << MO.getIndex();
-
- if (TM.getRelocationModel() == Reloc::PIC_) {
- if (Subtarget->isPICStyleStub())
- O << "-\"" << TAI->getPrivateGlobalPrefix() << getFunctionNumber()
- << "$pb\"";
- else if (Subtarget->isPICStyleGOT())
- O << "@GOTOFF";
- }
-
- printOffset(MO.getOffset());
-
- if (isMemOp && Subtarget->isPICStyleRIPRel() && !NotRIPRel)
- O << "(%rip)";
- return;
- }
- case MachineOperand::MO_GlobalAddress: {
- bool isCallOp = Modifier && !strcmp(Modifier, "call");
- bool isMemOp = Modifier && !strcmp(Modifier, "mem");
- bool needCloseParen = false;
-
- const GlobalValue *GV = MO.getGlobal();
- const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
- if (!GVar) {
- // If GV is an alias then use the aliasee for determining
- // thread-localness.
- if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
- GVar = dyn_cast_or_null<GlobalVariable>(GA->resolveAliasedGlobal(false));
- }
-
- bool isThreadLocal = GVar && GVar->isThreadLocal();
-
- std::string Name = Mang->getValueName(GV);
- decorateName(Name, GV);
-
- if (!isMemOp && !isCallOp)
- O << '$';
- else if (Name[0] == '$') {
- // The name begins with a dollar-sign. In order to avoid having it look
- // like an integer immediate to the assembler, enclose it in parens.
- O << '(';
- needCloseParen = true;
- }
-
- if (shouldPrintStub(TM, Subtarget)) {
- // Link-once, declaration, or Weakly-linked global variables need
- // non-lazily-resolved stubs
- if (GV->isDeclaration() || GV->isWeakForLinker()) {
- // Dynamically-resolved functions need a stub for the function.
- if (isCallOp && isa<Function>(GV)) {
- // Function stubs are no longer needed for Mac OS X 10.5 and up.
- if (Subtarget->isTargetDarwin() && Subtarget->getDarwinVers() >= 9) {
- O << Name;
- } else {
- FnStubs.insert(Name);
- printSuffixedName(Name, "$stub");
- }
- } else if (GV->hasHiddenVisibility()) {
- if (!GV->isDeclaration() && !GV->hasCommonLinkage())
- // Definition is not definitely in the current translation unit.
- O << Name;
- else {
- HiddenGVStubs.insert(Name);
- printSuffixedName(Name, "$non_lazy_ptr");
- }
- } else {
- GVStubs.insert(Name);
- printSuffixedName(Name, "$non_lazy_ptr");
- }
- } else {
- if (GV->hasDLLImportLinkage())
- O << "__imp_";
- O << Name;
- }
-
- if (!isCallOp && TM.getRelocationModel() == Reloc::PIC_)
- O << '-' << getPICLabelString(getFunctionNumber(), TAI, Subtarget);
- } else {
- if (GV->hasDLLImportLinkage()) {
- O << "__imp_";
- }
- O << Name;
-
- if (isCallOp) {
- if (shouldPrintPLT(TM, Subtarget)) {
- // Assemble call via PLT for externally visible symbols
- if (!GV->hasHiddenVisibility() && !GV->hasProtectedVisibility() &&
- !GV->hasLocalLinkage())
- O << "@PLT";
- }
- if (Subtarget->isTargetCygMing() && GV->isDeclaration())
- // Save function name for later type emission
- FnStubs.insert(Name);
- }
- }
-
- if (GV->hasExternalWeakLinkage())
- ExtWeakSymbols.insert(GV);
-
- printOffset(MO.getOffset());
-
- if (isThreadLocal) {
- TLSModel::Model model = getTLSModel(GVar, TM.getRelocationModel());
- switch (model) {
- case TLSModel::GeneralDynamic:
- O << "@TLSGD";
- break;
- case TLSModel::LocalDynamic:
- // O << "@TLSLD"; // local dynamic not implemented
- O << "@TLSGD";
- break;
- case TLSModel::InitialExec:
- if (Subtarget->is64Bit()) {
- assert (!NotRIPRel);
- O << "@GOTTPOFF(%rip)";
- } else {
- O << "@INDNTPOFF";
- }
- break;
- case TLSModel::LocalExec:
- if (Subtarget->is64Bit())
- O << "@TPOFF";
- else
- O << "@NTPOFF";
- break;
- default:
- assert (0 && "Unknown TLS model");
- }
- } else if (isMemOp) {
- if (shouldPrintGOT(TM, Subtarget)) {
- if (Subtarget->GVRequiresExtraLoad(GV, TM, false))
- O << "@GOT";
- else
- O << "@GOTOFF";
- } else if (Subtarget->isPICStyleRIPRel() && !NotRIPRel) {
- if (TM.getRelocationModel() != Reloc::Static) {
- if (Subtarget->GVRequiresExtraLoad(GV, TM, false))
- O << "@GOTPCREL";
-
- if (needCloseParen) {
- needCloseParen = false;
- O << ')';
- }
- }
-
- // Use rip when possible to reduce code size, except when
- // index or base register are also part of the address. e.g.
- // foo(%rip)(%rcx,%rax,4) is not legal
- O << "(%rip)";
- }
- }
-
- if (needCloseParen)
- O << ')';
-
- return;
- }
- case MachineOperand::MO_ExternalSymbol: {
- bool isCallOp = Modifier && !strcmp(Modifier, "call");
- bool isMemOp = Modifier && !strcmp(Modifier, "mem");
- bool needCloseParen = false;
- std::string Name(TAI->getGlobalPrefix());
- Name += MO.getSymbolName();
- // Print function stub suffix unless it's Mac OS X 10.5 and up.
- if (isCallOp && shouldPrintStub(TM, Subtarget) &&
- !(Subtarget->isTargetDarwin() && Subtarget->getDarwinVers() >= 9)) {
- FnStubs.insert(Name);
- printSuffixedName(Name, "$stub");
- return;
- }
- if (!isMemOp && !isCallOp)
- O << '$';
- else if (Name[0] == '$') {
- // The name begins with a dollar-sign. In order to avoid having it look
- // like an integer immediate to the assembler, enclose it in parens.
- O << '(';
- needCloseParen = true;
- }
-
- O << Name;
-
- if (shouldPrintPLT(TM, Subtarget)) {
- std::string GOTName(TAI->getGlobalPrefix());
- GOTName+="_GLOBAL_OFFSET_TABLE_";
- if (Name == GOTName)
- // HACK! Emit extra offset to PC during printing GOT offset to
- // compensate for the size of popl instruction. The resulting code
- // should look like:
- // call .piclabel
- // piclabel:
- // popl %some_register
- // addl $_GLOBAL_ADDRESS_TABLE_ + [.-piclabel], %some_register
- O << " + [.-"
- << getPICLabelString(getFunctionNumber(), TAI, Subtarget) << ']';
-
- if (isCallOp)
- O << "@PLT";
- }
-
- if (needCloseParen)
- O << ')';
-
- if (!isCallOp && Subtarget->isPICStyleRIPRel())
- O << "(%rip)";
-
- return;
- }
- default:
- O << "<unknown operand type>"; return;
+ } else {
+ assert(Op.isExpr() && "unknown operand kind in printOperand");
+ O << '$' << *Op.getExpr();
}
-#endif
}
-void X86ATTAsmPrinter::printLeaMemReference(const MCInst *MI, unsigned Op) {
- const char *Modifier = 0;
- bool NotRIPRel = false;
-
+void X86ATTInstPrinter::printLeaMemReference(const MCInst *MI, unsigned Op) {
const MCOperand &BaseReg = MI->getOperand(Op);
const MCOperand &IndexReg = MI->getOperand(Op+2);
const MCOperand &DispSpec = MI->getOperand(Op+3);
- NotRIPRel |= IndexReg.getReg() || BaseReg.getReg();
if (DispSpec.isImm()) {
int64_t DispVal = DispSpec.getImm();
if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg()))
O << DispVal;
} else {
- abort();
- //assert(DispSpec.isGlobal() || DispSpec.isCPI() ||
- // DispSpec.isJTI() || DispSpec.isSymbol());
- //printOperand(MI, Op+3, "mem", NotRIPRel);
+ assert(DispSpec.isExpr() && "non-immediate displacement for LEA?");
+ O << *DispSpec.getExpr();
}
if (IndexReg.getReg() || BaseReg.getReg()) {
- unsigned ScaleVal = MI->getOperand(Op+1).getImm();
- unsigned BaseRegOperand = 0, IndexRegOperand = 2;
-
- // There are cases where we can end up with ESP/RSP in the indexreg slot.
- // If this happens, swap the base/index register to support assemblers that
- // don't work when the index is *SP.
- // FIXME: REMOVE THIS.
- if (IndexReg.getReg() == X86::ESP || IndexReg.getReg() == X86::RSP) {
- assert(ScaleVal == 1 && "Scale not supported for stack pointer!");
- abort();
- //std::swap(BaseReg, IndexReg);
- //std::swap(BaseRegOperand, IndexRegOperand);
- }
-
O << '(';
if (BaseReg.getReg())
- printOperand(MI, Op+BaseRegOperand, Modifier);
+ printOperand(MI, Op);
if (IndexReg.getReg()) {
O << ',';
- printOperand(MI, Op+IndexRegOperand, Modifier);
+ printOperand(MI, Op+2);
+ unsigned ScaleVal = MI->getOperand(Op+1).getImm();
if (ScaleVal != 1)
O << ',' << ScaleVal;
}
}
}
-void X86ATTAsmPrinter::printMemReference(const MCInst *MI, unsigned Op) {
- //assert(isMem(MI, Op) && "Invalid memory reference!");
- const MCOperand &Segment = MI->getOperand(Op+4);
- if (Segment.getReg()) {
+void X86ATTInstPrinter::printMemReference(const MCInst *MI, unsigned Op) {
+ // If this has a segment register, print it.
+ if (MI->getOperand(Op+4).getReg()) {
printOperand(MI, Op+4);
O << ':';
}