mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-11-04 05:17:07 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208607 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			550 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			550 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//==-- AArch64InstPrinter.cpp - Convert AArch64 MCInst to assembly syntax --==//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This class prints an AArch64 MCInst to a .s file.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "AArch64InstPrinter.h"
 | 
						|
#include "MCTargetDesc/AArch64MCTargetDesc.h"
 | 
						|
#include "Utils/AArch64BaseInfo.h"
 | 
						|
#include "llvm/MC/MCExpr.h"
 | 
						|
#include "llvm/MC/MCInst.h"
 | 
						|
#include "llvm/MC/MCRegisterInfo.h"
 | 
						|
#include "llvm/Support/ErrorHandling.h"
 | 
						|
#include "llvm/Support/Format.h"
 | 
						|
#include "llvm/Support/raw_ostream.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
#define DEBUG_TYPE "asm-printer"
 | 
						|
 | 
						|
#define GET_INSTRUCTION_NAME
 | 
						|
#define PRINT_ALIAS_INSTR
 | 
						|
#include "AArch64GenAsmWriter.inc"
 | 
						|
 | 
						|
static int64_t unpackSignedImm(int BitWidth, uint64_t Value) {
 | 
						|
  assert(!(Value & ~((1ULL << BitWidth)-1)) && "immediate not n-bit");
 | 
						|
  if (Value & (1ULL <<  (BitWidth - 1)))
 | 
						|
    return static_cast<int64_t>(Value) - (1LL << BitWidth);
 | 
						|
  else
 | 
						|
    return Value;
 | 
						|
}
 | 
						|
 | 
						|
