Files
clang-p2996/llvm/lib/Target/VE/VEAsmPrinter.cpp
Reid Kleckner 89b57061f7 Move TargetRegistry.(h|cpp) from Support to MC
This moves the registry higher in the LLVM library dependency stack.
Every client of the target registry needs to link against MC anyway to
actually use the target, so we might as well move this out of Support.

This allows us to ensure that Support doesn't have includes from MC/*.

Differential Revision: https://reviews.llvm.org/D111454
2021-10-08 14:51:48 -07:00

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/MC/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());
}