1 //===-- X86ATTInstPrinter.cpp - AT&T assembly instruction printing --------===// 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 file includes code for rendering MCInst instances as AT&T-style 11 // assembly. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "X86ATTInstPrinter.h" 16 #include "MCTargetDesc/X86BaseInfo.h" 17 #include "X86InstComments.h" 18 #include "llvm/MC/MCExpr.h" 19 #include "llvm/MC/MCInst.h" 20 #include "llvm/MC/MCInstrDesc.h" 21 #include "llvm/MC/MCInstrInfo.h" 22 #include "llvm/MC/MCSubtargetInfo.h" 23 #include "llvm/Support/Casting.h" 24 #include "llvm/Support/ErrorHandling.h" 25 #include "llvm/Support/Format.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include <cassert> 28 #include <cinttypes> 29 #include <cstdint> 30 31 using namespace llvm; 32 33 #define DEBUG_TYPE "asm-printer" 34 35 // Include the auto-generated portion of the assembly writer. 36 #define PRINT_ALIAS_INSTR 37 #include "X86GenAsmWriter.inc" 38 39 void X86ATTInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { 40 OS << markup("<reg:") << '%' << getRegisterName(RegNo) << markup(">"); 41 } 42 43 void X86ATTInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, 44 StringRef Annot, const MCSubtargetInfo &STI) { 45 const MCInstrDesc &Desc = MII.get(MI->getOpcode()); 46 uint64_t TSFlags = Desc.TSFlags; 47 48 // If verbose assembly is enabled, we can print some informative comments. 49 if (CommentStream) 50 HasCustomInstComment = 51 EmitAnyX86InstComments(MI, *CommentStream, getRegisterName); 52 53 unsigned Flags = MI->getFlags(); 54 if (TSFlags & X86II::LOCK) 55 OS << "\tlock\t"; 56 if (!(TSFlags & X86II::LOCK) && Flags & X86::IP_HAS_LOCK) 57 OS << "\tlock\t"; 58 59 if (Flags & X86::IP_HAS_REPEAT_NE) 60 OS << "\trepne\t"; 61 else if (Flags & X86::IP_HAS_REPEAT) 62 OS << "\trep\t"; 63 64 // Output CALLpcrel32 as "callq" in 64-bit mode. 65 // In Intel annotation it's always emitted as "call". 66 // 67 // TODO: Probably this hack should be redesigned via InstAlias in 68 // InstrInfo.td as soon as Requires clause is supported properly 69 // for InstAlias. 70 if (MI->getOpcode() == X86::CALLpcrel32 && 71 (STI.getFeatureBits()[X86::Mode64Bit])) { 72 OS << "\tcallq\t"; 73 printPCRelImm(MI, 0, OS); 74 } 75 // data16 and data32 both have the same encoding of 0x66. While data32 is 76 // valid only in 16 bit systems, data16 is valid in the rest. 77 // There seems to be some lack of support of the Requires clause that causes 78 // 0x66 to be interpreted as "data16" by the asm printer. 79 // Thus we add an adjustment here in order to print the "right" instruction. 80 else if (MI->getOpcode() == X86::DATA16_PREFIX && 81 (STI.getFeatureBits()[X86::Mode16Bit])) { 82 MCInst Data32MI(*MI); 83 Data32MI.setOpcode(X86::DATA32_PREFIX); 84 printInstruction(&Data32MI, OS); 85 } 86 // Try to print any aliases first. 87 else if (!printAliasInstr(MI, OS)) 88 printInstruction(MI, OS); 89 90 // Next always print the annotation. 91 printAnnotation(OS, Annot); 92 } 93 94 void X86ATTInstPrinter::printSSEAVXCC(const MCInst *MI, unsigned Op, 95 raw_ostream &O) { 96 int64_t Imm = MI->getOperand(Op).getImm(); 97 switch (Imm) { 98 default: llvm_unreachable("Invalid ssecc/avxcc argument!"); 99 case 0: O << "eq"; break; 100 case 1: O << "lt"; break; 101 case 2: O << "le"; break; 102 case 3: O << "unord"; break; 103 case 4: O << "neq"; break; 104 case 5: O << "nlt"; break; 105 case 6: O << "nle"; break; 106 case 7: O << "ord"; break; 107 case 8: O << "eq_uq"; break; 108 case 9: O << "nge"; break; 109 case 0xa: O << "ngt"; break; 110 case 0xb: O << "false"; break; 111 case 0xc: O << "neq_oq"; break; 112 case 0xd: O << "ge"; break; 113 case 0xe: O << "gt"; break; 114 case 0xf: O << "true"; break; 115 case 0x10: O << "eq_os"; break; 116 case 0x11: O << "lt_oq"; break; 117 case 0x12: O << "le_oq"; break; 118 case 0x13: O << "unord_s"; break; 119 case 0x14: O << "neq_us"; break; 120 case 0x15: O << "nlt_uq"; break; 121 case 0x16: O << "nle_uq"; break; 122 case 0x17: O << "ord_s"; break; 123 case 0x18: O << "eq_us"; break; 124 case 0x19: O << "nge_uq"; break; 125 case 0x1a: O << "ngt_uq"; break; 126 case 0x1b: O << "false_os"; break; 127 case 0x1c: O << "neq_os"; break; 128 case 0x1d: O << "ge_oq"; break; 129 case 0x1e: O << "gt_oq"; break; 130 case 0x1f: O << "true_us"; break; 131 } 132 } 133 134 void X86ATTInstPrinter::printXOPCC(const MCInst *MI, unsigned Op, 135 raw_ostream &O) { 136 int64_t Imm = MI->getOperand(Op).getImm(); 137 switch (Imm) { 138 default: llvm_unreachable("Invalid xopcc argument!"); 139 case 0: O << "lt"; break; 140 case 1: O << "le"; break; 141 case 2: O << "gt"; break; 142 case 3: O << "ge"; break; 143 case 4: O << "eq"; break; 144 case 5: O << "neq"; break; 145 case 6: O << "false"; break; 146 case 7: O << "true"; break; 147 } 148 } 149 150 void X86ATTInstPrinter::printRoundingControl(const MCInst *MI, unsigned Op, 151 raw_ostream &O) { 152 int64_t Imm = MI->getOperand(Op).getImm() & 0x3; 153 switch (Imm) { 154 case 0: O << "{rn-sae}"; break; 155 case 1: O << "{rd-sae}"; break; 156 case 2: O << "{ru-sae}"; break; 157 case 3: O << "{rz-sae}"; break; 158 } 159 } 160 161 /// printPCRelImm - This is used to print an immediate value that ends up 162 /// being encoded as a pc-relative value (e.g. for jumps and calls). These 163 /// print slightly differently than normal immediates. For example, a $ is not 164 /// emitted. 165 void X86ATTInstPrinter::printPCRelImm(const MCInst *MI, unsigned OpNo, 166 raw_ostream &O) { 167 const MCOperand &Op = MI->getOperand(OpNo); 168 if (Op.isImm()) 169 O << formatImm(Op.getImm()); 170 else { 171 assert(Op.isExpr() && "unknown pcrel immediate operand"); 172 // If a symbolic branch target was added as a constant expression then print 173 // that address in hex. 174 const MCConstantExpr *BranchTarget = dyn_cast<MCConstantExpr>(Op.getExpr()); 175 int64_t Address; 176 if (BranchTarget && BranchTarget->evaluateAsAbsolute(Address)) { 177 O << formatHex((uint64_t)Address); 178 } else { 179 // Otherwise, just print the expression. 180 Op.getExpr()->print(O, &MAI); 181 } 182 } 183 } 184 185 void X86ATTInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 186 raw_ostream &O) { 187 const MCOperand &Op = MI->getOperand(OpNo); 188 if (Op.isReg()) { 189 printRegName(O, Op.getReg()); 190 } else if (Op.isImm()) { 191 // Print immediates as signed values. 192 int64_t Imm = Op.getImm(); 193 O << markup("<imm:") << '$' << formatImm(Imm) << markup(">"); 194 195 // TODO: This should be in a helper function in the base class, so it can 196 // be used by other printers. 197 198 // If there are no instruction-specific comments, add a comment clarifying 199 // the hex value of the immediate operand when it isn't in the range 200 // [-256,255]. 201 if (CommentStream && !HasCustomInstComment && (Imm > 255 || Imm < -256)) { 202 // Don't print unnecessary hex sign bits. 203 if (Imm == (int16_t)(Imm)) 204 *CommentStream << format("imm = 0x%" PRIX16 "\n", (uint16_t)Imm); 205 else if (Imm == (int32_t)(Imm)) 206 *CommentStream << format("imm = 0x%" PRIX32 "\n", (uint32_t)Imm); 207 else 208 *CommentStream << format("imm = 0x%" PRIX64 "\n", (uint64_t)Imm); 209 } 210 } else { 211 assert(Op.isExpr() && "unknown operand kind in printOperand"); 212 O << markup("<imm:") << '$'; 213 Op.getExpr()->print(O, &MAI); 214 O << markup(">"); 215 } 216 } 217 218 void X86ATTInstPrinter::printMemReference(const MCInst *MI, unsigned Op, 219 raw_ostream &O) { 220 const MCOperand &BaseReg = MI->getOperand(Op + X86::AddrBaseReg); 221 const MCOperand &IndexReg = MI->getOperand(Op + X86::AddrIndexReg); 222 const MCOperand &DispSpec = MI->getOperand(Op + X86::AddrDisp); 223 const MCOperand &SegReg = MI->getOperand(Op + X86::AddrSegmentReg); 224 225 O << markup("<mem:"); 226 227 // If this has a segment register, print it. 228 if (SegReg.getReg()) { 229 printOperand(MI, Op + X86::AddrSegmentReg, O); 230 O << ':'; 231 } 232 233 if (DispSpec.isImm()) { 234 int64_t DispVal = DispSpec.getImm(); 235 if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg())) 236 O << formatImm(DispVal); 237 } else { 238 assert(DispSpec.isExpr() && "non-immediate displacement for LEA?"); 239 DispSpec.getExpr()->print(O, &MAI); 240 } 241 242 if (IndexReg.getReg() || BaseReg.getReg()) { 243 O << '('; 244 if (BaseReg.getReg()) 245 printOperand(MI, Op + X86::AddrBaseReg, O); 246 247 if (IndexReg.getReg()) { 248 O << ','; 249 printOperand(MI, Op + X86::AddrIndexReg, O); 250 unsigned ScaleVal = MI->getOperand(Op + X86::AddrScaleAmt).getImm(); 251 if (ScaleVal != 1) { 252 O << ',' << markup("<imm:") << ScaleVal // never printed in hex. 253 << markup(">"); 254 } 255 } 256 O << ')'; 257 } 258 259 O << markup(">"); 260 } 261 262 void X86ATTInstPrinter::printSrcIdx(const MCInst *MI, unsigned Op, 263 raw_ostream &O) { 264 const MCOperand &SegReg = MI->getOperand(Op + 1); 265 266 O << markup("<mem:"); 267 268 // If this has a segment register, print it. 269 if (SegReg.getReg()) { 270 printOperand(MI, Op + 1, O); 271 O << ':'; 272 } 273 274 O << "("; 275 printOperand(MI, Op, O); 276 O << ")"; 277 278 O << markup(">"); 279 } 280 281 void X86ATTInstPrinter::printDstIdx(const MCInst *MI, unsigned Op, 282 raw_ostream &O) { 283 O << markup("<mem:"); 284 285 O << "%es:("; 286 printOperand(MI, Op, O); 287 O << ")"; 288 289 O << markup(">"); 290 } 291 292 void X86ATTInstPrinter::printMemOffset(const MCInst *MI, unsigned Op, 293 raw_ostream &O) { 294 const MCOperand &DispSpec = MI->getOperand(Op); 295 const MCOperand &SegReg = MI->getOperand(Op + 1); 296 297 O << markup("<mem:"); 298 299 // If this has a segment register, print it. 300 if (SegReg.getReg()) { 301 printOperand(MI, Op + 1, O); 302 O << ':'; 303 } 304 305 if (DispSpec.isImm()) { 306 O << formatImm(DispSpec.getImm()); 307 } else { 308 assert(DispSpec.isExpr() && "non-immediate displacement?"); 309 DispSpec.getExpr()->print(O, &MAI); 310 } 311 312 O << markup(">"); 313 } 314 315 void X86ATTInstPrinter::printU8Imm(const MCInst *MI, unsigned Op, 316 raw_ostream &O) { 317 if (MI->getOperand(Op).isExpr()) 318 return printOperand(MI, Op, O); 319 320 O << markup("<imm:") << '$' << formatImm(MI->getOperand(Op).getImm() & 0xff) 321 << markup(">"); 322 } 323