AArch64InstPrinter::AArch64InstPrinter(const MCAsmInfo &MAI,
 | 
						|
                                       const MCInstrInfo &MII,
 | 
						|
                                       const MCRegisterInfo &MRI,
 | 
						|
                                       const MCSubtargetInfo &STI) :
 | 
						|
  MCInstPrinter(MAI, MII, MRI) {
 | 
						|
  // Initialize the set of available features.
 | 
						|
  setAvailableFeatures(STI.getFeatureBits());
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
 | 
						|
  OS << getRegisterName(RegNo);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printOffsetSImm9Operand(const MCInst *MI,
 | 
						|
                                              unsigned OpNum, raw_ostream &O) {
 | 
						|
  const MCOperand &MOImm = MI->getOperand(OpNum);
 | 
						|
  int32_t Imm = unpackSignedImm(9, MOImm.getImm());
 | 
						|
 | 
						|
  O << '#' << Imm;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printAddrRegExtendOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                          raw_ostream &O, unsigned MemSize,
 | 
						|
                                          unsigned RmSize) {
 | 
						|
  unsigned ExtImm = MI->getOperand(OpNum).getImm();
 | 
						|
  unsigned OptionHi = ExtImm >> 1;
 | 
						|
  unsigned S = ExtImm & 1;
 | 
						|
  bool IsLSL = OptionHi == 1 && RmSize == 64;
 | 
						|
 | 
						|
  const char *Ext;
 | 
						|
  switch (OptionHi) {
 | 
						|
  case 1:
 | 
						|
    Ext = (RmSize == 32) ? "uxtw" : "lsl";
 | 
						|
    break;
 | 
						|
  case 3:
 | 
						|
    Ext = (RmSize == 32) ? "sxtw" : "sxtx";
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    llvm_unreachable("Incorrect Option on load/store (reg offset)");
 | 
						|
  }
 | 
						|
  O << Ext;
 | 
						|
 | 
						|
  if (S) {
 | 
						|
    unsigned ShiftAmt = Log2_32(MemSize);
 | 
						|
    O << " #" << ShiftAmt;
 | 
						|
  } else if (IsLSL) {
 | 
						|
    O << " #0";
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printAddSubImmLSL0Operand(const MCInst *MI,
 | 
						|
                                              unsigned OpNum, raw_ostream &O) {
 | 
						|
  const MCOperand &Imm12Op = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  if (Imm12Op.isImm()) {
 | 
						|
    int64_t Imm12 = Imm12Op.getImm();
 | 
						|
    assert(Imm12 >= 0 && "Invalid immediate for add/sub imm");
 | 
						|
    O << "#" << Imm12;
 | 
						|
  } else {
 | 
						|
    assert(Imm12Op.isExpr() && "Unexpected shift operand type");
 | 
						|
    O << "#" << *Imm12Op.getExpr();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printAddSubImmLSL12Operand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                               raw_ostream &O) {
 | 
						|
 | 
						|
  printAddSubImmLSL0Operand(MI, OpNum, O);
 | 
						|
 | 
						|
  O << ", lsl #12";
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printBareImmOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                        raw_ostream &O) {
 | 
						|
  const MCOperand &MO = MI->getOperand(OpNum);
 | 
						|
  O << MO.getImm();
 | 
						|
}
 | 
						|
 | 
						|
template<unsigned RegWidth> void
 | 
						|
AArch64InstPrinter::printBFILSBOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                       raw_ostream &O) {
 | 
						|
  const MCOperand &ImmROp = MI->getOperand(OpNum);
 | 
						|
  unsigned LSB = ImmROp.getImm() == 0 ? 0 : RegWidth - ImmROp.getImm();
 | 
						|
 | 
						|
  O << '#' << LSB;
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printBFIWidthOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                              raw_ostream &O) {
 | 
						|
  const MCOperand &ImmSOp = MI->getOperand(OpNum);
 | 
						|
  unsigned Width = ImmSOp.getImm() + 1;
 | 
						|
 | 
						|
  O << '#' << Width;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printBFXWidthOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                         raw_ostream &O) {
 | 
						|
  const MCOperand &ImmSOp = MI->getOperand(OpNum);
 | 
						|
  const MCOperand &ImmROp = MI->getOperand(OpNum - 1);
 | 
						|
 | 
						|
  unsigned ImmR = ImmROp.getImm();
 | 
						|
  unsigned ImmS = ImmSOp.getImm();
 | 
						|
 | 
						|
  assert(ImmS >= ImmR && "Invalid ImmR, ImmS combination for bitfield extract");
 | 
						|
 | 
						|
  O << '#' << (ImmS - ImmR + 1);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printCRxOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                    raw_ostream &O) {
 | 
						|
    const MCOperand &CRx = MI->getOperand(OpNum);
 | 
						|
 | 
						|
    O << 'c' << CRx.getImm();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printCVTFixedPosOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                            raw_ostream &O) {
 | 
						|
    const MCOperand &ScaleOp = MI->getOperand(OpNum);
 | 
						|
 | 
						|
    O << '#' << (64 - ScaleOp.getImm());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                           raw_ostream &o) {
 | 
						|
  const MCOperand &MOImm8 = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  assert(MOImm8.isImm()
 | 
						|
         && "Immediate operand required for floating-point immediate inst");
 | 
						|
 | 
						|
  uint32_t Imm8 = MOImm8.getImm();
 | 
						|
  uint32_t Fraction = Imm8 & 0xf;
 | 
						|
  uint32_t Exponent = (Imm8 >> 4) & 0x7;
 | 
						|
  uint32_t Negative = (Imm8 >> 7) & 0x1;
 | 
						|
 | 
						|
  float Val = 1.0f + Fraction / 16.0f;
 | 
						|
 | 
						|
  // That is:
 | 
						|
  // 000 -> 2^1,  001 -> 2^2,  010 -> 2^3,  011 -> 2^4,
 | 
						|
  // 100 -> 2^-3, 101 -> 2^-2, 110 -> 2^-1, 111 -> 2^0
 | 
						|
  if (Exponent & 0x4) {
 | 
						|
    Val /= 1 << (7 - Exponent);
 | 
						|
  } else {
 | 
						|
    Val *= 1 << (Exponent + 1);
 | 
						|
  }
 | 
						|
 | 
						|
  Val = Negative ? -Val : Val;
 | 
						|
 | 
						|
  o << '#' << format("%.8f", Val);
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printFPZeroOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                            raw_ostream &o) {
 | 
						|
  o << "#0.0";
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printCondCodeOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                         raw_ostream &O) {
 | 
						|
  const MCOperand &MO = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  O << A64CondCodeToString(static_cast<A64CC::CondCodes>(MO.getImm()));
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printInverseCondCodeOperand(const MCInst *MI,
 | 
						|
                                                unsigned OpNum,
 | 
						|
                                                raw_ostream &O) {
 | 
						|
  A64CC::CondCodes CC =
 | 
						|
      static_cast<A64CC::CondCodes>(MI->getOperand(OpNum).getImm());
 | 
						|
  O << A64CondCodeToString(A64InvertCondCode(CC));
 | 
						|
}
 | 
						|
 | 
						|
template <unsigned field_width, unsigned scale> void
 | 
						|
AArch64InstPrinter::printLabelOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                            raw_ostream &O) {
 | 
						|
  const MCOperand &MO = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  if (!MO.isImm()) {
 | 
						|
    printOperand(MI, OpNum, O);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // The immediate of LDR (lit) instructions is a signed 19-bit immediate, which
 | 
						|
  // is multiplied by 4 (because all A64 instructions are 32-bits wide).
 | 
						|
  uint64_t UImm = MO.getImm();
 | 
						|
  uint64_t Sign = UImm & (1LL << (field_width - 1));
 | 
						|
  int64_t SImm = scale * ((UImm & ~Sign) - Sign);
 | 
						|
 | 
						|
  O << "#" << SImm;
 | 
						|
}
 | 
						|
 | 
						|
template<unsigned RegWidth> void
 | 
						|
AArch64InstPrinter::printLogicalImmOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                           raw_ostream &O) {
 | 
						|
  const MCOperand &MO = MI->getOperand(OpNum);
 | 
						|
  uint64_t Val;
 | 
						|
  A64Imms::isLogicalImmBits(RegWidth, MO.getImm(), Val);
 | 
						|
  O << "#0x";
 | 
						|
  O.write_hex(Val);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printOffsetUImm12Operand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                               raw_ostream &O, int MemSize) {
 | 
						|
  const MCOperand &MOImm = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  if (MOImm.isImm()) {
 | 
						|
    uint32_t Imm = MOImm.getImm() * MemSize;
 | 
						|
 | 
						|
    O << "#" << Imm;
 | 
						|
  } else {
 | 
						|
    O << "#" << *MOImm.getExpr();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printShiftOperand(const MCInst *MI,  unsigned OpNum,
 | 
						|
                                      raw_ostream &O,
 | 
						|
                                      A64SE::ShiftExtSpecifiers Shift) {
 | 
						|
    const MCOperand &MO = MI->getOperand(OpNum);
 | 
						|
 | 
						|
    // LSL #0 is not printed
 | 
						|
    if (Shift == A64SE::LSL && MO.isImm() && MO.getImm() == 0)
 | 
						|
        return;
 | 
						|
 | 
						|
    switch (Shift) {
 | 
						|
    case A64SE::LSL: O << "lsl"; break;
 | 
						|
    case A64SE::LSR: O << "lsr"; break;
 | 
						|
    case A64SE::ASR: O << "asr"; break;
 | 
						|
    case A64SE::ROR: O << "ror"; break;
 | 
						|
    default: llvm_unreachable("Invalid shift specifier in logical instruction");
 | 
						|
    }
 | 
						|
 | 
						|
  O << " #" << MO.getImm();
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printMoveWideImmOperand(const MCInst *MI,  unsigned OpNum,
 | 
						|
                                            raw_ostream &O) {
 | 
						|
  const MCOperand &UImm16MO = MI->getOperand(OpNum);
 | 
						|
  const MCOperand &ShiftMO = MI->getOperand(OpNum + 1);
 | 
						|
 | 
						|
  if (UImm16MO.isImm()) {
 | 
						|
    O << '#' << UImm16MO.getImm();
 | 
						|
 | 
						|
    if (ShiftMO.getImm() != 0)
 | 
						|
      O << ", lsl #" << (ShiftMO.getImm() * 16);
 | 
						|
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  O << "#" << *UImm16MO.getExpr();
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printNamedImmOperand(const NamedImmMapper &Mapper,
 | 
						|
                                              const MCInst *MI, unsigned OpNum,
 | 
						|
                                              raw_ostream &O) {
 | 
						|
  bool ValidName;
 | 
						|
  const MCOperand &MO = MI->getOperand(OpNum);
 | 
						|
  StringRef Name = Mapper.toString(MO.getImm(), ValidName);
 | 
						|
 | 
						|
  if (ValidName)
 | 
						|
    O << Name;
 | 
						|
  else
 | 
						|
    O << '#' << MO.getImm();
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
AArch64InstPrinter::printSysRegOperand(const A64SysReg::SysRegMapper &Mapper,
 | 
						|
                                       const MCInst *MI, unsigned OpNum,
 | 
						|
                                       raw_ostream &O) {
 | 
						|
  const MCOperand &MO = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  bool ValidName;
 | 
						|
  std::string Name = Mapper.toString(MO.getImm(), ValidName);
 | 
						|
  if (ValidName) {
 | 
						|
    O << Name;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void AArch64InstPrinter::printRegExtendOperand(const MCInst *MI,
 | 
						|
                                               unsigned OpNum,
 | 
						|
                                               raw_ostream &O,
 | 
						|
                                               A64SE::ShiftExtSpecifiers Ext) {
 | 
						|
  // FIXME: In principle TableGen should be able to detect this itself far more
 | 
						|
  // easily. We will only accumulate more of these hacks.
 | 
						|
  unsigned Reg0 = MI->getOperand(0).getReg();
 | 
						|
  unsigned Reg1 = MI->getOperand(1).getReg();
 | 
						|
 | 
						|
  if (isStackReg(Reg0) || isStackReg(Reg1)) {
 | 
						|
    A64SE::ShiftExtSpecifiers LSLEquiv;
 | 
						|
 | 
						|
    if (Reg0 == AArch64::XSP || Reg1 == AArch64::XSP)
 | 
						|
      LSLEquiv = A64SE::UXTX;
 | 
						|
    else
 | 
						|
      LSLEquiv = A64SE::UXTW;
 | 
						|
 | 
						|
    if (Ext == LSLEquiv) {
 | 
						|
      O << "lsl #" << MI->getOperand(OpNum).getImm();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  switch (Ext) {
 | 
						|
  case A64SE::UXTB: O << "uxtb"; break;
 | 
						|
  case A64SE::UXTH: O << "uxth"; break;
 | 
						|
  case A64SE::UXTW: O << "uxtw"; break;
 | 
						|
  case A64SE::UXTX: O << "uxtx"; break;
 | 
						|
  case A64SE::SXTB: O << "sxtb"; break;
 | 
						|
  case A64SE::SXTH: O << "sxth"; break;
 | 
						|
  case A64SE::SXTW: O << "sxtw"; break;
 | 
						|
  case A64SE::SXTX: O << "sxtx"; break;
 | 
						|
  default: llvm_unreachable("Unexpected shift type for printing");
 | 
						|
  }
 | 
						|
 | 
						|
  const MCOperand &MO = MI->getOperand(OpNum);
 | 
						|
  if (MO.getImm() != 0)
 | 
						|
    O << " #" << MO.getImm();
 | 
						|
}
 | 
						|
 | 
						|
template<int MemScale> void
 | 
						|
AArch64InstPrinter::printSImm7ScaledOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                      raw_ostream &O) {
 | 
						|
  const MCOperand &MOImm = MI->getOperand(OpNum);
 | 
						|
  int32_t Imm = unpackSignedImm(7, MOImm.getImm());
 | 
						|
 | 
						|
  O << "#" << (Imm * MemScale);
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printVPRRegister(const MCInst *MI, unsigned OpNo,
 | 
						|
                                          raw_ostream &O) {
 | 
						|
  unsigned Reg = MI->getOperand(OpNo).getReg();
 | 
						|
  std::string Name = getRegisterName(Reg);
 | 
						|
  Name[0] = 'v';
 | 
						|
  O << Name;
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
 | 
						|
                                      raw_ostream &O) {
 | 
						|
  const MCOperand &Op = MI->getOperand(OpNo);
 | 
						|
  if (Op.isReg()) {
 | 
						|
    unsigned Reg = Op.getReg();
 | 
						|
    O << getRegisterName(Reg);
 | 
						|
  } else if (Op.isImm()) {
 | 
						|
    O << '#' << Op.getImm();
 | 
						|
  } else {
 | 
						|
    assert(Op.isExpr() && "unknown operand kind in printOperand");
 | 
						|
    // If a symbolic branch target was added as a constant expression then print
 | 
						|
    // that address in hex.
 | 
						|
    const MCConstantExpr *BranchTarget = dyn_cast<MCConstantExpr>(Op.getExpr());
 | 
						|
    int64_t Address;
 | 
						|
    if (BranchTarget && BranchTarget->EvaluateAsAbsolute(Address)) {
 | 
						|
      O << "0x";
 | 
						|
      O.write_hex(Address);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      // Otherwise, just print the expression.
 | 
						|
      O << *Op.getExpr();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void AArch64InstPrinter::printInst(const MCInst *MI, raw_ostream &O,
 | 
						|
                                   StringRef Annot) {
 | 
						|
  if (MI->getOpcode() == AArch64::TLSDESCCALL) {
 | 
						|
    // This is a special assembler directive which applies an
 | 
						|
    // R_AARCH64_TLSDESC_CALL to the following (BLR) instruction. It has a fixed
 | 
						|
    // form outside the normal TableGenerated scheme.
 | 
						|
    O << "\t.tlsdesccall " << *MI->getOperand(0).getExpr();
 | 
						|
  } else if (!printAliasInstr(MI, O))
 | 
						|
    printInstruction(MI, O);
 | 
						|
 | 
						|
  printAnnotation(O, Annot);
 | 
						|
}
 | 
						|
 | 
						|
template <A64SE::ShiftExtSpecifiers Ext, bool isHalf>
 | 
						|
void AArch64InstPrinter::printNeonMovImmShiftOperand(const MCInst *MI,
 | 
						|
                                                     unsigned OpNum,
 | 
						|
                                                     raw_ostream &O) {
 | 
						|
  const MCOperand &MO = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  assert(MO.isImm() &&
 | 
						|
         "Immediate operand required for Neon vector immediate inst.");
 | 
						|
 | 
						|
  bool IsLSL = false;
 | 
						|
  if (Ext == A64SE::LSL)
 | 
						|
    IsLSL = true;
 | 
						|
  else if (Ext != A64SE::MSL)
 | 
						|
    llvm_unreachable("Invalid shift specifier in movi instruction");
 | 
						|
 | 
						|
  int64_t Imm = MO.getImm();
 | 
						|
 | 
						|
  // MSL and LSLH accepts encoded shift amount 0 or 1.
 | 
						|
  if ((!IsLSL || (IsLSL && isHalf)) && Imm != 0 && Imm != 1)
 | 
						|
    llvm_unreachable("Invalid shift amount in movi instruction");
 | 
						|
 | 
						|
  // LSH accepts encoded shift amount 0, 1, 2 or 3.
 | 
						|
  if (IsLSL && (Imm < 0 || Imm > 3))
 | 
						|
    llvm_unreachable("Invalid shift amount in movi instruction");
 | 
						|
 | 
						|
  // Print shift amount as multiple of 8 with MSL encoded shift amount
 | 
						|
  // 0 and 1 printed as 8 and 16.
 | 
						|
  if (!IsLSL)
 | 
						|
    Imm++;
 | 
						|
  Imm *= 8;
 | 
						|
 | 
						|
  // LSL #0 is not printed
 | 
						|
  if (IsLSL) {
 | 
						|
    if (Imm == 0)
 | 
						|
      return;
 | 
						|
    O << ", lsl";
 | 
						|
  } else
 | 
						|
    O << ", msl";
 | 
						|
 | 
						|
  O << " #" << Imm;
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printNeonUImm0Operand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                               raw_ostream &o) {
 | 
						|
  o << "#0x0";
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printUImmHexOperand(const MCInst *MI, unsigned OpNum,
 | 
						|
                                             raw_ostream &O) {
 | 
						|
  const MCOperand &MOUImm = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  assert(MOUImm.isImm() &&
 | 
						|
         "Immediate operand required for Neon vector immediate inst.");
 | 
						|
 | 
						|
  unsigned Imm = MOUImm.getImm();
 | 
						|
 | 
						|
  O << "#0x";
 | 
						|
  O.write_hex(Imm);
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printUImmBareOperand(const MCInst *MI,
 | 
						|
                                              unsigned OpNum,
 | 
						|
                                              raw_ostream &O) {
 | 
						|
  const MCOperand &MOUImm = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  assert(MOUImm.isImm()
 | 
						|
         && "Immediate operand required for Neon vector immediate inst.");
 | 
						|
 | 
						|
  unsigned Imm = MOUImm.getImm();
 | 
						|
  O << Imm;
 | 
						|
}
 | 
						|
 | 
						|
void AArch64InstPrinter::printNeonUImm64MaskOperand(const MCInst *MI,
 | 
						|
                                                    unsigned OpNum,
 | 
						|
                                                    raw_ostream &O) {
 | 
						|
  const MCOperand &MOUImm8 = MI->getOperand(OpNum);
 | 
						|
 | 
						|
  assert(MOUImm8.isImm() &&
 | 
						|
         "Immediate operand required for Neon vector immediate bytemask inst.");
 | 
						|
 | 
						|
  uint32_t UImm8 = MOUImm8.getImm();
 | 
						|
  uint64_t Mask = 0;
 | 
						|
 | 
						|
  // Replicates 0x00 or 0xff byte in a 64-bit vector
 | 
						|
  for (unsigned ByteNum = 0; ByteNum < 8; ++ByteNum) {
 | 
						|
    if ((UImm8 >> ByteNum) & 1)
 | 
						|
      Mask |= (uint64_t)0xff << (8 * ByteNum);
 | 
						|
  }
 | 
						|
 | 
						|
  O << "#0x";
 | 
						|
  O.write_hex(Mask);
 | 
						|
}
 | 
						|
 | 
						|
// If Count > 1, there are two valid kinds of vector list:
 | 
						|
//   (1) {Vn.layout, Vn+1.layout, ... , Vm.layout}
 | 
						|
//   (2) {Vn.layout - Vm.layout}
 | 
						|
// We choose the first kind as output.
 | 
						|
template <A64Layout::VectorLayout Layout, unsigned Count>
 | 
						|
void AArch64InstPrinter::printVectorList(const MCInst *MI, unsigned OpNum,
 | 
						|
                                         raw_ostream &O) {
 | 
						|
  assert(Count >= 1 && Count <= 4 && "Invalid Number of Vectors");
 | 
						|
 | 
						|
  unsigned Reg = MI->getOperand(OpNum).getReg();
 | 
						|
  std::string LayoutStr = A64VectorLayoutToString(Layout);
 | 
						|
  O << "{ ";
 | 
						|
  if (Count > 1) { // Print sub registers separately
 | 
						|
    bool IsVec64 = (Layout < A64Layout::VL_16B);
 | 
						|
    unsigned SubRegIdx = IsVec64 ? AArch64::dsub_0 : AArch64::qsub_0;
 | 
						|
    for (unsigned I = 0; I < Count; I++) {
 | 
						|
      std::string Name = getRegisterName(MRI.getSubReg(Reg, SubRegIdx++));
 | 
						|
      Name[0] = 'v';
 | 
						|
      O << Name << LayoutStr;
 | 
						|
      if (I != Count - 1)
 | 
						|
        O << ", ";
 | 
						|
    }
 | 
						|
  } else { // Print the register directly when NumVecs is 1.
 | 
						|
    std::string Name = getRegisterName(Reg);
 | 
						|
    Name[0] = 'v';
 | 
						|
    O << Name << LayoutStr;
 | 
						|
  }
 | 
						|
  O << " }";
 | 
						|
}
 |