001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.lir2mir.ia32;
014
015import static org.jikesrvm.compilers.opt.OptimizingCompilerException.UNREACHABLE;
016import static org.jikesrvm.compilers.opt.OptimizingCompilerException.opt_assert;
017import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_CMPL;
018import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_CMPL;
019import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE;
020import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE;
021import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHL;
022import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHR;
023import static org.jikesrvm.compilers.opt.ir.Operators.LONG_USHR;
024import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.CALL_SAVE_VOLATILE;
025import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ADC;
026import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ADD;
027import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_AND;
028import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ANDNPD;
029import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ANDNPS;
030import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ANDPD;
031import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ANDPS;
032import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_BT;
033import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CALL;
034import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CDQ;
035import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMOV;
036import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMP;
037import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPEQSD;
038import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPEQSS;
039import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPLESD;
040import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPLESS;
041import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPLTSD;
042import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMPLTSS;
043import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CVTSS2SD;
044import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_DIV;
045import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FCMOV;
046import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FCOMI;
047import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FCOMIP;
048import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FFREE;
049import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FILD;
050import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FIST;
051import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLD;
052import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLD1;
053import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDL2E;
054import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDL2T;
055import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDLG2;
056import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDLN2;
057import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDPI;
058import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDZ;
059import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FMOV;
060import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FPREM;
061import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FSTP;
062import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_IDIV;
063import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_IMUL1;
064import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_IMUL2;
065import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_JCC;
066import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_LEA;
067import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_LOCK_CMPXCHG;
068import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_LOCK_CMPXCHG8B;
069import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_METHODSTART;
070import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOV;
071import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVD;
072import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSD;
073import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSS;
074import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSX__B;
075import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVZX__B;
076import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MUL;
077import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_NEG;
078import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_NOT;
079import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_OR;
080import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ORPD;
081import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ORPS;
082import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_RCR;
083import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_RDTSC;
084import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SAR;
085import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SBB;
086import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SET__B;
087import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHL;
088import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHR;
089import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SUB;
090import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SYSCALL;
091import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_TRAPIF;
092import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_XOR;
093import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_XORPD;
094import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_XORPS;
095import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.MIR_LOWTABLESWITCH;
096
097import java.util.Enumeration;
098
099import org.jikesrvm.VM;
100import org.jikesrvm.classloader.TypeReference;
101import org.jikesrvm.compilers.opt.DefUse;
102import org.jikesrvm.compilers.opt.OptimizingCompilerException;
103import org.jikesrvm.compilers.opt.ir.Binary;
104import org.jikesrvm.compilers.opt.ir.CacheOp;
105import org.jikesrvm.compilers.opt.ir.Call;
106import org.jikesrvm.compilers.opt.ir.CondMove;
107import org.jikesrvm.compilers.opt.ir.GuardedBinary;
108import org.jikesrvm.compilers.opt.ir.IfCmp;
109import org.jikesrvm.compilers.opt.ir.Instruction;
110import org.jikesrvm.compilers.opt.ir.LowTableSwitch;
111import org.jikesrvm.compilers.opt.ir.Move;
112import org.jikesrvm.compilers.opt.ir.Nullary;
113import org.jikesrvm.compilers.opt.ir.Operator;
114import org.jikesrvm.compilers.opt.ir.OsrPoint;
115import org.jikesrvm.compilers.opt.ir.Prologue;
116import org.jikesrvm.compilers.opt.ir.Register;
117import org.jikesrvm.compilers.opt.ir.TrapIf;
118import org.jikesrvm.compilers.opt.ir.Unary;
119import org.jikesrvm.compilers.opt.ir.ia32.MIR_BinaryAcc;
120import org.jikesrvm.compilers.opt.ir.ia32.MIR_Call;
121import org.jikesrvm.compilers.opt.ir.ia32.MIR_Compare;
122import org.jikesrvm.compilers.opt.ir.ia32.MIR_CompareExchange;
123import org.jikesrvm.compilers.opt.ir.ia32.MIR_CompareExchange8B;
124import org.jikesrvm.compilers.opt.ir.ia32.MIR_CondBranch;
125import org.jikesrvm.compilers.opt.ir.ia32.MIR_CondMove;
126import org.jikesrvm.compilers.opt.ir.ia32.MIR_ConvertDW2QW;
127import org.jikesrvm.compilers.opt.ir.ia32.MIR_Divide;
128import org.jikesrvm.compilers.opt.ir.ia32.MIR_Lea;
129import org.jikesrvm.compilers.opt.ir.ia32.MIR_LowTableSwitch;
130import org.jikesrvm.compilers.opt.ir.ia32.MIR_Move;
131import org.jikesrvm.compilers.opt.ir.ia32.MIR_Multiply;
132import org.jikesrvm.compilers.opt.ir.ia32.MIR_Nullary;
133import org.jikesrvm.compilers.opt.ir.ia32.MIR_RDTSC;
134import org.jikesrvm.compilers.opt.ir.ia32.MIR_Set;
135import org.jikesrvm.compilers.opt.ir.ia32.MIR_TrapIf;
136import org.jikesrvm.compilers.opt.ir.ia32.MIR_Unary;
137import org.jikesrvm.compilers.opt.ir.ia32.MIR_UnaryAcc;
138import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
139import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
140import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
141import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand;
142import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand;
143import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand;
144import org.jikesrvm.compilers.opt.ir.operand.InlinedOsrTypeInfoOperand;
145import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
146import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
147import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
148import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
149import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
150import org.jikesrvm.compilers.opt.ir.operand.Operand;
151import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
152import org.jikesrvm.compilers.opt.ir.operand.StackLocationOperand;
153import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
154import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
155import org.jikesrvm.compilers.opt.ir.operand.ia32.BURSManagedFPROperand;
156import org.jikesrvm.compilers.opt.ir.operand.ia32.IA32ConditionOperand;
157import org.jikesrvm.compilers.opt.lir2mir.BURS;
158import org.jikesrvm.compilers.opt.lir2mir.BURS_MemOp_Helpers;
159import org.jikesrvm.runtime.Entrypoints;
160import org.jikesrvm.runtime.Magic;
161import org.jikesrvm.runtime.RuntimeEntrypoints;
162import org.jikesrvm.runtime.Statics;
163import org.vmmagic.unboxed.Offset;
164
165/**
166 * Contains IA32-specific helper functions for BURS.
167 */
168public abstract class BURS_Helpers extends BURS_MemOp_Helpers {
169  /** Constant log10(2), supported as an x87 constant */
170  private static final double LG2 = Double
171      .parseDouble("0.3010299956639811952256464283594894482");
172
173  /** Constant ln(2), supported as an x87 constant */
174  private static final double LN2 = Double
175      .parseDouble("0.6931471805599453094286904741849753009");
176
177  /** Constant log2(e), supported as an x87 constant */
178  private static final double L2E = Double
179      .parseDouble("1.4426950408889634073876517827983434472");
180
181  /** Constant log2(10), supported as an x87 constant */
182  private static final double L2T = Double
183      .parseDouble("3.3219280948873623478083405569094566090");
184
185  /** Mask to flip sign bits in XMM registers */
186  private static final Offset floatSignMask =
187    VM.BuildForSSE2Full ?
188      Offset.fromIntSignExtend(Statics.findOrCreate16ByteSizeLiteral(0x8000000080000000L, 0x8000000080000000L)) :
189      Offset.zero();
190
191  /** Mask to flip sign bits in XMM registers */
192  private static final Offset doubleSignMask =
193    VM.BuildForSSE2Full ?
194      Offset.fromIntSignExtend(Statics.findOrCreate16ByteSizeLiteral(0x8000000000000000L, 0x8000000000000000L)) :
195      Offset.zero();
196
197  /** Mask to abs an XMM registers */
198  private static final Offset floatAbsMask =
199    VM.BuildForSSE2Full ?
200      Offset.fromIntSignExtend(Statics.findOrCreate16ByteSizeLiteral(0x7FFFFFFF7FFFFFFFL, 0x7FFFFFFF7FFFFFFFL)) :
201      Offset.zero();
202
203  /** Mask to abs an XMM registers */
204  private static final Offset doubleAbsMask =
205    VM.BuildForSSE2Full ?
206      Offset.fromIntSignExtend(Statics.findOrCreate16ByteSizeLiteral(0x7FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL)) :
207      Offset.zero();
208
209  /**
210   * When emitting certain rules this holds the condition code state to be
211   * consumed by a parent rule
212   */
213  private ConditionOperand cc;
214
215  public BURS_Helpers(BURS burs) {
216    super(burs);
217  }
218
219  /**
220   * Create the MIR instruction given by operator from the Binary LIR operands
221   * @param operator the MIR operator
222   * @param s the instruction being replaced
223   * @param result the destination register/memory
224   * @param val1 the first operand
225   * @param val2 the second operand
226   */
227  protected void EMIT_Commutative(Operator operator, Instruction s, Operand result, Operand val1, Operand val2) {
228    if (VM.VerifyAssertions) opt_assert(result.isRegister() || result.isMemory());
229    // Swap operands to reduce chance of generating a move or to normalize
230    // constants into val2
231    if (val2.similar(result) || val1.isConstant()) {
232      Operand temp = val1;
233      val1 = val2;
234      val2 = temp;
235    }
236    // Do we need to move prior to the operator - result = val1
237    if (!result.similar(val1)) {
238      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copy(), val1)));
239    }
240    EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
241  }
242
243  /**
244   * Create the MIR instruction given by operator from the Binary LIR operands
245   * @param operator the MIR operator
246   * @param s the instruction being replaced
247   * @param result the destination register/memory
248   * @param val1 the first operand
249   * @param val2 the second operand
250   */
251  protected void EMIT_NonCommutative(Operator operator, Instruction s, Operand result, Operand val1, Operand val2) {
252    if (VM.VerifyAssertions) opt_assert(result.isRegister() || result.isMemory());
253    if (result.similar(val1)) {
254      // Straight forward case where instruction is already in accumulate form
255      EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
256    } else if (!result.similar(val2)) {
257      // Move first operand to result and perform operator on result, if
258      // possible redundant moves should be remove by register allocator
259      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copy(), val1)));
260      EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
261    } else {
262      // Potential to clobber second operand during move to result. Use a
263      // temporary register to perform the operation and rely on register
264      // allocator to remove redundant moves
265      RegisterOperand temp = regpool.makeTemp(result);
266      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val1)));
267      EMIT(MIR_BinaryAcc.mutate(s, operator, temp.copyRO(), val2));
268      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result, temp.copyRO())));
269    }
270  }
271
272  /**
273   * Create the MIR instruction given by operator from the Binary LIR operands
274   * @param operator the MIR operator
275   * @param s the instruction being replaced
276   * @param result the destination register/memory
277   * @param value the first operand
278   */
279  protected void EMIT_Unary(Operator operator, Instruction s, Operand result, Operand value) {
280    if (VM.VerifyAssertions) opt_assert(result.isRegister() || result.isMemory());
281    // Do we need to move prior to the operator - result = val1
282    if (!result.similar(value)) {
283      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copy(), value)));
284    }
285    EMIT(MIR_UnaryAcc.mutate(s, operator, result));
286  }
287
288  /**
289   * Create the MIR LEA instruction performing a few simplifications if possible
290   * @param s the instruction being replaced
291   * @param result the destination register
292   * @param mo the memory operand
293   */
294  protected void EMIT_Lea(Instruction s, RegisterOperand result, MemoryOperand mo) {
295    // A memory operand is: base + scaled index + displacement
296    if ((mo.index == null) && mo.disp.isZero()) {
297      if (VM.VerifyAssertions) opt_assert(mo.scale == 0 && mo.base != null);
298      // If there is no index or displacement emit a move
299      EMIT(MIR_Move.mutate(s, IA32_MOV, result, mo.base));
300    } else if ((mo.index == null) && result.similar(mo.base)) {
301      if (VM.VerifyAssertions) opt_assert(mo.scale == 0);
302      // If there is no index and we're redefining the same register, emit an add
303      EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(mo.disp.toInt())));
304    } else {
305      // Lea is simplest form
306      EMIT(MIR_Lea.mutate(s, IA32_LEA, result, mo));
307    }
308  }
309
310  /**
311   * Convert the given comparison with a boolean (int) value into a condition
312   * suitable for the carry flag
313   * @param x the value 1 (true) or 0 (false)
314   * @param cond either equal or not equal
315   * @return lower or higher equal
316   */
317  protected static ConditionOperand BIT_TEST(int x, ConditionOperand cond) {
318    if (VM.VerifyAssertions) opt_assert((x == 0) || (x == 1));
319    if (VM.VerifyAssertions) opt_assert(EQ_NE(cond));
320    if ((x == 1 && cond.isEQUAL()) ||
321        (x == 0 && cond.isNOT_EQUAL())) {
322      return ConditionOperand.LOWER();
323    } else {
324      return ConditionOperand.HIGHER_EQUAL();
325    }
326  }
327
328  /**
329   * Follow a chain of Move operations filtering back to a def
330   *
331   * @param use the place to start from
332   * @return the operand at the start of the chain
333   */
334  protected static Operand follow(Operand use) {
335    if (!use.isRegister()) {
336      return use;
337    } else {
338      RegisterOperand rop = use.asRegister();
339      Enumeration<RegisterOperand> defs = DefUse.defs(rop.getRegister());
340      if (!defs.hasMoreElements()) {
341        return use;
342      } else {
343        Operand def = defs.nextElement();
344        if (defs.hasMoreElements()) {
345          return def;
346        } else {
347          Instruction instr = def.instruction;
348          if (Move.conforms(instr)) {
349            return follow(Move.getVal(instr));
350          } else if (MIR_Move.conforms(instr)) {
351            return follow(MIR_Move.getValue(instr));
352          } else {
353            return def;
354          }
355        }
356      }
357    }
358  }
359
360  /**
361   * Remember a condition code in a child node
362   *
363   * @param c condition code to record
364   */
365  protected final void pushCOND(ConditionOperand c) {
366    if (VM.VerifyAssertions) {
367      opt_assert(cc == null);
368    }
369    cc = c;
370  }
371
372  /**
373   * Acquire remembered condition code in parent
374   *
375   * @return condition code
376   */
377  protected final ConditionOperand consumeCOND() {
378    ConditionOperand ans = cc;
379    if (VM.VerifyAssertions) {
380      opt_assert(cc != null);
381    }
382    cc = null;
383    return ans;
384  }
385
386  /**
387   * Can an IV be the scale in a LEA instruction?
388   *
389   * @param op operand to examine
390   * @param trueCost the cost if this can be part of an LEA
391   * @return trueCost or INFINITE
392   */
393  protected static int LEA_SHIFT(Operand op, int trueCost) {
394    return LEA_SHIFT(op, trueCost, INFINITE);
395  }
396
397  /**
398   * Can an IV be the scale in a LEA instruction?
399   *
400   * @param op operand to examine
401   * @param trueCost the cost if this can be part of an LEA
402   * @param falseCost the cost if this can't be part of an LEA
403   * @return trueCost or falseCost
404   */
405  protected static int LEA_SHIFT(Operand op, int trueCost, int falseCost) {
406    if (op.isIntConstant()) {
407      int val = IV(op);
408      if (val >= 0 && val <= 3) {
409        return trueCost;
410      }
411    }
412    return falseCost;
413  }
414
415  protected final byte LEA_SHIFT(Operand op) {
416    switch (IV(op)) {
417      case 0:
418        return B_S;
419      case 1:
420        return W_S;
421      case 2:
422        return DW_S;
423      case 3:
424        return QW_S;
425      default:
426        throw new OptimizingCompilerException("bad val for LEA shift " + op);
427    }
428  }
429
430  /**
431   * Is the given instruction's constant operand a x87 floating point constant
432   *
433   * @param s the instruction to examine
434   * @param trueCost the cost if this is a valid constant
435   * @return trueCost or INFINITE depending on the given constant
436   */
437  protected static int is387_FPC(Instruction s, int trueCost) {
438    Operand val = Binary.getVal2(s);
439    if (val instanceof FloatConstantOperand) {
440      FloatConstantOperand fc = (FloatConstantOperand) val;
441      if (fc.value == 1.0f) {
442        return trueCost;
443      } else if (fc.value == 0.0f) {
444        return trueCost;
445      } else if (fc.value == (float) Math.PI) {
446        return trueCost;
447      } else if (fc.value == (float) LG2) {
448        return trueCost;
449      } else if (fc.value == (float) LN2) {
450        return trueCost;
451      } else if (fc.value == (float) L2E) {
452        return trueCost;
453      } else if (fc.value == (float) L2T) {
454        return trueCost;
455      }
456    } else {
457      DoubleConstantOperand dc = (DoubleConstantOperand) val;
458      if (dc.value == 1.0) {
459        return trueCost;
460      } else if (dc.value == 0.0) {
461        return trueCost;
462      } else if (dc.value == Math.PI) {
463        return trueCost;
464      } else if (dc.value == LG2) {
465        return trueCost;
466      } else if (dc.value == LN2) {
467        return trueCost;
468      } else if (dc.value == L2E) {
469        return trueCost;
470      } else if (dc.value == L2T) {
471        return trueCost;
472      }
473    }
474    return INFINITE;
475  }
476
477  protected final Operator get387_FPC(Instruction s) {
478    Operand val = Binary.getVal2(s);
479    if (val instanceof FloatConstantOperand) {
480      FloatConstantOperand fc = (FloatConstantOperand) val;
481      if (fc.value == 1.0f) {
482        return IA32_FLD1;
483      } else if (fc.value == 0.0f) {
484        return IA32_FLDZ;
485      } else if (fc.value == (float) Math.PI) {
486        return IA32_FLDPI;
487      } else if (fc.value == (float) LG2) {
488        return IA32_FLDLG2;
489      } else if (fc.value == (float) LN2) {
490        return IA32_FLDLN2;
491      } else if (fc.value == (float) L2E) {
492        return IA32_FLDL2E;
493      } else if (fc.value == (float) L2T) {
494        return IA32_FLDL2T;
495      }
496    } else {
497      DoubleConstantOperand dc = (DoubleConstantOperand) val;
498      if (dc.value == 1.0) {
499        return IA32_FLD1;
500      } else if (dc.value == 0.0) {
501        return IA32_FLDZ;
502      } else if (dc.value == Math.PI) {
503        return IA32_FLDPI;
504      } else if (dc.value == LG2) {
505        return IA32_FLDLG2;
506      } else if (dc.value == LN2) {
507        return IA32_FLDLN2;
508      } else if (dc.value == L2E) {
509        return IA32_FLDL2E;
510      } else if (dc.value == L2T) {
511        return IA32_FLDL2T;
512      }
513    }
514    throw new OptimizingCompilerException("BURS_Helpers", "unexpected 387 constant " + val);
515  }
516
517  /**
518   * Can the given condition for a compare be converted to a test?
519   *
520   * @param op a condition
521   * @return {@code true} if and only if the condition for the compare
522   *  can be reduced to a test
523   */
524  protected static boolean CMP_TO_TEST(ConditionOperand op) {
525    switch(op.value) {
526    case ConditionOperand.EQUAL:
527    case ConditionOperand.NOT_EQUAL:
528    case ConditionOperand.LESS:
529    case ConditionOperand.GREATER_EQUAL:
530    case ConditionOperand.GREATER:
531    case ConditionOperand.LESS_EQUAL:
532      return true;
533    default:
534      return false;
535    }
536  }
537
538  protected final IA32ConditionOperand COND(ConditionOperand op) {
539    return new IA32ConditionOperand(op);
540  }
541
542  // Get particular physical registers
543  protected final Register getEAX() {
544    return getIR().regpool.getPhysicalRegisterSet().asIA32().getEAX();
545  }
546
547  protected final Register getECX() {
548    return getIR().regpool.getPhysicalRegisterSet().asIA32().getECX();
549  }
550
551  protected final Register getEDX() {
552    return getIR().regpool.getPhysicalRegisterSet().asIA32().getEDX();
553  }
554
555  protected final Register getEBX() {
556    return getIR().regpool.getPhysicalRegisterSet().asIA32().getEBX();
557  }
558
559  protected final Register getESP() {
560    return getIR().regpool.getPhysicalRegisterSet().asIA32().getESP();
561  }
562
563  protected final Register getEBP() {
564    return getIR().regpool.getPhysicalRegisterSet().asIA32().getEBP();
565  }
566
567  protected final Register getESI() {
568    return getIR().regpool.getPhysicalRegisterSet().asIA32().getESI();
569  }
570
571  protected final Register getEDI() {
572    return getIR().regpool.getPhysicalRegisterSet().asIA32().getEDI();
573  }
574
575  protected final Register getFPR(int n) {
576    return getIR().regpool.getPhysicalRegisterSet().asIA32().getFPR(n);
577  }
578
579  protected final Operand myFP0() {
580    return new BURSManagedFPROperand(0);
581  }
582
583  protected final Operand myFP1() {
584    return new BURSManagedFPROperand(1);
585  }
586
587  protected final Register getST0() {
588    return getIR().regpool.getPhysicalRegisterSet().asIA32().getST0();
589  }
590
591  /**
592   * Emits code to move the operand into a register operand if it
593   * isn't one already.
594   *
595   * @param movop the Operator that needs to be used for the move
596   * @param op the operand to move
597   * @param s instruction to get source position information
598   * @return a new operand if a move was inserted, the old operand
599   *  otherwise
600   */
601  private Operand asReg(Instruction s, Operator movop, Operand op) {
602    if (op.isRegister()) {
603      return op;
604    }
605    RegisterOperand tmp = regpool.makeTemp(op);
606    EMIT(CPOS(s, MIR_Move.create(movop, tmp, op)));
607    return tmp.copy();
608  }
609
610  /**
611   * Set the size field of the given memory operand and return it
612   *
613   * @param mo memory operand size to set
614   * @param size the new size
615   * @return mo
616   */
617  protected final MemoryOperand setSize(MemoryOperand mo, int size) {
618    mo.size = (byte) size;
619    return mo;
620  }
621
622  /**
623   * Create a slot on the stack in memory for a conversion
624   *
625   * @param size for memory operand
626   * @return memory operand of slot in stack
627   */
628  protected final Operand MO_CONV(byte size) {
629    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
630    return new StackLocationOperand(true, offset, size);
631  }
632
633  /**
634   * Creates a 64bit slot on the stack in memory for a conversion and
635   * stores the given long.
636   *
637   * @param op an operand representing a long
638   */
639  protected final void STORE_LONG_FOR_CONV(Operand op) {
640    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
641    if (VM.BuildFor32Addr) {
642      if (op instanceof RegisterOperand) {
643        RegisterOperand hval = (RegisterOperand) op;
644        RegisterOperand lval = new RegisterOperand(regpool.getSecondReg(hval.getRegister()),
645            TypeReference.Int);
646        EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset + 4, DW), hval));
647        EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset, DW), lval));
648      } else {
649        LongConstantOperand val = LC(op);
650        EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset + 4, DW), IC(val.upper32())));
651        EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset, DW), IC(val.lower32())));
652      }
653    } else {
654      if (op instanceof RegisterOperand) {
655        RegisterOperand val = (RegisterOperand) op;
656        EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset, QW), val));
657      } else {
658        LongConstantOperand val = LC(op);
659        EMIT(MIR_Move.create(IA32_MOV, new StackLocationOperand(true, offset, QW), val));
660      }
661    }
662  }
663
664  /**
665   * Create memory operand to load from a given jtoc offset
666   *
667   * @param offset location in JTOC
668   * @param size of value in JTOC
669   * @return created memory operand
670   */
671  static MemoryOperand loadFromJTOC(Offset offset, byte size) {
672    LocationOperand loc = new LocationOperand(offset);
673    Operand guard = TG();
674    return MemoryOperand.D(Magic.getTocPointer().plus(offset), size, loc, guard);
675  }
676
677  /*
678   * IA32-specific emit rules that are complex enough that we didn't want to
679   * write them in the LIR2MIR.rules file. However, all expansions in this file
680   * are called during BURS and thus are constrained to generate nonbranching
681   * code (ie they can't create new basic blocks and/or do branching).
682   */
683
684  /**
685   * Emit code to get a caught exception object into a register
686   *
687   * @param s the instruction to expand
688   */
689  protected final void GET_EXCEPTION_OBJECT(Instruction s) {
690    int offset = -burs.ir.stackManager.allocateSpaceForCaughtException();
691    StackLocationOperand sl = new StackLocationOperand(true, offset, DW);
692    EMIT(MIR_Move.mutate(s, IA32_MOV, Nullary.getResult(s), sl));
693  }
694
695  /**
696   * Emit code to move a value in a register to the stack location where a
697   * caught exception object is expected to be.
698   *
699   * @param s the instruction to expand
700   */
701  protected final void SET_EXCEPTION_OBJECT(Instruction s) {
702    int offset = -burs.ir.stackManager.allocateSpaceForCaughtException();
703    StackLocationOperand sl = new StackLocationOperand(true, offset, DW);
704    Operand val = CacheOp.getRef(s);
705    if (val.isRegister()) {
706        EMIT(MIR_Move.mutate(s, IA32_MOV, sl, val));
707    } else if (val.isIntConstant()) {
708        RegisterOperand temp = regpool.makeTempInt();
709        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val)));
710        val = temp.copyRO(); // for opt compiler var usage info?
711        EMIT(MIR_Move.mutate(s, IA32_MOV, sl, temp));
712    } else {
713        throw new OptimizingCompilerException("BURS_Helpers",
714                "unexpected operand type " + val + " in SET_EXCEPTION_OBJECT");
715    }
716  }
717
718  /**
719   * Expansion of INT_2LONG
720   *
721   * @param s the instruction to expand
722   * @param result the result operand
723   * @param value the second operand
724   * @param signExtend should the value be sign or zero extended?
725   */
726  protected final void INT_2LONG(Instruction s, RegisterOperand result,
727      Operand value, boolean signExtend) {
728    if (VM.BuildFor32Addr) {
729      Register hr = result.getRegister();
730      Register lr = regpool.getSecondReg(hr);
731      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(lr, TypeReference.Int), value)));
732      if (signExtend) {
733        EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
734            new RegisterOperand(hr, TypeReference.Int),
735            new RegisterOperand(lr, TypeReference.Int))));
736        EMIT(MIR_BinaryAcc.mutate(s,IA32_SAR,
737            new RegisterOperand(hr, TypeReference.Int),
738            IC(31)));
739      } else {
740        EMIT(MIR_Move.mutate(s, IA32_MOV,
741            new RegisterOperand(hr, TypeReference.Int),
742            IC(0)));
743      }
744    } else {
745      //MOVZX, MOVSX doesn't accept memory as target
746      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result,value)));
747      if (signExtend) {
748        EMIT(CPOS(s,MIR_BinaryAcc.create(IA32_SHL,
749            result,
750            LC(32))));
751        EMIT(MIR_BinaryAcc.mutate(s,IA32_SAR,
752            result,
753            LC(32)));
754      } else {
755        EMIT(CPOS(s,MIR_BinaryAcc.create(IA32_SHL,
756            result,
757            LC(32))));
758        EMIT(MIR_BinaryAcc.mutate(s,IA32_SHR,
759            result,
760            LC(32)));
761      }
762    }
763  }
764
765  /**
766   * Expansion of FLOAT_2INT and DOUBLE_2INT, using the FIST instruction. This
767   * expansion does some boolean logic and conditional moves in order to avoid
768   * changing the floating-point rounding mode or inserting branches. Other
769   * expansions are possible, and may be better?
770   *
771   * @param s the instruction to expand
772   * @param result the result operand
773   * @param value the second operand
774   */
775  protected final void FPR_2INT(Instruction s, RegisterOperand result, Operand value) {
776    MemoryOperand M;
777
778    // Step 1: Get value to be converted into myFP0
779    // and in 'strict' IEEE mode.
780    if (value instanceof MemoryOperand) {
781      // value is in memory, all we have to do is load it
782      EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), value)));
783    } else {
784      // sigh. value is an FP register. Unfortunately,
785      // SPECjbb requires some 'strict' FP semantics. Naturally, we don't
786      // normally implement strict semantics, but we try to slide by in
787      // order to pass the benchmark.
788      // In order to pass SPECjbb, it turns out we need to enforce 'strict'
789      // semantics before doing a particular f2int conversion. To do this
790      // we must have a store/load sequence to cause IEEE rounding.
791      if (value instanceof BURSManagedFPROperand) {
792        if (VM.VerifyAssertions) {
793          opt_assert(value.similar(myFP0()));
794        }
795        EMIT(CPOS(s, MIR_Move.create(IA32_FSTP, MO_CONV(DW), value)));
796        EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), MO_CONV(DW))));
797      } else {
798        EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, MO_CONV(DW), value)));
799        EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), MO_CONV(DW))));
800      }
801    }
802
803    // FP Stack: myFP0 = value
804    EMIT(CPOS(s, MIR_Move.create(IA32_FIST, MO_CONV(DW), myFP0())));
805    // MO_CONV now holds myFP0 converted to an integer (round-toward nearest)
806    // FP Stack: myFP0 == value
807
808    // isPositive == 1 iff 0.0 < value
809    // isNegative == 1 iff 0.0 > value
810    Register one = regpool.getInteger();
811    Register isPositive = regpool.getInteger();
812    Register isNegative = regpool.getInteger();
813    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(one, TypeReference.Int), IC(1))));
814    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(isPositive, TypeReference.Int), IC(0))));
815    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(isNegative, TypeReference.Int), IC(0))));
816    EMIT(CPOS(s, MIR_Nullary.create(IA32_FLDZ, myFP0())));
817    // FP Stack: myFP0 = 0.0; myFP1 = value
818    EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP1())));
819    // FP Stack: myFP0 = value
820    EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
821                             new RegisterOperand(isPositive, TypeReference.Int),
822                             new RegisterOperand(one, TypeReference.Int),
823                             IA32ConditionOperand.LLT())));
824    EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
825                             new RegisterOperand(isNegative, TypeReference.Int),
826                             new RegisterOperand(one, TypeReference.Int),
827                             IA32ConditionOperand.LGT())));
828
829    EMIT(CPOS(s, MIR_Move.create(IA32_FILD, myFP0(), MO_CONV(DW))));
830    // FP Stack: myFP0 = round(value), myFP1 = value
831
832    // addee = 1 iff round(x) < x
833    // subtractee = 1 iff round(x) > x
834    Register addee = regpool.getInteger();
835    Register subtractee = regpool.getInteger();
836    EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP1())));
837    // FP Stack: myFP0 = value
838    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(addee, TypeReference.Int), IC(0))));
839    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(subtractee, TypeReference.Int), IC(0))));
840    EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
841                             new RegisterOperand(addee, TypeReference.Int),
842                             new RegisterOperand(one, TypeReference.Int),
843                             IA32ConditionOperand.LLT())));
844    EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
845                             new RegisterOperand(subtractee, TypeReference.Int),
846                             new RegisterOperand(one, TypeReference.Int),
847                             IA32ConditionOperand.LGT())));
848
849    // Now a little tricky part.
850    // We will add 1 iff isNegative and x > round(x)
851    // We will subtract 1 iff isPositive and x < round(x)
852    EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND,
853                              new RegisterOperand(addee, TypeReference.Int),
854                              new RegisterOperand(isNegative, TypeReference.Int))));
855    EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND,
856                              new RegisterOperand(subtractee, TypeReference.Int),
857                              new RegisterOperand(isPositive, TypeReference.Int))));
858    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copy(), MO_CONV(DW))));
859    EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD, result.copy(), new RegisterOperand(addee, TypeReference.Int))));
860    EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, result.copy(), new RegisterOperand(subtractee, TypeReference.Int))));
861
862    // Compare myFP0 with (double)Integer.MAX_VALUE
863    M = MemoryOperand.D(Magic.getTocPointer().plus(Entrypoints.maxintField.getOffset()), QW, null, null);
864    EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), M)));
865    // FP Stack: myFP0 = (double)Integer.MAX_VALUE; myFP1 = value
866    EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP1())));
867    // FP Stack: myFP0 = value
868    // If MAX_VALUE < value, then result := MAX_INT
869    Register maxInt = regpool.getInteger();
870    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(maxInt, TypeReference.Int), IC(Integer.MAX_VALUE))));
871    EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
872                             result.copy(),
873                             new RegisterOperand(maxInt, TypeReference.Int),
874                             IA32ConditionOperand.LLT())));
875
876    // Compare myFP0 with (double)Integer.MIN_VALUE
877    M = MemoryOperand.D(Magic.getTocPointer().plus(Entrypoints.minintField.getOffset()), QW, null, null);
878    EMIT(CPOS(s, MIR_Move.create(IA32_FLD, myFP0(), M)));
879    // FP Stack: myFP0 = (double)Integer.MIN_VALUE; myFP1 = value
880    EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP1())));
881    // FP Stack: myFP0 = value
882    // If MIN_VALUE > value, then result := MIN_INT
883    Register minInt = regpool.getInteger();
884    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(minInt, TypeReference.Int), IC(Integer.MIN_VALUE))));
885    EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
886                             result.copy(),
887                             new RegisterOperand(minInt, TypeReference.Int),
888                             IA32ConditionOperand.LGT())));
889
890    // Set condition flags: set PE iff myFP0 is a NaN
891    EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMIP, myFP0(), myFP0())));
892    // FP Stack: back to original level (all BURS managed slots freed)
893    // If FP0 was classified as a NaN, then result := 0
894    Register zero = regpool.getInteger();
895    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(zero, TypeReference.Int), IC(0))));
896    EMIT(CPOS(s, MIR_CondMove.create(IA32_CMOV,
897                             result.copy(),
898                             new RegisterOperand(zero, TypeReference.Int),
899                             IA32ConditionOperand.PE())));
900  }
901
902  /**
903   * Emits code to move 64 bits from FPRs to GPRs
904   *
905   * @param s instruction to modify for the move
906   */
907  protected final void FPR2GPR_64(Instruction s) {
908    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
909    StackLocationOperand sl = new StackLocationOperand(true, offset, QW);
910    StackLocationOperand sl1 = new StackLocationOperand(true, offset + 4, DW);
911    StackLocationOperand sl2 = new StackLocationOperand(true, offset, DW);
912    EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, sl, Unary.getVal(s))));
913    RegisterOperand i1 = Unary.getResult(s);
914    RegisterOperand i2 = new RegisterOperand(regpool
915        .getSecondReg(i1.getRegister()), TypeReference.Int);
916    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, i1, sl1)));
917    EMIT(MIR_Move.mutate(s, IA32_MOV, i2, sl2));
918  }
919
920  /**
921   * Emits code to move 64 bits from GPRs to FPRs.
922   *
923   * @param s instruction to modify for the move
924   */
925  protected final void GPR2FPR_64(Instruction s) {
926    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
927    StackLocationOperand sl = new StackLocationOperand(true, offset, QW);
928    StackLocationOperand sl1 = new StackLocationOperand(true, offset + 4, DW);
929    StackLocationOperand sl2 = new StackLocationOperand(true, offset, DW);
930    Operand i1, i2;
931    Operand val = Unary.getVal(s);
932    if (val instanceof RegisterOperand) {
933      RegisterOperand rval = (RegisterOperand) val;
934      i1 = val;
935      i2 = new RegisterOperand(regpool.getSecondReg(rval.getRegister()), TypeReference.Int);
936    } else {
937      LongConstantOperand rhs = (LongConstantOperand) val;
938      i1 = IC(rhs.upper32());
939      i2 = IC(rhs.lower32());
940    }
941    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl1, i1)));
942    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl2, i2)));
943    EMIT(MIR_Move.mutate(s, IA32_FMOV, Unary.getResult(s), sl));
944  }
945
946  /**
947   * Returns the appropriate move operator based on the type of operand.
948   *
949   * @param o an operand
950   * @return correct move operator
951   */
952  protected final Operator SSE2_MOVE(Operand o) {
953    return o.isFloat() ? IA32_MOVSS : IA32_MOVSD;
954  }
955
956  /**
957   * Returns the size based on the type of operand.
958   *
959   * @param o an operand
960   * @return size in bytes
961   */
962  protected final byte SSE2_SIZE(Operand o) {
963    return o.isFloat() ? DW : QW;
964  }
965
966  /**
967   * Performs a long -&gt; double/float conversion using x87 and
968   * marshalls back to XMMs.
969   *
970   * @param s instruction to modify for the conversion
971   */
972  protected final void SSE2_X87_FROMLONG(Instruction s) {
973    Operand result = Unary.getResult(s);
974    STORE_LONG_FOR_CONV(Unary.getVal(s));
975    // conversion space allocated, contains the long to load.
976    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
977    StackLocationOperand sl = new StackLocationOperand(true, offset, SSE2_SIZE(result));
978    RegisterOperand st0 = new RegisterOperand(getST0(), result.getType());
979    EMIT(CPOS(s, MIR_Move.create(IA32_FILD, st0, sl)));
980    EMIT(CPOS(s, MIR_Move.create(IA32_FSTP, sl.copy(), st0.copyD2U())));
981    EMIT(CPOS(s, MIR_Move.mutate(s, SSE2_MOVE(result), result, sl.copy())));
982  }
983
984  /**
985   * Performs a long -&gt; double/float conversion using x87 and
986   * marshalls between to XMMs.
987   *
988   * @param s instruction to modify for the conversion
989   */
990  protected final void SSE2_X87_REM(Instruction s) {
991    Operand result = Binary.getClearResult(s);
992    RegisterOperand st0 = new RegisterOperand(getST0(), result.getType());
993    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
994    StackLocationOperand sl = new StackLocationOperand(true, offset, SSE2_SIZE(result));
995    EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), sl, Binary.getVal2(s))));
996    EMIT(CPOS(s, MIR_Move.create(IA32_FLD, st0, sl.copy())));
997    EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), sl.copy(), Binary.getVal1(s))));
998    EMIT(CPOS(s, MIR_Move.create(IA32_FLD, st0.copy(), sl.copy())));
999    // The parameters to FPREM actually get ignored (implied ST0/ST1)
1000    EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_FPREM, st0.copy(), st0.copy())));
1001    EMIT(CPOS(s, MIR_Move.create(IA32_FSTP, sl.copy(), st0.copy())));
1002    EMIT(CPOS(s, MIR_Nullary.create(IA32_FFREE, st0.copy())));
1003    EMIT(MIR_Move.mutate(s, SSE2_MOVE(result), result, sl.copy()));
1004  }
1005
1006  /**
1007   * Emits code to move 64 bits from SSE2 FPRs to GPRs
1008   *
1009   * @param s instruction to modify for the move
1010   */
1011  protected final void SSE2_FPR2GPR_64(Instruction s) {
1012    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
1013    StackLocationOperand sl = new StackLocationOperand(true, offset, QW);
1014    if (VM.BuildFor32Addr) {
1015      StackLocationOperand sl1 = new StackLocationOperand(true, offset + 4, DW);
1016      StackLocationOperand sl2 = new StackLocationOperand(true, offset, DW);
1017      EMIT(CPOS(s, MIR_Move.create(IA32_MOVSD, sl, Unary.getVal(s))));
1018      RegisterOperand i1 = Unary.getResult(s);
1019      RegisterOperand i2 = new RegisterOperand(regpool
1020          .getSecondReg(i1.getRegister()), TypeReference.Int);
1021      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, i1, sl1)));
1022      EMIT(MIR_Move.mutate(s, IA32_MOV, i2, sl2));
1023    } else {
1024      EMIT(CPOS(s, MIR_Move.create(IA32_MOVSD, sl, Unary.getVal(s))));
1025      EMIT(MIR_Move.mutate(s, IA32_MOV, Unary.getResult(s), sl));
1026    }
1027  }
1028
1029  /**
1030   * Emits code to move 64 bits from GPRs to SSE2 FPRs
1031   *
1032   * @param s instruction to modify for the move
1033   */
1034  protected final void SSE2_GPR2FPR_64(Instruction s) {
1035    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
1036    StackLocationOperand sl = new StackLocationOperand(true, offset, QW);
1037    Operand val = Unary.getVal(s);
1038    if (VM.BuildFor32Addr) {
1039      StackLocationOperand sl1 = new StackLocationOperand(true, offset + 4, DW);
1040      StackLocationOperand sl2 = new StackLocationOperand(true, offset, DW);
1041      Operand i1, i2;
1042      if (val instanceof RegisterOperand) {
1043        RegisterOperand rval = (RegisterOperand) val;
1044        i1 = val;
1045        i2 = new RegisterOperand(regpool.getSecondReg(rval.getRegister()), TypeReference.Int);
1046      } else {
1047        LongConstantOperand rhs = (LongConstantOperand) val;
1048        i1 = IC(rhs.upper32());
1049        i2 = IC(rhs.lower32());
1050      }
1051      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl1, i1)));
1052      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl2, i2)));
1053      EMIT(MIR_Move.mutate(s, IA32_MOVSD, Unary.getResult(s), sl));
1054    } else {
1055      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl, val)));
1056      EMIT(MIR_Move.mutate(s, IA32_MOVSD, Unary.getResult(s), sl));
1057    }
1058  }
1059
1060  /**
1061   * Emits code to move 32 bits from FPRs to GPRs.
1062   *
1063   * @param s instruction to modify for the move
1064   */
1065  protected final void SSE2_FPR2GPR_32(Instruction s) {
1066    EMIT(MIR_Move.mutate(s, IA32_MOVD, Unary.getResult(s), Unary.getVal(s)));
1067//    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
1068//    StackLocationOperand sl = new StackLocationOperand(true, offset, DW);
1069//    EMIT(CPOS(s, MIR_Move.create(IA32_MOVSS, sl, Unary.getVal(s))));
1070//    EMIT(MIR_Move.mutate(s, IA32_MOV, Unary.getResult(s), sl.copy()));
1071  }
1072
1073  /**
1074   * Emits code to move 32 bits from GPRs to FPRs.
1075   *
1076   * @param s instruction to modify for the move
1077   */
1078  protected final void SSE2_GPR2FPR_32(Instruction s) {
1079    EMIT(MIR_Move.mutate(s, IA32_MOVD, Unary.getResult(s), Unary.getVal(s)));
1080//    int offset = -burs.ir.stackManager.allocateSpaceForConversion();
1081//    StackLocationOperand sl = new StackLocationOperand(true, offset, DW);
1082//    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, sl, Unary.getVal(s))));
1083//    EMIT(MIR_Move.mutate(s, IA32_MOVSS, Unary.getResult(s), sl.copy()));
1084  }
1085
1086  /**
1087   * BURS expansion of a commutative SSE2 operation.
1088   *
1089   * @param operator the operator
1090   * @param s the instruction in question
1091   * @param result the instruction's result operand
1092   * @param val1 the instruction's first value operand
1093   * @param val2 the instruction's second value operand
1094   */
1095  protected void SSE2_COP(Operator operator, Instruction s, Operand result, Operand val1, Operand val2) {
1096    if (VM.VerifyAssertions) opt_assert(result.isRegister());
1097    // Swap operands to reduce chance of generating a move or to normalize
1098    // constants into val2
1099    if (val2.similar(result)) {
1100      Operand temp = val1;
1101      val1 = val2;
1102      val2 = temp;
1103    }
1104    // Do we need to move prior to the operator - result = val1
1105    if (!result.similar(val1)) {
1106      EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), result.copy(), val1)));
1107    }
1108    EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
1109  }
1110
1111  /**
1112   * BURS expansion of a non commutative SSE2 operation.
1113   *
1114   * @param operator the operator
1115   * @param s the instruction in question
1116   * @param result the instruction's result operand
1117   * @param val1 the instruction's first value operand
1118   * @param val2 the instruction's second value operand
1119
1120   */
1121  protected void SSE2_NCOP(Operator operator, Instruction s, Operand result, Operand val1, Operand val2) {
1122    if (VM.VerifyAssertions) opt_assert(result.isRegister());
1123    if (result.similar(val1)) {
1124      // Straight forward case where instruction is already in accumulate form
1125      EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
1126    } else if (!result.similar(val2)) {
1127      // Move first operand to result and perform operator on result, if
1128      // possible redundant moves should be remove by register allocator
1129      EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), result.copy(), val1)));
1130      EMIT(MIR_BinaryAcc.mutate(s, operator, result, val2));
1131    } else {
1132      // Potential to clobber second operand during move to result. Use a
1133      // temporary register to perform the operation and rely on register
1134      // allocator to remove redundant moves
1135      RegisterOperand temp = regpool.makeTemp(result);
1136      EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), temp, val1)));
1137      EMIT(MIR_BinaryAcc.mutate(s, operator, temp.copyRO(), val2));
1138      EMIT(CPOS(s, MIR_Move.create(SSE2_MOVE(result), result, temp.copyRO())));
1139    }
1140  }
1141
1142  /**
1143   * Expansion of SSE2 negation ops.
1144   *
1145   * @param single {@code true} if 32 bit value (float), {@code false} for 64 bit (double)
1146   * @param s the instruction in question
1147   * @param result the instruction's result operand
1148   * @param value the instruction's value operand
1149   */
1150  protected final void SSE2_NEG(boolean single, Instruction s, Operand result, Operand value) {
1151    if (VM.VerifyAssertions) opt_assert(result.isRegister());
1152    if (!result.similar(value)) {
1153      EMIT(CPOS(s, MIR_Move.create(single ? IA32_MOVSS : IA32_MOVSD, result.copy(), value)));
1154    }
1155    Offset signMaskOffset = single ? floatSignMask : doubleSignMask;
1156    EMIT(MIR_BinaryAcc.mutate(s, single ? IA32_XORPS : IA32_XORPD, result,
1157        MemoryOperand.D(Magic.getTocPointer().plus(signMaskOffset), PARAGRAPH,
1158            new LocationOperand(signMaskOffset), TG())));
1159  }
1160
1161  /**
1162   * Expansion of SSE2 conversions double &lt;-&gt; float
1163   *
1164   * @param op the operator
1165   * @param s the instruction in question
1166   * @param result the instruction's result operand
1167   * @param value the instruction's value operand
1168   */
1169  protected final void SSE2_CONV(Operator op, Instruction s, Operand result, Operand value) {
1170    if (VM.VerifyAssertions) opt_assert(result.isRegister());
1171    EMIT(MIR_Unary.mutate(s, op, result, value));
1172  }
1173
1174  /**
1175   * Expansion of SSE2 comparison operations
1176   *
1177   * @param op the operator
1178   * @param s the instruction in question
1179   * @param val1 the instruction's first value operand
1180   * @param val2 the instruction's second value operand
1181   */
1182  protected final void SSE2_IFCMP(Operator op, Instruction s, Operand val1, Operand val2) {
1183    EMIT(CPOS(s, MIR_Compare.create(op, val1, val2)));
1184    EMIT(s); // ComplexLIR2MIRExpansion will handle rest of the work.
1185  }
1186
1187  protected static Operator SSE2_CMP_OP(ConditionOperand cond, boolean single) {
1188    switch(cond.value) {
1189    case ConditionOperand.CMPL_EQUAL:
1190      return single ? IA32_CMPEQSS : IA32_CMPEQSD;
1191    case ConditionOperand.CMPG_LESS:
1192      return single ? IA32_CMPLTSS : IA32_CMPLTSD;
1193    case ConditionOperand.CMPG_LESS_EQUAL:
1194      return single ? IA32_CMPLESS : IA32_CMPLESD;
1195    default:
1196      return null;
1197    }
1198  }
1199
1200  protected final void SSE2_FCMP_FCMOV(Instruction s, RegisterOperand result, Operand lhsCmp, Operand rhsCmp,
1201      ConditionOperand cond, Operand trueValue, Operand falseValue) {
1202    final boolean singleResult = result.isFloat();
1203    final boolean singleCmp = lhsCmp.isFloat();
1204
1205    // TODO: support for the MAXSS/MAXSD instructions taking care of NaN cases
1206    // find cmpOperator flipping code or operands as necessary
1207    Operator cmpOperator = SSE2_CMP_OP(cond, singleCmp);
1208    boolean needFlipOperands = false;
1209    boolean needFlipCode = false;
1210    if (cmpOperator == null) {
1211      needFlipOperands = !needFlipOperands;
1212      cmpOperator = SSE2_CMP_OP(cond.flipOperands(), singleCmp);
1213      if (cmpOperator == null) {
1214        needFlipCode = !needFlipCode;
1215        cmpOperator = SSE2_CMP_OP(cond.flipCode(), singleCmp);
1216        if (cmpOperator == null) {
1217          needFlipOperands = !needFlipOperands;
1218          cmpOperator = SSE2_CMP_OP(cond.flipOperands(), singleCmp);
1219          if (VM.VerifyAssertions) opt_assert(cmpOperator != null);
1220        }
1221      }
1222    }
1223    if (needFlipOperands) {
1224      Operand temp = lhsCmp;
1225      lhsCmp = rhsCmp;
1226      rhsCmp = temp;
1227    }
1228    if (needFlipCode) {
1229      Operand temp = falseValue;
1230      falseValue = trueValue;
1231      trueValue = temp;
1232    }
1233    // place true value in a temporary register to be used for generation of result
1234    RegisterOperand temp = regpool.makeTemp(result);
1235    EMIT(CPOS(s, MIR_Move.create(singleResult ? IA32_MOVSS : IA32_MOVSD, temp, trueValue)));
1236    // do compare ensuring size is >= size of result
1237    if (!singleResult && singleCmp) {
1238      RegisterOperand temp2 = regpool.makeTemp(result);
1239      EMIT(CPOS(s, MIR_Unary.create(IA32_CVTSS2SD, temp2, rhsCmp)));
1240      EMIT(CPOS(s, MIR_Unary.create(IA32_CVTSS2SD, result.copyRO(), lhsCmp)));
1241      rhsCmp = temp2;
1242      cmpOperator = SSE2_CMP_OP(cond, false);
1243    } else {
1244      if (!result.similar(lhsCmp)) {
1245        EMIT(CPOS(s, MIR_Move.create(singleResult ? IA32_MOVSS : IA32_MOVSD, result.copyRO(), lhsCmp)));
1246      }
1247    }
1248    EMIT(MIR_BinaryAcc.mutate(s, cmpOperator, result, rhsCmp));
1249    // result contains all 1s or 0s, use masks and OR to perform conditional move
1250    EMIT(CPOS(s, MIR_BinaryAcc.create(singleResult ? IA32_ANDPS : IA32_ANDPD, temp.copyRO(), result.copyRO())));
1251    EMIT(CPOS(s, MIR_BinaryAcc.create(singleResult ? IA32_ANDNPS : IA32_ANDNPD, result.copyRO(), falseValue)));
1252    EMIT(CPOS(s, MIR_BinaryAcc.create(singleResult ? IA32_ORPS : IA32_ORPD, result.copyRO(), temp.copyRO())));
1253  }
1254
1255  protected static boolean IS_MATERIALIZE_ZERO(Instruction s) {
1256    Operand val = Binary.getVal2(s); // float or double value
1257    return (val.isFloatConstant() && Float.floatToRawIntBits(val.asFloatConstant().value) == 0) ||
1258           (val.isDoubleConstant() && Double.doubleToRawLongBits(val.asDoubleConstant().value) == 0L);
1259  }
1260
1261  protected static boolean SIMILAR_REGISTERS(Operand... ops) {
1262    Operand last = null;
1263    for (Operand op : ops) {
1264      if (!op.isRegister() || (last != null && !op.similar(last))) {
1265        return false;
1266      }
1267      last = op;
1268    }
1269    return true;
1270  }
1271
1272  protected static boolean SSE2_IS_GT_OR_GE(ConditionOperand cond) {
1273    switch(cond.value) {
1274    case ConditionOperand.CMPG_GREATER:
1275    case ConditionOperand.CMPG_GREATER_EQUAL:
1276    case ConditionOperand.CMPL_GREATER:
1277    case ConditionOperand.CMPL_GREATER_EQUAL:
1278      return true;
1279    }
1280    return false;
1281  }
1282
1283  protected static boolean SSE2_IS_LT_OR_LE(ConditionOperand cond) {
1284    switch(cond.value) {
1285    case ConditionOperand.CMPG_LESS:
1286    case ConditionOperand.CMPG_LESS_EQUAL:
1287    case ConditionOperand.CMPL_LESS:
1288    case ConditionOperand.CMPL_LESS_EQUAL:
1289      return true;
1290    }
1291    return false;
1292  }
1293
1294  protected final void SSE2_ABS(boolean single, Instruction s, Operand result, Operand value) {
1295    if (VM.VerifyAssertions) opt_assert(result.isRegister());
1296    if (!result.similar(value)) {
1297      EMIT(CPOS(s, MIR_Move.create(single ? IA32_MOVSS : IA32_MOVSD, result.copy(), value)));
1298    }
1299    Offset absMaskOffset = single ? floatAbsMask : doubleAbsMask;
1300    EMIT(MIR_BinaryAcc.mutate(s, single ? IA32_ANDPS : IA32_ANDPD, result,
1301        MemoryOperand.D(Magic.getTocPointer().plus(absMaskOffset), PARAGRAPH,
1302            new LocationOperand(absMaskOffset), TG())));
1303  }
1304
1305  /**
1306   * Expansion of SSE2 floating point constant loads
1307   *
1308   * @param s the instruction to mutate
1309   */
1310  protected final void SSE2_FPCONSTANT(Instruction s) {
1311    RegisterOperand res = Binary.getResult(s);
1312    Operand val = Binary.getVal2(s); // float or double value
1313    if (val.isFloatConstant() && Float.floatToRawIntBits(val.asFloatConstant().value) == 0) {
1314      EMIT(MIR_BinaryAcc.mutate(s, IA32_XORPS, res, res.copyRO()));
1315    } else if (val.isDoubleConstant() && Double.doubleToRawLongBits(val.asDoubleConstant().value) == 0L) {
1316      EMIT(MIR_BinaryAcc.mutate(s, IA32_XORPD, res, res.copyRO()));
1317    } else {
1318      EMIT(MIR_Move.mutate(s, SSE2_MOVE(res), res, MO_MC(s)));
1319    }
1320  }
1321
1322  /**
1323   * Expansion of INT_DIV, SIGNED_DIV_64_32, UNSIGNED_DIV_64_32 and INT_REM
1324   *
1325   * @param s the instruction to expand
1326   * @param result the result operand
1327   * @param val1 the first operand
1328   * @param val2 the second operand
1329   * @param isDiv {@code true} for division,
1330   *  {@code false} for reminder
1331   * @param signed {@code true} for signed,
1332   *  {@code false} for unsigned
1333   */
1334  protected final void INT_DIVIDES(Instruction s, RegisterOperand result, Operand val1, Operand val2,
1335                                   boolean isDiv, boolean signed) {
1336    if (val1.isIntConstant()) {
1337      int value = val1.asIntConstant().value;
1338      if (value < 0) {
1339        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int), IC(-1))));
1340        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), val1)));
1341      } else {
1342        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int), IC(0))));
1343        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), val1)));
1344      }
1345    } else if (val1.isLongConstant()) {
1346      int upper32 = val1.asLongConstant().upper32();
1347      int lower32 = val1.asLongConstant().lower32();
1348      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int), IC(upper32))));
1349      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), IC(lower32))));
1350    } else if (val1.getType().isLongType()) {
1351      if (VM.BuildFor32Addr) {
1352        Register upperReg = ((RegisterOperand) val1).getRegister();
1353        Register lowerReg = regpool.getSecondReg(upperReg);
1354        EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1355                                     new RegisterOperand(getEDX(), TypeReference.Int),
1356                                     new RegisterOperand(upperReg, TypeReference.Int))));
1357        EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1358                                     new RegisterOperand(getEAX(), TypeReference.Int),
1359                                     new RegisterOperand(lowerReg, TypeReference.Int))));
1360      } else {
1361        EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1362            new RegisterOperand(getEDX(), TypeReference.Int),
1363            val1)));
1364        EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1365            new RegisterOperand(getEAX(), TypeReference.Int),
1366            val1)));
1367        EMIT(CPOS(s, MIR_Move.create(IA32_SHR,
1368            new RegisterOperand(getEDX(), TypeReference.Int),
1369            LC(32))));
1370      }
1371    } else {
1372      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), val1)));
1373      EMIT(CPOS(s, MIR_ConvertDW2QW.create(IA32_CDQ,
1374                                   new RegisterOperand(getEDX(), TypeReference.Int),
1375                                   new RegisterOperand(getEAX(), TypeReference.Int))));
1376    }
1377    if (val2.isIntConstant()) {
1378      RegisterOperand temp = regpool.makeTempInt();
1379      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val2)));
1380      val2 = temp.copyRO();
1381    }
1382    EMIT(MIR_Divide.mutate(s,
1383                           signed ? IA32_IDIV : IA32_DIV,
1384                           new RegisterOperand(getEDX(), TypeReference.Int),
1385                           new RegisterOperand(getEAX(), TypeReference.Int),
1386                           val2,
1387                           GuardedBinary.getGuard(s)));
1388    if (isDiv) {
1389      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new RegisterOperand(getEAX(), TypeReference.Int))));
1390    } else {
1391      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new RegisterOperand(getEDX(), TypeReference.Int))));
1392    }
1393  }
1394
1395  /**
1396   * Creates the MIR instruction given by the operators from the Binary LIR operands
1397   * @param operator1 the 1st MIR operator
1398   * @param operator2 the 2nd MIR operator
1399   * @param s the instruction being replaced
1400   * @param result the destination register/memory
1401   * @param value1 the first operand
1402   * @param value2 the second operand
1403   * @param commutative is the operation commutative?
1404   */
1405  protected final void EMIT_LongBinary(Operator operator1, Operator operator2,
1406                                       Instruction s, Operand result,
1407                                       Operand value1, Operand value2,
1408                                       boolean commutative) {
1409    // Save moves by swapping operands for commutative operations
1410    if (commutative && value2.similar(result)) {
1411      Operand temp = value1;
1412      value1 = value2;
1413      value2 = temp;
1414    }
1415    // commutative combinations are:
1416    // reg, reg, reg
1417    // reg, reg, mem
1418    // reg, reg, constant
1419    // reg, mem, constant
1420    // mem, mem, reg        - where the 2 mems are identical
1421    // mem, mem, constant   - where the 2 mems are identical
1422    // non-commutative combinations are also:
1423    // reg, constant, reg
1424    // reg, constant, mem
1425    // mem, constant, mem
1426
1427    // Break apart result
1428
1429    // Get into accumulate form
1430    Operand lhs, lowlhs;
1431    boolean needsMove = !value1.similar(result);
1432    if (result.isRegister()) {
1433      Register lhsReg = result.asRegister().getRegister();
1434      Register lowlhsReg = regpool.getSecondReg(lhsReg);
1435      lowlhs = new RegisterOperand(lowlhsReg, TypeReference.Int);
1436      lhs = new RegisterOperand(lhsReg, TypeReference.Int);
1437    } else {
1438      // Memory operand
1439      if (VM.VerifyAssertions) opt_assert(result.isMemory());
1440      lowlhs = setSize(result.asMemory(), DW);
1441      lhs = lowlhs.copy();
1442      lhs.asMemory().disp = lhs.asMemory().disp.plus(4);
1443    }
1444
1445    // Clobbering can occur when a move is needed and result and value2 have the
1446    // same type (e.g. when both result and value2 use the same register after
1447    // register allocation).
1448    boolean computeOnTemp = needsMove && result.similar(value2);
1449    RegisterOperand temp1 = null;
1450    RegisterOperand temp2 = null;
1451
1452    if (needsMove && !computeOnTemp) {
1453      Operand rhs1, lowrhs1;
1454      if (value1.isRegister()) {
1455        Register rhs1Reg = value1.asRegister().getRegister();
1456        Register lowrhs1Reg = regpool.getSecondReg(rhs1Reg);
1457        lowrhs1 = new RegisterOperand(lowrhs1Reg, TypeReference.Int);
1458        rhs1 = new RegisterOperand(rhs1Reg, TypeReference.Int);
1459      } else if (value1.isMemory()) {
1460        lowrhs1 = setSize(value1.asMemory(),DW);
1461        rhs1 = lowrhs1.copy();
1462        rhs1.asMemory().disp = rhs1.asMemory().disp.plus(4);
1463      } else {
1464        // Long constant operand
1465        if (VM.VerifyAssertions) opt_assert(value1.isLongConstant());
1466        rhs1    = IC(value1.asLongConstant().upper32());
1467        lowrhs1 = IC(value1.asLongConstant().lower32());
1468      }
1469      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lowlhs.copy(), lowrhs1)));
1470      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lhs.copy(), rhs1)));
1471    } else if (needsMove && computeOnTemp) {
1472      // Clobbering can't occur for commutative operations due to canonical forms
1473      if (VM.VerifyAssertions && computeOnTemp) opt_assert(!commutative);
1474
1475      // In order to prevent clobbering, the calculation will be done on temp
1476      // registers and the result will be moved back to the proper result register
1477      // later. Register allocation and subsequent optimizations will clean up
1478      // any unneeded moves.
1479      Operand rhs1, lowrhs1;
1480      temp1 = regpool.makeTempInt();
1481      temp2 = regpool.makeTempInt();
1482      // Move value1 into temp
1483      if (value1.isRegister()) {
1484        Register rhs1Reg = value1.asRegister().getRegister();
1485        Register lowrhs1Reg = regpool.getSecondReg(rhs1Reg);
1486        lowrhs1 = new RegisterOperand(lowrhs1Reg, TypeReference.Int);
1487        rhs1 = new RegisterOperand(rhs1Reg, TypeReference.Int);
1488      } else if (value1.isMemory()) {
1489        if (VM.VerifyAssertions) opt_assert(VM.NOT_REACHED);
1490        lowrhs1 = setSize(value1.asMemory(),DW);
1491        rhs1 = lowrhs1.copy();
1492        rhs1.asMemory().disp = rhs1.asMemory().disp.plus(4);
1493      } else {
1494        rhs1 = IC(value1.asLongConstant().upper32());
1495        lowrhs1 = IC(value1.asLongConstant().lower32());
1496      }
1497      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp1, lowrhs1)));
1498      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp2, rhs1)));
1499      lowlhs = temp1;
1500      lhs = temp2;
1501    }
1502    // Break apart RHS 2
1503    Operand rhs2, lowrhs2;
1504    if (value2.isRegister()) {
1505      Register rhsReg2 = value2.asRegister().getRegister();
1506      Register lowrhsReg2 = regpool.getSecondReg(rhsReg2);
1507      rhs2    = new RegisterOperand(rhsReg2, TypeReference.Int);
1508      lowrhs2 = new RegisterOperand(lowrhsReg2, TypeReference.Int);
1509    } else if (value2.isLongConstant()) {
1510      rhs2    = IC(value2.asLongConstant().upper32());
1511      lowrhs2 = IC(value2.asLongConstant().lower32());
1512    } else {
1513      // Memory operand
1514      lowrhs2 = setSize(value2.asMemory(),DW);
1515      rhs2 = lowrhs2.copy();
1516      rhs2.asMemory().disp = rhs2.asMemory().disp.plus(4);
1517    }
1518
1519    // Peep hole optimizations
1520    if ((operator1 == IA32_ADD) &&
1521        lowrhs2.isIntConstant() &&
1522        (lowrhs2.asIntConstant().value == 0)
1523        ) {
1524      // operation has no effect
1525      operator1 = null;
1526      operator2 = IA32_ADD;
1527    } else if ((operator1 == IA32_SUB) &&
1528        lowrhs2.isIntConstant() &&
1529        (lowrhs2.asIntConstant().value == 0)
1530        ) {
1531      // operation has no effect
1532      operator1 = null;
1533      operator2 = IA32_SUB;
1534    } else if (operator1 == IA32_OR) {
1535      if (lowrhs2.isIntConstant()) {
1536        if (lowrhs2.asIntConstant().value == 0) {
1537          // operation has no effect
1538          operator1 = null;
1539        } else if (lowrhs2.asIntConstant().value == -1) {
1540          // move 0
1541          operator1 = IA32_MOV;
1542        }
1543      }
1544      if (rhs2.isIntConstant()) {
1545        if (rhs2.asIntConstant().value == 0) {
1546          // operation has no effect
1547          operator2 = null;
1548        } else if (rhs2.asIntConstant().value == -1) {
1549          // move -1
1550          operator2 = IA32_MOV;
1551        }
1552      }
1553    } else if (operator1 == IA32_AND) {
1554      if (lowrhs2.isIntConstant()) {
1555        if (lowrhs2.asIntConstant().value == -1) {
1556          // operation has no effect
1557          operator1 = null;
1558        } else if (lowrhs2.asIntConstant().value == 0) {
1559          // move 0
1560          operator1 = IA32_MOV;
1561        }
1562      }
1563      if (rhs2.isIntConstant()) {
1564        if (rhs2.asIntConstant().value == -1) {
1565          // operation has no effect
1566          operator2 = null;
1567        } else if (rhs2.asIntConstant().value == 0) {
1568          // move 0
1569          operator2 = IA32_MOV;
1570        }
1571      }
1572    } else if (operator1 == IA32_XOR) {
1573      if (lowrhs2.isIntConstant()) {
1574        if (lowrhs2.asIntConstant().value == 0) {
1575          // operation has no effect
1576          operator1 = null;
1577        } else if (lowrhs2.asIntConstant().value == -1) {
1578          operator1 = IA32_NOT;
1579        }
1580      }
1581      if (rhs2.isIntConstant()) {
1582        if (rhs2.asIntConstant().value == 0) {
1583          // operation has no effect
1584          operator2 = null;
1585        } else if (rhs2.asIntConstant().value == -1) {
1586          operator2 = IA32_NOT;
1587        }
1588      }
1589    }
1590    // End of peephole optimizations
1591
1592    if (operator1 == null) {
1593      // no operation
1594    } else if (operator1 == IA32_MOV) {
1595      EMIT(CPOS(s, MIR_Move.create(operator1,
1596          lowlhs,
1597          lowrhs2)));
1598    } else if (operator1 == IA32_NOT) {
1599      EMIT(CPOS(s, MIR_UnaryAcc.create(operator1,
1600              lowlhs)));
1601    } else {
1602      EMIT(CPOS(s, MIR_BinaryAcc.create(operator1,
1603         lowlhs,
1604         lowrhs2)));
1605    }
1606    if (operator2 == null) {
1607      // no operation
1608    } else if (operator2 == IA32_MOV) {
1609      EMIT(CPOS(s, MIR_Move.create(operator2,
1610          lhs,
1611          rhs2)));
1612    } else if (operator2 == IA32_NOT) {
1613      EMIT(CPOS(s, MIR_UnaryAcc.create(operator2,
1614          lhs)));
1615    } else {
1616      EMIT(CPOS(s, MIR_BinaryAcc.create(operator2,
1617          lhs,
1618          rhs2)));
1619    }
1620
1621    // Move results from temporaries to original result registers
1622    if (computeOnTemp) {
1623      if (result.isRegister()) {
1624        Register lhsReg = result.asRegister().getRegister();
1625        Register lowlhsReg = regpool.getSecondReg(lhsReg);
1626        lowlhs = new RegisterOperand(lowlhsReg, TypeReference.Int);
1627        lhs = new RegisterOperand(lhsReg, TypeReference.Int);
1628      } else {
1629        // Memory operand
1630        if (VM.VerifyAssertions) opt_assert(result.isMemory());
1631        lowlhs = setSize(result.asMemory(), DW);
1632        lhs = lowlhs.copy();
1633        lhs.asMemory().disp = lhs.asMemory().disp.plus(4);
1634      }
1635      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lowlhs, temp1)));
1636      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lhs, temp2)));
1637    }
1638
1639  }
1640
1641  /**
1642   * Expansion of LONG_MUL
1643   *
1644   * @param s the instruction to expand
1645   * @param result the result operand
1646   * @param value1 the first operand
1647   * @param value2 the second operand
1648   */
1649  protected final void LONG_MUL(Instruction s, RegisterOperand result,
1650      Operand value1, Operand value2) {
1651    if (value2.isRegister()) {
1652      // Leave for complex LIR2MIR expansion as the most efficient form requires
1653      // a branch
1654      if (VM.VerifyAssertions) opt_assert(Binary.getResult(s).similar(result) &&
1655          Binary.getVal1(s).similar(value1) && Binary.getVal2(s).similar(value2));
1656      EMIT(s);
1657    } else {
1658      // The value of value1 should be identical to result, to avoid moves, and a
1659      // register in the case of multiplication with a constant
1660      if ((value2.similar(result)) || value1.isLongConstant()) {
1661        Operand temp = value1;
1662        value1 = value2;
1663        value2 = temp;
1664      }
1665      if (VM.VerifyAssertions) opt_assert(value1.isRegister() && value2.isLongConstant());
1666
1667      // In general, (a,b) * (c,d) = (l(a imul d)+l(b imul c)+u(b mul d), l(b mul d))
1668
1669      Register lhsReg = result.getRegister();
1670      Register lowlhsReg = regpool.getSecondReg(lhsReg);
1671
1672      LongConstantOperand rhs2 = (LongConstantOperand) value2;
1673      Register rhsReg1 = value1.asRegister().getRegister(); // a
1674      Register lowrhsReg1 = regpool.getSecondReg(rhsReg1); // b
1675      int high2 = rhs2.upper32(); // c
1676      int low2 = rhs2.lower32(); // d
1677
1678      // We only have to handle those cases that Simplifier wouldn't get.
1679      // Simplifier catches
1680      // high low
1681      // 0 0 (0L)
1682      // 0 1 (1L)
1683      // -1 -1 (-1L)
1684      // So, the possible cases we need to handle here:
1685      // -1 0
1686      // -1 1
1687      // -1 *
1688      // 0 -1
1689      // 0 *
1690      // 1 -1
1691      // 1 0
1692      // 1 1
1693      // 1 *
1694      // * -1
1695      // * 0
1696      // * 1
1697      // * *
1698      // (where * is something other than -1,0,1)
1699      if (high2 == -1) {
1700        if (low2 == 0) {
1701          // -1, 0
1702          // CLAIM: (a,b) * (-1,0) = (-b,0)
1703          if (VM.VerifyAssertions) opt_assert(lhsReg != lowrhsReg1);
1704          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1705              new RegisterOperand(lhsReg, TypeReference.Int),
1706              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1707          EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
1708              new RegisterOperand(lhsReg, TypeReference.Int))));
1709          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1710              new RegisterOperand(lowlhsReg, TypeReference.Int),
1711              IC(0))));
1712        } else if (low2 == 1) {
1713          // -1, 1
1714          // CLAIM: (a,b) * (-1,1) = (a-b,b)
1715          if (lowlhsReg != lowrhsReg1) {
1716            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1717                new RegisterOperand(lowlhsReg, TypeReference.Int),
1718                new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1719          }
1720          if (lhsReg != rhsReg1) {
1721            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1722                new RegisterOperand(lhsReg, TypeReference.Int),
1723                new RegisterOperand(rhsReg1, TypeReference.Int))));
1724          }
1725          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
1726              new RegisterOperand(lhsReg, TypeReference.Int),
1727              new RegisterOperand(lowlhsReg, TypeReference.Int))));
1728        } else {
1729          // -1, *
1730          // CLAIM: (a,b) * (-1, d) = (l(a imul d)-b+u(b mul d), l(b mul d))
1731          if (lhsReg != rhsReg1) {
1732            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1733                new RegisterOperand(lhsReg, TypeReference.Int),
1734                new RegisterOperand(rhsReg1, TypeReference.Int))));
1735          }
1736          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1737              new RegisterOperand(lhsReg, TypeReference.Int),
1738              IC(low2))));
1739          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB,
1740              new RegisterOperand(lhsReg, TypeReference.Int),
1741              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1742          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1743              new RegisterOperand(getEAX(), TypeReference.Int),
1744              IC(low2))));
1745          EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
1746              new RegisterOperand(getEDX(), TypeReference.Int),
1747              new RegisterOperand(getEAX(), TypeReference.Int),
1748              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1749          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1750              new RegisterOperand(lowlhsReg, TypeReference.Int),
1751              new RegisterOperand(getEAX(), TypeReference.Int))));
1752          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1753              new RegisterOperand(lhsReg, TypeReference.Int),
1754              new RegisterOperand(getEDX(), TypeReference.Int))));
1755        }
1756      } else if (high2 == 0) {
1757        if (low2 == -1) {
1758          // 0, -1
1759          // CLAIM: (a,b) * (0,-1) = (b-(a+(b!=0?1:0)),-b)
1760          // avoid clobbering a and b by using tmp
1761          Register tmp = regpool.getInteger();
1762          if (lowlhsReg != lowrhsReg1) {
1763            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1764                new RegisterOperand(lowlhsReg, TypeReference.Int),
1765                new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1766          }
1767          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1768              new RegisterOperand(tmp, TypeReference.Int),
1769              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1770          EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
1771              new RegisterOperand(lowlhsReg, TypeReference.Int))));
1772          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
1773              new RegisterOperand(tmp, TypeReference.Int),
1774              new RegisterOperand(rhsReg1, TypeReference.Int))));
1775          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1776              new RegisterOperand(lhsReg, TypeReference.Int),
1777              new RegisterOperand(tmp, TypeReference.Int))));
1778        } else {
1779          // 0, *
1780          // CLAIM: (a,b) * (0,d) = (l(a imul d)+u(b mul d), l(b mul d))
1781          if (lhsReg != rhsReg1) {
1782            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1783                new RegisterOperand(lhsReg, TypeReference.Int),
1784                new RegisterOperand(rhsReg1, TypeReference.Int))));
1785          }
1786          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1787              new RegisterOperand(lhsReg, TypeReference.Int),
1788              IC(low2))));
1789          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1790              new RegisterOperand(getEAX(), TypeReference.Int),
1791              IC(low2))));
1792          EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
1793              new RegisterOperand(getEDX(), TypeReference.Int),
1794              new RegisterOperand(getEAX(), TypeReference.Int),
1795              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1796          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1797              new RegisterOperand(lowlhsReg, TypeReference.Int),
1798              new RegisterOperand(getEAX(), TypeReference.Int))));
1799          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1800              new RegisterOperand(lhsReg, TypeReference.Int),
1801              new RegisterOperand(getEDX(), TypeReference.Int))));
1802        }
1803      } else if (high2 == 1) {
1804        if (low2 == -1) {
1805          // 1, -1
1806          // CLAIM: (a,b) * (1,-1) = (2b-(a+(b!=0?1:0)),-b)
1807          // avoid clobbering a and b by using tmp
1808          Register tmp = regpool.getInteger();
1809          if (lowlhsReg != lowrhsReg1) {
1810            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1811                new RegisterOperand(lowlhsReg, TypeReference.Int),
1812                new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1813          }
1814          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1815              new RegisterOperand(tmp, TypeReference.Int),
1816              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1817          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1818              new RegisterOperand(tmp, TypeReference.Int),
1819              new RegisterOperand(tmp, TypeReference.Int))));
1820          EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
1821              new RegisterOperand(lowlhsReg, TypeReference.Int))));
1822          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
1823              new RegisterOperand(tmp, TypeReference.Int),
1824              new RegisterOperand(rhsReg1, TypeReference.Int))));
1825          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1826              new RegisterOperand(lhsReg, TypeReference.Int),
1827              new RegisterOperand(tmp, TypeReference.Int))));
1828        } else if (low2 == 0) {
1829          // 1, 0
1830          // CLAIM: (x,y) * (1,0) = (y,0)
1831          // NB we should have simplified this LONG_MUL to a LONG_SHIFT
1832          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1833              new RegisterOperand(lhsReg, TypeReference.Int),
1834              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1835          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1836              new RegisterOperand(lowlhsReg, TypeReference.Int),
1837              IC(0))));
1838        } else if (low2 == 1) {
1839          // 1, 1
1840          // CLAIM: (x,y) * (1,1) = (x+y,y)
1841          // NB we should have simplified this LONG_MUL to a LONG_SHIFT and LONG_ADDs
1842          if (lowlhsReg != lowrhsReg1) {
1843            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1844                new RegisterOperand(lowlhsReg, TypeReference.Int),
1845                new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1846          }
1847          if (lhsReg != rhsReg1) {
1848            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1849                new RegisterOperand(lhsReg, TypeReference.Int),
1850                new RegisterOperand(rhsReg1, TypeReference.Int))));
1851          }
1852          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1853              new RegisterOperand(lhsReg, TypeReference.Int),
1854              new RegisterOperand(lowlhsReg, TypeReference.Int))));
1855        } else {
1856          // 1, *
1857          // CLAIM: (a,b) * (1,d) = (l(a imul d)+b+u(b mul d), l(b mul d))
1858          if (lhsReg != rhsReg1) {
1859            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1860                new RegisterOperand(lhsReg, TypeReference.Int),
1861                new RegisterOperand(rhsReg1, TypeReference.Int))));
1862          }
1863          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1864              new RegisterOperand(lhsReg, TypeReference.Int),
1865              IC(low2))));
1866          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1867              new RegisterOperand(lhsReg, TypeReference.Int),
1868              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1869          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1870              new RegisterOperand(getEAX(), TypeReference.Int),
1871              IC(low2))));
1872          EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
1873              new RegisterOperand(getEDX(), TypeReference.Int),
1874              new RegisterOperand(getEAX(), TypeReference.Int),
1875              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1876          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1877              new RegisterOperand(lowlhsReg, TypeReference.Int),
1878              new RegisterOperand(getEAX(), TypeReference.Int))));
1879          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1880              new RegisterOperand(lhsReg, TypeReference.Int),
1881              new RegisterOperand(getEDX(), TypeReference.Int))));
1882        }
1883      } else {
1884        if (low2 == -1) {
1885          // *, -1
1886          // CLAIM: (a,b) * (c, -1) = ((b+1)*c - (a + b==0?1:0), -b)
1887          // avoid clobbering a and b by using tmp
1888          Register tmp = regpool.getInteger();
1889          if (lowlhsReg != lowrhsReg1) {
1890            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1891                new RegisterOperand(lowlhsReg, TypeReference.Int),
1892                new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1893          }
1894          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1895              new RegisterOperand(tmp, TypeReference.Int),
1896              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1897          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1898              new RegisterOperand(tmp, TypeReference.Int),
1899              IC(1))));
1900          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1901              new RegisterOperand(tmp, TypeReference.Int),
1902              IC(high2))));
1903          EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG,
1904              new RegisterOperand(lowlhsReg, TypeReference.Int))));
1905          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB,
1906              new RegisterOperand(tmp, TypeReference.Int),
1907              new RegisterOperand(rhsReg1, TypeReference.Int))));
1908          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1909              new RegisterOperand(lhsReg, TypeReference.Int),
1910              new RegisterOperand(tmp, TypeReference.Int))));
1911        } else if (low2 == 0) {
1912          // *, 0
1913          // CLAIM: (a,b) * (c,0) = (l(b imul c),0)
1914          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1915              new RegisterOperand(lhsReg, TypeReference.Int),
1916              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1917          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1918              new RegisterOperand(lhsReg, TypeReference.Int),
1919              IC(high2))));
1920          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1921              new RegisterOperand(lowlhsReg, TypeReference.Int),
1922              IC(0))));
1923        } else if (low2 == 1) {
1924          // *, 1
1925          // CLAIM: (x,y) * (z,1) = (l(y imul z)+x,y)
1926          if (lowlhsReg != lowrhsReg1) {
1927            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1928                new RegisterOperand(lowlhsReg, TypeReference.Int),
1929                new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1930          }
1931          if (lhsReg != rhsReg1) {
1932            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1933                new RegisterOperand(lhsReg, TypeReference.Int),
1934                new RegisterOperand(rhsReg1, TypeReference.Int))));
1935          }
1936          Register tmp = regpool.getInteger();
1937          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1938              new RegisterOperand(tmp, TypeReference.Int),
1939              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1940          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1941              new RegisterOperand(tmp, TypeReference.Int),
1942              IC(high2))));
1943          EMIT(CPOS(s, MIR_Move.create(IA32_ADD,
1944              new RegisterOperand(lhsReg, TypeReference.Int),
1945              new RegisterOperand(tmp, TypeReference.Int))));
1946        } else {
1947          // *, * can't do anything interesting and both operands have non-zero words
1948          // (a,b) * (c,d) = (l(a imul d)+l(b imul c)+u(b mul d), l(b mul d))
1949          if (lhsReg != rhsReg1) {
1950            EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1951                new RegisterOperand(lhsReg, TypeReference.Int),
1952                new RegisterOperand(rhsReg1, TypeReference.Int))));
1953          }
1954          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1955              new RegisterOperand(lhsReg, TypeReference.Int),
1956              IC(low2))));
1957          Register tmp = regpool.getInteger();
1958          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1959              new RegisterOperand(tmp, TypeReference.Int),
1960              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1961          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1962              new RegisterOperand(tmp, TypeReference.Int),
1963              IC(high2))));
1964          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1965              new RegisterOperand(lhsReg, TypeReference.Int),
1966              new RegisterOperand(tmp, TypeReference.Int))));
1967          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1968              new RegisterOperand(getEAX(), TypeReference.Int),
1969              IC(low2))));
1970          EMIT(CPOS(s, MIR_Multiply.create(IA32_MUL,
1971              new RegisterOperand(getEDX(), TypeReference.Int),
1972              new RegisterOperand(getEAX(), TypeReference.Int),
1973              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1974          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
1975              new RegisterOperand(lowlhsReg, TypeReference.Int),
1976              new RegisterOperand(getEAX(), TypeReference.Int))));
1977          EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1978              new RegisterOperand(lhsReg, TypeReference.Int),
1979              new RegisterOperand(getEDX(), TypeReference.Int))));
1980        }
1981      }
1982    }
1983  }
1984
1985  /**
1986   * Expansion of LONG_MULs whose operands are ints
1987   *
1988   * @param s the instruction to expand
1989   * @param result the result operand
1990   * @param value1 the first operand
1991   * @param value2 the second operand
1992   * @param signed signed or unsigned multiplication?
1993   */
1994  protected final void  INT_TO_LONG_MUL(Instruction s, RegisterOperand result,
1995                                        Operand value1, Operand value2, boolean signed) {
1996    // Canonicalize with any constant on LHS that is placed in EAX
1997    if (value2.isConstant()) {
1998      Operand temp = value1;
1999      value1 = value2;
2000      value2 = temp;
2001    }
2002    // place LHS value into EAX
2003    if (value1.isRegister()) {
2004      RegisterOperand value1RO = value1.asRegister();
2005      RegisterOperand lhsRO;
2006      if (value1.getType().isLongType()) {
2007        Register lhsReg = value1RO.getRegister();
2008        Register lowlhsReg = regpool.getSecondReg(lhsReg);
2009        lhsRO = new RegisterOperand(lowlhsReg, TypeReference.Int);
2010      } else {
2011        if (VM.VerifyAssertions) VM._assert(value1.getType().isIntType());
2012        lhsRO = value1RO.copyRO();
2013      }
2014      EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2015                     new RegisterOperand(getEAX(), TypeReference.Int),
2016                     lhsRO)));
2017    } else {
2018      if (VM.VerifyAssertions) VM._assert(value1.isConstant());
2019      int lhsVal;
2020      if (value1.isIntConstant()) {
2021        lhsVal = value1.asIntConstant().value;
2022      } else {
2023        if (VM.VerifyAssertions) VM._assert(value1.isLongConstant());
2024        lhsVal = value1.asLongConstant().lower32();
2025      }
2026      EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2027                     new RegisterOperand(getEAX(), TypeReference.Int),
2028                     IC(lhsVal))));
2029    }
2030    // Multiply by low-half of RHS
2031    if (VM.VerifyAssertions) VM._assert(value2.isRegister());
2032    RegisterOperand value2RO = value2.asRegister();
2033    Register rhsReg = value2RO.getRegister();
2034    Register lowrhsReg;
2035    if (rhsReg.isLong()) {
2036      lowrhsReg = regpool.getSecondReg(rhsReg);
2037    } else {
2038      if (VM.VerifyAssertions) VM._assert(rhsReg.isInteger());
2039      lowrhsReg = rhsReg;
2040    }
2041    EMIT(MIR_Multiply.mutate(s, signed ? IA32_IMUL1 : IA32_MUL,
2042           new RegisterOperand(getEDX(), TypeReference.Int),
2043           new RegisterOperand(getEAX(), TypeReference.Int),
2044           new RegisterOperand(lowrhsReg, TypeReference.Int)));
2045    // Move result into correct registers
2046    Register resultReg = result.getRegister();
2047    Register lowresultReg = regpool.getSecondReg(resultReg);
2048    EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2049                      new RegisterOperand(lowresultReg, TypeReference.Int),
2050                      new RegisterOperand(getEAX(), TypeReference.Int))));
2051    EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2052                      new RegisterOperand(resultReg, TypeReference.Int),
2053                      new RegisterOperand(getEDX(), TypeReference.Int))));
2054  }
2055
2056  /**
2057   * Expansion of LONG_DIV and LONG_REM
2058   *
2059   * @param s the instruction to expand
2060   * @param result the result operand
2061   * @param val1 the first operand
2062   * @param val2 the second operand
2063   * @param isDiv {@code true} for div, {@code false} for rem
2064   * @param signed {@code true} for signed division,
2065   *  {@code false} for unsigned
2066   */
2067  protected final void LONG_DIVIDES(Instruction s, RegisterOperand result, Operand val1, Operand val2,
2068                                   boolean isDiv, boolean signed) {
2069      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Long), val1)));
2070      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Long), val1)));
2071      EMIT(CPOS(s, MIR_Move.create(IA32_SAR, new RegisterOperand(getEDX(), TypeReference.Long), LC(0x3f))));
2072
2073    if (val2.isLongConstant() || val2.isIntConstant()) {
2074      RegisterOperand temp = regpool.makeTempLong();
2075      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val2)));
2076      val2 = temp.copyRO();
2077    }
2078    EMIT(MIR_Divide.mutate(s,
2079                           signed ? IA32_IDIV : IA32_DIV,
2080                           new RegisterOperand(getEDX(), TypeReference.Long),
2081                           new RegisterOperand(getEAX(), TypeReference.Long),
2082                           val2,
2083                           GuardedBinary.getGuard(s)));
2084    if (isDiv) {
2085      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new RegisterOperand(getEAX(), TypeReference.Long))));
2086    } else {
2087      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result.copyD2D(), new RegisterOperand(getEDX(), TypeReference.Long))));
2088    }
2089  }
2090
2091
2092  /**
2093   * Creates the MIR instruction for LONG_NEG or LONG_NOT
2094   * @param s the instruction being replaced
2095   * @param result the destination register/memory
2096   * @param value1 the operand
2097   * @param negOrNot true for neg
2098  */
2099  protected final void EMIT_LongUnary(Instruction s, Operand result,
2100                                      Operand value1, boolean negOrNot) {
2101    // Break apart result
2102    // Get into accumulate form
2103    Operand lhs, lowlhs;
2104    boolean needsMove = !value1.similar(result);
2105    if (result.isRegister()) {
2106      Register lhsReg = result.asRegister().getRegister();
2107      Register lowlhsReg = regpool.getSecondReg(lhsReg);
2108      lowlhs = new RegisterOperand(lowlhsReg, TypeReference.Int);
2109      lhs = new RegisterOperand(lhsReg, TypeReference.Int);
2110    } else {
2111      // Memory operand
2112      if (VM.VerifyAssertions) opt_assert(result.isMemory());
2113      lowlhs = setSize(result.asMemory(),DW);
2114      lhs = lowlhs.copy();
2115      lhs.asMemory().disp = lhs.asMemory().disp.plus(4);
2116    }
2117    if (needsMove) {
2118      Operand rhs1, lowrhs1;
2119      if (value1.isRegister()) {
2120        Register rhs1Reg = value1.asRegister().getRegister();
2121        Register lowrhs1Reg = regpool.getSecondReg(rhs1Reg);
2122        lowrhs1 = new RegisterOperand(lowrhs1Reg, TypeReference.Int);
2123        rhs1 = new RegisterOperand(rhs1Reg, TypeReference.Int);
2124      } else {
2125        // Memory operand
2126        if (VM.VerifyAssertions) opt_assert(value1.isMemory());
2127        lowrhs1 = setSize(value1.asMemory(),DW);
2128        rhs1 = lowrhs1.copy();
2129        rhs1.asMemory().disp = rhs1.asMemory().disp.plus(4);
2130      }
2131      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lowlhs.copy(), lowrhs1)));
2132      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lhs.copy(), rhs1)));
2133    }
2134    if (negOrNot) {
2135      // Perform negation
2136      EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, lowlhs)));
2137      EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT, lhs)));
2138      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, lhs.copy(), IC(-1))));
2139    } else {
2140      // Perform not
2141      EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT, lowlhs)));
2142      EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NOT, lhs)));
2143    }
2144  }
2145
2146  /**
2147   * Expansion of LONG_SHL
2148   * @param s the instruction to expand
2149   * @param result the result operand
2150   * @param val1 the shifted operand
2151   * @param val2 the shift amount operand
2152   * @param maskWith3f should the shift operand by masked with 0x3f? This is
2153   *          default behaviour on Intel but it differs from how we combine
2154   *          shift operands in HIR
2155   */
2156  protected final void LONG_SHL(Instruction s, Operand result,
2157      Operand val1, Operand val2, boolean maskWith3f) {
2158    if (!val2.isIntConstant()) {
2159      // the most efficient form of expanding a shift by a variable amount
2160      // requires a branch so leave for complex operators
2161      // NB if !maskWith3f - we assume that a mask with 0x3F was required as
2162      // no optimizations currently exploits shift by registers of > 63
2163      // returning 0
2164      Binary.mutate(s, LONG_SHL, result.asRegister(), val1, val2);
2165      EMIT(s);
2166    } else if (result.isRegister()) {
2167      int shift = val2.asIntConstant().value;
2168      Register lhsReg = result.asRegister().getRegister();
2169      Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
2170      Register rhsReg1 = val1.asRegister().getRegister();
2171      Register lowrhsReg1 = burs.ir.regpool.getSecondReg(rhsReg1);
2172
2173      if (shift == 0) {
2174        // operation is a nop.
2175        if (!result.similar(val1)) {
2176          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2177              new RegisterOperand(lowlhsReg, TypeReference.Int),
2178              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2179          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2180              new RegisterOperand(lhsReg, TypeReference.Int),
2181              new RegisterOperand(rhsReg1, TypeReference.Int))));
2182        }
2183      } else if (shift == 1) {
2184        if (!result.similar(val1)) {
2185          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2186              new RegisterOperand(lowlhsReg, TypeReference.Int),
2187              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2188          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2189              new RegisterOperand(lhsReg, TypeReference.Int),
2190              new RegisterOperand(rhsReg1, TypeReference.Int))));
2191        }
2192        EMIT(CPOS(s,
2193            MIR_BinaryAcc.create(IA32_ADD,
2194                new RegisterOperand(lowlhsReg, TypeReference.Int),
2195                new RegisterOperand(lowlhsReg, TypeReference.Int))));
2196        EMIT(MIR_BinaryAcc.mutate(s,
2197            IA32_ADC,
2198            new RegisterOperand(lhsReg, TypeReference.Int),
2199            new RegisterOperand(lhsReg, TypeReference.Int)));
2200      } else if (shift == 2) {
2201        // bits to shift in: tmp = lowrhsReg >> 30
2202        Register tmp = regpool.getInteger();
2203        EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2204            new RegisterOperand(tmp, TypeReference.Int),
2205            new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2206        EMIT(CPOS(s,
2207            MIR_BinaryAcc.create(IA32_SHR,
2208                new RegisterOperand(tmp, TypeReference.Int),
2209                IC(30))));
2210        // compute top half: lhsReg = (rhsReg1 << 2) + tmp
2211        EMIT(CPOS(s,
2212            MIR_Lea.create(IA32_LEA,
2213                new RegisterOperand(lhsReg, TypeReference.Int),
2214                MemoryOperand.BIS(new RegisterOperand(tmp, TypeReference.Int),
2215                    new RegisterOperand(rhsReg1, TypeReference.Int),
2216                    (byte)2, (byte)4, null, null))));
2217        // compute bottom half: lowlhsReg = lowlhsReg << 2
2218        EMIT(CPOS(s,
2219            MIR_Lea.create(IA32_LEA,
2220                new RegisterOperand(lowlhsReg, TypeReference.Int),
2221                new MemoryOperand(null, // base
2222                    new RegisterOperand(lowrhsReg1, TypeReference.Int), //index
2223                    (byte)2, // scale
2224                    Offset.zero(), // displacement
2225                    (byte)4, // size
2226                    null, // location
2227                    null // guard
2228                    ))));
2229      } else if (shift == 3) {
2230        // bits to shift in: tmp = lowrhsReg >>> 29
2231        Register tmp = regpool.getInteger();
2232        EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2233            new RegisterOperand(tmp, TypeReference.Int),
2234            new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2235        EMIT(CPOS(s,
2236            MIR_BinaryAcc.create(IA32_SHR,
2237                new RegisterOperand(tmp, TypeReference.Int),
2238                IC(29))));
2239        // compute top half: lhsReg = (rhsReg1 << 3) + tmp
2240        EMIT(CPOS(s,
2241            MIR_Lea.create(IA32_LEA,
2242                new RegisterOperand(lhsReg, TypeReference.Int),
2243                MemoryOperand.BIS(new RegisterOperand(tmp, TypeReference.Int),
2244                    new RegisterOperand(rhsReg1, TypeReference.Int),
2245                    (byte)3, (byte)4, null, null))));
2246        // compute bottom half: lowlhsReg = lowlhsReg << 3
2247        EMIT(CPOS(s,
2248            MIR_Lea.create(IA32_LEA,
2249                new RegisterOperand(lowlhsReg, TypeReference.Int),
2250                new MemoryOperand(null, // base
2251                    new RegisterOperand(lowrhsReg1, TypeReference.Int), //index
2252                    (byte)3, // scale
2253                    Offset.zero(), // displacement
2254                    (byte)4, // size
2255                    null, // location
2256                    null // guard
2257                    ))));
2258      } else if (shift < 32) {
2259        if (!result.similar(val1)) {
2260          EMIT(CPOS(s,
2261              MIR_Move.create(IA32_MOV,
2262              new RegisterOperand(lhsReg, TypeReference.Int),
2263              new RegisterOperand(rhsReg1, TypeReference.Int))));
2264        }
2265        // bits to shift in: tmp = lowrhsReg >>> (32 - shift)
2266        Register tmp = regpool.getInteger();
2267        EMIT(CPOS(s,
2268            MIR_Move.create(IA32_MOV,
2269                new RegisterOperand(tmp, TypeReference.Int),
2270                new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2271        EMIT(CPOS(s,
2272            MIR_BinaryAcc.create(IA32_SHR,
2273                new RegisterOperand(tmp, TypeReference.Int),
2274                IC(32 - shift))));
2275        // compute top half: lhsReg = (lhsReg1 << shift) | tmp
2276        EMIT(CPOS(s,
2277            MIR_BinaryAcc.create(IA32_SHL,
2278                new RegisterOperand(lhsReg, TypeReference.Int),
2279                IC(shift))));
2280        EMIT(CPOS(s,
2281            MIR_BinaryAcc.create(IA32_OR,
2282                new RegisterOperand(lhsReg, TypeReference.Int),
2283                new RegisterOperand(tmp, TypeReference.Int))));
2284        // compute bottom half: lowlhsReg = lowlhsReg << shift
2285        if (!result.similar(val1)) {
2286          EMIT(CPOS(s,
2287              MIR_Move.create(IA32_MOV,
2288              new RegisterOperand(lowlhsReg, TypeReference.Int),
2289              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2290        }
2291        EMIT(MIR_BinaryAcc.mutate(s, IA32_SHL,
2292                new RegisterOperand(lowlhsReg, TypeReference.Int),
2293                IC(shift)));
2294      } else if (shift == 32) {
2295        // lhsReg = lowrhsReg1
2296        EMIT(CPOS(s,
2297            MIR_Move.create(IA32_MOV,
2298                new RegisterOperand(lhsReg, TypeReference.Int),
2299                new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2300        // lowlhsReg = 0
2301        EMIT(MIR_Move.mutate(s, IA32_MOV,
2302            new RegisterOperand(lowlhsReg, TypeReference.Int),
2303            IC(0)));
2304      } else if (shift == 33) {
2305        // lhsReg = lowrhsReg1 << 1
2306        EMIT(CPOS(s,
2307            MIR_Lea.create(IA32_LEA,
2308                new RegisterOperand(lhsReg, TypeReference.Int),
2309                new MemoryOperand(null, // base
2310                    new RegisterOperand(lowrhsReg1, TypeReference.Int), //index
2311                    (byte)1, // scale
2312                    Offset.zero(), // displacement
2313                    (byte)4, // size
2314                    null, // location
2315                    null // guard
2316                    ))));
2317        // lowlhsReg = 0
2318        EMIT(MIR_Move.mutate(s, IA32_MOV,
2319            new RegisterOperand(lowlhsReg, TypeReference.Int),
2320            IC(0)));
2321      } else if (shift == 34) {
2322        // lhsReg = lowrhsReg1 << 2
2323        EMIT(CPOS(s,
2324            MIR_Lea.create(IA32_LEA,
2325                new RegisterOperand(lhsReg, TypeReference.Int),
2326                new MemoryOperand(null, // base
2327                    new RegisterOperand(lowrhsReg1, TypeReference.Int), //index
2328                    (byte)2, // scale
2329                    Offset.zero(), // displacement
2330                    (byte)4, // size
2331                    null, // location
2332                    null // guard
2333                    ))));
2334        // lowlhsReg = 0
2335        EMIT(MIR_Move.mutate(s, IA32_MOV,
2336            new RegisterOperand(lowlhsReg, TypeReference.Int),
2337            IC(0)));
2338      } else if (shift == 35) {
2339        // lhsReg = lowrhsReg1 << 3
2340        EMIT(CPOS(s,
2341            MIR_Lea.create(IA32_LEA,
2342                new RegisterOperand(lhsReg, TypeReference.Int),
2343                new MemoryOperand(null, // base
2344                    new RegisterOperand(lowrhsReg1, TypeReference.Int), //index
2345                    (byte)3, // scale
2346                    Offset.zero(), // displacement
2347                    (byte)4, // size
2348                    null, // location
2349                    null // guard
2350                    ))));
2351        // lowlhsReg = 0
2352        EMIT(MIR_Move.mutate(s, IA32_MOV,
2353            new RegisterOperand(lowlhsReg, TypeReference.Int),
2354            IC(0)));
2355      } else {
2356        if ((maskWith3f) || (shift < 64)) {
2357          // lhsReg = lowrhsReg1 << ((shift - 32) & 0x1f)
2358          EMIT(CPOS(s,
2359              MIR_Move.create(IA32_MOV,
2360                  new RegisterOperand(lhsReg, TypeReference.Int),
2361                  new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2362          EMIT(CPOS(s,
2363              MIR_BinaryAcc.create(IA32_SHL,
2364                  new RegisterOperand(lhsReg, TypeReference.Int),
2365                  IC((shift - 32) & 0x1F))));
2366          // lowlhsReg = 0
2367          EMIT(MIR_Move.mutate(s, IA32_MOV,
2368              new RegisterOperand(lowlhsReg, TypeReference.Int),
2369              IC(0)));
2370        } else {
2371          // lhsReg = 0
2372          EMIT(CPOS(s,
2373              MIR_Move.create(IA32_MOV,
2374              new RegisterOperand(lhsReg, TypeReference.Int),
2375              IC(0))));
2376          // lowlhsReg = 0
2377          EMIT(MIR_Move.mutate(s, IA32_MOV,
2378              new RegisterOperand(lowlhsReg, TypeReference.Int),
2379              IC(0)));
2380        }
2381      }
2382    } else {
2383      throw new OptimizingCompilerException("BURS_Helpers",
2384          "unexpected parameters: " + result + "=" + val1 + "<<" + val2);
2385    }
2386  }
2387
2388  /**
2389   * Expansion of LONG_SHR
2390   * @param s the instruction to expand
2391   * @param result the result operand
2392   * @param val1 the shifted operand
2393   * @param val2 the shift amount operand
2394   * @param maskWith3f should the shift operand by masked with 0x3f? This is
2395   *          default behaviour on Intel but it differs from how we combine
2396   *          shift operands in HIR
2397   */
2398  protected final void LONG_SHR(Instruction s, Operand result,
2399      Operand val1, Operand val2, boolean maskWith3f) {
2400    if (!val2.isIntConstant()) {
2401      // the most efficient form of expanding a shift by a variable amount
2402      // requires a branch so leave for complex operators
2403      // NB if !maskWith3f - we assume that a mask with 0x3F was required as
2404      // no optimizations currently exploits shift by registers of > 63
2405      // returning 0
2406      Binary.mutate(s, LONG_SHR, result.asRegister(), val1, val2);
2407      EMIT(s);
2408    } else if (result.isRegister()) {
2409      int shift = val2.asIntConstant().value;
2410      if (maskWith3f) {
2411        shift = shift & 0x3F;
2412      }
2413      Register lhsReg = result.asRegister().getRegister();
2414      Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
2415      Register rhsReg1 = val1.asRegister().getRegister();
2416      Register lowrhsReg1 = burs.ir.regpool.getSecondReg(rhsReg1);
2417
2418      if (shift == 0) {
2419        // operation is a nop.
2420        if (!result.similar(val1)) {
2421          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2422              new RegisterOperand(lowlhsReg, TypeReference.Int),
2423              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2424          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2425              new RegisterOperand(lhsReg, TypeReference.Int),
2426              new RegisterOperand(rhsReg1, TypeReference.Int))));
2427        }
2428      } else if (shift == 1) {
2429        if (!result.similar(val1)) {
2430          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2431              new RegisterOperand(lowlhsReg, TypeReference.Int),
2432              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2433          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2434              new RegisterOperand(lhsReg, TypeReference.Int),
2435              new RegisterOperand(rhsReg1, TypeReference.Int))));
2436        }
2437        // lhsReg = lhsReg >> 1
2438        EMIT(CPOS(s,
2439            MIR_BinaryAcc.create(IA32_SAR,
2440                new RegisterOperand(lhsReg, TypeReference.Int),
2441                IC(1))));
2442        // lowlhsReg = (lhsReg << 31) | (lowlhsReg >>> 1)
2443        EMIT(MIR_BinaryAcc.mutate(s, IA32_RCR,
2444            new RegisterOperand(lowlhsReg, TypeReference.Int),
2445            IC(1)));
2446      } else if (shift < 32) {
2447        // bits to shift in: tmp = rhsReg << (32 - shift)
2448        // TODO: use of LEA for SHL
2449        Register tmp = regpool.getInteger();
2450        EMIT(CPOS(s,
2451            MIR_Move.create(IA32_MOV,
2452                new RegisterOperand(tmp, TypeReference.Int),
2453                new RegisterOperand(rhsReg1, TypeReference.Int))));
2454        EMIT(CPOS(s,
2455            MIR_BinaryAcc.create(IA32_SHL,
2456                new RegisterOperand(tmp, TypeReference.Int),
2457                IC(32 - shift))));
2458        // compute bottom half: lowlhsReg = (lowlhsReg1 >>> shift) | tmp
2459        if (!result.similar(val1)) {
2460          EMIT(CPOS(s,
2461              MIR_Move.create(IA32_MOV,
2462                  new RegisterOperand(lowlhsReg, TypeReference.Int),
2463                  new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2464        }
2465        EMIT(CPOS(s,
2466            MIR_BinaryAcc.create(IA32_SHR,
2467                new RegisterOperand(lowlhsReg, TypeReference.Int),
2468                IC(shift))));
2469        EMIT(CPOS(s,
2470            MIR_BinaryAcc.create(IA32_OR,
2471                new RegisterOperand(lowlhsReg, TypeReference.Int),
2472                new RegisterOperand(tmp, TypeReference.Int))));
2473        // compute top half: lhsReg = lhsReg >> shift
2474        if (!result.similar(val1)) {
2475          EMIT(CPOS(s,
2476              MIR_Move.create(IA32_MOV,
2477                  new RegisterOperand(lhsReg, TypeReference.Int),
2478                  new RegisterOperand(rhsReg1, TypeReference.Int))));
2479        }
2480        EMIT(MIR_BinaryAcc.mutate(s, IA32_SAR,
2481            new RegisterOperand(lhsReg, TypeReference.Int),
2482            IC(shift)));
2483      } else if (shift == 32) {
2484        // lowlhsReg = rhsReg1
2485        EMIT(MIR_Move.mutate(s, IA32_MOV,
2486            new RegisterOperand(lowlhsReg, TypeReference.Int),
2487            new RegisterOperand(rhsReg1, TypeReference.Int)));
2488        // lhsReg = rhsReg1 >> 31
2489        if (!result.similar(val1)) {
2490          EMIT(CPOS(s,
2491              MIR_Move.create(IA32_MOV,
2492                  new RegisterOperand(lhsReg, TypeReference.Int),
2493                  new RegisterOperand(rhsReg1, TypeReference.Int))));
2494        }
2495        EMIT(CPOS(s,
2496            MIR_BinaryAcc.create(IA32_SAR,
2497                new RegisterOperand(lhsReg, TypeReference.Int),
2498                IC(31))));
2499      } else {
2500        if ((!maskWith3f && (shift >= 0x3F)) ||
2501            (maskWith3f && ((shift & 0x3F) == 0x3F))) {
2502          // lhsReg = rhsReg1 >> 31
2503          if (!result.similar(val1)) {
2504            EMIT(CPOS(s,
2505                MIR_Move.create(IA32_MOV,
2506                    new RegisterOperand(lhsReg, TypeReference.Int),
2507                    new RegisterOperand(rhsReg1, TypeReference.Int))));
2508          }
2509          EMIT(CPOS(s,
2510              MIR_BinaryAcc.create(IA32_SAR,
2511                  new RegisterOperand(lhsReg, TypeReference.Int),
2512                  IC(31))));
2513          // lowlhsReg = lhsReg
2514          EMIT(MIR_Move.mutate(s, IA32_MOV,
2515              new RegisterOperand(lowlhsReg, TypeReference.Int),
2516              new RegisterOperand(lhsReg, TypeReference.Int)));
2517        } else {
2518          // lhsReg = rhsReg1 >> 31
2519          if (!result.similar(val1)) {
2520            EMIT(CPOS(s,
2521                MIR_Move.create(IA32_MOV,
2522                    new RegisterOperand(lhsReg, TypeReference.Int),
2523                    new RegisterOperand(rhsReg1, TypeReference.Int))));
2524          }
2525          EMIT(CPOS(s,
2526              MIR_BinaryAcc.create(IA32_SAR,
2527                  new RegisterOperand(lhsReg, TypeReference.Int),
2528                  IC(31))));
2529          // lowlhsReg = rhsReg1 >> shift
2530          EMIT(MIR_Move.mutate(s, IA32_MOV,
2531              new RegisterOperand(lowlhsReg, TypeReference.Int),
2532              new RegisterOperand(rhsReg1, TypeReference.Int)));
2533          EMIT(CPOS(s,
2534              MIR_BinaryAcc.create(IA32_SAR,
2535                  new RegisterOperand(lowlhsReg, TypeReference.Int),
2536                  IC((shift - 32) & 0x3F))));
2537        }
2538      }
2539    } else {
2540      throw new OptimizingCompilerException("BURS_Helpers",
2541          "unexpected parameters: " + result + "=" + val1 + ">>" + val2);
2542    }
2543  }
2544
2545  /**
2546   * Expansion of LONG_USHR
2547   * @param s the instruction to expand
2548   * @param result the result operand
2549   * @param val1 the shifted operand
2550   * @param val2 the shift amount operand
2551   * @param maskWith3f should the shift operand by masked with 0x3f? This is
2552   *          default behaviour on Intel but it differs from how we combine
2553   *          shift operands in HIR
2554   */
2555  protected final void LONG_USHR(Instruction s, Operand result,
2556      Operand val1, Operand val2, boolean maskWith3f) {
2557    if (!val2.isIntConstant()) {
2558      // the most efficient form of expanding a shift by a variable amount
2559      // requires a branch so leave for complex operators
2560      // NB if !maskWith3f - we assume that a mask with 0x3F was required as
2561      // no optimizations currently exploits shift by registers of > 63
2562      // returning 0
2563      Binary.mutate(s, LONG_USHR, result.asRegister(), val1, val2);
2564      EMIT(s);
2565    } else if (result.isRegister()) {
2566      int shift = val2.asIntConstant().value;
2567      if (maskWith3f) {
2568        shift = shift & 0x3F;
2569      }
2570      Register lhsReg = result.asRegister().getRegister();
2571      Register lowlhsReg = burs.ir.regpool.getSecondReg(lhsReg);
2572      Register rhsReg1 = val1.asRegister().getRegister();
2573      Register lowrhsReg1 = burs.ir.regpool.getSecondReg(rhsReg1);
2574
2575      if (shift == 0) {
2576        // operation is a nop.
2577        if (!result.similar(val1)) {
2578          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2579              new RegisterOperand(lowlhsReg, TypeReference.Int),
2580              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2581          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2582              new RegisterOperand(lhsReg, TypeReference.Int),
2583              new RegisterOperand(rhsReg1, TypeReference.Int))));
2584        }
2585      } else if (shift == 1) {
2586        if (!result.similar(val1)) {
2587          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2588              new RegisterOperand(lowlhsReg, TypeReference.Int),
2589              new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2590          EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2591              new RegisterOperand(lhsReg, TypeReference.Int),
2592              new RegisterOperand(rhsReg1, TypeReference.Int))));
2593        }
2594        // lhsReg = lhsReg >>> 1
2595        EMIT(CPOS(s,
2596            MIR_BinaryAcc.create(IA32_SHR,
2597                new RegisterOperand(lhsReg, TypeReference.Int),
2598                IC(1))));
2599        // lowlhsReg = (lhsReg << 31) | (lowlhsReg >>> 1)
2600        EMIT(MIR_BinaryAcc.mutate(s, IA32_RCR,
2601            new RegisterOperand(lowlhsReg, TypeReference.Int),
2602            IC(1)));
2603      } else if (shift < 32) {
2604        // bits to shift in: tmp = rhsReg << (32 - shift)
2605        // TODO: use LEA for SHL operator
2606        Register tmp = regpool.getInteger();
2607        EMIT(CPOS(s,
2608            MIR_Move.create(IA32_MOV,
2609                new RegisterOperand(tmp, TypeReference.Int),
2610                new RegisterOperand(rhsReg1, TypeReference.Int))));
2611        EMIT(CPOS(s,
2612            MIR_BinaryAcc.create(IA32_SHL,
2613                new RegisterOperand(tmp, TypeReference.Int),
2614                IC(32 - shift))));
2615        // compute bottom half: lowlhsReg = (lowlhsReg1 >>> shift) | tmp
2616        if (!result.similar(val1)) {
2617          EMIT(CPOS(s,
2618              MIR_Move.create(IA32_MOV,
2619                  new RegisterOperand(lowlhsReg, TypeReference.Int),
2620                  new RegisterOperand(lowrhsReg1, TypeReference.Int))));
2621        }
2622        EMIT(CPOS(s,
2623            MIR_BinaryAcc.create(IA32_SHR,
2624                new RegisterOperand(lowlhsReg, TypeReference.Int),
2625                IC(shift))));
2626        EMIT(CPOS(s,
2627            MIR_BinaryAcc.create(IA32_OR,
2628                new RegisterOperand(lowlhsReg, TypeReference.Int),
2629                new RegisterOperand(tmp, TypeReference.Int))));
2630        // compute top half: lhsReg = lhsReg >>> shift
2631        if (!result.similar(val1)) {
2632          EMIT(CPOS(s,
2633              MIR_Move.create(IA32_MOV,
2634                  new RegisterOperand(lhsReg, TypeReference.Int),
2635                  new RegisterOperand(rhsReg1, TypeReference.Int))));
2636        }
2637        EMIT(MIR_BinaryAcc.mutate(s, IA32_SHR,
2638            new RegisterOperand(lhsReg, TypeReference.Int),
2639            IC(shift)));
2640      } else if (shift == 32) {
2641        // lowlhsReg = rhsReg1
2642        EMIT(MIR_Move.mutate(s, IA32_MOV,
2643            new RegisterOperand(lowlhsReg, TypeReference.Int),
2644            new RegisterOperand(rhsReg1, TypeReference.Int)));
2645        // lhsReg = 0
2646        EMIT(CPOS(s,
2647            MIR_Move.create(IA32_MOV,
2648                new RegisterOperand(lhsReg, TypeReference.Int),
2649                IC(0))));
2650      } else {
2651        if (maskWith3f || (shift < 64)) {
2652          // lowlhsReg = rhsReg1 >>> (shift & 0x1F)
2653          EMIT(CPOS(s,
2654              MIR_Move.create(IA32_MOV,
2655              new RegisterOperand(lowlhsReg, TypeReference.Int),
2656              new RegisterOperand(rhsReg1, TypeReference.Int))));
2657          EMIT(CPOS(s,
2658              MIR_BinaryAcc.create(IA32_SHR,
2659              new RegisterOperand(lowlhsReg, TypeReference.Int),
2660              IC(shift & 0x1F))));
2661        } else {
2662          // lowlhsReg = 0
2663          EMIT(CPOS(s,
2664              MIR_Move.create(IA32_MOV,
2665                  new RegisterOperand(lowlhsReg, TypeReference.Int),
2666                  IC(0))));
2667        }
2668        // lhsReg = 0
2669        EMIT(MIR_Move.mutate(s, IA32_MOV,
2670                new RegisterOperand(lhsReg, TypeReference.Int),
2671                IC(0)));
2672      }
2673    } else {
2674      throw new OptimizingCompilerException("BURS_Helpers",
2675          "unexpected parameters: " + result + "=" + val1 + ">>" + val2);
2676    }
2677  }
2678
2679  /**
2680   * Expansion of RDTSC (called GET_TIME_BASE for consistency with PPC)
2681   *
2682   * @param s the instruction to expand
2683   * @param result the result/first operand
2684   */
2685  protected final void GET_TIME_BASE(Instruction s,
2686      RegisterOperand result) {
2687    if (VM.BuildFor32Addr) {
2688      Register highReg = result.getRegister();
2689      Register lowReg = regpool.getSecondReg(highReg);
2690      EMIT(CPOS(s, MIR_RDTSC.create(IA32_RDTSC,
2691          new RegisterOperand(getEAX(), TypeReference.Int),
2692          new RegisterOperand(getEDX(), TypeReference.Int))));
2693      EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2694          new RegisterOperand(lowReg, TypeReference.Int),
2695          new RegisterOperand(getEAX(), TypeReference.Int))));
2696      EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2697          new RegisterOperand(highReg, TypeReference.Int),
2698          new RegisterOperand(getEDX(), TypeReference.Int))));
2699    } else {
2700      Register res = result.getRegister();
2701       EMIT(CPOS(s, MIR_RDTSC.create(IA32_RDTSC,
2702           new RegisterOperand(getEAX(), TypeReference.Int),
2703           new RegisterOperand(getEDX(), TypeReference.Int))));
2704       EMIT(CPOS(s, MIR_Move.create(IA32_MOV,
2705               new RegisterOperand(res, TypeReference.Long),
2706               new RegisterOperand(getEDX(), TypeReference.Long))));
2707       EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SHL,
2708               new RegisterOperand(getEDX(), TypeReference.Long),
2709               LC(32))));
2710       EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR,
2711           new RegisterOperand(res, TypeReference.Long),
2712           new RegisterOperand(getEAX(), TypeReference.Long))));
2713    }
2714  }
2715
2716  /**
2717   * Expansion of LONG_CMP: compare to values and set result to -1, 0, 1 for &lt;, =, &gt;,
2718   * respectively
2719   *
2720   * @param s the compare instruction
2721   * @param res the result/first operand
2722   * @param val1 the first value
2723   * @param val2 the second value
2724   */
2725  protected final void LONG_CMP(Instruction s, RegisterOperand res, Operand val1, Operand val2) {
2726    if (VM.BuildFor32Addr) {
2727      RegisterOperand one = regpool.makeTempInt();
2728      RegisterOperand lone = regpool.makeTempInt();
2729      Operand two, ltwo;
2730      if (val1 instanceof RegisterOperand) {
2731        Register val1_reg = val1.asRegister().getRegister();
2732        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, new RegisterOperand(val1_reg, TypeReference.Int))));
2733        EMIT(CPOS(s,
2734                  MIR_Move.create(IA32_MOV,
2735                                  lone,
2736                                  new RegisterOperand(regpool.getSecondReg(val1_reg), TypeReference.Int))));
2737      } else {
2738        LongConstantOperand tmp = (LongConstantOperand) val1;
2739        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, IC(tmp.upper32()))));
2740        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lone, IC(tmp.lower32()))));
2741      }
2742      if (val2 instanceof RegisterOperand) {
2743        two = val2;
2744        ltwo = L(burs.ir.regpool.getSecondReg(val2.asRegister().getRegister()));
2745      } else {
2746        LongConstantOperand tmp = (LongConstantOperand) val2;
2747        two = IC(tmp.upper32());
2748        ltwo = IC(tmp.lower32());
2749      }
2750      EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, lone.copyRO(), ltwo)));
2751      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
2752      EMIT(CPOS(s, MIR_Set
2753          .create(IA32_SET__B, res, IA32ConditionOperand.LT()))); // res =
2754      // (val1 < val2) ? 1 :0
2755      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, one.copyRO(), lone.copyRO())));
2756      EMIT(CPOS(s,
2757                MIR_Set.create(IA32_SET__B,
2758                               lone.copyRO(),
2759                               IA32ConditionOperand.NE()))); // lone = (val1 != val2) ? 1 : 0
2760      EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, res.copyRO()))); // res = (val1 <
2761      // val2) ? -1 :0
2762      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, res.copyRO(), lone.copyRO())));
2763      EMIT(MIR_Unary.mutate(s, IA32_MOVSX__B, res.copyRO(), res.copyRO()));
2764    } else {
2765      RegisterOperand one = regpool.makeTempLong();
2766      RegisterOperand two = regpool.makeTempLong();
2767      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, val1)));
2768      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, two, val2)));
2769      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, one, two)));
2770      EMIT(CPOS(s,
2771           MIR_Set.create(IA32_SET__B,
2772                             res,
2773                             IA32ConditionOperand.NE())));
2774      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SAR, one.copyRO(), LC(64))));
2775      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, res.copyRO(), one.copyRO())));
2776    }
2777  }
2778
2779  /**
2780   * Expansion of FP_ADD_ACC, FP_MUL_ACC, FP_SUB_ACC, and FP_DIV_ACC. Moves
2781   * first value into fp0, accumulates second value into fp0 using op, moves fp0
2782   * into result.
2783   *
2784   * @param s the instruction to expand
2785   * @param op the floating point op to use
2786   * @param result the result operand
2787   * @param val1 the first operand
2788   * @param val2 the second operand
2789   */
2790  protected final void FP_MOV_OP_MOV(Instruction s, Operator op, Operand result, Operand val1,
2791                                     Operand val2) {
2792    if (VM.BuildForSSE2) {
2793      UNREACHABLE();
2794    } else {
2795      EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, D(getFPR(0)), val1)));
2796      EMIT(MIR_BinaryAcc.mutate(s, op, D(getFPR(0)), val2));
2797      EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, result, D(getFPR(0)))));
2798    }
2799  }
2800
2801  /**
2802   * Expansion of FP_REM
2803   *
2804   * @param s the instruction to expand
2805   * @param val1 the first operand
2806   * @param val2 the second operand
2807   */
2808  protected final void FP_REM(Instruction s, Operand val1, Operand val2) {
2809    EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, D(getFPR(1)), val2)));
2810    EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, D(getFPR(0)), val1)));
2811    EMIT(MIR_BinaryAcc.mutate(s, IA32_FPREM, D(getFPR(0)), D(getFPR(1))));
2812  }
2813
2814  /**
2815   * Expansion for [DF]CMP[GL] compare to values and set result to -1, 0, 1 for &lt;, =, &gt;
2816   * respectively
2817   *
2818   * @param s the compare instruction
2819   */
2820  protected final void threeValueFPCmp(Instruction s) {
2821    // IMPORTANT: FCOMI only sets 3 of the 6 bits in EFLAGS, so
2822    // we can't quite just translate the condition operand as if it
2823    // were an integer compare.
2824    // FCMOI sets ZF, PF, and CF as follows:
2825    // Compare Results ZF PF CF
2826    // left > right 0 0 0
2827    // left < right 0 0 1
2828    // left == right 1 0 0
2829    // UNORDERED 1 1 1
2830    RegisterOperand one = (RegisterOperand) Binary.getClearVal1(s);
2831    RegisterOperand two = (RegisterOperand) Binary.getClearVal2(s);
2832    RegisterOperand res = Binary.getClearResult(s);
2833    RegisterOperand temp = burs.ir.regpool.makeTempInt();
2834    Register FP0 = burs.ir.regpool.getPhysicalRegisterSet().getFPR(0);
2835    if ((s.operator() == DOUBLE_CMPL) || (s.operator() == FLOAT_CMPL)) {
2836      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, IC(0))));
2837      // Perform compare
2838      EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, new RegisterOperand(FP0, TypeReference.Int), one)));
2839      EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMI, new RegisterOperand(FP0, TypeReference.Int), two)));
2840      // res = (value1 > value2) ? 1 : 0
2841      // temp = ((value1 < value2) || unordered) ? -1 : 0
2842      EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, res, IA32ConditionOperand.LGT())));
2843      EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res.copyRO(), res.copyRO()));
2844      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, temp.copyRO(), temp.copyRO())));
2845    } else {
2846      RegisterOperand temp2 = burs.ir.regpool.makeTempInt();
2847      // Perform compare
2848      EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, new RegisterOperand(FP0, TypeReference.Int), one)));
2849      EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMI, new RegisterOperand(FP0, TypeReference.Int), two)));
2850      // res = (value1 > value2) ? 1 : 0
2851      // temp2 = (value1 unordered value2) ? 1 : 0
2852      // temp = ((value1 unordered value2) ? 1 : 0) - 0 - CF
2853      // (i.e. temp = (value1 < value2) ? -1 : 0)
2854      EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, IA32ConditionOperand
2855          .PO())));
2856      EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, res, IA32ConditionOperand
2857          .LGT())));
2858      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp2, temp.copyRO())));
2859      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, temp.copyRO(), IC(0))));
2860      // Put result from temp2 in res
2861      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, res.copyRO(), temp2.copyRO())));
2862    }
2863    EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, res.copyRO(), temp.copyRO())));
2864    EMIT(MIR_Unary.mutate(s, IA32_MOVSX__B, res.copyRO(), res.copyRO()));
2865  }
2866
2867  /**
2868   * @param cond a condition operand
2869   * @return whether the given condition operand need its operands flipping as its
2870   * non-commutative
2871   */
2872  private boolean getCMP_needsSwap(ConditionOperand cond) {
2873    switch (cond.value) {
2874      case ConditionOperand.BORROW_FROM_RSUB:
2875      case ConditionOperand.NO_BORROW_FROM_RSUB:
2876      case ConditionOperand.OVERFLOW_FROM_RSUB:
2877      case ConditionOperand.NO_OVERFLOW_FROM_RSUB:
2878      case ConditionOperand.RBIT_TEST:
2879      case ConditionOperand.NO_RBIT_TEST:
2880        return true;
2881      default:
2882        return false;
2883    }
2884  }
2885  /**
2886   * Gives the MIR condition operator appropriate for the given condition
2887   * @param s the comparison instruction
2888   * @param cond the condition
2889   * @param val1 first operand for the compare
2890   * @param val2 second operand for the compare
2891   */
2892  protected void EMIT_Compare(Instruction s, ConditionOperand cond,
2893      Operand val1, Operand val2) {
2894    // Swap operands for non-commutative operators
2895    if (getCMP_needsSwap(cond)) {
2896      Operand temp = val1;
2897      val2 = val1;
2898      val1 = temp;
2899    }
2900    switch (cond.value) {
2901      case ConditionOperand.CARRY_FROM_ADD:
2902      case ConditionOperand.NO_CARRY_FROM_ADD:
2903      case ConditionOperand.OVERFLOW_FROM_ADD:
2904      case ConditionOperand.NO_OVERFLOW_FROM_ADD: {
2905        RegisterOperand temp = regpool.makeTempInt();
2906        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val1.copy())));
2907        EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, temp.copyRO(), val2));
2908        break;
2909      }
2910      case ConditionOperand.BIT_TEST:
2911      case ConditionOperand.NO_BIT_TEST:
2912      case ConditionOperand.RBIT_TEST:
2913      case ConditionOperand.NO_RBIT_TEST:
2914        if (val2 instanceof MemoryOperand) {
2915          RegisterOperand temp = regpool.makeTempInt();
2916          EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val2.copy())));
2917          val2 = temp;
2918        }
2919        EMIT(MIR_Compare.mutate(s, IA32_BT, val1.copy(), val2.copy()));
2920        break;
2921      case ConditionOperand.OVERFLOW_FROM_MUL:
2922      case ConditionOperand.NO_OVERFLOW_FROM_MUL: {
2923        RegisterOperand temp = regpool.makeTempInt();
2924        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, temp, val1.copy())));
2925        EMIT(MIR_BinaryAcc.mutate(s, IA32_IMUL2, temp.copyRO(), val2));
2926        break;
2927      }
2928      default:
2929        EMIT(MIR_Compare.mutate(s, IA32_CMP, val1.copy(), val2.copy()));
2930        break;
2931    }
2932  }
2933
2934  /**
2935   * Expansion of BOOLEAN_CMP_INT
2936   *
2937   * @param s the instruction to copy position info from
2938   * @param res the result operand
2939   * @param val1 the first value
2940   * @param val2 the second value
2941   * @param cond the condition operand
2942   */
2943  protected final void BOOLEAN_CMP_INT(Instruction s, RegisterOperand res, Operand val1, Operand val2,
2944                                       ConditionOperand cond) {
2945    EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, val1, val2)));
2946    RegisterOperand temp = regpool.makeTemp(TypeReference.Boolean);
2947    EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, COND(cond))));
2948    EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res, temp.copyD2U()));
2949  }
2950
2951  /**
2952   * Expansion of a special case of BOOLEAN_CMP_INT when the condition registers
2953   * have already been set by the previous ALU op.
2954   *
2955   * @param s the instruction to copy position info from
2956   * @param res the result operand
2957   * @param cond the condition operand
2958   */
2959  protected final void BOOLEAN_CMP_INT(Instruction s, RegisterOperand res, ConditionOperand cond) {
2960    RegisterOperand temp = regpool.makeTemp(TypeReference.Boolean);
2961    EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, COND(cond))));
2962    EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res, temp.copyD2U()));
2963  }
2964
2965  /**
2966   * Expansion of BOOLEAN_CMP_DOUBLE
2967   *
2968   * @param s the instruction to copy position info from
2969   * @param res the result operand
2970   * @param val1 the first value
2971   * @param val2 the second value
2972   * @param cond the condition operand
2973   */
2974  protected final void BOOLEAN_CMP_DOUBLE(Instruction s, RegisterOperand res, ConditionOperand cond,
2975                                          Operand val1, Operand val2) {
2976    RegisterOperand temp = regpool.makeTemp(TypeReference.Boolean);
2977    EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, D(getFPR(0)), CondMove.getVal1(s))));
2978    EMIT(CPOS(s, MIR_Compare.create(IA32_FCOMI, D(getFPR(0)), CondMove
2979        .getVal2(s))));
2980    EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, COND(cond))));
2981    EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res, temp.copyD2U()));
2982  }
2983
2984  /**
2985   * Expansion of BOOLEAN_CMP_LONG
2986   *
2987   * @param s the instruction to copy position info from
2988   * @param res the result operand
2989   * @param val1 the first value
2990   * @param val2 the second value
2991   * @param cond the condition operand
2992   */
2993  protected final void BOOLEAN_CMP_LONG(Instruction s, RegisterOperand res, Operand val1, Operand val2,
2994                                        ConditionOperand cond) {
2995    // Can we simplify to a shift?
2996    if (cond.isLESS() && val2.isLongConstant() && val2.asLongConstant().value == 0 && val1.isRegister()) {
2997      // Put the most significant bit of val1 into res
2998      Register val1_reg = val1.asRegister().getRegister();
2999      EMIT(MIR_Move.create(IA32_MOV, res.copyRO(), new RegisterOperand(val1_reg, TypeReference.Int)));
3000      EMIT(MIR_BinaryAcc.mutate(s, IA32_SHR, res, IC(31)));
3001    } else if (cond.isGREATER_EQUAL() && val2.isLongConstant() && val2.asLongConstant().value == 0 && val1.isRegister()) {
3002      // Put the most significant bit of val1 into res and invert
3003      Register val1_reg = val1.asRegister().getRegister();
3004      EMIT(MIR_Move.create(IA32_MOV, res.copyRO(), new RegisterOperand(val1_reg, TypeReference.Int)));
3005      EMIT(MIR_BinaryAcc.mutate(s, IA32_SHR, res, IC(31)));
3006      EMIT(MIR_BinaryAcc.create(IA32_XOR, res.copyRO(), IC(1)));
3007    } else {
3008      // Long comparison is a subtraction:
3009      // <, >= : easy to compute as SF !=/== OF
3010      // >, <= : flipOperands and treat as a </>=
3011      // ==/!= : do subtract then OR 2 32-bit quantities test for zero/non-zero
3012      if (cond.isGREATER() || cond.isLESS_EQUAL()) {
3013        Operand swap_temp;
3014        cond.flipOperands();
3015        swap_temp = val1;
3016        val1 = val2;
3017        val2 = swap_temp;
3018      }
3019      if (VM.VerifyAssertions) {
3020        opt_assert(cond.isEQUAL() || cond.isNOT_EQUAL() || cond.isLESS() || cond.isGREATER_EQUAL());
3021      }
3022      RegisterOperand one = regpool.makeTempInt();
3023      RegisterOperand lone = regpool.makeTempInt();
3024      Operand two, ltwo;
3025      if (val1 instanceof RegisterOperand) {
3026        Register val1_reg = val1.asRegister().getRegister();
3027        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, new RegisterOperand(val1_reg, TypeReference.Int))));
3028        EMIT(CPOS(s,
3029            MIR_Move.create(IA32_MOV,
3030                lone,
3031                new RegisterOperand(regpool.getSecondReg(val1_reg), TypeReference.Int))));
3032      } else {
3033        LongConstantOperand tmp = (LongConstantOperand) val1;
3034        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, IC(tmp.upper32()))));
3035        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lone, IC(tmp.lower32()))));
3036      }
3037      if (val2 instanceof RegisterOperand) {
3038        two = val2;
3039        ((RegisterOperand)two).setType(TypeReference.Int);
3040        ltwo = new RegisterOperand(burs.ir.regpool.getSecondReg(val2.asRegister().getRegister()), TypeReference.Int);
3041      } else {
3042        LongConstantOperand tmp = (LongConstantOperand) val2;
3043        two = IC(tmp.upper32());
3044        ltwo = IC(tmp.lower32());
3045      }
3046      if (cond.isEQUAL() || cond.isNOT_EQUAL()) {
3047        EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, lone.copyRO(), ltwo)));
3048        EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
3049        EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, one.copyRO(), lone.copyRO())));
3050      } else {
3051        EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, lone.copyRO(), ltwo)));
3052        EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
3053      }
3054      RegisterOperand temp = regpool.makeTemp(TypeReference.Boolean);
3055      EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, temp, COND(cond))));
3056      EMIT(MIR_Unary.mutate(s, IA32_MOVZX__B, res, temp.copyRO()));
3057    }
3058  }
3059
3060  /**
3061   * Generate a long compare and cmov
3062   *
3063   * @param s the instruction to copy position info from
3064   * @param result the result of the conditional move
3065   * @param val1 the first value
3066   * @param val2 the second value
3067   * @param cond the condition operand
3068   * @param trueValue the value to move to result if cond is true
3069   * @param falseValue the value to move to result if cond is not true
3070   */
3071  protected final void LCMP_CMOV(Instruction s, RegisterOperand result, Operand val1, Operand val2,
3072                                 ConditionOperand cond, Operand trueValue, Operand falseValue) {
3073    // Long comparison is a subtraction:
3074    // <, >= : easy to compute as SF !=/== OF
3075    // >, <= : flipOperands and treat as a </>=
3076    // ==/!= : do subtract then OR 2 32-bit quantities test for zero/non-zero
3077    if (cond.isGREATER() || cond.isLESS_EQUAL()) {
3078      Operand swap_temp;
3079      cond.flipOperands();
3080      swap_temp = val1;
3081      val1 = val2;
3082      val2 = swap_temp;
3083    }
3084    if (VM.VerifyAssertions) {
3085      opt_assert(cond.isEQUAL() || cond.isNOT_EQUAL() || cond.isLESS() || cond.isGREATER_EQUAL());
3086    }
3087    RegisterOperand one = regpool.makeTempInt();
3088    RegisterOperand lone = regpool.makeTempInt();
3089    Operand two, ltwo;
3090    if (val1 instanceof RegisterOperand) {
3091      Register val1_reg = val1.asRegister().getRegister();
3092      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, new RegisterOperand(val1_reg, TypeReference.Int))));
3093      EMIT(CPOS(s,
3094                MIR_Move.create(IA32_MOV,
3095                                lone,
3096                                new RegisterOperand(regpool.getSecondReg(val1_reg), TypeReference.Int))));
3097    } else {
3098      LongConstantOperand tmp = (LongConstantOperand) val1;
3099      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, one, IC(tmp.upper32()))));
3100      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, lone, IC(tmp.lower32()))));
3101    }
3102    if (val2 instanceof RegisterOperand) {
3103      two = val2;
3104      ((RegisterOperand)two).setType(TypeReference.Int);
3105      ltwo = new RegisterOperand(burs.ir.regpool.getSecondReg(val2.asRegister().getRegister()), TypeReference.Int);
3106    } else {
3107      LongConstantOperand tmp = (LongConstantOperand) val2;
3108      two = IC(tmp.upper32());
3109      ltwo = IC(tmp.lower32());
3110    }
3111    if (cond.isEQUAL() || cond.isNOT_EQUAL()) {
3112      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, lone.copyRO(), ltwo)));
3113      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
3114      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, one.copyRO(), lone.copyRO())));
3115    } else {
3116      EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, lone.copyRO(), ltwo)));
3117      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SBB, one.copyRO(), two)));
3118    }
3119    CMOV_MOV(s, result, cond, trueValue, falseValue);
3120  }
3121
3122  /**
3123   * Generate a compare and branch sequence. Used in the expansion of trees
3124   * where INT_IFCMP is a root
3125   *
3126   * @param s the ifcmp instruction
3127   * @param guardResult the guard result of the ifcmp
3128   * @param val1 the first value operand
3129   * @param val2 the second value operand
3130   * @param cond the condition operand
3131   */
3132  protected final void IFCMP(Instruction s, RegisterOperand guardResult, Operand val1, Operand val2,
3133                             ConditionOperand cond) {
3134    if (VM.VerifyAssertions) {
3135      // We only need make sure the guard information is correct when
3136      // validating, the null check combining phase removes all guards
3137      EMIT(CPOS(s, Move.create(GUARD_MOVE, guardResult, new TrueGuardOperand())));
3138    }
3139    EMIT(CPOS(s, MIR_Compare.create(IA32_CMP, val1, val2)));
3140    EMIT(MIR_CondBranch.mutate(s, IA32_JCC, COND(cond), IfCmp.getTarget(s), IfCmp.getBranchProfile(s)));
3141  }
3142
3143  /**
3144   * Generate an integer move portion of a conditional move.
3145   *
3146   * @param s the instruction to copy position info from
3147   * @param result the result of the conditional move
3148   * @param cond the condition operand
3149   * @param trueValue the value to move to result if cond is true
3150   * @param falseValue the value to move to result if cond is not true
3151   */
3152  protected final void CMOV_MOV(Instruction s, RegisterOperand result, ConditionOperand cond,
3153                                Operand trueValue, Operand falseValue) {
3154    if (result.similar(trueValue)) {
3155      // in this case, only need a conditional move for the false branch.
3156      EMIT(MIR_CondMove.mutate(s, IA32_CMOV, result, asReg(s, IA32_MOV, falseValue), COND(cond.flipCode())));
3157    } else if (result.similar(falseValue)) {
3158      // in this case, only need a conditional move for the true branch.
3159      EMIT(MIR_CondMove.mutate(s, IA32_CMOV, result, asReg(s, IA32_MOV, trueValue), COND(cond)));
3160    } else {
3161      // need to handle both possible assignments. Unconditionally
3162      // assign one value then conditionally assign the other.
3163      if (falseValue.isRegister()) {
3164        EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result, trueValue)));
3165        EMIT(MIR_CondMove.mutate(s, IA32_CMOV, result.copyRO(), falseValue, COND(cond.flipCode())));
3166      } else {
3167        if (trueValue.isRegister()) {
3168          EMIT(CPOS(s, MIR_Move.create(IA32_MOV, result, falseValue)));
3169          EMIT(MIR_CondMove.mutate(s, IA32_CMOV, result.copyRO(), trueValue, COND(cond)));
3170        } else {
3171          // Perform constant move without creating a register (costs
3172          // 1 or 2 more instructions but saves a register)
3173          int true_const = ((IntConstantOperand) trueValue).value;
3174          int false_const = ((IntConstantOperand) falseValue).value;
3175          if (cond.isLOWER()) {
3176            // Comparison sets carry flag so use to avoid setb, movzx
3177            // result = cond ? -1 : 0
3178            EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB, result, result.copyRO())));
3179            if (true_const - false_const != -1) {
3180              if (true_const - false_const == 1) {
3181                EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, result.copyRO())));
3182              } else {
3183                EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND, result.copyRO(), IC(true_const - false_const))));
3184              }
3185            }
3186            if (false_const != 0) {
3187              EMIT(MIR_BinaryAcc.create(IA32_ADD, result.copyRO(), IC(false_const)));
3188            }
3189          } else if (cond.isHIGHER_EQUAL()) {
3190            // Comparison sets carry flag so use to avoid setb, movzx
3191            // result = cond ? 0 : -1
3192            EMIT(CPOS(s, MIR_BinaryAcc.mutate(s, IA32_SBB, result, result.copyRO())));
3193            if (false_const - true_const != -1) {
3194              if (false_const - true_const == 1) {
3195                EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, result.copyRO())));
3196              } else {
3197                EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND, result.copyRO(), IC(false_const - true_const))));
3198              }
3199            }
3200            if (true_const != 0) {
3201              EMIT(MIR_BinaryAcc.create(IA32_ADD, result, IC(true_const)));
3202            }
3203          } else {
3204            // Generate values for consts trying to avoid zero extending the
3205            // set__b result
3206            // result = cond ? 1 : 0
3207            EMIT(CPOS(s, MIR_Set.create(IA32_SET__B, result.copyRO(), COND(cond))));
3208
3209            if ((true_const - false_const) == 1) {
3210              // result = (cond ? 1 : 0) + false_const
3211              EMIT(CPOS(s, MIR_Unary.create(IA32_MOVZX__B, result.copyRO(), result.copyRO())));
3212              EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(false_const)));
3213            } else if ((false_const - true_const) == 1) {
3214              // result = (cond ? -1 : 0) + false_const
3215              EMIT(CPOS(s, MIR_Unary.create(IA32_MOVZX__B, result.copyRO(), result.copyRO())));
3216              EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, result.copyRO())));
3217              EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(false_const)));
3218            } else if (((false_const - true_const) > 0) && ((false_const - true_const) <= 0xFF)) {
3219              // result = cond ? 0 : -1
3220              // result = (cond ? 0 : -1) & (false_const - true__const)
3221              // result = ((cond ? 0 : -1) & (false_const - true_const)) +
3222              // true_const
3223              EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_SUB, result.copyRO(), IC(1))));
3224              EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND, result.copyRO(), IC(false_const - true_const))));
3225              EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(true_const)));
3226            } else {
3227              // result = cond ? -1 : 0
3228              // result = (cond ? -1 : 0) & (true_const - false_const)
3229              // result = ((cond ? -1 : 0) & (true_const - false_const)) +
3230              // false_const
3231              if (((true_const - false_const) > 0xFF) || ((true_const - false_const) < 0)) {
3232                EMIT(CPOS(s, MIR_Unary.create(IA32_MOVZX__B, result.copyRO(), result.copyRO())));
3233              }
3234              EMIT(CPOS(s, MIR_UnaryAcc.create(IA32_NEG, result.copyRO())));
3235              EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_AND, result.copyRO(), IC(true_const - false_const))));
3236              EMIT(MIR_BinaryAcc.mutate(s, IA32_ADD, result, IC(false_const)));
3237            }
3238          }
3239        }
3240      }
3241    }
3242  }
3243
3244  /**
3245   * Generate a floating point move portion of a conditional move.
3246   *
3247   * @param s the instruction to copy position info from
3248   * @param result the result of the conditional move
3249   * @param cond the condition operand
3250   * @param trueValue the value to move to result if cond is true
3251   * @param falseValue the value to move to result if cond is not true
3252   */
3253  protected final void CMOV_FMOV(Instruction s, RegisterOperand result, ConditionOperand cond,
3254                                 Operand trueValue, Operand falseValue) {
3255    RegisterOperand FP0 = new RegisterOperand(burs.ir.regpool.getPhysicalRegisterSet().getFPR(0), result.getType());
3256    // need to handle both possible assignments. Unconditionally
3257    // assign one value then conditionally assign the other.
3258    if (falseValue.isRegister()) {
3259      EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, FP0, trueValue)));
3260      EMIT(MIR_CondMove.mutate(s, IA32_FCMOV, FP0.copyRO(), falseValue, COND(cond.flipCode())));
3261    } else {
3262      EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, FP0, falseValue)));
3263      EMIT(MIR_CondMove.mutate(s, IA32_FCMOV, FP0.copyRO(), asReg(s, IA32_FMOV, trueValue), COND(cond)));
3264    }
3265    EMIT(CPOS(s, MIR_Move.create(IA32_FMOV, result.copyRO(), FP0.copyRO())));
3266  }
3267
3268  /**
3269   * Expand a prologue by expanding out longs into pairs of ints
3270   *
3271   * @param s the prologue instruction
3272   */
3273  protected final void PROLOGUE(Instruction s) {
3274    if (VM.BuildFor32Addr) {
3275      int numFormals = Prologue.getNumberOfFormals(s);
3276      int numLongs = 0;
3277      for (int i = 0; i < numFormals; i++) {
3278        if (Prologue.getFormal(s, i).getType().isLongType()) {
3279          numLongs++;
3280        }
3281      }
3282      if (numLongs != 0) {
3283        Instruction s2 = Prologue.create(IR_PROLOGUE, numFormals + numLongs);
3284        for (int sidx = 0, s2idx = 0; sidx < numFormals; sidx++) {
3285          RegisterOperand sForm = Prologue.getFormal(s, sidx);
3286          if (sForm.getType().isLongType()) {
3287            sForm.setType(TypeReference.Int);
3288            Prologue.setFormal(s2, s2idx++, sForm);
3289            Register r2 = regpool.getSecondReg(sForm.getRegister());
3290            Prologue.setFormal(s2, s2idx++, new RegisterOperand(r2, TypeReference.Int));
3291            sForm.getRegister().clearType();
3292            sForm.getRegister().setInteger();
3293            r2.clearType();
3294            r2.setInteger();
3295          } else {
3296            Prologue.setFormal(s2, s2idx++, sForm);
3297          }
3298        }
3299        EMIT(s2);
3300      } else {
3301        EMIT(s);
3302      }
3303    } else {
3304      EMIT(s);
3305    }
3306  }
3307
3308  /**
3309   * Expansion of CALL. Expand longs registers into pairs of int registers.
3310   *
3311   * @param s the instruction to expand
3312   * @param address the operand containing the target address
3313   */
3314  protected final void CALL(Instruction s, Operand address) {
3315    if (VM.BuildFor32Addr) {
3316      // Step 1: Find out how many parameters we're going to have.
3317      int numParams = Call.getNumberOfParams(s);
3318      int longParams = 0;
3319      for (int pNum = 0; pNum < numParams; pNum++) {
3320        if (Call.getParam(s, pNum).getType().isLongType()) {
3321          longParams++;
3322        }
3323      }
3324
3325      // Step 2: Figure out what the result and result2 values will be.
3326      RegisterOperand result = Call.getResult(s);
3327      RegisterOperand result2 = null;
3328      if (result != null && result.getType().isLongType()) {
3329        result.setType(TypeReference.Int);
3330        result2 = new RegisterOperand(regpool.getSecondReg(result.getRegister()), TypeReference.Int);
3331      }
3332
3333      // Step 3: Mutate the Call to an MIR_Call.
3334      // Note MIR_Call and Call have a different number of fixed
3335      // arguments, so some amount of copying is required.
3336      Operand[] params = new Operand[numParams];
3337      for (int i = 0; i < numParams; i++) {
3338        params[i] = Call.getParam(s, i);
3339      }
3340      MIR_Call.mutate(s, IA32_CALL, result, result2, address, Call.getMethod(s), numParams + longParams);
3341      for (int paramIdx = 0, mirCallIdx = 0; paramIdx < numParams;) {
3342        Operand param = params[paramIdx++];
3343        if (param instanceof RegisterOperand) {
3344          RegisterOperand rparam = (RegisterOperand) param;
3345          MIR_Call.setParam(s, mirCallIdx++, rparam);
3346          if (rparam.getType().isLongType()) {
3347            rparam.setType(TypeReference.Int);
3348            MIR_Call.setParam(s, mirCallIdx - 1, rparam);
3349            MIR_Call.setParam(s, mirCallIdx++,
3350              new RegisterOperand(regpool.getSecondReg(rparam.getRegister()), TypeReference.Int));
3351          }
3352        } else if (param instanceof LongConstantOperand) {
3353          LongConstantOperand val = (LongConstantOperand) param;
3354          MIR_Call.setParam(s, mirCallIdx++, IC(val.upper32()));
3355          MIR_Call.setParam(s, mirCallIdx++, IC(val.lower32()));
3356        } else {
3357          MIR_Call.setParam(s, mirCallIdx++, param);
3358        }
3359      }
3360    } else {
3361      MIR_Call.mutate(s, IA32_CALL, Call.getResult(s), null,
3362          address, Call.getMethod(s), Call.getNumberOfParams(s));
3363    }
3364
3365    // emit the call instruction.
3366    EMIT(s);
3367  }
3368
3369  /**
3370   * Expansion of SYSCALL. Expand longs registers into pairs of int registers.
3371   *
3372   * @param s the instruction to expand
3373   * @param address the operand containing the target address
3374   */
3375  protected final void SYSCALL(Instruction s, Operand address) {
3376    burs.ir.setHasSysCall(true);
3377
3378    if (VM.BuildFor32Addr) {
3379      // Step 1: Find out how many parameters we're going to have.
3380      int numParams = Call.getNumberOfParams(s);
3381      int longParams = 0;
3382      for (int pNum = 0; pNum < numParams; pNum++) {
3383        if (Call.getParam(s, pNum).getType().isLongType()) {
3384          longParams++;
3385        }
3386      }
3387
3388      // Step 2: Figure out what the result and result2 values will be.
3389      RegisterOperand result = Call.getResult(s);
3390      RegisterOperand result2 = null;
3391      // NOTE: C callee returns longs little endian!
3392      if (result != null && result.getType().isLongType()) {
3393        result.setType(TypeReference.Int);
3394        result2 = result;
3395        result = new RegisterOperand(regpool.getSecondReg(result.getRegister()), TypeReference.Int);
3396      }
3397
3398      // Step 3: Mutate the Call to an MIR_Call.
3399      // Note MIR_Call and Call have a different number of fixed
3400      // arguments, so some amount of copying is required.
3401      Operand[] params = new Operand[numParams];
3402      for (int i = 0; i < numParams; i++) {
3403        params[i] = Call.getParam(s, i);
3404      }
3405      MIR_Call.mutate(s, IA32_SYSCALL, result, result2, address, Call
3406          .getMethod(s), numParams + longParams);
3407      for (int paramIdx = 0, mirCallIdx = 0; paramIdx < numParams;) {
3408        Operand param = params[paramIdx++];
3409        if (param instanceof RegisterOperand) {
3410          // NOTE: longs passed little endian to C callee!
3411          RegisterOperand rparam = (RegisterOperand) param;
3412          if (rparam.getType().isLongType()) {
3413            rparam.setType(TypeReference.Int);
3414            MIR_Call.setParam(s, mirCallIdx++,
3415              new RegisterOperand(regpool.getSecondReg(rparam.getRegister()), TypeReference.Int));
3416          }
3417          MIR_Call.setParam(s, mirCallIdx++, param);
3418        } else if (param instanceof LongConstantOperand) {
3419          long value = ((LongConstantOperand) param).value;
3420          int valueHigh = (int) (value >> 32);
3421          int valueLow = (int) (value & 0xffffffff);
3422          // NOTE: longs passed little endian to C callee!
3423          MIR_Call.setParam(s, mirCallIdx++, IC(valueLow));
3424          MIR_Call.setParam(s, mirCallIdx++, IC(valueHigh));
3425        } else {
3426          MIR_Call.setParam(s, mirCallIdx++, param);
3427        }
3428      }
3429    } else {
3430      MIR_Call.mutate(s, IA32_SYSCALL, Call.getResult(s), null,
3431          address, Call.getMethod(s), Call.getNumberOfParams(s));
3432    }
3433
3434    // emit the call instruction.
3435    EMIT(s);
3436  }
3437
3438  /**
3439   * Expansion of LOWTABLESWITCH.
3440   *
3441   * @param s the instruction to expand
3442   */
3443  protected final void LOWTABLESWITCH(Instruction s) {
3444    // (1) We're changing index from a U to a DU.
3445    // Inject a fresh copy instruction to make sure we aren't
3446    // going to get into trouble (if someone else was also using index).
3447    RegisterOperand newIndex = regpool.makeTempInt();
3448    EMIT(CPOS(s, MIR_Move.create(IA32_MOV, newIndex, LowTableSwitch.getIndex(s))));
3449    RegisterOperand methodStart = regpool.makeTemp(TypeReference.Address);
3450    EMIT(CPOS(s, MIR_Nullary.create(IA32_METHODSTART, methodStart)));
3451    int number = LowTableSwitch.getNumberOfTargets(s);
3452    Instruction s2 = CPOS(s, MIR_LowTableSwitch.create(MIR_LOWTABLESWITCH, newIndex.copyRO(), methodStart.copyD2U(), number * 2));
3453    for (int i = 0; i < number; i++) {
3454      MIR_LowTableSwitch.setTarget(s2, i, LowTableSwitch.getTarget(s, i));
3455      MIR_LowTableSwitch.setBranchProfile(s2, i, LowTableSwitch
3456          .getBranchProfile(s, i));
3457    }
3458    EMIT(s2);
3459  }
3460
3461  /**
3462   * Expansion of RESOLVE. Dynamic link point. Build up MIR instructions for
3463   * Resolve.
3464   *
3465   * @param s the instruction to expand
3466   */
3467  protected final void RESOLVE(Instruction s) {
3468    Operand target = loadFromJTOC(Entrypoints.optResolveMethod.getOffset(), DW);
3469    EMIT(CPOS(s,
3470              MIR_Call.mutate0(s,
3471                               CALL_SAVE_VOLATILE,
3472                               null,
3473                               null,
3474                               target,
3475                               MethodOperand.STATIC(Entrypoints.optResolveMethod))));
3476  }
3477
3478  /**
3479   * Expansion of TRAP_IF, with an int constant as the second value.
3480   *
3481   * @param s the instruction to expand
3482   * @param longConstant is the argument a long constant?
3483   */
3484  protected final void TRAP_IF_IMM(Instruction s, boolean longConstant) {
3485    RegisterOperand gRes = TrapIf.getGuardResult(s);
3486    RegisterOperand v1 = (RegisterOperand) TrapIf.getVal1(s);
3487    ConstantOperand v2 = (ConstantOperand) TrapIf.getVal2(s);
3488    ConditionOperand cond = TrapIf.getCond(s);
3489    TrapCodeOperand tc = TrapIf.getTCode(s);
3490
3491    // A slightly ugly matter, but we need to deal with combining
3492    // the two pieces of a long register from a LONG_ZERO_CHECK.
3493    // A little awkward, but probably the easiest workaround...
3494    if (VM.BuildFor32Addr && longConstant) {
3495      if (VM.VerifyAssertions) {
3496        opt_assert((tc.getTrapCode() == RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO) &&
3497                   (((LongConstantOperand) v2).value == 0L));
3498      }
3499      RegisterOperand vr = v1.copyRO();
3500      vr.setType(TypeReference.Int);
3501      RegisterOperand rr = regpool.makeTempInt();
3502      EMIT(CPOS(s, MIR_Move.create(IA32_MOV, rr, vr)));
3503      EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR,
3504                                rr.copy(),
3505                                new RegisterOperand(regpool.getSecondReg(v1.getRegister()), TypeReference.Int))));
3506      v1 = rr.copyD2U();
3507      v2 = IC(0);
3508    }
3509    // emit the trap instruction
3510    EMIT(MIR_TrapIf.mutate(s, IA32_TRAPIF, gRes, v1, v2, COND(cond), tc));
3511  }
3512
3513  /**
3514   * This routine expands an ATTEMPT instruction into an atomic
3515   * compare exchange. The atomic compare and exchange will place at
3516   * mo the value of newValue if the value of mo is oldValue. The
3517   * result register is set to 0/1 depending on whether the valye was
3518   * replaced or not.
3519   *
3520   * @param result the register operand that is set to 0/1 as a result of the
3521   *          attempt
3522   * @param mo the address at which to attempt the exchange
3523   * @param oldValue the old value at the address mo
3524   * @param newValue the new value at the address mo
3525   */
3526  protected final void ATTEMPT(RegisterOperand result, MemoryOperand mo, Operand oldValue,
3527                               Operand newValue) {
3528    RegisterOperand temp = regpool.makeTempInt();
3529    RegisterOperand temp2 = regpool.makeTemp(result);
3530    EMIT(MIR_Move.create(IA32_MOV, temp, newValue));
3531    EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), oldValue));
3532    EMIT(MIR_CompareExchange.create(IA32_LOCK_CMPXCHG,
3533                                    new RegisterOperand(getEAX(), TypeReference.Int),
3534                                    mo,
3535                                    temp.copyRO()));
3536    EMIT(MIR_Set.create(IA32_SET__B, temp2, IA32ConditionOperand.EQ()));
3537    // need to zero-extend the result of the set
3538    EMIT(MIR_Unary.create(IA32_MOVZX__B, result, temp2.copy()));
3539  }
3540
3541  /**
3542   * This routine expands an ATTEMPT instruction into an atomic
3543   * compare exchange. The atomic compare and exchange will place at
3544   * mo the value of newValue if the value of mo is oldValue. The
3545   * result register is set to 0/1 depending on whether the valye was
3546   * replaced or not.
3547   *
3548   * @param result the register operand that is set to 0/1 as a result
3549   * of the attempt
3550   * @param mo       the address at which to attempt the exchange
3551   * @param oldValue the old value to check for at the address mo
3552   * @param newValue the new value to place at the address mo
3553   */
3554  protected final void ATTEMPT_LONG(RegisterOperand result,
3555                                    MemoryOperand mo,
3556                                    Operand oldValue,
3557                                    Operand newValue) {
3558    // Set up EDX:EAX with the old value
3559    if (oldValue.isRegister()) {
3560      Register oldValue_hval = oldValue.asRegister().getRegister();
3561      Register oldValue_lval = regpool.getSecondReg(oldValue_hval);
3562      EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int),
3563          new RegisterOperand(oldValue_hval, TypeReference.Int)));
3564      EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int),
3565          new RegisterOperand(oldValue_lval, TypeReference.Int)));
3566    } else {
3567      if (VM.VerifyAssertions) opt_assert(oldValue.isLongConstant());
3568      LongConstantOperand val = oldValue.asLongConstant();
3569      EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEDX(), TypeReference.Int),
3570          IC(val.upper32())));
3571      EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int),
3572          IC(val.lower32())));
3573    }
3574
3575    // Set up ECX:EBX with the new value
3576    if (newValue.isRegister()) {
3577      Register newValue_hval = newValue.asRegister().getRegister();
3578      Register newValue_lval = regpool.getSecondReg(newValue_hval);
3579      EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getECX(), TypeReference.Int),
3580          new RegisterOperand(newValue_hval, TypeReference.Int)));
3581      EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEBX(), TypeReference.Int),
3582          new RegisterOperand(newValue_lval, TypeReference.Int)));
3583    } else {
3584      if (VM.VerifyAssertions) opt_assert(newValue.isLongConstant());
3585      LongConstantOperand val = newValue.asLongConstant();
3586      EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getECX(), TypeReference.Int),
3587          IC(val.upper32())));
3588      EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEBX(), TypeReference.Int),
3589          IC(val.lower32())));
3590    }
3591
3592    EMIT(MIR_CompareExchange8B.create(IA32_LOCK_CMPXCHG8B,
3593         new RegisterOperand(getEDX(), TypeReference.Int),
3594         new RegisterOperand(getEAX(), TypeReference.Int),
3595         mo,
3596         new RegisterOperand(getECX(), TypeReference.Int),
3597         new RegisterOperand(getEBX(), TypeReference.Int)));
3598
3599    RegisterOperand temp = regpool.makeTemp(result);
3600    EMIT(MIR_Set.create(IA32_SET__B, temp, IA32ConditionOperand.EQ()));
3601    // need to zero-extend the result of the set
3602    EMIT(MIR_Unary.create(IA32_MOVZX__B, result, temp.copy()));
3603  }
3604
3605  /**
3606   * This routine expands the compound pattern IFCMP(ATTEMPT, ZERO) into an
3607   * atomic compare/exchange followed by a branch on success/failure of the
3608   * attempted atomic compare/exchange.
3609   *
3610   * @param mo the address at which to attempt the exchange
3611   * @param oldValue the old value at the address mo
3612   * @param newValue the new value at the address mo
3613   * @param cond the condition to branch on
3614   * @param target the branch target
3615   * @param bp the branch profile information
3616   */
3617  protected final void ATTEMPT_IFCMP(MemoryOperand mo, Operand oldValue, Operand newValue,
3618                                     ConditionOperand cond, BranchOperand target, BranchProfileOperand bp) {
3619    RegisterOperand temp = regpool.makeTempInt();
3620    EMIT(MIR_Move.create(IA32_MOV, temp, newValue));
3621    EMIT(MIR_Move.create(IA32_MOV, new RegisterOperand(getEAX(), TypeReference.Int), oldValue));
3622    EMIT(MIR_CompareExchange.create(IA32_LOCK_CMPXCHG,
3623                                    new RegisterOperand(getEAX(), TypeReference.Int),
3624                                    mo,
3625                                    temp.copyRO()));
3626    EMIT(MIR_CondBranch.create(IA32_JCC, COND(cond), target, bp));
3627  }
3628
3629  /**
3630   * special case handling OSR instructions expand long type variables to two
3631   * integers
3632   * @param burs the burs instance
3633   * @param s an OSRPoint instruction
3634   */
3635  protected void OSR(BURS burs, Instruction s) {
3636    if (VM.VerifyAssertions) {
3637      opt_assert(OsrPoint.conforms(s));
3638    }
3639
3640    // Check type info first because this needs to be done
3641    // for both 32-bit and 64-bit cases.
3642    InlinedOsrTypeInfoOperand typeInfo;
3643    if (VM.BuildFor32Addr) {
3644      // Clearing type info is ok, because instruction will be mutated and the
3645      // info will be reinserted
3646      typeInfo = OsrPoint.getClearInlinedTypeInfo(s);
3647    } else {
3648      // Instruction won't be changed so info needs to be left in
3649      typeInfo = OsrPoint.getInlinedTypeInfo(s);
3650    }
3651
3652    if (VM.VerifyAssertions) {
3653      if (typeInfo == null) {
3654        VM.sysWriteln("OsrPoint " + s + " has a <null> type info:");
3655        VM.sysWriteln("  position :" + s.bcIndex + "@" + s.position.method);
3656      }
3657      opt_assert(typeInfo != null);
3658    }
3659
3660    int numparam = OsrPoint.getNumberOfElements(s);
3661
3662    if (VM.BuildFor32Addr) {
3663      // 1. how many params
3664      int numlong = 0;
3665      for (int i = 0; i < numparam; i++) {
3666        Operand param = OsrPoint.getElement(s, i);
3667        if (param.getType().isLongType()) {
3668          numlong++;
3669        }
3670      }
3671
3672      // 2. collect params
3673      Operand[] params = new Operand[numparam];
3674      for (int i = 0; i < numparam; i++) {
3675        params[i] = OsrPoint.getClearElement(s, i);
3676      }
3677
3678      // set the number of valid params in osr type info, used
3679      // in LinearScan
3680      typeInfo.validOps = numparam;
3681
3682      // 3: only makes second half register of long being used
3683      // creates room for long types.
3684      burs.append(OsrPoint.mutate(s, s.operator(), typeInfo, numparam + numlong));
3685
3686      int pidx = numparam;
3687      for (int i = 0; i < numparam; i++) {
3688        Operand param = params[i];
3689        OsrPoint.setElement(s, i, param);
3690        if (param instanceof RegisterOperand) {
3691          RegisterOperand rparam = (RegisterOperand) param;
3692          // the second half is appended at the end
3693          // LinearScan will update the map.
3694          if (rparam.getType().isLongType()) {
3695            OsrPoint.setElement(s, pidx++, L(burs.ir.regpool
3696                .getSecondReg(rparam.getRegister())));
3697          }
3698        } else if (param instanceof LongConstantOperand) {
3699          LongConstantOperand val = (LongConstantOperand) param;
3700
3701          if (VM.TraceOnStackReplacement) {
3702            VM.sysWriteln("caught a long const " + val);
3703          }
3704
3705          OsrPoint.setElement(s, i, IC(val.upper32()));
3706          OsrPoint.setElement(s, pidx++, IC(val.lower32()));
3707        } else if (param instanceof IntConstantOperand) {
3708        } else {
3709          throw new OptimizingCompilerException("BURS_Helpers", "unexpected parameter type" + param);
3710        }
3711      }
3712
3713      if (pidx != (numparam + numlong)) {
3714        VM.sysWriteln("pidx = " + pidx);
3715        VM.sysWriteln("numparam = " + numparam);
3716        VM.sysWriteln("numlong = " + numlong);
3717      }
3718
3719      if (VM.VerifyAssertions) {
3720        opt_assert(pidx == (numparam + numlong));
3721      }
3722    } else {
3723      // set the number of valid params in osr type info, used
3724      // in LinearScan
3725      typeInfo.validOps = numparam;
3726
3727      burs.append(s);
3728   }
3729  }
3730}