summaryrefslogtreecommitdiff
path: root/lib/Target/X86/InstSelectSimple.cpp
blob: 44705586da935807ca83473a7f2a35f1a2d05229 (plain)
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
//===-- InstSelectSimple.cpp - A simple instruction selector for x86 ------===//
//
// This file defines a simple peephole instruction selector for the x86 platform
//
//===----------------------------------------------------------------------===//

#include "X86.h"
#include "X86InstrInfo.h"
#include "llvm/Function.h"
#include "llvm/iTerminators.h"
#include "llvm/iOther.h"
#include "llvm/Type.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Support/InstVisitor.h"
#include <map>

namespace {
  struct ISel : public FunctionPass, InstVisitor<ISel> {
    TargetMachine &TM;
    MachineFunction *F;                    // The function we are compiling into
    MachineBasicBlock *BB;                 // The current MBB we are compiling

    unsigned CurReg;
    std::map<Value*, unsigned> RegMap;  // Mapping between Val's and SSA Regs

    ISel(TargetMachine &tm)
      : TM(tm), F(0), BB(0), CurReg(MRegisterInfo::FirstVirtualRegister) {}

    /// runOnFunction - Top level implementation of instruction selection for
    /// the entire function.
    ///
    bool runOnFunction(Function &Fn) {
      F = &MachineFunction::construct(&Fn, TM);
      visit(Fn);
      RegMap.clear();
      F = 0;
      return false;  // We never modify the LLVM itself.
    }

    /// visitBasicBlock - This method is called when we are visiting a new basic
    /// block.  This simply creates a new MachineBasicBlock to emit code into
    /// and adds it to the current MachineFunction.  Subsequent visit* for
    /// instructions will be invoked for all instructions in the basic block.
    ///
    void visitBasicBlock(BasicBlock &LLVM_BB) {
      BB = new MachineBasicBlock(&LLVM_BB);
      // FIXME: Use the auto-insert form when it's available
      F->getBasicBlockList().push_back(BB);
    }

    // Visitation methods for various instructions.  These methods simply emit
    // fixed X86 code for each instruction.
    //
    void visitReturnInst(ReturnInst &RI);
    void visitAdd(BinaryOperator &B);
    void visitShiftInst(ShiftInst &I);

    void visitInstruction(Instruction &I) {
      std::cerr << "Cannot instruction select: " << I;
      abort();
    }

    
    /// copyConstantToRegister - Output the instructions required to put the
    /// specified constant into the specified register.
    ///
    void copyConstantToRegister(Constant *C, unsigned Reg);

    /// getReg - This method turns an LLVM value into a register number.  This
    /// is guaranteed to produce the same register number for a particular value
    /// every time it is queried.
    ///
    unsigned getReg(Value &V) { return getReg(&V); }  // Allow references
    unsigned getReg(Value *V) {
      unsigned &Reg = RegMap[V];
      if (Reg == 0)
        Reg = CurReg++;

      // If this operand is a constant, emit the code to copy the constant into
      // the register here...
      //
      if (Constant *C = dyn_cast<Constant>(V))
        copyConstantToRegister(C, Reg);

      return Reg;
    }
  };
}


/// copyConstantToRegister - Output the instructions required to put the
/// specified constant into the specified register.
///
void ISel::copyConstantToRegister(Constant *C, unsigned R) {
  assert (!isa<ConstantExpr>(C) && "Constant expressions not yet handled!\n");

  switch (C->getType()->getPrimitiveID()) {
  case Type::SByteTyID:
    BuildMI(BB, X86::MOVir8, 1, R).addSImm(cast<ConstantSInt>(C)->getValue());
    break;
  case Type::UByteTyID:
    BuildMI(BB, X86::MOVir8, 1, R).addZImm(cast<ConstantUInt>(C)->getValue());
    break;
  case Type::ShortTyID:
    BuildMI(BB, X86::MOVir16, 1, R).addSImm(cast<ConstantSInt>(C)->getValue());
    break;
  case Type::UShortTyID:
    BuildMI(BB, X86::MOVir16, 1, R).addZImm(cast<ConstantUInt>(C)->getValue());
    break;
  case Type::IntTyID:
    BuildMI(BB, X86::MOVir32, 1, R).addSImm(cast<ConstantSInt>(C)->getValue());
    break;
  case Type::UIntTyID:
    BuildMI(BB, X86::MOVir32, 1, R).addZImm(cast<ConstantUInt>(C)->getValue());
    break;
  default: assert(0 && "Type not handled yet!");      
  }
}


