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