1251607Sdim//===-- SystemZMCInstLower.cpp - Lower MachineInstr to MCInst -------------===//
2251607Sdim//
3251607Sdim//                     The LLVM Compiler Infrastructure
4251607Sdim//
5251607Sdim// This file is distributed under the University of Illinois Open Source
6251607Sdim// License. See LICENSE.TXT for details.
7251607Sdim//
8251607Sdim//===----------------------------------------------------------------------===//
9251607Sdim
10251607Sdim#include "SystemZMCInstLower.h"
11251607Sdim#include "SystemZAsmPrinter.h"
12251607Sdim#include "llvm/MC/MCExpr.h"
13251607Sdim#include "llvm/MC/MCStreamer.h"
14251607Sdim#include "llvm/Target/Mangler.h"
15251607Sdim
16251607Sdimusing namespace llvm;
17251607Sdim
18251607Sdim// Where relaxable pairs of reloc-generating instructions exist,
19251607Sdim// we tend to use the longest form by default, since that produces
20251607Sdim// correct assembly in cases where no relaxation is performed.
21251607Sdim// If Opcode is one such instruction, return the opcode for the
22251607Sdim// shortest possible form instead, otherwise return Opcode itself.
23251607Sdimstatic unsigned getShortenedInstr(unsigned Opcode) {
24251607Sdim  switch (Opcode) {
25251607Sdim  case SystemZ::BRCL:  return SystemZ::BRC;
26251607Sdim  case SystemZ::JG:    return SystemZ::J;
27251607Sdim  case SystemZ::BRASL: return SystemZ::BRAS;
28251607Sdim  }
29251607Sdim  return Opcode;
30251607Sdim}
31251607Sdim
32251607Sdim// Return the VK_* enumeration for MachineOperand target flags Flags.
33251607Sdimstatic MCSymbolRefExpr::VariantKind getVariantKind(unsigned Flags) {
34251607Sdim  switch (Flags & SystemZII::MO_SYMBOL_MODIFIER) {
35251607Sdim    case 0:
36251607Sdim      return MCSymbolRefExpr::VK_None;
37251607Sdim    case SystemZII::MO_GOT:
38251607Sdim      return MCSymbolRefExpr::VK_GOT;
39251607Sdim  }
40251607Sdim  llvm_unreachable("Unrecognised MO_ACCESS_MODEL");
41251607Sdim}
42251607Sdim
43251607SdimSystemZMCInstLower::SystemZMCInstLower(Mangler *mang, MCContext &ctx,
44251607Sdim                                       SystemZAsmPrinter &asmprinter)
45251607Sdim  : Mang(mang), Ctx(ctx), AsmPrinter(asmprinter) {}
46251607Sdim
47251607SdimMCOperand SystemZMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
48251607Sdim                                                 const MCSymbol *Symbol,
49251607Sdim                                                 int64_t Offset) const {
50251607Sdim  MCSymbolRefExpr::VariantKind Kind = getVariantKind(MO.getTargetFlags());
51251607Sdim  const MCExpr *Expr = MCSymbolRefExpr::Create(Symbol, Kind, Ctx);
52251607Sdim  if (Offset) {
53251607Sdim    const MCExpr *OffsetExpr = MCConstantExpr::Create(Offset, Ctx);
54251607Sdim    Expr = MCBinaryExpr::CreateAdd(Expr, OffsetExpr, Ctx);
55251607Sdim  }
56251607Sdim  return MCOperand::CreateExpr(Expr);
57251607Sdim}
58251607Sdim
59251607SdimMCOperand SystemZMCInstLower::lowerOperand(const MachineOperand &MO) const {
60251607Sdim  switch (MO.getType()) {
61251607Sdim  default:
62251607Sdim    llvm_unreachable("unknown operand type");
63251607Sdim
64251607Sdim  case MachineOperand::MO_Register:
65251607Sdim    // Ignore all implicit register operands.
66251607Sdim    if (MO.isImplicit())
67251607Sdim      return MCOperand();
68251607Sdim    return MCOperand::CreateReg(MO.getReg());
69251607Sdim
70251607Sdim  case MachineOperand::MO_Immediate:
71251607Sdim    return MCOperand::CreateImm(MO.getImm());
72251607Sdim
73251607Sdim  case MachineOperand::MO_MachineBasicBlock:
74251607Sdim    return lowerSymbolOperand(MO, MO.getMBB()->getSymbol(),
75251607Sdim                              /* MO has no offset field */0);
76251607Sdim
77251607Sdim  case MachineOperand::MO_GlobalAddress:
78251607Sdim    return lowerSymbolOperand(MO, Mang->getSymbol(MO.getGlobal()),
79251607Sdim                              MO.getOffset());
80251607Sdim
81251607Sdim  case MachineOperand::MO_ExternalSymbol: {
82251607Sdim    StringRef Name = MO.getSymbolName();
83251607Sdim    return lowerSymbolOperand(MO, AsmPrinter.GetExternalSymbolSymbol(Name),
84251607Sdim                              MO.getOffset());
85251607Sdim  }
86251607Sdim
87251607Sdim  case MachineOperand::MO_JumpTableIndex:
88251607Sdim    return lowerSymbolOperand(MO, AsmPrinter.GetJTISymbol(MO.getIndex()),
89251607Sdim                              /* MO has no offset field */0);
90251607Sdim
91251607Sdim  case MachineOperand::MO_ConstantPoolIndex:
92251607Sdim    return lowerSymbolOperand(MO, AsmPrinter.GetCPISymbol(MO.getIndex()),
93251607Sdim                              MO.getOffset());
94251607Sdim
95251607Sdim  case MachineOperand::MO_BlockAddress: {
96251607Sdim    const BlockAddress *BA = MO.getBlockAddress();
97251607Sdim    return lowerSymbolOperand(MO, AsmPrinter.GetBlockAddressSymbol(BA),
98251607Sdim                              MO.getOffset());
99251607Sdim  }
100251607Sdim  }
101251607Sdim}
102251607Sdim
103251607Sdimvoid SystemZMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const {
104251607Sdim  unsigned Opcode = MI->getOpcode();
105251607Sdim  // When emitting binary code, start with the shortest form of an instruction
106251607Sdim  // and then relax it where necessary.
107251607Sdim  if (!AsmPrinter.OutStreamer.hasRawTextSupport())
108251607Sdim    Opcode = getShortenedInstr(Opcode);
109251607Sdim  OutMI.setOpcode(Opcode);
110251607Sdim  for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
111251607Sdim    const MachineOperand &MO = MI->getOperand(I);
112251607Sdim    MCOperand MCOp = lowerOperand(MO);
113251607Sdim    if (MCOp.isValid())
114251607Sdim      OutMI.addOperand(MCOp);
115251607Sdim  }
116251607Sdim}
117