394 lines
14 KiB
C++
394 lines
14 KiB
C++
//===-- VEAsmPrinter.cpp - VE LLVM assembly writer ------------------------===//
|
|
//
|
|
// 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 a printer that converts from our internal representation
|
|
// of machine-dependent LLVM code to GAS-format VE assembly language.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "MCTargetDesc/VEInstPrinter.h"
|
|
#include "MCTargetDesc/VEMCExpr.h"
|
|
#include "MCTargetDesc/VETargetStreamer.h"
|
|
#include "TargetInfo/VETargetInfo.h"
|
|
#include "VE.h"
|
|
#include "VEInstrInfo.h"
|
|
#include "VETargetMachine.h"
|
|
#include "llvm/CodeGen/AsmPrinter.h"
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
|
#include "llvm/IR/Mangler.h"
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCInstBuilder.h"
|
|
#include "llvm/MC/MCStreamer.h"
|
|
#include "llvm/MC/MCSymbol.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "ve-asmprinter"
|
|
|
|
namespace {
|
|
class VEAsmPrinter : public AsmPrinter {
|
|
VETargetStreamer &getTargetStreamer() {
|
|
return static_cast<VETargetStreamer &>(*OutStreamer->getTargetStreamer());
|
|
}
|
|
|
|
public:
|
|
explicit VEAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
|
|
: AsmPrinter(TM, std::move(Streamer)) {}
|
|
|
|
StringRef getPassName() const override { return "VE Assembly Printer"; }
|
|
|
|
void lowerGETGOTAndEmitMCInsts(const MachineInstr *MI,
|
|
const MCSubtargetInfo &STI);
|
|
void lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI,
|
|
const MCSubtargetInfo &STI);
|
|
void lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI,
|
|
const MCSubtargetInfo &STI);
|
|
|
|
void emitInstruction(const MachineInstr *MI) override;
|
|
|
|
static const char *getRegisterName(unsigned RegNo) {
|
|
return VEInstPrinter::getRegisterName(RegNo);
|
|
}
|
|
void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS);
|
|
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
|
const char *ExtraCode, raw_ostream &O) override;
|
|
};
|
|
} // end of anonymous namespace
|
|
|
|
static MCOperand createVEMCOperand(VEMCExpr::VariantKind Kind, MCSymbol *Sym,
|
|
MCContext &OutContext) {
|
|
const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym, OutContext);
|
|
const VEMCExpr *expr = VEMCExpr::create(Kind, MCSym, OutContext);
|
|
return MCOperand::createExpr(expr);
|
|
}
|
|
|
|
static MCOperand createGOTRelExprOp(VEMCExpr::VariantKind Kind,
|
|
MCSymbol *GOTLabel, MCContext &OutContext) {
|
|
const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);
|
|
const VEMCExpr *expr = VEMCExpr::create(Kind, GOT, OutContext);
|
|
return MCOperand::createExpr(expr);
|
|
}
|
|
|
|
static void emitSIC(MCStreamer &OutStreamer, MCOperand &RD,
|
|
const MCSubtargetInfo &STI) {
|
|
MCInst SICInst;
|
|
SICInst.setOpcode(VE::SIC);
|
|
SICInst.addOperand(RD);
|
|
OutStreamer.emitInstruction(SICInst, STI);
|
|
}
|
|
|
|
static void emitBSIC(MCStreamer &OutStreamer, MCOperand &R1, MCOperand &R2,
|
|
const MCSubtargetInfo &STI) {
|
|
MCInst BSICInst;
|
|
BSICInst.setOpcode(VE::BSICrii);
|
|
BSICInst.addOperand(R1);
|
|
BSICInst.addOperand(R2);
|
|
MCOperand czero = MCOperand::createImm(0);
|
|
BSICInst.addOperand(czero);
|
|
BSICInst.addOperand(czero);
|
|
OutStreamer.emitInstruction(BSICInst, STI);
|
|
}
|
|
|
|
static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
|
|
const MCSubtargetInfo &STI) {
|
|
MCInst LEAInst;
|
|
LEAInst.setOpcode(VE::LEAzii);
|
|
LEAInst.addOperand(RD);
|
|
MCOperand CZero = MCOperand::createImm(0);
|
|
LEAInst.addOperand(CZero);
|
|
LEAInst.addOperand(CZero);
|
|
LEAInst.addOperand(Imm);
|
|
OutStreamer.emitInstruction(LEAInst, STI);
|
|
}
|
|
|
|
static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
|
|
const MCSubtargetInfo &STI) {
|
|
MCInst LEASLInst;
|
|
LEASLInst.setOpcode(VE::LEASLzii);
|
|
LEASLInst.addOperand(RD);
|
|
MCOperand CZero = MCOperand::createImm(0);
|
|
LEASLInst.addOperand(CZero);
|
|
LEASLInst.addOperand(CZero);
|
|
LEASLInst.addOperand(Imm);
|
|
OutStreamer.emitInstruction(LEASLInst, STI);
|
|
}
|
|
|
|
static void emitLEAzii(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
|
|
MCOperand &RD, const MCSubtargetInfo &STI) {
|
|
MCInst LEAInst;
|
|
LEAInst.setOpcode(VE::LEAzii);
|
|
LEAInst.addOperand(RD);
|
|
MCOperand CZero = MCOperand::createImm(0);
|
|
LEAInst.addOperand(CZero);
|
|
LEAInst.addOperand(RS1);
|
|
LEAInst.addOperand(Imm);
|
|
OutStreamer.emitInstruction(LEAInst, STI);
|
|
}
|
|
|
|
static void emitLEASLrri(MCStreamer &OutStreamer, MCOperand &RS1,
|
|
MCOperand &RS2, MCOperand &Imm, MCOperand &RD,
|
|
const MCSubtargetInfo &STI) {
|
|
MCInst LEASLInst;
|
|
LEASLInst.setOpcode(VE::LEASLrri);
|
|
LEASLInst.addOperand(RD);
|
|
LEASLInst.addOperand(RS1);
|
|
LEASLInst.addOperand(RS2);
|
|
LEASLInst.addOperand(Imm);
|
|
OutStreamer.emitInstruction(LEASLInst, STI);
|
|
}
|
|
|
|
static void emitBinary(MCStreamer &OutStreamer, unsigned Opcode, MCOperand &RS1,
|
|
MCOperand &Src2, MCOperand &RD,
|
|
const MCSubtargetInfo &STI) {
|
|
MCInst Inst;
|
|
Inst.setOpcode(Opcode);
|
|
Inst.addOperand(RD);
|
|
Inst.addOperand(RS1);
|
|
Inst.addOperand(Src2);
|
|
OutStreamer.emitInstruction(Inst, STI);
|
|
}
|
|
|
|
static void emitANDrm(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
|
|
MCOperand &RD, const MCSubtargetInfo &STI) {
|
|
emitBinary(OutStreamer, VE::ANDrm, RS1, Imm, RD, STI);
|
|
}
|
|
|
|
static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
|
|
VEMCExpr::VariantKind HiKind, VEMCExpr::VariantKind LoKind,
|
|
MCOperand &RD, MCContext &OutContext,
|
|
const MCSubtargetInfo &STI) {
|
|
|
|
MCOperand hi = createVEMCOperand(HiKind, GOTSym, OutContext);
|
|
MCOperand lo = createVEMCOperand(LoKind, GOTSym, OutContext);
|
|
emitLEAzzi(OutStreamer, lo, RD, STI);
|
|
MCOperand M032 = MCOperand::createImm(M0(32));
|
|
emitANDrm(OutStreamer, RD, M032, RD, STI);
|
|
emitLEASLzzi(OutStreamer, hi, RD, STI);
|
|
}
|
|
|
|
void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr *MI,
|
|
const MCSubtargetInfo &STI) {
|
|
MCSymbol *GOTLabel =
|
|
OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
|
|
|
|
const MachineOperand &MO = MI->getOperand(0);
|
|
MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
|
|
|
|
if (!isPositionIndependent()) {
|
|
// Just load the address of GOT to MCRegOP.
|
|
switch (TM.getCodeModel()) {
|
|
default:
|
|
llvm_unreachable("Unsupported absolute code model");
|
|
case CodeModel::Small:
|
|
case CodeModel::Medium:
|
|
case CodeModel::Large:
|
|
emitHiLo(*OutStreamer, GOTLabel, VEMCExpr::VK_VE_HI32,
|
|
VEMCExpr::VK_VE_LO32, MCRegOP, OutContext, STI);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
MCOperand RegGOT = MCOperand::createReg(VE::SX15); // GOT
|
|
MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
|
|
|
|
// lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24)
|
|
// and %got, %got, (32)0
|
|
// sic %plt
|
|
// lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%plt, %got)
|
|
MCOperand cim24 = MCOperand::createImm(-24);
|
|
MCOperand loImm =
|
|
createGOTRelExprOp(VEMCExpr::VK_VE_PC_LO32, GOTLabel, OutContext);
|
|
emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI);
|
|
MCOperand M032 = MCOperand::createImm(M0(32));
|
|
emitANDrm(*OutStreamer, MCRegOP, M032, MCRegOP, STI);
|
|
emitSIC(*OutStreamer, RegPLT, STI);
|
|
MCOperand hiImm =
|
|
createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32, GOTLabel, OutContext);
|
|
emitLEASLrri(*OutStreamer, RegGOT, RegPLT, hiImm, MCRegOP, STI);
|
|
}
|
|
|
|
void VEAsmPrinter::lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI,
|
|
const MCSubtargetInfo &STI) {
|
|
const MachineOperand &MO = MI->getOperand(0);
|
|
MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
|
|
const MachineOperand &Addr = MI->getOperand(1);
|
|
MCSymbol *AddrSym = nullptr;
|
|
|
|
switch (Addr.getType()) {
|
|
default:
|
|
llvm_unreachable("<unknown operand type>");
|
|
return;
|
|
case MachineOperand::MO_MachineBasicBlock:
|
|
report_fatal_error("MBB is not supported yet");
|
|
return;
|
|
case MachineOperand::MO_ConstantPoolIndex:
|
|
report_fatal_error("ConstantPool is not supported yet");
|
|
return;
|
|
case MachineOperand::MO_ExternalSymbol:
|
|
AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
|
|
break;
|
|
case MachineOperand::MO_GlobalAddress:
|
|
AddrSym = getSymbol(Addr.getGlobal());
|
|
break;
|
|
}
|
|
|
|
if (!isPositionIndependent()) {
|
|
llvm_unreachable("Unsupported uses of %plt in not PIC code");
|
|
return;
|
|
}
|
|
|
|
MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
|
|
|
|
// lea %dst, func@plt_lo(-24)
|
|
// and %dst, %dst, (32)0
|
|
// sic %plt ; FIXME: is it safe to use %plt here?
|
|
// lea.sl %dst, func@plt_hi(%plt, %dst)
|
|
MCOperand cim24 = MCOperand::createImm(-24);
|
|
MCOperand loImm =
|
|
createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, AddrSym, OutContext);
|
|
emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI);
|
|
MCOperand M032 = MCOperand::createImm(M0(32));
|
|
emitANDrm(*OutStreamer, MCRegOP, M032, MCRegOP, STI);
|
|
emitSIC(*OutStreamer, RegPLT, STI);
|
|
MCOperand hiImm =
|
|
createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, AddrSym, OutContext);
|
|
emitLEASLrri(*OutStreamer, MCRegOP, RegPLT, hiImm, MCRegOP, STI);
|
|
}
|
|
|
|
void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI,
|
|
const MCSubtargetInfo &STI) {
|
|
const MachineOperand &Addr = MI->getOperand(0);
|
|
MCSymbol *AddrSym = nullptr;
|
|
|
|
switch (Addr.getType()) {
|
|
default:
|
|
llvm_unreachable("<unknown operand type>");
|
|
return;
|
|
case MachineOperand::MO_MachineBasicBlock:
|
|
report_fatal_error("MBB is not supported yet");
|
|
return;
|
|
case MachineOperand::MO_ConstantPoolIndex:
|
|
report_fatal_error("ConstantPool is not supported yet");
|
|
return;
|
|
case MachineOperand::MO_ExternalSymbol:
|
|
AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
|
|
break;
|
|
case MachineOperand::MO_GlobalAddress:
|
|
AddrSym = getSymbol(Addr.getGlobal());
|
|
break;
|
|
}
|
|
|
|
MCOperand RegLR = MCOperand::createReg(VE::SX10); // LR
|
|
MCOperand RegS0 = MCOperand::createReg(VE::SX0); // S0
|
|
MCOperand RegS12 = MCOperand::createReg(VE::SX12); // S12
|
|
MCSymbol *GetTLSLabel = OutContext.getOrCreateSymbol(Twine("__tls_get_addr"));
|
|
|
|
// lea %s0, sym@tls_gd_lo(-24)
|
|
// and %s0, %s0, (32)0
|
|
// sic %lr
|
|
// lea.sl %s0, sym@tls_gd_hi(%lr, %s0)
|
|
// lea %s12, __tls_get_addr@plt_lo(8)
|
|
// and %s12, %s12, (32)0
|
|
// lea.sl %s12, __tls_get_addr@plt_hi(%s12, %lr)
|
|
// bsic %lr, (, %s12)
|
|
MCOperand cim24 = MCOperand::createImm(-24);
|
|
MCOperand loImm =
|
|
createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_LO32, AddrSym, OutContext);
|
|
emitLEAzii(*OutStreamer, cim24, loImm, RegS0, STI);
|
|
MCOperand M032 = MCOperand::createImm(M0(32));
|
|
emitANDrm(*OutStreamer, RegS0, M032, RegS0, STI);
|
|
emitSIC(*OutStreamer, RegLR, STI);
|
|
MCOperand hiImm =
|
|
createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32, AddrSym, OutContext);
|
|
emitLEASLrri(*OutStreamer, RegS0, RegLR, hiImm, RegS0, STI);
|
|
MCOperand ci8 = MCOperand::createImm(8);
|
|
MCOperand loImm2 =
|
|
createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, GetTLSLabel, OutContext);
|
|
emitLEAzii(*OutStreamer, ci8, loImm2, RegS12, STI);
|
|
emitANDrm(*OutStreamer, RegS12, M032, RegS12, STI);
|
|
MCOperand hiImm2 =
|
|
createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, GetTLSLabel, OutContext);
|
|
emitLEASLrri(*OutStreamer, RegS12, RegLR, hiImm2, RegS12, STI);
|
|
emitBSIC(*OutStreamer, RegLR, RegS12, STI);
|
|
}
|
|
|
|
void VEAsmPrinter::emitInstruction(const MachineInstr *MI) {
|
|
|
|
switch (MI->getOpcode()) {
|
|
default:
|
|
break;
|
|
case TargetOpcode::DBG_VALUE:
|
|
// FIXME: Debug Value.
|
|
return;
|
|
case VE::GETGOT:
|
|
lowerGETGOTAndEmitMCInsts(MI, getSubtargetInfo());
|
|
return;
|
|
case VE::GETFUNPLT:
|
|
lowerGETFunPLTAndEmitMCInsts(MI, getSubtargetInfo());
|
|
return;
|
|
case VE::GETTLSADDR:
|
|
lowerGETTLSAddrAndEmitMCInsts(MI, getSubtargetInfo());
|
|
return;
|
|
}
|
|
|
|
MachineBasicBlock::const_instr_iterator I = MI->getIterator();
|
|
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
|
|
do {
|
|
MCInst TmpInst;
|
|
LowerVEMachineInstrToMCInst(&*I, TmpInst, *this);
|
|
EmitToStreamer(*OutStreamer, TmpInst);
|
|
} while ((++I != E) && I->isInsideBundle()); // Delay slot check.
|
|
}
|
|
|
|
void VEAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
|
|
raw_ostream &O) {
|
|
const MachineOperand &MO = MI->getOperand(OpNum);
|
|
|
|
switch (MO.getType()) {
|
|
case MachineOperand::MO_Register:
|
|
O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
|
|
break;
|
|
default:
|
|
llvm_unreachable("<unknown operand type>");
|
|
}
|
|
}
|
|
|
|
// PrintAsmOperand - Print out an operand for an inline asm expression.
|
|
bool VEAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
|
const char *ExtraCode, raw_ostream &O) {
|
|
if (ExtraCode && ExtraCode[0]) {
|
|
if (ExtraCode[1] != 0)
|
|
return true; // Unknown modifier.
|
|
|
|
switch (ExtraCode[0]) {
|
|
default:
|
|
// See if this is a generic print operand
|
|
return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
|
|
case 'r':
|
|
case 'v':
|
|
break;
|
|
}
|
|
}
|
|
|
|
printOperand(MI, OpNo, O);
|
|
|
|
return false;
|
|
}
|
|
|
|
// Force static initialization.
|
|
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeVEAsmPrinter() {
|
|
RegisterAsmPrinter<VEAsmPrinter> X(getTheVETarget());
|
|
}
|