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