blob: 5d833213e6f1555dccbc34d569658c7e9c7795ba [file] [log] [blame]
//===-- SystemZMCInstLower.cpp - Lower MachineInstr to MCInst -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "SystemZMCInstLower.h"
#include "SystemZAsmPrinter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Target/Mangler.h"
using namespace llvm;
// Where relaxable pairs of reloc-generating instructions exist,
// we tend to use the longest form by default, since that produces
// correct assembly in cases where no relaxation is performed.
// If Opcode is one such instruction, return the opcode for the
// shortest possible form instead, otherwise return Opcode itself.
static unsigned getShortenedInstr(unsigned Opcode) {
switch (Opcode) {
case SystemZ::BRCL: return SystemZ::BRC;
case SystemZ::JG: return SystemZ::J;
case SystemZ::BRASL: return SystemZ::BRAS;
}
return Opcode;
}
// Return the VK_* enumeration for MachineOperand target flags Flags.
static MCSymbolRefExpr::VariantKind getVariantKind(unsigned Flags) {
switch (Flags & SystemZII::MO_SYMBOL_MODIFIER) {
case 0:
return MCSymbolRefExpr::VK_None;
case SystemZII::MO_GOT:
return MCSymbolRefExpr::VK_GOT;
}
llvm_unreachable("Unrecognised MO_ACCESS_MODEL");
}
SystemZMCInstLower::SystemZMCInstLower(Mangler *mang, MCContext &ctx,
SystemZAsmPrinter &asmprinter)
: Mang(mang), Ctx(ctx), AsmPrinter(asmprinter) {}
MCOperand SystemZMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
const MCSymbol *Symbol,
int64_t Offset) const {
MCSymbolRefExpr::VariantKind Kind = getVariantKind(MO.getTargetFlags());
const MCExpr *Expr = MCSymbolRefExpr::Create(Symbol, Kind, Ctx);
if (Offset) {
const MCExpr *OffsetExpr = MCConstantExpr::Create(Offset, Ctx);
Expr = MCBinaryExpr::CreateAdd(Expr, OffsetExpr, Ctx);
}
return MCOperand::CreateExpr(Expr);
}
MCOperand SystemZMCInstLower::lowerOperand(const MachineOperand &MO) const {
switch (MO.getType()) {
default:
llvm_unreachable("unknown operand type");
case MachineOperand::MO_Register:
// Ignore all implicit register operands.
if (MO.isImplicit())
return MCOperand();
return MCOperand::CreateReg(MO.getReg());
case MachineOperand::MO_Immediate:
return MCOperand::CreateImm(MO.getImm());
case MachineOperand::MO_MachineBasicBlock:
return lowerSymbolOperand(MO, MO.getMBB()->getSymbol(),
/* MO has no offset field */0);
case MachineOperand::MO_GlobalAddress:
return lowerSymbolOperand(MO, Mang->getSymbol(MO.getGlobal()),
MO.getOffset());
case MachineOperand::MO_ExternalSymbol: {
StringRef Name = MO.getSymbolName();
return lowerSymbolOperand(MO, AsmPrinter.GetExternalSymbolSymbol(Name),
MO.getOffset());
}
case MachineOperand::MO_JumpTableIndex:
return lowerSymbolOperand(MO, AsmPrinter.GetJTISymbol(MO.getIndex()),
/* MO has no offset field */0);
case MachineOperand::MO_ConstantPoolIndex:
return lowerSymbolOperand(MO, AsmPrinter.GetCPISymbol(MO.getIndex()),
MO.getOffset());
case MachineOperand::MO_BlockAddress: {
const BlockAddress *BA = MO.getBlockAddress();
return lowerSymbolOperand(MO, AsmPrinter.GetBlockAddressSymbol(BA),
MO.getOffset());
}
}
}
void SystemZMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const {
unsigned Opcode = MI->getOpcode();
// When emitting binary code, start with the shortest form of an instruction
// and then relax it where necessary.
if (!AsmPrinter.OutStreamer.hasRawTextSupport())
Opcode = getShortenedInstr(Opcode);
OutMI.setOpcode(Opcode);
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);
}
}