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