| //===- MipsMCInstLower.cpp - Convert Mips MachineInstr to MCInst ----------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file contains code to lower Mips MachineInstrs to their corresponding | |
| // MCInst records. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "MipsMCInstLower.h" | |
| #include "MCTargetDesc/MipsBaseInfo.h" | |
| #include "MCTargetDesc/MipsMCExpr.h" | |
| #include "MipsAsmPrinter.h" | |
| #include "llvm/CodeGen/MachineBasicBlock.h" | |
| #include "llvm/CodeGen/MachineInstr.h" | |
| #include "llvm/CodeGen/MachineOperand.h" | |
| #include "llvm/MC/MCExpr.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include <cassert> | |
| using namespace llvm; | |
| MipsMCInstLower::MipsMCInstLower(MipsAsmPrinter &asmprinter) | |
| : AsmPrinter(asmprinter) {} | |
| void MipsMCInstLower::Initialize(MCContext *C) { | |
| Ctx = C; | |
| } | |
| MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO, | |
| MachineOperandType MOTy, | |
| unsigned Offset) const { | |
| MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None; | |
| MipsMCExpr::MipsExprKind TargetKind = MipsMCExpr::MEK_None; | |
| bool IsGpOff = false; | |
| const MCSymbol *Symbol; | |
| switch(MO.getTargetFlags()) { | |
| default: | |
| llvm_unreachable("Invalid target flag!"); | |
| case MipsII::MO_NO_FLAG: | |
| break; | |
| case MipsII::MO_GPREL: | |
| TargetKind = MipsMCExpr::MEK_GPREL; | |
| break; | |
| case MipsII::MO_GOT_CALL: | |
| TargetKind = MipsMCExpr::MEK_GOT_CALL; | |
| break; | |
| case MipsII::MO_GOT: | |
| TargetKind = MipsMCExpr::MEK_GOT; | |
| break; | |
| case MipsII::MO_ABS_HI: | |
| TargetKind = MipsMCExpr::MEK_HI; | |
| break; | |
| case MipsII::MO_ABS_LO: | |
| TargetKind = MipsMCExpr::MEK_LO; | |
| break; | |
| case MipsII::MO_TLSGD: | |
| TargetKind = MipsMCExpr::MEK_TLSGD; | |
| break; | |
| case MipsII::MO_TLSLDM: | |
| TargetKind = MipsMCExpr::MEK_TLSLDM; | |
| break; | |
| case MipsII::MO_DTPREL_HI: | |
| TargetKind = MipsMCExpr::MEK_DTPREL_HI; | |
| break; | |
| case MipsII::MO_DTPREL_LO: | |
| TargetKind = MipsMCExpr::MEK_DTPREL_LO; | |
| break; | |
| case MipsII::MO_GOTTPREL: | |
| TargetKind = MipsMCExpr::MEK_GOTTPREL; | |
| break; | |
| case MipsII::MO_TPREL_HI: | |
| TargetKind = MipsMCExpr::MEK_TPREL_HI; | |
| break; | |
| case MipsII::MO_TPREL_LO: | |
| TargetKind = MipsMCExpr::MEK_TPREL_LO; | |
| break; | |
| case MipsII::MO_GPOFF_HI: | |
| TargetKind = MipsMCExpr::MEK_HI; | |
| IsGpOff = true; | |
| break; | |
| case MipsII::MO_GPOFF_LO: | |
| TargetKind = MipsMCExpr::MEK_LO; | |
| IsGpOff = true; | |
| break; | |
| case MipsII::MO_GOT_DISP: | |
| TargetKind = MipsMCExpr::MEK_GOT_DISP; | |
| break; | |
| case MipsII::MO_GOT_HI16: | |
| TargetKind = MipsMCExpr::MEK_GOT_HI16; | |
| break; | |
| case MipsII::MO_GOT_LO16: | |
| TargetKind = MipsMCExpr::MEK_GOT_LO16; | |
| break; | |
| case MipsII::MO_GOT_PAGE: | |
| TargetKind = MipsMCExpr::MEK_GOT_PAGE; | |
| break; | |
| case MipsII::MO_GOT_OFST: | |
| TargetKind = MipsMCExpr::MEK_GOT_OFST; | |
| break; | |
| case MipsII::MO_HIGHER: | |
| TargetKind = MipsMCExpr::MEK_HIGHER; | |
| break; | |
| case MipsII::MO_HIGHEST: | |
| TargetKind = MipsMCExpr::MEK_HIGHEST; | |
| break; | |
| case MipsII::MO_CALL_HI16: | |
| TargetKind = MipsMCExpr::MEK_CALL_HI16; | |
| break; | |
| case MipsII::MO_CALL_LO16: | |
| TargetKind = MipsMCExpr::MEK_CALL_LO16; | |
| break; | |
| } | |
| switch (MOTy) { | |
| case MachineOperand::MO_MachineBasicBlock: | |
| Symbol = MO.getMBB()->getSymbol(); | |
| break; | |
| case MachineOperand::MO_GlobalAddress: | |
| Symbol = AsmPrinter.getSymbol(MO.getGlobal()); | |
| Offset += MO.getOffset(); | |
| break; | |
| case MachineOperand::MO_BlockAddress: | |
| Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress()); | |
| Offset += MO.getOffset(); | |
| break; | |
| case MachineOperand::MO_ExternalSymbol: | |
| Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName()); | |
| Offset += MO.getOffset(); | |
| break; | |
| case MachineOperand::MO_MCSymbol: | |
| Symbol = MO.getMCSymbol(); | |
| Offset += MO.getOffset(); | |
| break; | |
| case MachineOperand::MO_JumpTableIndex: | |
| Symbol = AsmPrinter.GetJTISymbol(MO.getIndex()); | |
| break; | |
| case MachineOperand::MO_ConstantPoolIndex: | |
| Symbol = AsmPrinter.GetCPISymbol(MO.getIndex()); | |
| Offset += MO.getOffset(); | |
| break; | |
| default: | |
| llvm_unreachable("<unknown operand type>"); | |
| } | |
| const MCExpr *Expr = MCSymbolRefExpr::create(Symbol, Kind, *Ctx); | |
| if (Offset) { | |
| // Assume offset is never negative. | |
| assert(Offset > 0); | |
| Expr = MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, *Ctx), | |
| *Ctx); | |
| } | |
| if (IsGpOff) | |
| Expr = MipsMCExpr::createGpOff(TargetKind, Expr, *Ctx); | |
| else if (TargetKind != MipsMCExpr::MEK_None) | |
| Expr = MipsMCExpr::create(TargetKind, Expr, *Ctx); | |
| return MCOperand::createExpr(Expr); | |
| } | |
| MCOperand MipsMCInstLower::LowerOperand(const MachineOperand &MO, | |
| unsigned offset) const { | |
| MachineOperandType MOTy = MO.getType(); | |
| switch (MOTy) { | |
| default: llvm_unreachable("unknown operand type"); | |
| case MachineOperand::MO_Register: | |
| // Ignore all implicit register operands. | |
| if (MO.isImplicit()) break; | |
| return MCOperand::createReg(MO.getReg()); | |
| case MachineOperand::MO_Immediate: | |
| return MCOperand::createImm(MO.getImm() + offset); | |
| case MachineOperand::MO_MachineBasicBlock: | |
| case MachineOperand::MO_GlobalAddress: | |
| case MachineOperand::MO_ExternalSymbol: | |
| case MachineOperand::MO_MCSymbol: | |
| case MachineOperand::MO_JumpTableIndex: | |
| case MachineOperand::MO_ConstantPoolIndex: | |
| case MachineOperand::MO_BlockAddress: | |
| return LowerSymbolOperand(MO, MOTy, offset); | |
| case MachineOperand::MO_RegisterMask: | |
| break; | |
| } | |
| return MCOperand(); | |
| } | |
| MCOperand MipsMCInstLower::createSub(MachineBasicBlock *BB1, | |
| MachineBasicBlock *BB2, | |
| MipsMCExpr::MipsExprKind Kind) const { | |
| const MCSymbolRefExpr *Sym1 = MCSymbolRefExpr::create(BB1->getSymbol(), *Ctx); | |
| const MCSymbolRefExpr *Sym2 = MCSymbolRefExpr::create(BB2->getSymbol(), *Ctx); | |
| const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Sym1, Sym2, *Ctx); | |
| return MCOperand::createExpr(MipsMCExpr::create(Kind, Sub, *Ctx)); | |
| } | |
| void MipsMCInstLower:: | |
| lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI) const { | |
| OutMI.setOpcode(Mips::LUi); | |
| // Lower register operand. | |
| OutMI.addOperand(LowerOperand(MI->getOperand(0))); | |
| MipsMCExpr::MipsExprKind Kind; | |
| unsigned TargetFlags = MI->getOperand(1).getTargetFlags(); | |
| switch (TargetFlags) { | |
| case MipsII::MO_HIGHEST: | |
| Kind = MipsMCExpr::MEK_HIGHEST; | |
| break; | |
| case MipsII::MO_HIGHER: | |
| Kind = MipsMCExpr::MEK_HIGHER; | |
| break; | |
| case MipsII::MO_ABS_HI: | |
| Kind = MipsMCExpr::MEK_HI; | |
| break; | |
| case MipsII::MO_ABS_LO: | |
| Kind = MipsMCExpr::MEK_LO; | |
| break; | |
| default: | |
| report_fatal_error("Unexpected flags for lowerLongBranchLUi"); | |
| } | |
| if (MI->getNumOperands() == 2) { | |
| const MCExpr *Expr = | |
| MCSymbolRefExpr::create(MI->getOperand(1).getMBB()->getSymbol(), *Ctx); | |
| const MipsMCExpr *MipsExpr = MipsMCExpr::create(Kind, Expr, *Ctx); | |
| OutMI.addOperand(MCOperand::createExpr(MipsExpr)); | |
| } else if (MI->getNumOperands() == 3) { | |
| // Create %hi($tgt-$baltgt). | |
| OutMI.addOperand(createSub(MI->getOperand(1).getMBB(), | |
| MI->getOperand(2).getMBB(), Kind)); | |
| } | |
| } | |
| void MipsMCInstLower::lowerLongBranchADDiu(const MachineInstr *MI, | |
| MCInst &OutMI, int Opcode) const { | |
| OutMI.setOpcode(Opcode); | |
| MipsMCExpr::MipsExprKind Kind; | |
| unsigned TargetFlags = MI->getOperand(2).getTargetFlags(); | |
| switch (TargetFlags) { | |
| case MipsII::MO_HIGHEST: | |
| Kind = MipsMCExpr::MEK_HIGHEST; | |
| break; | |
| case MipsII::MO_HIGHER: | |
| Kind = MipsMCExpr::MEK_HIGHER; | |
| break; | |
| case MipsII::MO_ABS_HI: | |
| Kind = MipsMCExpr::MEK_HI; | |
| break; | |
| case MipsII::MO_ABS_LO: | |
| Kind = MipsMCExpr::MEK_LO; | |
| break; | |
| default: | |
| report_fatal_error("Unexpected flags for lowerLongBranchADDiu"); | |
| } | |
| // Lower two register operands. | |
| for (unsigned I = 0, E = 2; I != E; ++I) { | |
| const MachineOperand &MO = MI->getOperand(I); | |
| OutMI.addOperand(LowerOperand(MO)); | |
| } | |
| if (MI->getNumOperands() == 3) { | |
| // Lower register operand. | |
| const MCExpr *Expr = | |
| MCSymbolRefExpr::create(MI->getOperand(2).getMBB()->getSymbol(), *Ctx); | |
| const MipsMCExpr *MipsExpr = MipsMCExpr::create(Kind, Expr, *Ctx); | |
| OutMI.addOperand(MCOperand::createExpr(MipsExpr)); | |
| } else if (MI->getNumOperands() == 4) { | |
| // Create %lo($tgt-$baltgt) or %hi($tgt-$baltgt). | |
| OutMI.addOperand(createSub(MI->getOperand(2).getMBB(), | |
| MI->getOperand(3).getMBB(), Kind)); | |
| } | |
| } | |
| bool MipsMCInstLower::lowerLongBranch(const MachineInstr *MI, | |
| MCInst &OutMI) const { | |
| switch (MI->getOpcode()) { | |
| default: | |
| return false; | |
| case Mips::LONG_BRANCH_LUi: | |
| lowerLongBranchLUi(MI, OutMI); | |
| return true; | |
| case Mips::LONG_BRANCH_ADDiu: | |
| lowerLongBranchADDiu(MI, OutMI, Mips::ADDiu); | |
| return true; | |
| case Mips::LONG_BRANCH_DADDiu: | |
| lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu); | |
| return true; | |
| } | |
| } | |
| void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { | |
| if (lowerLongBranch(MI, OutMI)) | |
| return; | |
| OutMI.setOpcode(MI->getOpcode()); | |
| for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { | |
| const MachineOperand &MO = MI->getOperand(i); | |
| MCOperand MCOp = LowerOperand(MO); | |
| if (MCOp.isValid()) | |
| OutMI.addOperand(MCOp); | |
| } | |
| } |