/// 'ret' instruction - Here we are interested in meeting the x86 ABI.  As such,
/// we have the following possibilities:
///
///   ret void: No return value, simply emit a 'ret' instruction
///   ret sbyte, ubyte : Extend value into EAX and return
///   ret short, ushort: Extend value into EAX and return
///   ret int, uint    : Move value into EAX and return
///   ret pointer      : Move value into EAX and return
///   ret long, ulong  : Move value into EAX/EDX (?) and return
///   ret float/double : ?  Top of FP stack?  XMM0?
///
void ISel::visitReturnInst(ReturnInst &I) {
  if (I.getNumOperands() != 0) {  // Not 'ret void'?
    // Move result into a hard register... then emit a ret
    visitInstruction(I);  // abort
  }

  // Emit a simple 'ret' instruction... appending it to the end of the basic
  // block
  BuildMI(BB, X86::RET, 0);
}

/// SimpleLog2 - Compute and return Log2 of the input, valid only for inputs 1,
/// 2, 4, & 8.  Used to convert operand size into dense classes.
///
static inline unsigned SimpleLog2(unsigned N) {
  switch (N) {
  case 1: return 0;
  case 2: return 1;
  case 4: return 2;
  case 8: return 3;
  default: assert(0 && "Invalid operand to SimpleLog2!");
  }
  return 0;  // not reached
}

