| //===- MipsMCInstLower.cpp - Convert Mips MachineInstr to MCInst ----------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file contains code to lower Mips MachineInstrs to their corresponding | |
| // MCInst records. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "MipsMCInstLower.h" | |
| #include "MCTargetDesc/MipsBaseInfo.h" | |
| #include "MCTargetDesc/MipsMCAsmInfo.h" | |
| #include "MipsAsmPrinter.h" | |
| #include "llvm/CodeGen/MachineBasicBlock.h" | |
| #include "llvm/CodeGen/MachineInstr.h" | |
| #include "llvm/CodeGen/MachineOperand.h" | |
| #include "llvm/MC/MCContext.h" | |
| #include "llvm/MC/MCExpr.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| using namespace llvm; | |
| MipsMCInstLower::MipsMCInstLower(MipsAsmPrinter &asmprinter) | |
| : AsmPrinter(asmprinter) {} | |
| void MipsMCInstLower::Initialize(MCContext *C) { | |
| Ctx = C; | |
| } | |
| MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO, | |
| MachineOperandType MOTy, | |
| int64_t Offset) const { | |
| Mips::Specifier TargetKind = Mips::S_None; | |
| bool IsGpOff = false; | |
| const MCSymbol *Symbol; | |
| SmallString<128> Name; | |
| unsigned TargetFlags = MO.getTargetFlags(); | |
| if (TargetFlags & MipsII::MO_DLLIMPORT) { | |
| // Handle dllimport linkage | |
| Name += "__imp_"; | |
| TargetFlags &= ~MipsII::MO_DLLIMPORT; | |
| } | |
| switch (TargetFlags) { | |
| default: | |
| llvm_unreachable("Invalid target flag!"); | |
| case MipsII::MO_NO_FLAG: | |
| break; | |
| case MipsII::MO_GPREL: | |
| TargetKind = Mips::S_GPREL; | |
| break; | |
| case MipsII::MO_GOT_CALL: | |
| TargetKind = Mips::S_GOT_CALL; | |
| break; | |
| case MipsII::MO_GOT: | |
| TargetKind = Mips::S_GOT; | |
| break; | |
| case MipsII::MO_ABS_HI: | |
| TargetKind = Mips::S_HI; | |
| break; | |
| case MipsII::MO_ABS_LO: | |
| TargetKind = Mips::S_LO; | |
| break; | |
| case MipsII::MO_TLSGD: | |
| TargetKind = Mips::S_TLSGD; | |
| break; | |
| case MipsII::MO_TLSLDM: | |
| TargetKind = Mips::S_TLSLDM; | |
| break; | |
| case MipsII::MO_DTPREL_HI: | |
| TargetKind = Mips::S_DTPREL_HI; | |
| break; | |
| case MipsII::MO_DTPREL_LO: | |
| TargetKind = Mips::S_DTPREL_LO; | |
| break; | |
| case MipsII::MO_GOTTPREL: | |
| TargetKind = Mips::S_GOTTPREL; | |
| break; | |
| case MipsII::MO_TPREL_HI: | |
| TargetKind = Mips::S_TPREL_HI; | |
| break; | |
| case MipsII::MO_TPREL_LO: | |
| TargetKind = Mips::S_TPREL_LO; | |
| break; | |
| case MipsII::MO_GPOFF_HI: | |
| TargetKind = Mips::S_HI; | |
| IsGpOff = true; | |
| break; | |
| case MipsII::MO_GPOFF_LO: | |
| TargetKind = Mips::S_LO; | |
| IsGpOff = true; | |
| break; | |
| case MipsII::MO_GOT_DISP: | |
| TargetKind = Mips::S_GOT_DISP; | |
| break; | |
| case MipsII::MO_GOT_HI16: | |
| TargetKind = Mips::S_GOT_HI16; | |
| break; | |
| case MipsII::MO_GOT_LO16: | |
| TargetKind = Mips::S_GOT_LO16; | |
| break; | |
| case MipsII::MO_GOT_PAGE: | |
| TargetKind = Mips::S_GOT_PAGE; | |
| break; | |
| case MipsII::MO_GOT_OFST: | |
| TargetKind = Mips::S_GOT_OFST; | |
| break; | |
| case MipsII::MO_HIGHER: | |
| TargetKind = Mips::S_HIGHER; | |
| break; | |
| case MipsII::MO_HIGHEST: | |
| TargetKind = Mips::S_HIGHEST; | |
| break; | |
| case MipsII::MO_CALL_HI16: | |
| TargetKind = Mips::S_CALL_HI16; | |
| break; | |
| case MipsII::MO_CALL_LO16: | |
| TargetKind = Mips::S_CALL_LO16; | |
| break; | |
| case MipsII::MO_JALR: | |
| return MCOperand(); | |
| } | |
| switch (MOTy) { | |
| case MachineOperand::MO_MachineBasicBlock: | |
| Symbol = MO.getMBB()->getSymbol(); | |
| break; | |
| case MachineOperand::MO_GlobalAddress: | |
| AsmPrinter.getNameWithPrefix(Name, MO.getGlobal()); | |
| Symbol = Ctx->getOrCreateSymbol(Name); | |
| 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, *Ctx); | |
| if (Offset) { | |
| // Note: Offset can also be negative | |
| Expr = MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, *Ctx), | |
| *Ctx); | |
| } | |
| if (IsGpOff) | |
| Expr = Mips::createGpOff(Expr, TargetKind, *Ctx); | |
| else if (TargetKind != Mips::S_None) | |
| Expr = MCSpecifierExpr::create(Expr, TargetKind, *Ctx); | |
| return MCOperand::createExpr(Expr); | |
| } | |
| MCOperand MipsMCInstLower::LowerOperand(const MachineOperand &MO, | |
| int64_t 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, | |
| Mips::Specifier 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(MCSpecifierExpr::create(Sub, Kind, *Ctx)); | |
| } | |
| void MipsMCInstLower:: | |
| lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI) const { | |
| OutMI.setOpcode(Mips::LUi); | |
| // Lower register operand. | |
| OutMI.addOperand(LowerOperand(MI->getOperand(0))); | |
| Mips::Specifier Spec; | |
| unsigned TargetFlags = MI->getOperand(1).getTargetFlags(); | |
| switch (TargetFlags) { | |
| case MipsII::MO_HIGHEST: | |
| Spec = Mips::S_HIGHEST; | |
| break; | |
| case MipsII::MO_HIGHER: | |
| Spec = Mips::S_HIGHER; | |
| break; | |
| case MipsII::MO_ABS_HI: | |
| Spec = Mips::S_HI; | |
| break; | |
| case MipsII::MO_ABS_LO: | |
| Spec = Mips::S_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 auto *MipsExpr = MCSpecifierExpr::create(Expr, Spec, *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(), Spec)); | |
| } | |
| } | |
| void MipsMCInstLower::lowerLongBranchADDiu(const MachineInstr *MI, | |
| MCInst &OutMI, int Opcode) const { | |
| OutMI.setOpcode(Opcode); | |
| Mips::Specifier Spec; | |
| unsigned TargetFlags = MI->getOperand(2).getTargetFlags(); | |
| switch (TargetFlags) { | |
| case MipsII::MO_HIGHEST: | |
| Spec = Mips::S_HIGHEST; | |
| break; | |
| case MipsII::MO_HIGHER: | |
| Spec = Mips::S_HIGHER; | |
| break; | |
| case MipsII::MO_ABS_HI: | |
| Spec = Mips::S_HI; | |
| break; | |
| case MipsII::MO_ABS_LO: | |
| Spec = Mips::S_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 auto *MipsExpr = MCSpecifierExpr::create(Expr, Spec, *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(), Spec)); | |
| } | |
| } | |
| bool MipsMCInstLower::lowerLongBranch(const MachineInstr *MI, | |
| MCInst &OutMI) const { | |
| switch (MI->getOpcode()) { | |
| default: | |
| return false; | |
| case Mips::LONG_BRANCH_LUi: | |
| case Mips::LONG_BRANCH_LUi2Op: | |
| case Mips::LONG_BRANCH_LUi2Op_64: | |
| lowerLongBranchLUi(MI, OutMI); | |
| return true; | |
| case Mips::LONG_BRANCH_ADDiu: | |
| case Mips::LONG_BRANCH_ADDiu2Op: | |
| lowerLongBranchADDiu(MI, OutMI, Mips::ADDiu); | |
| return true; | |
| case Mips::LONG_BRANCH_DADDiu: | |
| case Mips::LONG_BRANCH_DADDiu2Op: | |
| 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 (const MachineOperand &MO : MI->operands()) { | |
| MCOperand MCOp = LowerOperand(MO); | |
| if (MCOp.isValid()) | |
| OutMI.addOperand(MCOp); | |
| } | |
| } |