Home | History | Annotate | Download | only in InstPrinter
      1 //==-- AArch64InstPrinter.cpp - Convert AArch64 MCInst to assembly syntax --==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This class prints an AArch64 MCInst to a .s file.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #define DEBUG_TYPE "asm-printer"
     15 #include "AArch64InstPrinter.h"
     16 #include "MCTargetDesc/AArch64MCTargetDesc.h"
     17 #include "Utils/AArch64BaseInfo.h"
     18 #include "llvm/MC/MCInst.h"
     19 #include "llvm/MC/MCExpr.h"
     20 #include "llvm/MC/MCRegisterInfo.h"
     21 #include "llvm/Support/ErrorHandling.h"
     22 #include "llvm/Support/Format.h"
     23 #include "llvm/Support/raw_ostream.h"
     24 
     25 using namespace llvm;
     26 
     27 #define GET_INSTRUCTION_NAME
     28 #define PRINT_ALIAS_INSTR
     29 #include "AArch64GenAsmWriter.inc"
     30 
     31 static int64_t unpackSignedImm(int BitWidth, uint64_t Value) {
     32   assert(!(Value & ~((1ULL << BitWidth)-1)) && "immediate not n-bit");
     33   if (Value & (1ULL <<  (BitWidth - 1)))
     34     return static_cast<int64_t>(Value) - (1LL << BitWidth);
     35   else
     36     return Value;
     37 }
     38 
     39 AArch64InstPrinter::AArch64InstPrinter(const MCAsmInfo &MAI,
     40                                        const MCInstrInfo &MII,
     41                                        const MCRegisterInfo &MRI,
     42                                        const MCSubtargetInfo &STI) :
     43   MCInstPrinter(MAI, MII, MRI) {
     44   // Initialize the set of available features.
     45   setAvailableFeatures(STI.getFeatureBits());
     46 }
     47 
     48 void AArch64InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
     49   OS << getRegisterName(RegNo);
     50 }
     51 
     52 void
     53 AArch64InstPrinter::printOffsetSImm9Operand(const MCInst *MI,
     54                                               unsigned OpNum, raw_ostream &O) {
     55   const MCOperand &MOImm = MI->getOperand(OpNum);
     56   int32_t Imm = unpackSignedImm(9, MOImm.getImm());
     57 
     58   O << '#' << Imm;
     59 }
     60 
     61 void
     62 AArch64InstPrinter::printAddrRegExtendOperand(const MCInst *MI, unsigned OpNum,
     63                                           raw_ostream &O, unsigned MemSize,
     64                                           unsigned RmSize) {
     65   unsigned ExtImm = MI->getOperand(OpNum).getImm();
     66   unsigned OptionHi = ExtImm >> 1;
     67   unsigned S = ExtImm & 1;
     68   bool IsLSL = OptionHi == 1 && RmSize == 64;
     69 
     70   const char *Ext;
     71   switch (OptionHi) {
     72   case 1:
     73     Ext = (RmSize == 32) ? "uxtw" : "lsl";
     74     break;
     75   case 3:
     76     Ext = (RmSize == 32) ? "sxtw" : "sxtx";
     77     break;
     78   default:
     79     llvm_unreachable("Incorrect Option on load/store (reg offset)");
     80   }
     81   O << Ext;
     82 
     83   if (S) {
     84     unsigned ShiftAmt = Log2_32(MemSize);
     85     O << " #" << ShiftAmt;
     86   } else if (IsLSL) {
     87     O << " #0";
     88   }
     89 }
     90 
     91 void
     92 AArch64InstPrinter::printAddSubImmLSL0Operand(const MCInst *MI,
     93                                               unsigned OpNum, raw_ostream &O) {
     94   const MCOperand &Imm12Op = MI->getOperand(OpNum);
     95 
     96   if (Imm12Op.isImm()) {
     97     int64_t Imm12 = Imm12Op.getImm();
     98     assert(Imm12 >= 0 && "Invalid immediate for add/sub imm");
     99     O << "#" << Imm12;
    100   } else {
    101     assert(Imm12Op.isExpr() && "Unexpected shift operand type");
    102     O << "#" << *Imm12Op.getExpr();
    103   }
    104 }
    105 
    106 void
    107 AArch64InstPrinter::printAddSubImmLSL12Operand(const MCInst *MI, unsigned OpNum,
    108                                                raw_ostream &O) {
    109 
    110   printAddSubImmLSL0Operand(MI, OpNum, O);
    111 
    112   O << ", lsl #12";
    113 }
    114 
    115 void
    116 AArch64InstPrinter::printBareImmOperand(const MCInst *MI, unsigned OpNum,
    117                                         raw_ostream &O) {
    118   const MCOperand &MO = MI->getOperand(OpNum);
    119   O << MO.getImm();
    120 }
    121 
    122 template<unsigned RegWidth> void
    123 AArch64InstPrinter::printBFILSBOperand(const MCInst *MI, unsigned OpNum,
    124                                        raw_ostream &O) {
    125   const MCOperand &ImmROp = MI->getOperand(OpNum);
    126   unsigned LSB = ImmROp.getImm() == 0 ? 0 : RegWidth - ImmROp.getImm();
    127 
    128   O << '#' << LSB;
    129 }
    130 
    131 void AArch64InstPrinter::printBFIWidthOperand(const MCInst *MI, unsigned OpNum,
    132                                               raw_ostream &O) {
    133   const MCOperand &ImmSOp = MI->getOperand(OpNum);
    134   unsigned Width = ImmSOp.getImm() + 1;
    135 
    136   O << '#' << Width;
    137 }
    138 
    139 void
    140 AArch64InstPrinter::printBFXWidthOperand(const MCInst *MI, unsigned OpNum,
    141                                          raw_ostream &O) {
    142   const MCOperand &ImmSOp = MI->getOperand(OpNum);
    143   const MCOperand &ImmROp = MI->getOperand(OpNum - 1);
    144 
    145   unsigned ImmR = ImmROp.getImm();
    146   unsigned ImmS = ImmSOp.getImm();
    147 
    148   assert(ImmS >= ImmR && "Invalid ImmR, ImmS combination for bitfield extract");
    149 
    150   O << '#' << (ImmS - ImmR + 1);
    151 }
    152 
    153 void
    154 AArch64InstPrinter::printCRxOperand(const MCInst *MI, unsigned OpNum,
    155                                     raw_ostream &O) {
    156     const MCOperand &CRx = MI->getOperand(OpNum);
    157 
    158     O << 'c' << CRx.getImm();
    159 }
    160 
    161 
    162 void
    163 AArch64InstPrinter::printCVTFixedPosOperand(const MCInst *MI, unsigned OpNum,
    164                                             raw_ostream &O) {
    165     const MCOperand &ScaleOp = MI->getOperand(OpNum);
    166 
    167     O << '#' << (64 - ScaleOp.getImm());
    168 }
    169 
    170 
    171 void AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum,
    172                                            raw_ostream &o) {
    173   const MCOperand &MOImm8 = MI->getOperand(OpNum);
    174 
    175   assert(MOImm8.isImm()
    176          && "Immediate operand required for floating-point immediate inst");
    177 
    178   uint32_t Imm8 = MOImm8.getImm();
    179   uint32_t Fraction = Imm8 & 0xf;
    180   uint32_t Exponent = (Imm8 >> 4) & 0x7;
    181   uint32_t Negative = (Imm8 >> 7) & 0x1;
    182 
    183   float Val = 1.0f + Fraction / 16.0f;
    184 
    185   // That is:
    186   // 000 -> 2^1,  001 -> 2^2,  010 -> 2^3,  011 -> 2^4,
    187   // 100 -> 2^-3, 101 -> 2^-2, 110 -> 2^-1, 111 -> 2^0
    188   if (Exponent & 0x4) {
    189     Val /= 1 << (7 - Exponent);
    190   } else {
    191     Val *= 1 << (Exponent + 1);
    192   }
    193 
    194   Val = Negative ? -Val : Val;
    195 
    196   o << '#' << format("%.8f", Val);
    197 }
    198 
    199 void AArch64InstPrinter::printFPZeroOperand(const MCInst *MI, unsigned OpNum,
    200                                             raw_ostream &o) {
    201   o << "#0.0";
    202 }
    203 
    204 void
    205 AArch64InstPrinter::printCondCodeOperand(const MCInst *MI, unsigned OpNum,
    206                                          raw_ostream &O) {
    207   const MCOperand &MO = MI->getOperand(OpNum);
    208 
    209   O << A64CondCodeToString(static_cast<A64CC::CondCodes>(MO.getImm()));
    210 }
    211 
    212 template <unsigned field_width, unsigned scale> void
    213 AArch64InstPrinter::printLabelOperand(const MCInst *MI, unsigned OpNum,
    214                                             raw_ostream &O) {
    215   const MCOperand &MO = MI->getOperand(OpNum);
    216 
    217   if (!MO.isImm()) {
    218     printOperand(MI, OpNum, O);
    219     return;
    220   }
    221 
    222   // The immediate of LDR (lit) instructions is a signed 19-bit immediate, which
    223   // is multiplied by 4 (because all A64 instructions are 32-bits wide).
    224   uint64_t UImm = MO.getImm();
    225   uint64_t Sign = UImm & (1LL << (field_width - 1));
    226   int64_t SImm = scale * ((UImm & ~Sign) - Sign);
    227 
    228   O << "#" << SImm;
    229 }
    230 
    231 template<unsigned RegWidth> void
    232 AArch64InstPrinter::printLogicalImmOperand(const MCInst *MI, unsigned OpNum,
    233                                            raw_ostream &O) {
    234   const MCOperand &MO = MI->getOperand(OpNum);
    235   uint64_t Val;
    236   A64Imms::isLogicalImmBits(RegWidth, MO.getImm(), Val);
    237   O << "#0x";
    238   O.write_hex(Val);
    239 }
    240 
    241 void
    242 AArch64InstPrinter::printOffsetUImm12Operand(const MCInst *MI, unsigned OpNum,
    243                                                raw_ostream &O, int MemSize) {
    244   const MCOperand &MOImm = MI->getOperand(OpNum);
    245 
    246   if (MOImm.isImm()) {
    247     uint32_t Imm = MOImm.getImm() * MemSize;
    248 
    249     O << "#" << Imm;
    250   } else {
    251     O << "#" << *MOImm.getExpr();
    252   }
    253 }
    254 
    255 void
    256 AArch64InstPrinter::printShiftOperand(const MCInst *MI,  unsigned OpNum,
    257                                       raw_ostream &O,
    258                                       A64SE::ShiftExtSpecifiers Shift) {
    259     const MCOperand &MO = MI->getOperand(OpNum);
    260 
    261     // LSL #0 is not printed
    262     if (Shift == A64SE::LSL && MO.isImm() && MO.getImm() == 0)
    263         return;
    264 
    265     switch (Shift) {
    266     case A64SE::LSL: O << "lsl"; break;
    267     case A64SE::LSR: O << "lsr"; break;
    268     case A64SE::ASR: O << "asr"; break;
    269     case A64SE::ROR: O << "ror"; break;
    270     default: llvm_unreachable("Invalid shift specifier in logical instruction");
    271     }
    272 
    273   O << " #" << MO.getImm();
    274 }
    275 
    276 void
    277 AArch64InstPrinter::printMoveWideImmOperand(const MCInst *MI,  unsigned OpNum,
    278                                             raw_ostream &O) {
    279   const MCOperand &UImm16MO = MI->getOperand(OpNum);
    280   const MCOperand &ShiftMO = MI->getOperand(OpNum + 1);
    281 
    282   if (UImm16MO.isImm()) {
    283     O << '#' << UImm16MO.getImm();
    284 
    285     if (ShiftMO.getImm() != 0)
    286       O << ", lsl #" << (ShiftMO.getImm() * 16);
    287 
    288     return;
    289   }
    290 
    291   O << "#" << *UImm16MO.getExpr();
    292 }
    293 
    294 void AArch64InstPrinter::printNamedImmOperand(const NamedImmMapper &Mapper,
    295                                               const MCInst *MI, unsigned OpNum,
    296                                               raw_ostream &O) {
    297   bool ValidName;
    298   const MCOperand &MO = MI->getOperand(OpNum);
    299   StringRef Name = Mapper.toString(MO.getImm(), ValidName);
    300 
    301   if (ValidName)
    302     O << Name;
    303   else
    304     O << '#' << MO.getImm();
    305 }
    306 
    307 void
    308 AArch64InstPrinter::printSysRegOperand(const A64SysReg::SysRegMapper &Mapper,
    309                                        const MCInst *MI, unsigned OpNum,
    310                                        raw_ostream &O) {
    311   const MCOperand &MO = MI->getOperand(OpNum);
    312 
    313   bool ValidName;
    314   std::string Name = Mapper.toString(MO.getImm(), ValidName);
    315   if (ValidName) {
    316     O << Name;
    317     return;
    318   }
    319 }
    320 
    321 
    322 void AArch64InstPrinter::printRegExtendOperand(const MCInst *MI,
    323                                                unsigned OpNum,
    324                                                raw_ostream &O,
    325                                                A64SE::ShiftExtSpecifiers Ext) {
    326   // FIXME: In principle TableGen should be able to detect this itself far more
    327   // easily. We will only accumulate more of these hacks.
    328   unsigned Reg0 = MI->getOperand(0).getReg();
    329   unsigned Reg1 = MI->getOperand(1).getReg();
    330 
    331   if (isStackReg(Reg0) || isStackReg(Reg1)) {
    332     A64SE::ShiftExtSpecifiers LSLEquiv;
    333 
    334     if (Reg0 == AArch64::XSP || Reg1 == AArch64::XSP)
    335       LSLEquiv = A64SE::UXTX;
    336     else
    337       LSLEquiv = A64SE::UXTW;
    338 
    339     if (Ext == LSLEquiv) {
    340       O << "lsl #" << MI->getOperand(OpNum).getImm();
    341       return;
    342     }
    343   }
    344 
    345   switch (Ext) {
    346   case A64SE::UXTB: O << "uxtb"; break;
    347   case A64SE::UXTH: O << "uxth"; break;
    348   case A64SE::UXTW: O << "uxtw"; break;
    349   case A64SE::UXTX: O << "uxtx"; break;
    350   case A64SE::SXTB: O << "sxtb"; break;
    351   case A64SE::SXTH: O << "sxth"; break;
    352   case A64SE::SXTW: O << "sxtw"; break;
    353   case A64SE::SXTX: O << "sxtx"; break;
    354   default: llvm_unreachable("Unexpected shift type for printing");
    355   }
    356 
    357   const MCOperand &MO = MI->getOperand(OpNum);
    358   if (MO.getImm() != 0)
    359     O << " #" << MO.getImm();
    360 }
    361 
    362 template<int MemScale> void
    363 AArch64InstPrinter::printSImm7ScaledOperand(const MCInst *MI, unsigned OpNum,
    364                                       raw_ostream &O) {
    365   const MCOperand &MOImm = MI->getOperand(OpNum);
    366   int32_t Imm = unpackSignedImm(7, MOImm.getImm());
    367 
    368   O << "#" << (Imm * MemScale);
    369 }
    370 
    371 void AArch64InstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
    372                                       raw_ostream &O) {
    373   const MCOperand &Op = MI->getOperand(OpNo);
    374   if (Op.isReg()) {
    375     unsigned Reg = Op.getReg();
    376     O << getRegisterName(Reg);
    377   } else if (Op.isImm()) {
    378     O << '#' << Op.getImm();
    379   } else {
    380     assert(Op.isExpr() && "unknown operand kind in printOperand");
    381     // If a symbolic branch target was added as a constant expression then print
    382     // that address in hex.
    383     const MCConstantExpr *BranchTarget = dyn_cast<MCConstantExpr>(Op.getExpr());
    384     int64_t Address;
    385     if (BranchTarget && BranchTarget->EvaluateAsAbsolute(Address)) {
    386       O << "0x";
    387       O.write_hex(Address);
    388     }
    389     else {
    390       // Otherwise, just print the expression.
    391       O << *Op.getExpr();
    392     }
    393   }
    394 }
    395 
    396 
    397 void AArch64InstPrinter::printInst(const MCInst *MI, raw_ostream &O,
    398                                    StringRef Annot) {
    399   if (MI->getOpcode() == AArch64::TLSDESCCALL) {
    400     // This is a special assembler directive which applies an
    401     // R_AARCH64_TLSDESC_CALL to the following (BLR) instruction. It has a fixed
    402     // form outside the normal TableGenerated scheme.
    403     O << "\t.tlsdesccall " << *MI->getOperand(0).getExpr();
    404   } else if (!printAliasInstr(MI, O))
    405     printInstruction(MI, O);
    406 
    407   printAnnotation(O, Annot);
    408 }
    409