1*0b57cec5SDimitry Andric //===-- X86InstrBuilder.h - Functions to aid building x86 insts -*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file exposes functions that may be used with BuildMI from the 10*0b57cec5SDimitry Andric // MachineInstrBuilder.h file to handle X86'isms in a clean way. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric // The BuildMem function may be used with the BuildMI function to add entire 13*0b57cec5SDimitry Andric // memory references in a single, typed, function call. X86 memory references 14*0b57cec5SDimitry Andric // can be very complex expressions (described in the README), so wrapping them 15*0b57cec5SDimitry Andric // up behind an easier to use interface makes sense. Descriptions of the 16*0b57cec5SDimitry Andric // functions are included below. 17*0b57cec5SDimitry Andric // 18*0b57cec5SDimitry Andric // For reference, the order of operands for memory references is: 19*0b57cec5SDimitry Andric // (Operand), Base, Scale, Index, Displacement. 20*0b57cec5SDimitry Andric // 21*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H 24*0b57cec5SDimitry Andric #define LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 27*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 28*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 29*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 30*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 31*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 32*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 33*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 34*0b57cec5SDimitry Andric #include <cassert> 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric namespace llvm { 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric /// X86AddressMode - This struct holds a generalized full x86 address mode. 39*0b57cec5SDimitry Andric /// The base register can be a frame index, which will eventually be replaced 40*0b57cec5SDimitry Andric /// with BP or SP and Disp being offsetted accordingly. The displacement may 41*0b57cec5SDimitry Andric /// also include the offset of a global value. 42*0b57cec5SDimitry Andric struct X86AddressMode { 43*0b57cec5SDimitry Andric enum { 44*0b57cec5SDimitry Andric RegBase, 45*0b57cec5SDimitry Andric FrameIndexBase 46*0b57cec5SDimitry Andric } BaseType; 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric union { 49*0b57cec5SDimitry Andric unsigned Reg; 50*0b57cec5SDimitry Andric int FrameIndex; 51*0b57cec5SDimitry Andric } Base; 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric unsigned Scale; 54*0b57cec5SDimitry Andric unsigned IndexReg; 55*0b57cec5SDimitry Andric int Disp; 56*0b57cec5SDimitry Andric const GlobalValue *GV; 57*0b57cec5SDimitry Andric unsigned GVOpFlags; 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric X86AddressMode() 60*0b57cec5SDimitry Andric : BaseType(RegBase), Scale(1), IndexReg(0), Disp(0), GV(nullptr), 61*0b57cec5SDimitry Andric GVOpFlags(0) { 62*0b57cec5SDimitry Andric Base.Reg = 0; 63*0b57cec5SDimitry Andric } 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric void getFullAddress(SmallVectorImpl<MachineOperand> &MO) { 66*0b57cec5SDimitry Andric assert(Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8); 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric if (BaseType == X86AddressMode::RegBase) 69*0b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateReg(Base.Reg, false, false, false, 70*0b57cec5SDimitry Andric false, false, false, 0, false)); 71*0b57cec5SDimitry Andric else { 72*0b57cec5SDimitry Andric assert(BaseType == X86AddressMode::FrameIndexBase); 73*0b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateFI(Base.FrameIndex)); 74*0b57cec5SDimitry Andric } 75*0b57cec5SDimitry Andric 76*0b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateImm(Scale)); 77*0b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateReg(IndexReg, false, false, false, false, 78*0b57cec5SDimitry Andric false, false, 0, false)); 79*0b57cec5SDimitry Andric 80*0b57cec5SDimitry Andric if (GV) 81*0b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateGA(GV, Disp, GVOpFlags)); 82*0b57cec5SDimitry Andric else 83*0b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateImm(Disp)); 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateReg(0, false, false, false, false, false, 86*0b57cec5SDimitry Andric false, 0, false)); 87*0b57cec5SDimitry Andric } 88*0b57cec5SDimitry Andric }; 89*0b57cec5SDimitry Andric 90*0b57cec5SDimitry Andric /// Compute the addressing mode from an machine instruction starting with the 91*0b57cec5SDimitry Andric /// given operand. 92*0b57cec5SDimitry Andric static inline X86AddressMode getAddressFromInstr(const MachineInstr *MI, 93*0b57cec5SDimitry Andric unsigned Operand) { 94*0b57cec5SDimitry Andric X86AddressMode AM; 95*0b57cec5SDimitry Andric const MachineOperand &Op0 = MI->getOperand(Operand); 96*0b57cec5SDimitry Andric if (Op0.isReg()) { 97*0b57cec5SDimitry Andric AM.BaseType = X86AddressMode::RegBase; 98*0b57cec5SDimitry Andric AM.Base.Reg = Op0.getReg(); 99*0b57cec5SDimitry Andric } else { 100*0b57cec5SDimitry Andric AM.BaseType = X86AddressMode::FrameIndexBase; 101*0b57cec5SDimitry Andric AM.Base.FrameIndex = Op0.getIndex(); 102*0b57cec5SDimitry Andric } 103*0b57cec5SDimitry Andric 104*0b57cec5SDimitry Andric const MachineOperand &Op1 = MI->getOperand(Operand + 1); 105*0b57cec5SDimitry Andric AM.Scale = Op1.getImm(); 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric const MachineOperand &Op2 = MI->getOperand(Operand + 2); 108*0b57cec5SDimitry Andric AM.IndexReg = Op2.getReg(); 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric const MachineOperand &Op3 = MI->getOperand(Operand + 3); 111*0b57cec5SDimitry Andric if (Op3.isGlobal()) 112*0b57cec5SDimitry Andric AM.GV = Op3.getGlobal(); 113*0b57cec5SDimitry Andric else 114*0b57cec5SDimitry Andric AM.Disp = Op3.getImm(); 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric return AM; 117*0b57cec5SDimitry Andric } 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric /// addDirectMem - This function is used to add a direct memory reference to the 120*0b57cec5SDimitry Andric /// current instruction -- that is, a dereference of an address in a register, 121*0b57cec5SDimitry Andric /// with no scale, index or displacement. An example is: DWORD PTR [EAX]. 122*0b57cec5SDimitry Andric /// 123*0b57cec5SDimitry Andric static inline const MachineInstrBuilder & 124*0b57cec5SDimitry Andric addDirectMem(const MachineInstrBuilder &MIB, unsigned Reg) { 125*0b57cec5SDimitry Andric // Because memory references are always represented with five 126*0b57cec5SDimitry Andric // values, this adds: Reg, 1, NoReg, 0, NoReg to the instruction. 127*0b57cec5SDimitry Andric return MIB.addReg(Reg).addImm(1).addReg(0).addImm(0).addReg(0); 128*0b57cec5SDimitry Andric } 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric /// Replace the address used in the instruction with the direct memory 131*0b57cec5SDimitry Andric /// reference. 132*0b57cec5SDimitry Andric static inline void setDirectAddressInInstr(MachineInstr *MI, unsigned Operand, 133*0b57cec5SDimitry Andric unsigned Reg) { 134*0b57cec5SDimitry Andric // Direct memory address is in a form of: Reg, 1 (Scale), NoReg, 0, NoReg. 135*0b57cec5SDimitry Andric MI->getOperand(Operand).setReg(Reg); 136*0b57cec5SDimitry Andric MI->getOperand(Operand + 1).setImm(1); 137*0b57cec5SDimitry Andric MI->getOperand(Operand + 2).setReg(0); 138*0b57cec5SDimitry Andric MI->getOperand(Operand + 3).setImm(0); 139*0b57cec5SDimitry Andric MI->getOperand(Operand + 4).setReg(0); 140*0b57cec5SDimitry Andric } 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric static inline const MachineInstrBuilder & 143*0b57cec5SDimitry Andric addOffset(const MachineInstrBuilder &MIB, int Offset) { 144*0b57cec5SDimitry Andric return MIB.addImm(1).addReg(0).addImm(Offset).addReg(0); 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric static inline const MachineInstrBuilder & 148*0b57cec5SDimitry Andric addOffset(const MachineInstrBuilder &MIB, const MachineOperand& Offset) { 149*0b57cec5SDimitry Andric return MIB.addImm(1).addReg(0).add(Offset).addReg(0); 150*0b57cec5SDimitry Andric } 151*0b57cec5SDimitry Andric 152*0b57cec5SDimitry Andric /// addRegOffset - This function is used to add a memory reference of the form 153*0b57cec5SDimitry Andric /// [Reg + Offset], i.e., one with no scale or index, but with a 154*0b57cec5SDimitry Andric /// displacement. An example is: DWORD PTR [EAX + 4]. 155*0b57cec5SDimitry Andric /// 156*0b57cec5SDimitry Andric static inline const MachineInstrBuilder & 157*0b57cec5SDimitry Andric addRegOffset(const MachineInstrBuilder &MIB, 158*0b57cec5SDimitry Andric unsigned Reg, bool isKill, int Offset) { 159*0b57cec5SDimitry Andric return addOffset(MIB.addReg(Reg, getKillRegState(isKill)), Offset); 160*0b57cec5SDimitry Andric } 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric /// addRegReg - This function is used to add a memory reference of the form: 163*0b57cec5SDimitry Andric /// [Reg + Reg]. 164*0b57cec5SDimitry Andric static inline const MachineInstrBuilder &addRegReg(const MachineInstrBuilder &MIB, 165*0b57cec5SDimitry Andric unsigned Reg1, bool isKill1, 166*0b57cec5SDimitry Andric unsigned Reg2, bool isKill2) { 167*0b57cec5SDimitry Andric return MIB.addReg(Reg1, getKillRegState(isKill1)).addImm(1) 168*0b57cec5SDimitry Andric .addReg(Reg2, getKillRegState(isKill2)).addImm(0).addReg(0); 169*0b57cec5SDimitry Andric } 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric static inline const MachineInstrBuilder & 172*0b57cec5SDimitry Andric addFullAddress(const MachineInstrBuilder &MIB, 173*0b57cec5SDimitry Andric const X86AddressMode &AM) { 174*0b57cec5SDimitry Andric assert(AM.Scale == 1 || AM.Scale == 2 || AM.Scale == 4 || AM.Scale == 8); 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric if (AM.BaseType == X86AddressMode::RegBase) 177*0b57cec5SDimitry Andric MIB.addReg(AM.Base.Reg); 178*0b57cec5SDimitry Andric else { 179*0b57cec5SDimitry Andric assert(AM.BaseType == X86AddressMode::FrameIndexBase); 180*0b57cec5SDimitry Andric MIB.addFrameIndex(AM.Base.FrameIndex); 181*0b57cec5SDimitry Andric } 182*0b57cec5SDimitry Andric 183*0b57cec5SDimitry Andric MIB.addImm(AM.Scale).addReg(AM.IndexReg); 184*0b57cec5SDimitry Andric if (AM.GV) 185*0b57cec5SDimitry Andric MIB.addGlobalAddress(AM.GV, AM.Disp, AM.GVOpFlags); 186*0b57cec5SDimitry Andric else 187*0b57cec5SDimitry Andric MIB.addImm(AM.Disp); 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric return MIB.addReg(0); 190*0b57cec5SDimitry Andric } 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric /// addFrameReference - This function is used to add a reference to the base of 193*0b57cec5SDimitry Andric /// an abstract object on the stack frame of the current function. This 194*0b57cec5SDimitry Andric /// reference has base register as the FrameIndex offset until it is resolved. 195*0b57cec5SDimitry Andric /// This allows a constant offset to be specified as well... 196*0b57cec5SDimitry Andric /// 197*0b57cec5SDimitry Andric static inline const MachineInstrBuilder & 198*0b57cec5SDimitry Andric addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0) { 199*0b57cec5SDimitry Andric MachineInstr *MI = MIB; 200*0b57cec5SDimitry Andric MachineFunction &MF = *MI->getParent()->getParent(); 201*0b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 202*0b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 203*0b57cec5SDimitry Andric auto Flags = MachineMemOperand::MONone; 204*0b57cec5SDimitry Andric if (MCID.mayLoad()) 205*0b57cec5SDimitry Andric Flags |= MachineMemOperand::MOLoad; 206*0b57cec5SDimitry Andric if (MCID.mayStore()) 207*0b57cec5SDimitry Andric Flags |= MachineMemOperand::MOStore; 208*0b57cec5SDimitry Andric MachineMemOperand *MMO = MF.getMachineMemOperand( 209*0b57cec5SDimitry Andric MachinePointerInfo::getFixedStack(MF, FI, Offset), Flags, 210*0b57cec5SDimitry Andric MFI.getObjectSize(FI), MFI.getObjectAlignment(FI)); 211*0b57cec5SDimitry Andric return addOffset(MIB.addFrameIndex(FI), Offset) 212*0b57cec5SDimitry Andric .addMemOperand(MMO); 213*0b57cec5SDimitry Andric } 214*0b57cec5SDimitry Andric 215*0b57cec5SDimitry Andric /// addConstantPoolReference - This function is used to add a reference to the 216*0b57cec5SDimitry Andric /// base of a constant value spilled to the per-function constant pool. The 217*0b57cec5SDimitry Andric /// reference uses the abstract ConstantPoolIndex which is retained until 218*0b57cec5SDimitry Andric /// either machine code emission or assembly output. In PIC mode on x86-32, 219*0b57cec5SDimitry Andric /// the GlobalBaseReg parameter can be used to make this a 220*0b57cec5SDimitry Andric /// GlobalBaseReg-relative reference. 221*0b57cec5SDimitry Andric /// 222*0b57cec5SDimitry Andric static inline const MachineInstrBuilder & 223*0b57cec5SDimitry Andric addConstantPoolReference(const MachineInstrBuilder &MIB, unsigned CPI, 224*0b57cec5SDimitry Andric unsigned GlobalBaseReg, unsigned char OpFlags) { 225*0b57cec5SDimitry Andric //FIXME: factor this 226*0b57cec5SDimitry Andric return MIB.addReg(GlobalBaseReg).addImm(1).addReg(0) 227*0b57cec5SDimitry Andric .addConstantPoolIndex(CPI, 0, OpFlags).addReg(0); 228*0b57cec5SDimitry Andric } 229*0b57cec5SDimitry Andric 230*0b57cec5SDimitry Andric } // end namespace llvm 231*0b57cec5SDimitry Andric 232*0b57cec5SDimitry Andric #endif // LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H 233