106f32e7eSjoerg //===-- X86InstrBuilder.h - Functions to aid building x86 insts -*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file exposes functions that may be used with BuildMI from the
1006f32e7eSjoerg // MachineInstrBuilder.h file to handle X86'isms in a clean way.
1106f32e7eSjoerg //
1206f32e7eSjoerg // The BuildMem function may be used with the BuildMI function to add entire
1306f32e7eSjoerg // memory references in a single, typed, function call.  X86 memory references
1406f32e7eSjoerg // can be very complex expressions (described in the README), so wrapping them
1506f32e7eSjoerg // up behind an easier to use interface makes sense.  Descriptions of the
1606f32e7eSjoerg // functions are included below.
1706f32e7eSjoerg //
1806f32e7eSjoerg // For reference, the order of operands for memory references is:
1906f32e7eSjoerg // (Operand), Base, Scale, Index, Displacement.
2006f32e7eSjoerg //
2106f32e7eSjoerg //===----------------------------------------------------------------------===//
2206f32e7eSjoerg 
2306f32e7eSjoerg #ifndef LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H
2406f32e7eSjoerg #define LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H
2506f32e7eSjoerg 
2606f32e7eSjoerg #include "llvm/ADT/SmallVector.h"
2706f32e7eSjoerg #include "llvm/CodeGen/MachineFrameInfo.h"
2806f32e7eSjoerg #include "llvm/CodeGen/MachineFunction.h"
2906f32e7eSjoerg #include "llvm/CodeGen/MachineInstr.h"
3006f32e7eSjoerg #include "llvm/CodeGen/MachineInstrBuilder.h"
3106f32e7eSjoerg #include "llvm/CodeGen/MachineMemOperand.h"
3206f32e7eSjoerg #include "llvm/CodeGen/MachineOperand.h"
3306f32e7eSjoerg #include "llvm/MC/MCInstrDesc.h"
3406f32e7eSjoerg #include <cassert>
3506f32e7eSjoerg 
3606f32e7eSjoerg namespace llvm {
3706f32e7eSjoerg 
3806f32e7eSjoerg /// X86AddressMode - This struct holds a generalized full x86 address mode.
3906f32e7eSjoerg /// The base register can be a frame index, which will eventually be replaced
4006f32e7eSjoerg /// with BP or SP and Disp being offsetted accordingly.  The displacement may
4106f32e7eSjoerg /// also include the offset of a global value.
4206f32e7eSjoerg struct X86AddressMode {
4306f32e7eSjoerg   enum {
4406f32e7eSjoerg     RegBase,
4506f32e7eSjoerg     FrameIndexBase
4606f32e7eSjoerg   } BaseType;
4706f32e7eSjoerg 
4806f32e7eSjoerg   union {
4906f32e7eSjoerg     unsigned Reg;
5006f32e7eSjoerg     int FrameIndex;
5106f32e7eSjoerg   } Base;
5206f32e7eSjoerg 
5306f32e7eSjoerg   unsigned Scale;
5406f32e7eSjoerg   unsigned IndexReg;
5506f32e7eSjoerg   int Disp;
5606f32e7eSjoerg   const GlobalValue *GV;
5706f32e7eSjoerg   unsigned GVOpFlags;
5806f32e7eSjoerg 
X86AddressModeX86AddressMode5906f32e7eSjoerg   X86AddressMode()
6006f32e7eSjoerg     : BaseType(RegBase), Scale(1), IndexReg(0), Disp(0), GV(nullptr),
6106f32e7eSjoerg       GVOpFlags(0) {
6206f32e7eSjoerg     Base.Reg = 0;
6306f32e7eSjoerg   }
6406f32e7eSjoerg 
getFullAddressX86AddressMode6506f32e7eSjoerg   void getFullAddress(SmallVectorImpl<MachineOperand> &MO) {
6606f32e7eSjoerg     assert(Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8);
6706f32e7eSjoerg 
6806f32e7eSjoerg     if (BaseType == X86AddressMode::RegBase)
6906f32e7eSjoerg       MO.push_back(MachineOperand::CreateReg(Base.Reg, false, false, false,
7006f32e7eSjoerg                                              false, false, false, 0, false));
7106f32e7eSjoerg     else {
7206f32e7eSjoerg       assert(BaseType == X86AddressMode::FrameIndexBase);
7306f32e7eSjoerg       MO.push_back(MachineOperand::CreateFI(Base.FrameIndex));
7406f32e7eSjoerg     }
7506f32e7eSjoerg 
7606f32e7eSjoerg     MO.push_back(MachineOperand::CreateImm(Scale));
7706f32e7eSjoerg     MO.push_back(MachineOperand::CreateReg(IndexReg, false, false, false, false,
7806f32e7eSjoerg                                            false, false, 0, false));
7906f32e7eSjoerg 
8006f32e7eSjoerg     if (GV)
8106f32e7eSjoerg       MO.push_back(MachineOperand::CreateGA(GV, Disp, GVOpFlags));
8206f32e7eSjoerg     else
8306f32e7eSjoerg       MO.push_back(MachineOperand::CreateImm(Disp));
8406f32e7eSjoerg 
8506f32e7eSjoerg     MO.push_back(MachineOperand::CreateReg(0, false, false, false, false, false,
8606f32e7eSjoerg                                            false, 0, false));
8706f32e7eSjoerg   }
8806f32e7eSjoerg };
8906f32e7eSjoerg 
9006f32e7eSjoerg /// Compute the addressing mode from an machine instruction starting with the
9106f32e7eSjoerg /// given operand.
getAddressFromInstr(const MachineInstr * MI,unsigned Operand)9206f32e7eSjoerg static inline X86AddressMode getAddressFromInstr(const MachineInstr *MI,
9306f32e7eSjoerg                                                  unsigned Operand) {
9406f32e7eSjoerg   X86AddressMode AM;
9506f32e7eSjoerg   const MachineOperand &Op0 = MI->getOperand(Operand);
9606f32e7eSjoerg   if (Op0.isReg()) {
9706f32e7eSjoerg     AM.BaseType = X86AddressMode::RegBase;
9806f32e7eSjoerg     AM.Base.Reg = Op0.getReg();
9906f32e7eSjoerg   } else {
10006f32e7eSjoerg     AM.BaseType = X86AddressMode::FrameIndexBase;
10106f32e7eSjoerg     AM.Base.FrameIndex = Op0.getIndex();
10206f32e7eSjoerg   }
10306f32e7eSjoerg 
10406f32e7eSjoerg   const MachineOperand &Op1 = MI->getOperand(Operand + 1);
10506f32e7eSjoerg   AM.Scale = Op1.getImm();
10606f32e7eSjoerg 
10706f32e7eSjoerg   const MachineOperand &Op2 = MI->getOperand(Operand + 2);
10806f32e7eSjoerg   AM.IndexReg = Op2.getReg();
10906f32e7eSjoerg 
11006f32e7eSjoerg   const MachineOperand &Op3 = MI->getOperand(Operand + 3);
11106f32e7eSjoerg   if (Op3.isGlobal())
11206f32e7eSjoerg     AM.GV = Op3.getGlobal();
11306f32e7eSjoerg   else
11406f32e7eSjoerg     AM.Disp = Op3.getImm();
11506f32e7eSjoerg 
11606f32e7eSjoerg   return AM;
11706f32e7eSjoerg }
11806f32e7eSjoerg 
11906f32e7eSjoerg /// addDirectMem - This function is used to add a direct memory reference to the
12006f32e7eSjoerg /// current instruction -- that is, a dereference of an address in a register,
12106f32e7eSjoerg /// with no scale, index or displacement. An example is: DWORD PTR [EAX].
12206f32e7eSjoerg ///
12306f32e7eSjoerg static inline const MachineInstrBuilder &
addDirectMem(const MachineInstrBuilder & MIB,unsigned Reg)12406f32e7eSjoerg addDirectMem(const MachineInstrBuilder &MIB, unsigned Reg) {
12506f32e7eSjoerg   // Because memory references are always represented with five
12606f32e7eSjoerg   // values, this adds: Reg, 1, NoReg, 0, NoReg to the instruction.
12706f32e7eSjoerg   return MIB.addReg(Reg).addImm(1).addReg(0).addImm(0).addReg(0);
12806f32e7eSjoerg }
12906f32e7eSjoerg 
13006f32e7eSjoerg /// Replace the address used in the instruction with the direct memory
13106f32e7eSjoerg /// reference.
setDirectAddressInInstr(MachineInstr * MI,unsigned Operand,unsigned Reg)13206f32e7eSjoerg static inline void setDirectAddressInInstr(MachineInstr *MI, unsigned Operand,
13306f32e7eSjoerg                                            unsigned Reg) {
13406f32e7eSjoerg   // Direct memory address is in a form of: Reg/FI, 1 (Scale), NoReg, 0, NoReg.
13506f32e7eSjoerg   MI->getOperand(Operand).ChangeToRegister(Reg, /*isDef=*/false);
13606f32e7eSjoerg   MI->getOperand(Operand + 1).setImm(1);
13706f32e7eSjoerg   MI->getOperand(Operand + 2).setReg(0);
13806f32e7eSjoerg   MI->getOperand(Operand + 3).ChangeToImmediate(0);
13906f32e7eSjoerg   MI->getOperand(Operand + 4).setReg(0);
14006f32e7eSjoerg }
14106f32e7eSjoerg 
14206f32e7eSjoerg static inline const MachineInstrBuilder &
addOffset(const MachineInstrBuilder & MIB,int Offset)14306f32e7eSjoerg addOffset(const MachineInstrBuilder &MIB, int Offset) {
14406f32e7eSjoerg   return MIB.addImm(1).addReg(0).addImm(Offset).addReg(0);
14506f32e7eSjoerg }
14606f32e7eSjoerg 
14706f32e7eSjoerg static inline const MachineInstrBuilder &
addOffset(const MachineInstrBuilder & MIB,const MachineOperand & Offset)14806f32e7eSjoerg addOffset(const MachineInstrBuilder &MIB, const MachineOperand& Offset) {
14906f32e7eSjoerg   return MIB.addImm(1).addReg(0).add(Offset).addReg(0);
15006f32e7eSjoerg }
15106f32e7eSjoerg 
15206f32e7eSjoerg /// addRegOffset - This function is used to add a memory reference of the form
15306f32e7eSjoerg /// [Reg + Offset], i.e., one with no scale or index, but with a
15406f32e7eSjoerg /// displacement. An example is: DWORD PTR [EAX + 4].
15506f32e7eSjoerg ///
15606f32e7eSjoerg static inline const MachineInstrBuilder &
addRegOffset(const MachineInstrBuilder & MIB,unsigned Reg,bool isKill,int Offset)15706f32e7eSjoerg addRegOffset(const MachineInstrBuilder &MIB,
15806f32e7eSjoerg              unsigned Reg, bool isKill, int Offset) {
15906f32e7eSjoerg   return addOffset(MIB.addReg(Reg, getKillRegState(isKill)), Offset);
16006f32e7eSjoerg }
16106f32e7eSjoerg 
16206f32e7eSjoerg /// addRegReg - This function is used to add a memory reference of the form:
16306f32e7eSjoerg /// [Reg + Reg].
addRegReg(const MachineInstrBuilder & MIB,unsigned Reg1,bool isKill1,unsigned Reg2,bool isKill2)16406f32e7eSjoerg static inline const MachineInstrBuilder &addRegReg(const MachineInstrBuilder &MIB,
16506f32e7eSjoerg                                             unsigned Reg1, bool isKill1,
16606f32e7eSjoerg                                             unsigned Reg2, bool isKill2) {
16706f32e7eSjoerg   return MIB.addReg(Reg1, getKillRegState(isKill1)).addImm(1)
16806f32e7eSjoerg     .addReg(Reg2, getKillRegState(isKill2)).addImm(0).addReg(0);
16906f32e7eSjoerg }
17006f32e7eSjoerg 
17106f32e7eSjoerg static inline const MachineInstrBuilder &
addFullAddress(const MachineInstrBuilder & MIB,const X86AddressMode & AM)17206f32e7eSjoerg addFullAddress(const MachineInstrBuilder &MIB,
17306f32e7eSjoerg                const X86AddressMode &AM) {
17406f32e7eSjoerg   assert(AM.Scale == 1 || AM.Scale == 2 || AM.Scale == 4 || AM.Scale == 8);
17506f32e7eSjoerg 
17606f32e7eSjoerg   if (AM.BaseType == X86AddressMode::RegBase)
17706f32e7eSjoerg     MIB.addReg(AM.Base.Reg);
17806f32e7eSjoerg   else {
17906f32e7eSjoerg     assert(AM.BaseType == X86AddressMode::FrameIndexBase);
18006f32e7eSjoerg     MIB.addFrameIndex(AM.Base.FrameIndex);
18106f32e7eSjoerg   }
18206f32e7eSjoerg 
18306f32e7eSjoerg   MIB.addImm(AM.Scale).addReg(AM.IndexReg);
18406f32e7eSjoerg   if (AM.GV)
18506f32e7eSjoerg     MIB.addGlobalAddress(AM.GV, AM.Disp, AM.GVOpFlags);
18606f32e7eSjoerg   else
18706f32e7eSjoerg     MIB.addImm(AM.Disp);
18806f32e7eSjoerg 
18906f32e7eSjoerg   return MIB.addReg(0);
19006f32e7eSjoerg }
19106f32e7eSjoerg 
19206f32e7eSjoerg /// addFrameReference - This function is used to add a reference to the base of
19306f32e7eSjoerg /// an abstract object on the stack frame of the current function.  This
19406f32e7eSjoerg /// reference has base register as the FrameIndex offset until it is resolved.
19506f32e7eSjoerg /// This allows a constant offset to be specified as well...
19606f32e7eSjoerg ///
19706f32e7eSjoerg static inline const MachineInstrBuilder &
19806f32e7eSjoerg addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0) {
19906f32e7eSjoerg   MachineInstr *MI = MIB;
20006f32e7eSjoerg   MachineFunction &MF = *MI->getParent()->getParent();
20106f32e7eSjoerg   MachineFrameInfo &MFI = MF.getFrameInfo();
20206f32e7eSjoerg   const MCInstrDesc &MCID = MI->getDesc();
20306f32e7eSjoerg   auto Flags = MachineMemOperand::MONone;
20406f32e7eSjoerg   if (MCID.mayLoad())
20506f32e7eSjoerg     Flags |= MachineMemOperand::MOLoad;
20606f32e7eSjoerg   if (MCID.mayStore())
20706f32e7eSjoerg     Flags |= MachineMemOperand::MOStore;
20806f32e7eSjoerg   MachineMemOperand *MMO = MF.getMachineMemOperand(
20906f32e7eSjoerg       MachinePointerInfo::getFixedStack(MF, FI, Offset), Flags,
210*da58b97aSjoerg       MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
21106f32e7eSjoerg   return addOffset(MIB.addFrameIndex(FI), Offset)
21206f32e7eSjoerg             .addMemOperand(MMO);
21306f32e7eSjoerg }
21406f32e7eSjoerg 
21506f32e7eSjoerg /// addConstantPoolReference - This function is used to add a reference to the
21606f32e7eSjoerg /// base of a constant value spilled to the per-function constant pool.  The
21706f32e7eSjoerg /// reference uses the abstract ConstantPoolIndex which is retained until
21806f32e7eSjoerg /// either machine code emission or assembly output. In PIC mode on x86-32,
21906f32e7eSjoerg /// the GlobalBaseReg parameter can be used to make this a
22006f32e7eSjoerg /// GlobalBaseReg-relative reference.
22106f32e7eSjoerg ///
22206f32e7eSjoerg static inline const MachineInstrBuilder &
addConstantPoolReference(const MachineInstrBuilder & MIB,unsigned CPI,unsigned GlobalBaseReg,unsigned char OpFlags)22306f32e7eSjoerg addConstantPoolReference(const MachineInstrBuilder &MIB, unsigned CPI,
22406f32e7eSjoerg                          unsigned GlobalBaseReg, unsigned char OpFlags) {
22506f32e7eSjoerg   //FIXME: factor this
22606f32e7eSjoerg   return MIB.addReg(GlobalBaseReg).addImm(1).addReg(0)
22706f32e7eSjoerg     .addConstantPoolIndex(CPI, 0, OpFlags).addReg(0);
22806f32e7eSjoerg }
22906f32e7eSjoerg 
23006f32e7eSjoerg } // end namespace llvm
23106f32e7eSjoerg 
23206f32e7eSjoerg #endif // LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H
233