/// Shift instructions: 'shl', 'sar', 'shr' - Some special cases here
/// for constant immediate shift values, and for constant immediate
/// shift values equal to 1. Even the general case is sort of special,
/// because the shift amount has to be in CL, not just any old register.
///
void
ISel::visitShiftInst (ShiftInst & I)
{
  unsigned Op0r = getReg (I.getOperand (0));
  unsigned DestReg = getReg (I);
  bool isRightShift = (I.getOpcode () == Instruction::Shr);
  bool isOperandUnsigned = I.getType ()->isUnsigned ();
  unsigned OperandClass = SimpleLog2(I.getType()->getPrimitiveSize());

  if (ConstantUInt *CUI = dyn_cast <ConstantUInt> (I.getOperand (1)))
    {
      // The shift amount is constant, guaranteed to be a ubyte. Get its value.
      assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?");
      unsigned char shAmt = CUI->getValue();

      // Emit: <insn> reg, shamt  (shift-by-immediate opcode "ir" form.)
      if (isRightShift)
	{
	  if (isOperandUnsigned)
	    {
	      // This is a shift right logical (SHR).
	      switch (OperandClass)
		{
		case 0:
		  BuildMI (BB, X86::SHRir8, 2,
			   DestReg).addReg (Op0r).addZImm (shAmt);
		  break;
		case 1:
		  BuildMI (BB, X86::SHRir16, 2,
			   DestReg).addReg (Op0r).addZImm (shAmt);
		  break;
		case 2:
		  BuildMI (BB, X86::SHRir32, 2,
			   DestReg).addReg (Op0r).addZImm (shAmt);
		  break;
		case 3:
		default:
		  visitInstruction (I);
		  break;
		}
	    }
	  else
	    {
	      // This is a shift right arithmetic (SAR).
	      switch (OperandClass)
		{
		case 0:
		  BuildMI (BB, X86::SARir8, 2,
			   DestReg).addReg (Op0r).addZImm (shAmt);
		  break;
		case 1:
		  BuildMI (BB, X86::SARir16, 2,
			   DestReg).addReg (Op0r).addZImm (shAmt);
		  break;
		case 2:
		  BuildMI (BB, X86::SARir32, 2,
			   DestReg).addReg (Op0r).addZImm (shAmt);
		  break;
		case 3:
		default:
		  visitInstruction (I);
		  break;
		}
	    }
	}
      else
	{
	  // This is a left shift (SHL).
	  switch (OperandClass)
	    {
	    case 0:
	      BuildMI (BB, X86::SHLir8, 2,
		       DestReg).addReg (Op0r).addZImm (shAmt);
	      break;
	    case 1:
	      BuildMI (BB, X86::SHLir16, 2,
		       DestReg).addReg (Op0r).addZImm (shAmt);
	      break;
	    case 2:
	      BuildMI (BB, X86::SHLir32, 2,
		       DestReg).addReg (Op0r).addZImm (shAmt);
	      break;
	    case 3:
	    default:
	      visitInstruction (I);
	      break;
	    }
	}
    }
  else
    {
      // The shift amount is non-constant.
      //
      // In fact, you can only shift with a variable shift amount if
      // that amount is already in the CL register, so we have to put it
      // there first.
      //
      // Get it from the register it's in.
      unsigned Op1r = getReg (I.getOperand (1));
      // Emit: move cl, shiftAmount (put the shift amount in CL.)
      BuildMI (BB, X86::MOVrr8, 2, X86::CL).addReg (Op1r);
      // Emit: <insn> reg, cl       (shift-by-CL opcode; "rr" form.)
      if (isRightShift)
	{
	  if (OperandClass)
	    {
	      // This is a shift right logical (SHR).
	      switch (OperandClass)
		{
		case 0:
		  BuildMI (BB, X86::SHRrr8, 2,
			   DestReg).addReg (Op0r).addReg (X86::CL);
		  break;
		case 1:
		  BuildMI (BB, X86::SHRrr16, 2,
			   DestReg).addReg (Op0r).addReg (X86::CL);
		  break;
		case 2:
		  BuildMI (BB, X86::SHRrr32, 2,
			   DestReg).addReg (Op0r).addReg (X86::CL);
		  break;
		case 3:
		default:
		  visitInstruction (I);
		  break;
		}
	    }
	  else
	    {
	      // This is a shift right arithmetic (SAR).
	      switch (OperandClass)
		{
		case 0:
		  BuildMI (BB, X86::SARrr8, 2,
			   DestReg).addReg (Op0r).addReg (X86::CL);
		  break;
		case 1:
		  BuildMI (BB, X86::SARrr16, 2,
			   DestReg).addReg (Op0r).addReg (X86::CL);
		  break;
		case 2:
		  BuildMI (BB, X86::SARrr32, 2,
			   DestReg).addReg (Op0r).addReg (X86::CL);
		  break;
		case 3:
		default:
		  visitInstruction (I);
		  break;
		}
	    }
	}
      else
	{
	  // This is a left shift (SHL).
	  switch (OperandClass)
	    {
	    case 0:
	      BuildMI (BB, X86::SHLrr8, 2,
		       DestReg).addReg (Op0r).addReg (X86::CL);
	      break;
	    case 1:
	      BuildMI (BB, X86::SHLrr16, 2,
		       DestReg).addReg (Op0r).addReg (X86::CL);
	      break;
	    case 2:
	      BuildMI (BB, X86::SHLrr32, 2,
		       DestReg).addReg (Op0r).addReg (X86::CL);
	      break;
	    case 3:
	    default:
	      visitInstruction (I);
	      break;
	    }
	}
    }
}


/// 'add' instruction - Simply turn this into an x86 reg,reg add instruction.
void ISel::visitAdd(BinaryOperator &B) {
  unsigned Op0r = getReg(B.getOperand(0)), Op1r = getReg(B.getOperand(1));
  unsigned DestReg = getReg(B);

  switch (B.getType()->getPrimitiveSize()) {
  case 1:   // UByte, SByte
    BuildMI(BB, X86::ADDrr8, 2, DestReg).addReg(Op0r).addReg(Op1r);
    break;
  case 2:   // UShort, Short
    BuildMI(BB, X86::ADDrr16, 2, DestReg).addReg(Op0r).addReg(Op1r);
    break;
  case 4:   // UInt, Int
    BuildMI(BB, X86::ADDrr32, 2, DestReg).addReg(Op0r).addReg(Op1r);
    break;
  case 8:   // ULong, Long
    // Here we have a pair of operands each occupying a pair of registers.
    // We need to do an ADDrr32 of the least-significant pair immediately
    // followed by an ADCrr32 (Add with Carry) of the most-significant pair.
    // I don't know how we are representing these multi-register arguments.
  default:
    visitInstruction(B);  // abort
  }
}



/// createSimpleX86InstructionSelector - This pass converts an LLVM function
/// into a machine code representation is a very simple peep-hole fashion.  The
/// generated code sucks but the implementation is nice and simple.
///
Pass *createSimpleX86InstructionSelector(TargetMachine &TM) {
  return new ISel(TM);
}