Path: blob/main/contrib/llvm-project/llvm/lib/Target/X86/MCTargetDesc/X86ATTInstPrinter.cpp
35294 views
//===-- X86ATTInstPrinter.cpp - AT&T assembly instruction printing --------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file includes code for rendering MCInst instances as AT&T-style9// assembly.10//11//===----------------------------------------------------------------------===//1213#include "X86ATTInstPrinter.h"14#include "X86BaseInfo.h"15#include "X86InstComments.h"16#include "llvm/MC/MCExpr.h"17#include "llvm/MC/MCInst.h"18#include "llvm/MC/MCInstrAnalysis.h"19#include "llvm/MC/MCInstrInfo.h"20#include "llvm/MC/MCSubtargetInfo.h"21#include "llvm/Support/Casting.h"22#include "llvm/Support/ErrorHandling.h"23#include "llvm/Support/Format.h"24#include "llvm/Support/raw_ostream.h"25#include <cassert>26#include <cinttypes>27#include <cstdint>2829using namespace llvm;3031#define DEBUG_TYPE "asm-printer"3233// Include the auto-generated portion of the assembly writer.34#define PRINT_ALIAS_INSTR35#include "X86GenAsmWriter.inc"3637void X86ATTInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const {38markup(OS, Markup::Register) << '%' << getRegisterName(Reg);39}4041void X86ATTInstPrinter::printInst(const MCInst *MI, uint64_t Address,42StringRef Annot, const MCSubtargetInfo &STI,43raw_ostream &OS) {44// If verbose assembly is enabled, we can print some informative comments.45if (CommentStream)46HasCustomInstComment = EmitAnyX86InstComments(MI, *CommentStream, MII);4748printInstFlags(MI, OS, STI);4950// Output CALLpcrel32 as "callq" in 64-bit mode.51// In Intel annotation it's always emitted as "call".52//53// TODO: Probably this hack should be redesigned via InstAlias in54// InstrInfo.td as soon as Requires clause is supported properly55// for InstAlias.56if (MI->getOpcode() == X86::CALLpcrel32 &&57(STI.hasFeature(X86::Is64Bit))) {58OS << "\tcallq\t";59printPCRelImm(MI, Address, 0, OS);60}61// data16 and data32 both have the same encoding of 0x66. While data32 is62// valid only in 16 bit systems, data16 is valid in the rest.63// There seems to be some lack of support of the Requires clause that causes64// 0x66 to be interpreted as "data16" by the asm printer.65// Thus we add an adjustment here in order to print the "right" instruction.66else if (MI->getOpcode() == X86::DATA16_PREFIX &&67STI.hasFeature(X86::Is16Bit)) {68OS << "\tdata32";69}70// Try to print any aliases first.71else if (!printAliasInstr(MI, Address, OS) && !printVecCompareInstr(MI, OS))72printInstruction(MI, Address, OS);7374// Next always print the annotation.75printAnnotation(OS, Annot);76}7778bool X86ATTInstPrinter::printVecCompareInstr(const MCInst *MI,79raw_ostream &OS) {80if (MI->getNumOperands() == 0 ||81!MI->getOperand(MI->getNumOperands() - 1).isImm())82return false;8384int64_t Imm = MI->getOperand(MI->getNumOperands() - 1).getImm();8586const MCInstrDesc &Desc = MII.get(MI->getOpcode());8788// Custom print the vector compare instructions to get the immediate89// translated into the mnemonic.90switch (MI->getOpcode()) {91case X86::CMPPDrmi: case X86::CMPPDrri:92case X86::CMPPSrmi: case X86::CMPPSrri:93case X86::CMPSDrmi: case X86::CMPSDrri:94case X86::CMPSDrmi_Int: case X86::CMPSDrri_Int:95case X86::CMPSSrmi: case X86::CMPSSrri:96case X86::CMPSSrmi_Int: case X86::CMPSSrri_Int:97if (Imm >= 0 && Imm <= 7) {98OS << '\t';99printCMPMnemonic(MI, /*IsVCMP*/false, OS);100101if ((Desc.TSFlags & X86II::FormMask) == X86II::MRMSrcMem) {102if ((Desc.TSFlags & X86II::OpPrefixMask) == X86II::XS)103printdwordmem(MI, 2, OS);104else if ((Desc.TSFlags & X86II::OpPrefixMask) == X86II::XD)105printqwordmem(MI, 2, OS);106else107printxmmwordmem(MI, 2, OS);108} else109printOperand(MI, 2, OS);110111// Skip operand 1 as its tied to the dest.112113OS << ", ";114printOperand(MI, 0, OS);115return true;116}117break;118119case X86::VCMPPDrmi: case X86::VCMPPDrri:120case X86::VCMPPDYrmi: case X86::VCMPPDYrri:121case X86::VCMPPDZ128rmi: case X86::VCMPPDZ128rri:122case X86::VCMPPDZ256rmi: case X86::VCMPPDZ256rri:123case X86::VCMPPDZrmi: case X86::VCMPPDZrri:124case X86::VCMPPSrmi: case X86::VCMPPSrri:125case X86::VCMPPSYrmi: case X86::VCMPPSYrri:126case X86::VCMPPSZ128rmi: case X86::VCMPPSZ128rri:127case X86::VCMPPSZ256rmi: case X86::VCMPPSZ256rri:128case X86::VCMPPSZrmi: case X86::VCMPPSZrri:129case X86::VCMPSDrmi: case X86::VCMPSDrri:130case X86::VCMPSDZrmi: case X86::VCMPSDZrri:131case X86::VCMPSDrmi_Int: case X86::VCMPSDrri_Int:132case X86::VCMPSDZrmi_Int: case X86::VCMPSDZrri_Int:133case X86::VCMPSSrmi: case X86::VCMPSSrri:134case X86::VCMPSSZrmi: case X86::VCMPSSZrri:135case X86::VCMPSSrmi_Int: case X86::VCMPSSrri_Int:136case X86::VCMPSSZrmi_Int: case X86::VCMPSSZrri_Int:137case X86::VCMPPDZ128rmik: case X86::VCMPPDZ128rrik:138case X86::VCMPPDZ256rmik: case X86::VCMPPDZ256rrik:139case X86::VCMPPDZrmik: case X86::VCMPPDZrrik:140case X86::VCMPPSZ128rmik: case X86::VCMPPSZ128rrik:141case X86::VCMPPSZ256rmik: case X86::VCMPPSZ256rrik:142case X86::VCMPPSZrmik: case X86::VCMPPSZrrik:143case X86::VCMPSDZrmi_Intk: case X86::VCMPSDZrri_Intk:144case X86::VCMPSSZrmi_Intk: case X86::VCMPSSZrri_Intk:145case X86::VCMPPDZ128rmbi: case X86::VCMPPDZ128rmbik:146case X86::VCMPPDZ256rmbi: case X86::VCMPPDZ256rmbik:147case X86::VCMPPDZrmbi: case X86::VCMPPDZrmbik:148case X86::VCMPPSZ128rmbi: case X86::VCMPPSZ128rmbik:149case X86::VCMPPSZ256rmbi: case X86::VCMPPSZ256rmbik:150case X86::VCMPPSZrmbi: case X86::VCMPPSZrmbik:151case X86::VCMPPDZrrib: case X86::VCMPPDZrribk:152case X86::VCMPPSZrrib: case X86::VCMPPSZrribk:153case X86::VCMPSDZrrib_Int: case X86::VCMPSDZrrib_Intk:154case X86::VCMPSSZrrib_Int: case X86::VCMPSSZrrib_Intk:155case X86::VCMPPHZ128rmi: case X86::VCMPPHZ128rri:156case X86::VCMPPHZ256rmi: case X86::VCMPPHZ256rri:157case X86::VCMPPHZrmi: case X86::VCMPPHZrri:158case X86::VCMPSHZrmi: case X86::VCMPSHZrri:159case X86::VCMPSHZrmi_Int: case X86::VCMPSHZrri_Int:160case X86::VCMPPHZ128rmik: case X86::VCMPPHZ128rrik:161case X86::VCMPPHZ256rmik: case X86::VCMPPHZ256rrik:162case X86::VCMPPHZrmik: case X86::VCMPPHZrrik:163case X86::VCMPSHZrmi_Intk: case X86::VCMPSHZrri_Intk:164case X86::VCMPPHZ128rmbi: case X86::VCMPPHZ128rmbik:165case X86::VCMPPHZ256rmbi: case X86::VCMPPHZ256rmbik:166case X86::VCMPPHZrmbi: case X86::VCMPPHZrmbik:167case X86::VCMPPHZrrib: case X86::VCMPPHZrribk:168case X86::VCMPSHZrrib_Int: case X86::VCMPSHZrrib_Intk:169if (Imm >= 0 && Imm <= 31) {170OS << '\t';171printCMPMnemonic(MI, /*IsVCMP*/true, OS);172173unsigned CurOp = (Desc.TSFlags & X86II::EVEX_K) ? 3 : 2;174175if ((Desc.TSFlags & X86II::FormMask) == X86II::MRMSrcMem) {176if (Desc.TSFlags & X86II::EVEX_B) {177// Broadcast form.178// Load size is word for TA map. Otherwise it is based on W-bit.179if ((Desc.TSFlags & X86II::OpMapMask) == X86II::TA) {180assert(!(Desc.TSFlags & X86II::REX_W) && "Unknown W-bit value!");181printwordmem(MI, CurOp--, OS);182} else if (Desc.TSFlags & X86II::REX_W) {183printqwordmem(MI, CurOp--, OS);184} else {185printdwordmem(MI, CurOp--, OS);186}187188// Print the number of elements broadcasted.189unsigned NumElts;190if (Desc.TSFlags & X86II::EVEX_L2)191NumElts = (Desc.TSFlags & X86II::REX_W) ? 8 : 16;192else if (Desc.TSFlags & X86II::VEX_L)193NumElts = (Desc.TSFlags & X86II::REX_W) ? 4 : 8;194else195NumElts = (Desc.TSFlags & X86II::REX_W) ? 2 : 4;196if ((Desc.TSFlags & X86II::OpMapMask) == X86II::TA) {197assert(!(Desc.TSFlags & X86II::REX_W) && "Unknown W-bit value!");198NumElts *= 2;199}200OS << "{1to" << NumElts << "}";201} else {202if ((Desc.TSFlags & X86II::OpPrefixMask) == X86II::XS) {203if ((Desc.TSFlags & X86II::OpMapMask) == X86II::TA)204printwordmem(MI, CurOp--, OS);205else206printdwordmem(MI, CurOp--, OS);207} else if ((Desc.TSFlags & X86II::OpPrefixMask) == X86II::XD) {208assert((Desc.TSFlags & X86II::OpMapMask) != X86II::TA &&209"Unexpected op map!");210printqwordmem(MI, CurOp--, OS);211} else if (Desc.TSFlags & X86II::EVEX_L2) {212printzmmwordmem(MI, CurOp--, OS);213} else if (Desc.TSFlags & X86II::VEX_L) {214printymmwordmem(MI, CurOp--, OS);215} else {216printxmmwordmem(MI, CurOp--, OS);217}218}219} else {220if (Desc.TSFlags & X86II::EVEX_B)221OS << "{sae}, ";222printOperand(MI, CurOp--, OS);223}224225OS << ", ";226printOperand(MI, CurOp--, OS);227OS << ", ";228printOperand(MI, 0, OS);229if (CurOp > 0) {230// Print mask operand.231OS << " {";232printOperand(MI, CurOp--, OS);233OS << "}";234}235236return true;237}238break;239240case X86::VPCOMBmi: case X86::VPCOMBri:241case X86::VPCOMDmi: case X86::VPCOMDri:242case X86::VPCOMQmi: case X86::VPCOMQri:243case X86::VPCOMUBmi: case X86::VPCOMUBri:244case X86::VPCOMUDmi: case X86::VPCOMUDri:245case X86::VPCOMUQmi: case X86::VPCOMUQri:246case X86::VPCOMUWmi: case X86::VPCOMUWri:247case X86::VPCOMWmi: case X86::VPCOMWri:248if (Imm >= 0 && Imm <= 7) {249OS << '\t';250printVPCOMMnemonic(MI, OS);251252if ((Desc.TSFlags & X86II::FormMask) == X86II::MRMSrcMem)253printxmmwordmem(MI, 2, OS);254else255printOperand(MI, 2, OS);256257OS << ", ";258printOperand(MI, 1, OS);259OS << ", ";260printOperand(MI, 0, OS);261return true;262}263break;264265case X86::VPCMPBZ128rmi: case X86::VPCMPBZ128rri:266case X86::VPCMPBZ256rmi: case X86::VPCMPBZ256rri:267case X86::VPCMPBZrmi: case X86::VPCMPBZrri:268case X86::VPCMPDZ128rmi: case X86::VPCMPDZ128rri:269case X86::VPCMPDZ256rmi: case X86::VPCMPDZ256rri:270case X86::VPCMPDZrmi: case X86::VPCMPDZrri:271case X86::VPCMPQZ128rmi: case X86::VPCMPQZ128rri:272case X86::VPCMPQZ256rmi: case X86::VPCMPQZ256rri:273case X86::VPCMPQZrmi: case X86::VPCMPQZrri:274case X86::VPCMPUBZ128rmi: case X86::VPCMPUBZ128rri:275case X86::VPCMPUBZ256rmi: case X86::VPCMPUBZ256rri:276case X86::VPCMPUBZrmi: case X86::VPCMPUBZrri:277case X86::VPCMPUDZ128rmi: case X86::VPCMPUDZ128rri:278case X86::VPCMPUDZ256rmi: case X86::VPCMPUDZ256rri:279case X86::VPCMPUDZrmi: case X86::VPCMPUDZrri:280case X86::VPCMPUQZ128rmi: case X86::VPCMPUQZ128rri:281case X86::VPCMPUQZ256rmi: case X86::VPCMPUQZ256rri:282case X86::VPCMPUQZrmi: case X86::VPCMPUQZrri:283case X86::VPCMPUWZ128rmi: case X86::VPCMPUWZ128rri:284case X86::VPCMPUWZ256rmi: case X86::VPCMPUWZ256rri:285case X86::VPCMPUWZrmi: case X86::VPCMPUWZrri:286case X86::VPCMPWZ128rmi: case X86::VPCMPWZ128rri:287case X86::VPCMPWZ256rmi: case X86::VPCMPWZ256rri:288case X86::VPCMPWZrmi: case X86::VPCMPWZrri:289case X86::VPCMPBZ128rmik: case X86::VPCMPBZ128rrik:290case X86::VPCMPBZ256rmik: case X86::VPCMPBZ256rrik:291case X86::VPCMPBZrmik: case X86::VPCMPBZrrik:292case X86::VPCMPDZ128rmik: case X86::VPCMPDZ128rrik:293case X86::VPCMPDZ256rmik: case X86::VPCMPDZ256rrik:294case X86::VPCMPDZrmik: case X86::VPCMPDZrrik:295case X86::VPCMPQZ128rmik: case X86::VPCMPQZ128rrik:296case X86::VPCMPQZ256rmik: case X86::VPCMPQZ256rrik:297case X86::VPCMPQZrmik: case X86::VPCMPQZrrik:298case X86::VPCMPUBZ128rmik: case X86::VPCMPUBZ128rrik:299case X86::VPCMPUBZ256rmik: case X86::VPCMPUBZ256rrik:300case X86::VPCMPUBZrmik: case X86::VPCMPUBZrrik:301case X86::VPCMPUDZ128rmik: case X86::VPCMPUDZ128rrik:302case X86::VPCMPUDZ256rmik: case X86::VPCMPUDZ256rrik:303case X86::VPCMPUDZrmik: case X86::VPCMPUDZrrik:304case X86::VPCMPUQZ128rmik: case X86::VPCMPUQZ128rrik:305case X86::VPCMPUQZ256rmik: case X86::VPCMPUQZ256rrik:306case X86::VPCMPUQZrmik: case X86::VPCMPUQZrrik:307case X86::VPCMPUWZ128rmik: case X86::VPCMPUWZ128rrik:308case X86::VPCMPUWZ256rmik: case X86::VPCMPUWZ256rrik:309case X86::VPCMPUWZrmik: case X86::VPCMPUWZrrik:310case X86::VPCMPWZ128rmik: case X86::VPCMPWZ128rrik:311case X86::VPCMPWZ256rmik: case X86::VPCMPWZ256rrik:312case X86::VPCMPWZrmik: case X86::VPCMPWZrrik:313case X86::VPCMPDZ128rmib: case X86::VPCMPDZ128rmibk:314case X86::VPCMPDZ256rmib: case X86::VPCMPDZ256rmibk:315case X86::VPCMPDZrmib: case X86::VPCMPDZrmibk:316case X86::VPCMPQZ128rmib: case X86::VPCMPQZ128rmibk:317case X86::VPCMPQZ256rmib: case X86::VPCMPQZ256rmibk:318case X86::VPCMPQZrmib: case X86::VPCMPQZrmibk:319case X86::VPCMPUDZ128rmib: case X86::VPCMPUDZ128rmibk:320case X86::VPCMPUDZ256rmib: case X86::VPCMPUDZ256rmibk:321case X86::VPCMPUDZrmib: case X86::VPCMPUDZrmibk:322case X86::VPCMPUQZ128rmib: case X86::VPCMPUQZ128rmibk:323case X86::VPCMPUQZ256rmib: case X86::VPCMPUQZ256rmibk:324case X86::VPCMPUQZrmib: case X86::VPCMPUQZrmibk:325if ((Imm >= 0 && Imm <= 2) || (Imm >= 4 && Imm <= 6)) {326OS << '\t';327printVPCMPMnemonic(MI, OS);328329unsigned CurOp = (Desc.TSFlags & X86II::EVEX_K) ? 3 : 2;330331if ((Desc.TSFlags & X86II::FormMask) == X86II::MRMSrcMem) {332if (Desc.TSFlags & X86II::EVEX_B) {333// Broadcast form.334// Load size is based on W-bit as only D and Q are supported.335if (Desc.TSFlags & X86II::REX_W)336printqwordmem(MI, CurOp--, OS);337else338printdwordmem(MI, CurOp--, OS);339340// Print the number of elements broadcasted.341unsigned NumElts;342if (Desc.TSFlags & X86II::EVEX_L2)343NumElts = (Desc.TSFlags & X86II::REX_W) ? 8 : 16;344else if (Desc.TSFlags & X86II::VEX_L)345NumElts = (Desc.TSFlags & X86II::REX_W) ? 4 : 8;346else347NumElts = (Desc.TSFlags & X86II::REX_W) ? 2 : 4;348OS << "{1to" << NumElts << "}";349} else {350if (Desc.TSFlags & X86II::EVEX_L2)351printzmmwordmem(MI, CurOp--, OS);352else if (Desc.TSFlags & X86II::VEX_L)353printymmwordmem(MI, CurOp--, OS);354else355printxmmwordmem(MI, CurOp--, OS);356}357} else {358printOperand(MI, CurOp--, OS);359}360361OS << ", ";362printOperand(MI, CurOp--, OS);363OS << ", ";364printOperand(MI, 0, OS);365if (CurOp > 0) {366// Print mask operand.367OS << " {";368printOperand(MI, CurOp--, OS);369OS << "}";370}371372return true;373}374break;375}376377return false;378}379380void X86ATTInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,381raw_ostream &O) {382const MCOperand &Op = MI->getOperand(OpNo);383if (Op.isReg()) {384printRegName(O, Op.getReg());385} else if (Op.isImm()) {386// Print immediates as signed values.387int64_t Imm = Op.getImm();388markup(O, Markup::Immediate) << '$' << formatImm(Imm);389390// TODO: This should be in a helper function in the base class, so it can391// be used by other printers.392393// If there are no instruction-specific comments, add a comment clarifying394// the hex value of the immediate operand when it isn't in the range395// [-256,255].396if (CommentStream && !HasCustomInstComment && (Imm > 255 || Imm < -256)) {397// Don't print unnecessary hex sign bits.398if (Imm == (int16_t)(Imm))399*CommentStream << format("imm = 0x%" PRIX16 "\n", (uint16_t)Imm);400else if (Imm == (int32_t)(Imm))401*CommentStream << format("imm = 0x%" PRIX32 "\n", (uint32_t)Imm);402else403*CommentStream << format("imm = 0x%" PRIX64 "\n", (uint64_t)Imm);404}405} else {406assert(Op.isExpr() && "unknown operand kind in printOperand");407WithMarkup M = markup(O, Markup::Immediate);408O << '$';409Op.getExpr()->print(O, &MAI);410}411}412413void X86ATTInstPrinter::printMemReference(const MCInst *MI, unsigned Op,414raw_ostream &O) {415// Do not print the exact form of the memory operand if it references a known416// binary object.417if (SymbolizeOperands && MIA) {418uint64_t Target;419if (MIA->evaluateBranch(*MI, 0, 0, Target))420return;421if (MIA->evaluateMemoryOperandAddress(*MI, /*STI=*/nullptr, 0, 0))422return;423}424425const MCOperand &BaseReg = MI->getOperand(Op + X86::AddrBaseReg);426const MCOperand &IndexReg = MI->getOperand(Op + X86::AddrIndexReg);427const MCOperand &DispSpec = MI->getOperand(Op + X86::AddrDisp);428429WithMarkup M = markup(O, Markup::Memory);430431// If this has a segment register, print it.432printOptionalSegReg(MI, Op + X86::AddrSegmentReg, O);433434if (DispSpec.isImm()) {435int64_t DispVal = DispSpec.getImm();436if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg()))437O << formatImm(DispVal);438} else {439assert(DispSpec.isExpr() && "non-immediate displacement for LEA?");440DispSpec.getExpr()->print(O, &MAI);441}442443if (IndexReg.getReg() || BaseReg.getReg()) {444O << '(';445if (BaseReg.getReg())446printOperand(MI, Op + X86::AddrBaseReg, O);447448if (IndexReg.getReg()) {449O << ',';450printOperand(MI, Op + X86::AddrIndexReg, O);451unsigned ScaleVal = MI->getOperand(Op + X86::AddrScaleAmt).getImm();452if (ScaleVal != 1) {453O << ',';454markup(O, Markup::Immediate) << ScaleVal; // never printed in hex.455}456}457O << ')';458}459}460461void X86ATTInstPrinter::printSrcIdx(const MCInst *MI, unsigned Op,462raw_ostream &O) {463WithMarkup M = markup(O, Markup::Memory);464465// If this has a segment register, print it.466printOptionalSegReg(MI, Op + 1, O);467468O << "(";469printOperand(MI, Op, O);470O << ")";471}472473void X86ATTInstPrinter::printDstIdx(const MCInst *MI, unsigned Op,474raw_ostream &O) {475WithMarkup M = markup(O, Markup::Memory);476477O << "%es:(";478printOperand(MI, Op, O);479O << ")";480}481482void X86ATTInstPrinter::printMemOffset(const MCInst *MI, unsigned Op,483raw_ostream &O) {484const MCOperand &DispSpec = MI->getOperand(Op);485486WithMarkup M = markup(O, Markup::Memory);487488// If this has a segment register, print it.489printOptionalSegReg(MI, Op + 1, O);490491if (DispSpec.isImm()) {492O << formatImm(DispSpec.getImm());493} else {494assert(DispSpec.isExpr() && "non-immediate displacement?");495DispSpec.getExpr()->print(O, &MAI);496}497}498499void X86ATTInstPrinter::printU8Imm(const MCInst *MI, unsigned Op,500raw_ostream &O) {501if (MI->getOperand(Op).isExpr())502return printOperand(MI, Op, O);503504markup(O, Markup::Immediate)505<< '$' << formatImm(MI->getOperand(Op).getImm() & 0xff);506}507508void X86ATTInstPrinter::printSTiRegOperand(const MCInst *MI, unsigned OpNo,509raw_ostream &OS) {510const MCOperand &Op = MI->getOperand(OpNo);511unsigned Reg = Op.getReg();512// Override the default printing to print st(0) instead st.513if (Reg == X86::ST0)514markup(OS, Markup::Register) << "%st(0)";515else516printRegName(OS, Reg);517}518519520