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