10b57cec5SDimitry Andric //===-- X86InstrBuilder.h - Functions to aid building x86 insts -*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file exposes functions that may be used with BuildMI from the 100b57cec5SDimitry Andric // MachineInstrBuilder.h file to handle X86'isms in a clean way. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric // The BuildMem function may be used with the BuildMI function to add entire 130b57cec5SDimitry Andric // memory references in a single, typed, function call. X86 memory references 140b57cec5SDimitry Andric // can be very complex expressions (described in the README), so wrapping them 150b57cec5SDimitry Andric // up behind an easier to use interface makes sense. Descriptions of the 160b57cec5SDimitry Andric // functions are included below. 170b57cec5SDimitry Andric // 180b57cec5SDimitry Andric // For reference, the order of operands for memory references is: 190b57cec5SDimitry Andric // (Operand), Base, Scale, Index, Displacement. 200b57cec5SDimitry Andric // 210b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H 240b57cec5SDimitry Andric #define LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 330b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 340b57cec5SDimitry Andric #include <cassert> 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric namespace llvm { 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric /// X86AddressMode - This struct holds a generalized full x86 address mode. 390b57cec5SDimitry Andric /// The base register can be a frame index, which will eventually be replaced 400b57cec5SDimitry Andric /// with BP or SP and Disp being offsetted accordingly. The displacement may 410b57cec5SDimitry Andric /// also include the offset of a global value. 420b57cec5SDimitry Andric struct X86AddressMode { 430b57cec5SDimitry Andric enum { 440b57cec5SDimitry Andric RegBase, 450b57cec5SDimitry Andric FrameIndexBase 460b57cec5SDimitry Andric } BaseType; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric union { 490b57cec5SDimitry Andric unsigned Reg; 500b57cec5SDimitry Andric int FrameIndex; 510b57cec5SDimitry Andric } Base; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric unsigned Scale; 540b57cec5SDimitry Andric unsigned IndexReg; 550b57cec5SDimitry Andric int Disp; 560b57cec5SDimitry Andric const GlobalValue *GV; 570b57cec5SDimitry Andric unsigned GVOpFlags; 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric X86AddressMode() 600b57cec5SDimitry Andric : BaseType(RegBase), Scale(1), IndexReg(0), Disp(0), GV(nullptr), 610b57cec5SDimitry Andric GVOpFlags(0) { 620b57cec5SDimitry Andric Base.Reg = 0; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric void getFullAddress(SmallVectorImpl<MachineOperand> &MO) { 660b57cec5SDimitry Andric assert(Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8); 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric if (BaseType == X86AddressMode::RegBase) 690b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateReg(Base.Reg, false, false, false, 700b57cec5SDimitry Andric false, false, false, 0, false)); 710b57cec5SDimitry Andric else { 720b57cec5SDimitry Andric assert(BaseType == X86AddressMode::FrameIndexBase); 730b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateFI(Base.FrameIndex)); 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateImm(Scale)); 770b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateReg(IndexReg, false, false, false, false, 780b57cec5SDimitry Andric false, false, 0, false)); 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric if (GV) 810b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateGA(GV, Disp, GVOpFlags)); 820b57cec5SDimitry Andric else 830b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateImm(Disp)); 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric MO.push_back(MachineOperand::CreateReg(0, false, false, false, false, false, 860b57cec5SDimitry Andric false, 0, false)); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric }; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric /// Compute the addressing mode from an machine instruction starting with the 910b57cec5SDimitry Andric /// given operand. 920b57cec5SDimitry Andric static inline X86AddressMode getAddressFromInstr(const MachineInstr *MI, 930b57cec5SDimitry Andric unsigned Operand) { 940b57cec5SDimitry Andric X86AddressMode AM; 950b57cec5SDimitry Andric const MachineOperand &Op0 = MI->getOperand(Operand); 960b57cec5SDimitry Andric if (Op0.isReg()) { 970b57cec5SDimitry Andric AM.BaseType = X86AddressMode::RegBase; 980b57cec5SDimitry Andric AM.Base.Reg = Op0.getReg(); 990b57cec5SDimitry Andric } else { 1000b57cec5SDimitry Andric AM.BaseType = X86AddressMode::FrameIndexBase; 1010b57cec5SDimitry Andric AM.Base.FrameIndex = Op0.getIndex(); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric const MachineOperand &Op1 = MI->getOperand(Operand + 1); 1050b57cec5SDimitry Andric AM.Scale = Op1.getImm(); 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric const MachineOperand &Op2 = MI->getOperand(Operand + 2); 1080b57cec5SDimitry Andric AM.IndexReg = Op2.getReg(); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric const MachineOperand &Op3 = MI->getOperand(Operand + 3); 1110b57cec5SDimitry Andric if (Op3.isGlobal()) 1120b57cec5SDimitry Andric AM.GV = Op3.getGlobal(); 1130b57cec5SDimitry Andric else 1140b57cec5SDimitry Andric AM.Disp = Op3.getImm(); 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric return AM; 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric /// addDirectMem - This function is used to add a direct memory reference to the 1200b57cec5SDimitry Andric /// current instruction -- that is, a dereference of an address in a register, 1210b57cec5SDimitry Andric /// with no scale, index or displacement. An example is: DWORD PTR [EAX]. 1220b57cec5SDimitry Andric /// 1230b57cec5SDimitry Andric static inline const MachineInstrBuilder & 1240b57cec5SDimitry Andric addDirectMem(const MachineInstrBuilder &MIB, unsigned Reg) { 1250b57cec5SDimitry Andric // Because memory references are always represented with five 1260b57cec5SDimitry Andric // values, this adds: Reg, 1, NoReg, 0, NoReg to the instruction. 1270b57cec5SDimitry Andric return MIB.addReg(Reg).addImm(1).addReg(0).addImm(0).addReg(0); 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric /// Replace the address used in the instruction with the direct memory 1310b57cec5SDimitry Andric /// reference. 1320b57cec5SDimitry Andric static inline void setDirectAddressInInstr(MachineInstr *MI, unsigned Operand, 1330b57cec5SDimitry Andric unsigned Reg) { 1348bcb0991SDimitry Andric // Direct memory address is in a form of: Reg/FI, 1 (Scale), NoReg, 0, NoReg. 1358bcb0991SDimitry Andric MI->getOperand(Operand).ChangeToRegister(Reg, /*isDef=*/false); 1360b57cec5SDimitry Andric MI->getOperand(Operand + 1).setImm(1); 1370b57cec5SDimitry Andric MI->getOperand(Operand + 2).setReg(0); 1388bcb0991SDimitry Andric MI->getOperand(Operand + 3).ChangeToImmediate(0); 1390b57cec5SDimitry Andric MI->getOperand(Operand + 4).setReg(0); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric static inline const MachineInstrBuilder & 1430b57cec5SDimitry Andric addOffset(const MachineInstrBuilder &MIB, int Offset) { 1440b57cec5SDimitry Andric return MIB.addImm(1).addReg(0).addImm(Offset).addReg(0); 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric static inline const MachineInstrBuilder & 1480b57cec5SDimitry Andric addOffset(const MachineInstrBuilder &MIB, const MachineOperand& Offset) { 1490b57cec5SDimitry Andric return MIB.addImm(1).addReg(0).add(Offset).addReg(0); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric /// addRegOffset - This function is used to add a memory reference of the form 1530b57cec5SDimitry Andric /// [Reg + Offset], i.e., one with no scale or index, but with a 1540b57cec5SDimitry Andric /// displacement. An example is: DWORD PTR [EAX + 4]. 1550b57cec5SDimitry Andric /// 1560b57cec5SDimitry Andric static inline const MachineInstrBuilder & 1570b57cec5SDimitry Andric addRegOffset(const MachineInstrBuilder &MIB, 1580b57cec5SDimitry Andric unsigned Reg, bool isKill, int Offset) { 1590b57cec5SDimitry Andric return addOffset(MIB.addReg(Reg, getKillRegState(isKill)), Offset); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric /// addRegReg - This function is used to add a memory reference of the form: 1630b57cec5SDimitry Andric /// [Reg + Reg]. 1640b57cec5SDimitry Andric static inline const MachineInstrBuilder &addRegReg(const MachineInstrBuilder &MIB, 1650b57cec5SDimitry Andric unsigned Reg1, bool isKill1, 1660b57cec5SDimitry Andric unsigned Reg2, bool isKill2) { 1670b57cec5SDimitry Andric return MIB.addReg(Reg1, getKillRegState(isKill1)).addImm(1) 1680b57cec5SDimitry Andric .addReg(Reg2, getKillRegState(isKill2)).addImm(0).addReg(0); 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric static inline const MachineInstrBuilder & 1720b57cec5SDimitry Andric addFullAddress(const MachineInstrBuilder &MIB, 1730b57cec5SDimitry Andric const X86AddressMode &AM) { 1740b57cec5SDimitry Andric assert(AM.Scale == 1 || AM.Scale == 2 || AM.Scale == 4 || AM.Scale == 8); 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric if (AM.BaseType == X86AddressMode::RegBase) 1770b57cec5SDimitry Andric MIB.addReg(AM.Base.Reg); 1780b57cec5SDimitry Andric else { 1790b57cec5SDimitry Andric assert(AM.BaseType == X86AddressMode::FrameIndexBase); 1800b57cec5SDimitry Andric MIB.addFrameIndex(AM.Base.FrameIndex); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric MIB.addImm(AM.Scale).addReg(AM.IndexReg); 1840b57cec5SDimitry Andric if (AM.GV) 1850b57cec5SDimitry Andric MIB.addGlobalAddress(AM.GV, AM.Disp, AM.GVOpFlags); 1860b57cec5SDimitry Andric else 1870b57cec5SDimitry Andric MIB.addImm(AM.Disp); 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric return MIB.addReg(0); 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric /// addFrameReference - This function is used to add a reference to the base of 1930b57cec5SDimitry Andric /// an abstract object on the stack frame of the current function. This 1940b57cec5SDimitry Andric /// reference has base register as the FrameIndex offset until it is resolved. 1950b57cec5SDimitry Andric /// This allows a constant offset to be specified as well... 1960b57cec5SDimitry Andric /// 1970b57cec5SDimitry Andric static inline const MachineInstrBuilder & 1980b57cec5SDimitry Andric addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0) { 1990b57cec5SDimitry Andric MachineInstr *MI = MIB; 2000b57cec5SDimitry Andric MachineFunction &MF = *MI->getParent()->getParent(); 2010b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 2020b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 2030b57cec5SDimitry Andric auto Flags = MachineMemOperand::MONone; 2040b57cec5SDimitry Andric if (MCID.mayLoad()) 2050b57cec5SDimitry Andric Flags |= MachineMemOperand::MOLoad; 2060b57cec5SDimitry Andric if (MCID.mayStore()) 2070b57cec5SDimitry Andric Flags |= MachineMemOperand::MOStore; 2080b57cec5SDimitry Andric MachineMemOperand *MMO = MF.getMachineMemOperand( 2090b57cec5SDimitry Andric MachinePointerInfo::getFixedStack(MF, FI, Offset), Flags, 210*5ffd83dbSDimitry Andric MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); 2110b57cec5SDimitry Andric return addOffset(MIB.addFrameIndex(FI), Offset) 2120b57cec5SDimitry Andric .addMemOperand(MMO); 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric /// addConstantPoolReference - This function is used to add a reference to the 2160b57cec5SDimitry Andric /// base of a constant value spilled to the per-function constant pool. The 2170b57cec5SDimitry Andric /// reference uses the abstract ConstantPoolIndex which is retained until 2180b57cec5SDimitry Andric /// either machine code emission or assembly output. In PIC mode on x86-32, 2190b57cec5SDimitry Andric /// the GlobalBaseReg parameter can be used to make this a 2200b57cec5SDimitry Andric /// GlobalBaseReg-relative reference. 2210b57cec5SDimitry Andric /// 2220b57cec5SDimitry Andric static inline const MachineInstrBuilder & 2230b57cec5SDimitry Andric addConstantPoolReference(const MachineInstrBuilder &MIB, unsigned CPI, 2240b57cec5SDimitry Andric unsigned GlobalBaseReg, unsigned char OpFlags) { 2250b57cec5SDimitry Andric //FIXME: factor this 2260b57cec5SDimitry Andric return MIB.addReg(GlobalBaseReg).addImm(1).addReg(0) 2270b57cec5SDimitry Andric .addConstantPoolIndex(CPI, 0, OpFlags).addReg(0); 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric } // end namespace llvm 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric #endif // LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H 233