Newer
Older
//===-- X86FastISel.cpp - X86 FastISel implementation ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the X86-specific support for the FastISel class. Much
// of the target-specific code is generated by tablegen in the file
// X86GenFastISel.inc, which is #included here.
//
//===----------------------------------------------------------------------===//
#include "X86.h"
#include "X86InstrBuilder.h"
#include "X86RegisterInfo.h"
#include "X86Subtarget.h"
#include "X86TargetMachine.h"
#include "llvm/CodeGen/FastISel.h"
Owen Anderson
committed
#include "llvm/CodeGen/MachineRegisterInfo.h"
using namespace llvm;
class X86FastISel : public FastISel {
/// Subtarget - Keep a pointer to the X86Subtarget around so that we can
/// make the right decision when generating code for different targets.
const X86Subtarget *Subtarget;
explicit X86FastISel(MachineFunction &mf,
DenseMap<const Value *, unsigned> &vm,
DenseMap<const BasicBlock *, MachineBasicBlock *> &bm)
: FastISel(mf, vm, bm) {
virtual bool TargetSelectInstruction(Instruction *I);
#include "X86GenFastISel.inc"
private:
bool X86SelectConstAddr(Value *V, unsigned &Op0);
bool X86SelectLoad(Instruction *I);
Owen Anderson
committed
bool X86SelectStore(Instruction *I);
};
/// X86SelectConstAddr - Select and emit code to materialize constant address.
///
bool X86FastISel::X86SelectConstAddr(Value *V,
// FIXME: Only GlobalAddress for now.
GlobalValue *GV = dyn_cast<GlobalValue>(V);
if (!GV)
return false;
if (Subtarget->GVRequiresExtraLoad(GV, TM, false)) {
// Issue load from stub if necessary.
unsigned Opc = 0;
const TargetRegisterClass *RC = NULL;
if (TLI.getPointerTy() == MVT::i32) {
Opc = X86::MOV32rm;
RC = X86::GR32RegisterClass;
} else {
Opc = X86::MOV64rm;
RC = X86::GR64RegisterClass;
}
Op0 = createResultReg(RC);
X86AddressMode AM;
AM.GV = GV;
addFullAddress(BuildMI(MBB, TII.get(Opc), Op0), AM);
// Prevent loading GV stub multiple times in same MBB.
LocalValueMap[V] = Op0;
}
return true;
}
Owen Anderson
committed
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
/// X86SelectStore - Select and emit code to implement store instructions.
bool X86FastISel::X86SelectStore(Instruction* I) {
MVT VT = MVT::getMVT(I->getOperand(0)->getType());
if (VT == MVT::Other || !VT.isSimple())
// Unhandled type. Halt "fast" selection and bail.
return false;
if (VT == MVT::iPTR)
// Use pointer type.
VT = TLI.getPointerTy();
// We only handle legal types. For example, on x86-32 the instruction
// selector contains all of the 64-bit instructions from x86-64,
// under the assumption that i64 won't be used if the target doesn't
// support it.
if (!TLI.isTypeLegal(VT))
return false;
unsigned Op0 = getRegForValue(I->getOperand(0));
if (Op0 == 0)
// Unhandled operand. Halt "fast" selection and bail.
return false;
Value *V = I->getOperand(1);
unsigned Op1 = getRegForValue(V);
if (Op1 == 0) {
// Handle constant load address.
if (!isa<Constant>(V) || !X86SelectConstAddr(V, Op1))
// Unhandled operand. Halt "fast" selection and bail.
return false;
}
// Get opcode and regclass of the output for the given load instruction.
unsigned Opc = 0;
const TargetRegisterClass *RC = NULL;
switch (VT.getSimpleVT()) {
default: return false;
case MVT::i8:
Opc = X86::MOV8mr;
RC = X86::GR8RegisterClass;
break;
case MVT::i16:
Opc = X86::MOV16mr;
RC = X86::GR16RegisterClass;
break;
case MVT::i32:
Opc = X86::MOV32mr;
RC = X86::GR32RegisterClass;
break;
case MVT::i64:
// Must be in x86-64 mode.
Opc = X86::MOV64mr;
RC = X86::GR64RegisterClass;
break;
case MVT::f32:
if (Subtarget->hasSSE1()) {
Opc = X86::MOVSSmr;
RC = X86::FR32RegisterClass;
} else {
Opc = X86::ST_Fp32m;
RC = X86::RFP32RegisterClass;
}
break;
case MVT::f64:
if (Subtarget->hasSSE2()) {
Opc = X86::MOVSDmr;
RC = X86::FR64RegisterClass;
} else {
Opc = X86::ST_Fp64m;
RC = X86::RFP64RegisterClass;
}
break;
case MVT::f80:
Opc = X86::ST_FP80m;
RC = X86::RFP80RegisterClass;
break;
}
X86AddressMode AM;
if (Op1)
// Address is in register.
Owen Anderson
committed
AM.Base.Reg = Op1;
Owen Anderson
committed
else
AM.GV = cast<GlobalValue>(V);
Owen Anderson
committed
addFullAddress(BuildMI(MBB, TII.get(Opc)), AM).addReg(Op0);
Owen Anderson
committed
return true;
}
/// X86SelectLoad - Select and emit code to implement load instructions.
///
bool X86FastISel::X86SelectLoad(Instruction *I) {
MVT VT = MVT::getMVT(I->getType(), /*HandleUnknown=*/true);
if (VT == MVT::Other || !VT.isSimple())
// Unhandled type. Halt "fast" selection and bail.
return false;
if (VT == MVT::iPTR)
// Use pointer type.
VT = TLI.getPointerTy();
// We only handle legal types. For example, on x86-32 the instruction
// selector contains all of the 64-bit instructions from x86-64,
// under the assumption that i64 won't be used if the target doesn't
// support it.
if (!TLI.isTypeLegal(VT))
return false;
Value *V = I->getOperand(0);
unsigned Op0 = getRegForValue(V);
if (Op0 == 0) {
// Handle constant load address.
if (!isa<Constant>(V) || !X86SelectConstAddr(V, Op0))
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
// Unhandled operand. Halt "fast" selection and bail.
return false;
}
// Get opcode and regclass of the output for the given load instruction.
unsigned Opc = 0;
const TargetRegisterClass *RC = NULL;
switch (VT.getSimpleVT()) {
default: return false;
case MVT::i8:
Opc = X86::MOV8rm;
RC = X86::GR8RegisterClass;
break;
case MVT::i16:
Opc = X86::MOV16rm;
RC = X86::GR16RegisterClass;
break;
case MVT::i32:
Opc = X86::MOV32rm;
RC = X86::GR32RegisterClass;
break;
case MVT::i64:
// Must be in x86-64 mode.
Opc = X86::MOV64rm;
RC = X86::GR64RegisterClass;
break;
case MVT::f32:
if (Subtarget->hasSSE1()) {
Opc = X86::MOVSSrm;
RC = X86::FR32RegisterClass;
} else {
Opc = X86::LD_Fp32m;
RC = X86::RFP32RegisterClass;
}
break;
case MVT::f64:
if (Subtarget->hasSSE2()) {
Opc = X86::MOVSDrm;
RC = X86::FR64RegisterClass;
} else {
Opc = X86::LD_Fp64m;
RC = X86::RFP64RegisterClass;
}
break;
case MVT::f80:
Opc = X86::LD_Fp80m;
RC = X86::RFP80RegisterClass;
break;
}
unsigned ResultReg = createResultReg(RC);
X86AddressMode AM;
if (Op0)
// Address is in register.
AM.Base.Reg = Op0;
else
AM.GV = cast<GlobalValue>(V);
addFullAddress(BuildMI(MBB, TII.get(Opc), ResultReg), AM);
UpdateValueMap(I, ResultReg);
return true;
}
X86FastISel::TargetSelectInstruction(Instruction *I) {
switch (I->getOpcode()) {
default: break;
case Instruction::Load:
return X86SelectLoad(I);
Owen Anderson
committed
case Instruction::Store:
return X86SelectStore(I);
namespace llvm {
llvm::FastISel *X86::createFastISel(MachineFunction &mf,
DenseMap<const Value *, unsigned> &vm,
DenseMap<const BasicBlock *, MachineBasicBlock *> &bm) {
return new X86FastISel(mf, vm, bm);
}