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