001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.lir2mir.ia32;
014
015import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_2INT_opcode;
016import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_2LONG_opcode;
017import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_IFCMP_opcode;
018import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_2INT_opcode;
019import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_2LONG_opcode;
020import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_IFCMP_opcode;
021import static org.jikesrvm.compilers.opt.ir.Operators.LONG_IFCMP_opcode;
022import static org.jikesrvm.compilers.opt.ir.Operators.LONG_MUL_opcode;
023import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHL_opcode;
024import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHR_opcode;
025import static org.jikesrvm.compilers.opt.ir.Operators.LONG_USHR_opcode;
026import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ADD;
027import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CMP;
028import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CVTTSD2SI;
029import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_CVTTSS2SI;
030import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FISTP;
031import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLD;
032import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FLDCW;
033import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FNSTCW;
034import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FSTP;
035import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FUCOMIP;
036import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_IMUL2;
037import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_JCC;
038import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_JCC2;
039import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_JMP;
040import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOV;
041import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSD;
042import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSS;
043import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVZX__W;
044import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOV_opcode;
045import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MUL;
046import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_NOT;
047import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_OR;
048import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SAR;
049import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHL;
050import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHLD;
051import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHR;
052import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHRD;
053import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_TEST;
054import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_UCOMISD;
055import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_UCOMISS;
056import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_XOR;
057import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IMMQ_MOV;
058import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IMMQ_MOV_opcode;
059
060import java.util.Enumeration;
061
062import org.jikesrvm.VM;
063import org.jikesrvm.classloader.TypeReference;
064import org.jikesrvm.compilers.opt.DefUse;
065import org.jikesrvm.compilers.opt.OptimizingCompilerException;
066import org.jikesrvm.compilers.opt.ir.BBend;
067import org.jikesrvm.compilers.opt.ir.BasicBlock;
068import org.jikesrvm.compilers.opt.ir.Binary;
069import org.jikesrvm.compilers.opt.ir.IR;
070import org.jikesrvm.compilers.opt.ir.IRTools;
071import org.jikesrvm.compilers.opt.ir.IfCmp;
072import org.jikesrvm.compilers.opt.ir.Instruction;
073import org.jikesrvm.compilers.opt.ir.Label;
074import org.jikesrvm.compilers.opt.ir.Register;
075import org.jikesrvm.compilers.opt.ir.Unary;
076import org.jikesrvm.compilers.opt.ir.ia32.MIR_BinaryAcc;
077import org.jikesrvm.compilers.opt.ir.ia32.MIR_Branch;
078import org.jikesrvm.compilers.opt.ir.ia32.MIR_Compare;
079import org.jikesrvm.compilers.opt.ir.ia32.MIR_CondBranch;
080import org.jikesrvm.compilers.opt.ir.ia32.MIR_CondBranch2;
081import org.jikesrvm.compilers.opt.ir.ia32.MIR_DoubleShift;
082import org.jikesrvm.compilers.opt.ir.ia32.MIR_Move;
083import org.jikesrvm.compilers.opt.ir.ia32.MIR_Multiply;
084import org.jikesrvm.compilers.opt.ir.ia32.MIR_Test;
085import org.jikesrvm.compilers.opt.ir.ia32.MIR_Unary;
086import org.jikesrvm.compilers.opt.ir.ia32.MIR_UnaryAcc;
087import org.jikesrvm.compilers.opt.ir.ia32.MIR_UnaryNoRes;
088import org.jikesrvm.compilers.opt.ir.ia32.PhysicalRegisterSet;
089import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
090import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
091import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
092import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
093import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
094import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
095import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
096import org.jikesrvm.compilers.opt.ir.operand.Operand;
097import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
098import org.jikesrvm.compilers.opt.ir.operand.StackLocationOperand;
099import org.jikesrvm.compilers.opt.ir.operand.ia32.IA32ConditionOperand;
100import org.jikesrvm.runtime.Entrypoints;
101import org.jikesrvm.util.Bits;
102
103/**
104 * Handles the conversion from LIR to MIR of operators whose
105 * expansion requires the introduction of new control flow (new basic blocks).
106 */
107public abstract class ComplexLIR2MIRExpansion extends IRTools {
108
109  /**
110   * Converts the given IR to low level IA32 IR.
111   *
112   * @param ir IR to convert
113   */
114  public static void convert(IR ir) {
115    Instruction nextInstr;
116    for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = nextInstr) {
117      switch (s.getOpcode()) {
118        case FLOAT_IFCMP_opcode:
119        case DOUBLE_IFCMP_opcode:
120          nextInstr = fp_ifcmp(s);
121          break;
122        case FLOAT_2INT_opcode:
123          nextInstr = float_2int(s, ir);
124          break;
125        case FLOAT_2LONG_opcode:
126          nextInstr = float_2long(s, ir);
127          break;
128        case DOUBLE_2INT_opcode:
129          nextInstr = double_2int(s, ir);
130          break;
131        case DOUBLE_2LONG_opcode:
132          nextInstr = double_2long(s, ir);
133          break;
134
135        // long operations. Expand them into other operations
136        // for 32-bit addressing and leave them unchanged for
137        // 64-bit addressing.
138
139        case LONG_MUL_opcode:
140          if (VM.BuildFor32Addr) {
141            nextInstr = long_mul(s, ir);
142            break;
143          }
144          // Fall through
145        case LONG_SHL_opcode:
146          if (VM.BuildFor32Addr) {
147            nextInstr = long_shl(s, ir);
148            break;
149          }
150          // Fall through
151        case LONG_SHR_opcode:
152          if (VM.BuildFor32Addr) {
153            nextInstr = long_shr(s, ir);
154            break;
155          }
156          // Fall through
157        case LONG_USHR_opcode:
158          if (VM.BuildFor32Addr) {
159            nextInstr = long_ushr(s, ir);
160            break;
161          }
162          // Fall through
163        case LONG_IFCMP_opcode: {
164          if (VM.BuildFor32Addr) {
165            Operand val2 = IfCmp.getVal2(s);
166            if (val2 instanceof RegisterOperand) {
167              nextInstr = long_ifcmp(s, ir);
168            } else {
169              nextInstr = long_ifcmp_imm(s, ir);
170            }
171            break;
172          }
173          // Fall through
174        }
175        default:
176          nextInstr = s.nextInstructionInCodeOrder();
177          break;
178      }
179    }
180    DefUse.recomputeSpansBasicBlock(ir);
181  }
182
183  private static Instruction float_2int(Instruction s, IR ir) {
184    Instruction nextInstr = s.nextInstructionInCodeOrder();
185    while (Label.conforms(nextInstr) || BBend.conforms(nextInstr))  {
186      nextInstr = nextInstr.nextInstructionInCodeOrder();
187    }
188    // we need 6 basic blocks (in code order)
189    // 1: the current block that does a test to see if this is a regular f2i or
190    //    branches to the maxint/NaN case
191    // 2: a block to perform a regular f2i
192    // 3: a block to test for NaN
193    // 4: a block to perform give maxint
194    // 5: a block to perform NaN
195    // 6: the next basic block
196    BasicBlock testBB = s.getBasicBlock();
197    BasicBlock nextBB = testBB.splitNodeAt(s,ir);
198    ir.cfg.linkInCodeOrder(testBB, nextBB);
199    BasicBlock nanBB = testBB.splitNodeAt(s,ir);
200    ir.cfg.linkInCodeOrder(testBB, nanBB);
201    BasicBlock maxintBB = testBB.splitNodeAt(s,ir);
202    ir.cfg.linkInCodeOrder(testBB, maxintBB);
203    BasicBlock nanTestBB = testBB.splitNodeAt(s,ir);
204    ir.cfg.linkInCodeOrder(testBB, nanTestBB);
205    BasicBlock f2iBB = testBB.splitNodeAt(s,ir);
206    ir.cfg.linkInCodeOrder(testBB, f2iBB);
207
208    // Move the maxintFloat value and the value into registers and compare and
209    // branch if they are <= or unordered. NB we don't use a memory operand as
210    // that would require 2 jccs
211    RegisterOperand result = Unary.getResult(s);
212    RegisterOperand value = Unary.getVal(s).asRegister();
213    MemoryOperand maxint = BURS_Helpers.loadFromJTOC(Entrypoints.maxintFloatField.getOffset(), (byte)4);
214    RegisterOperand maxintReg = ir.regpool.makeTempFloat();
215    s.insertBefore(CPOS(s,MIR_Move.create(IA32_MOVSS, maxintReg, maxint)));
216    MIR_Compare.mutate(s, IA32_UCOMISS, maxintReg.copyRO(), value);
217    testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
218        IA32ConditionOperand.LLE(),
219        nanTestBB.makeJumpTarget(),
220        BranchProfileOperand.unlikely())));
221    testBB.insertOut(f2iBB);
222    testBB.insertOut(nanTestBB);
223
224    // Convert float to int knowing that if the value is < min int the Intel
225    // unspecified result is min int
226    f2iBB.appendInstruction(CPOS(s, MIR_Unary.create(IA32_CVTTSS2SI, result, value.copy())));
227    f2iBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
228        nextBB.makeJumpTarget())));
229    f2iBB.insertOut(nextBB);
230
231    // Did the compare find a NaN or a maximum integer?
232    nanTestBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
233        IA32ConditionOperand.PE(),
234        nanBB.makeJumpTarget(),
235        BranchProfileOperand.unlikely())));
236    nanTestBB.insertOut(nanBB);
237    nanTestBB.insertOut(maxintBB);
238
239    // Value was >= max integer
240    maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
241                                                       result.copyRO(),
242                                                       IC(Integer.MAX_VALUE))));
243    maxintBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
244        nextBB.makeJumpTarget())));
245    maxintBB.insertOut(nextBB);
246
247    // In case of NaN result is 0
248    nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
249                                                    result.copyRO(),
250                                                    IC(0))));
251    nanBB.insertOut(nextBB);
252    return nextInstr;
253  }
254
255  private static PhysicalRegisterSet phys(IR ir) {
256    return ir.regpool.getPhysicalRegisterSet().asIA32();
257  }
258
259  private static Instruction float_2long(Instruction s, IR ir) {
260    Instruction nextInstr = s.nextInstructionInCodeOrder();
261    while (Label.conforms(nextInstr) || BBend.conforms(nextInstr))  {
262      nextInstr = nextInstr.nextInstructionInCodeOrder();
263    }
264    // we need 6 basic blocks (in code order)
265    // 1: the current block that does a test to see if this is a regular f2l or
266    //    branches to the maxint/NaN case
267    // 2: a block to perform a regular f2l
268    // 3: a block to test for NaN
269    // 4: a block to perform give maxint
270    // 5: a block to perform NaN
271    // 6: the next basic block
272    BasicBlock testBB = s.getBasicBlock();
273    BasicBlock nextBB = testBB.splitNodeAt(s,ir);
274    ir.cfg.linkInCodeOrder(testBB, nextBB);
275    BasicBlock nanBB = testBB.splitNodeAt(s,ir);
276    ir.cfg.linkInCodeOrder(testBB, nanBB);
277    BasicBlock maxintBB = testBB.splitNodeAt(s,ir);
278    ir.cfg.linkInCodeOrder(testBB, maxintBB);
279    BasicBlock nanTestBB = testBB.splitNodeAt(s,ir);
280    ir.cfg.linkInCodeOrder(testBB, nanTestBB);
281    BasicBlock f2lBB = testBB.splitNodeAt(s,ir);
282    ir.cfg.linkInCodeOrder(testBB, f2lBB);
283
284    if (VM.BuildFor32Addr) {
285      // Move the maxlongFloat value and the value into x87 registers and compare and
286      // branch if they are <= or unordered.
287      RegisterOperand resultHi = Unary.getResult(s);
288      resultHi.setType(TypeReference.Int);
289      RegisterOperand resultLo = new RegisterOperand(ir.regpool.getSecondReg(resultHi.getRegister()),
290          TypeReference.Int);
291      RegisterOperand value = Unary.getVal(s).asRegister();
292      RegisterOperand cw = ir.regpool.makeTempInt();
293      MemoryOperand maxlong = BURS_Helpers.loadFromJTOC(Entrypoints.maxlongFloatField.getOffset(), (byte)4);
294      RegisterOperand st0 = new RegisterOperand(phys(ir).getST0(),
295          TypeReference.Float);
296      RegisterOperand st1 = new RegisterOperand(phys(ir).getST1(),
297          TypeReference.Float);
298      int offset = -ir.stackManager.allocateSpaceForConversion();
299      StackLocationOperand slLo = new StackLocationOperand(true, offset, 4);
300      StackLocationOperand slHi = new StackLocationOperand(true, offset + 4, 4);
301      StackLocationOperand sl = new StackLocationOperand(true, offset, 8);
302      MemoryOperand scratchLo = new MemoryOperand(ir.regpool.makeTROp(), null, (byte)0,
303          Entrypoints.scratchStorageField.getOffset(), (byte)4,
304          new LocationOperand(Entrypoints.scratchStorageField), null);
305      MemoryOperand scratchHi = new MemoryOperand(ir.regpool.makeTROp(), null, (byte)0,
306          Entrypoints.scratchStorageField.getOffset().plus(4), (byte)4,
307          new LocationOperand(Entrypoints.scratchStorageField), null);
308
309      s.insertBefore(CPOS(s, MIR_Move.create(IA32_MOVSS, slLo, value)));
310      s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0, slLo.copy())));
311      s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0.copyRO(), maxlong)));
312      MIR_Compare.mutate(s, IA32_FUCOMIP, st0.copyRO(), st1);
313      testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
314          IA32ConditionOperand.LLE(),
315          nanTestBB.makeJumpTarget(),
316          BranchProfileOperand.unlikely())));
317      testBB.insertOut(f2lBB);
318      testBB.insertOut(nanTestBB);
319
320      // Convert float to long knowing that if the value is < min long the Intel
321      // unspecified result is min long
322      // TODO: this would be a lot simpler and faster with SSE3's FISTTP instruction
323      f2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FNSTCW, scratchLo.copy())));
324      f2lBB.appendInstruction(CPOS(s, MIR_Unary.create(IA32_MOVZX__W, cw, scratchLo.copy())));
325      f2lBB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_OR, cw, IC(0xC00))));
326      f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, scratchHi, cw.copyRO())));
327      f2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchHi.copy())));
328      f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FISTP, sl, st0.copyRO())));
329      f2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchLo.copy())));
330      f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultLo, slLo.copy())));
331      f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultHi, slHi)));
332      f2lBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
333          nextBB.makeJumpTarget())));
334      f2lBB.insertOut(nextBB);
335
336      // Did the compare find a NaN or a maximum integer?
337      nanTestBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FSTP, st0.copyRO(), st0.copyRO())));
338      nanTestBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
339          IA32ConditionOperand.PE(),
340          nanBB.makeJumpTarget(),
341          BranchProfileOperand.unlikely())));
342      nanTestBB.insertOut(nanBB);
343      nanTestBB.insertOut(maxintBB);
344
345      // Value was >= max long
346      maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
347          resultLo.copyRO(),
348          IC((int)Long.MAX_VALUE))));
349      maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
350          resultHi.copyRO(),
351          IC((int)(Long.MAX_VALUE >>> 32)))));
352      maxintBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
353          nextBB.makeJumpTarget())));
354      maxintBB.insertOut(nextBB);
355
356      // In case of NaN result is 0
357      nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
358          resultLo.copyRO(),
359          IC(0))));
360      nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
361          resultHi.copyRO(),
362          IC(0))));
363      nanBB.insertOut(nextBB);
364    } else {
365      // Move the maxlongFloat value and the value into x87 registers and compare and
366      // branch if they are <= or unordered.
367      RegisterOperand result = Unary.getResult(s);
368      result.setType(TypeReference.Long);
369      RegisterOperand value = Unary.getVal(s).asRegister();
370      RegisterOperand cw = ir.regpool.makeTempInt();
371      MemoryOperand maxlong = BURS_Helpers.loadFromJTOC(Entrypoints.maxlongFloatField.getOffset(), (byte)4);
372      RegisterOperand st0 = new RegisterOperand(phys(ir).getST0(),
373          TypeReference.Float);
374      RegisterOperand st1 = new RegisterOperand(phys(ir).getST1(),
375          TypeReference.Float);
376      int offset = -ir.stackManager.allocateSpaceForConversion();
377      StackLocationOperand sl = new StackLocationOperand(true, offset, 8);
378      MemoryOperand scratchLo = new MemoryOperand(ir.regpool.makeTROp(), null, (byte)0,
379          Entrypoints.scratchStorageField.getOffset(), (byte)4,
380          new LocationOperand(Entrypoints.scratchStorageField), null);
381      MemoryOperand scratchHi = new MemoryOperand(ir.regpool.makeTROp(), null, (byte)0,
382          Entrypoints.scratchStorageField.getOffset().plus(4), (byte)4,
383          new LocationOperand(Entrypoints.scratchStorageField), null);
384
385      s.insertBefore(CPOS(s, MIR_Move.create(IA32_MOVSS, sl, value)));
386      s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0, sl.copy())));
387      s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0.copyRO(), maxlong)));
388      MIR_Compare.mutate(s, IA32_FUCOMIP, st0.copyRO(), st1);
389      testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
390          IA32ConditionOperand.LLE(),
391          nanTestBB.makeJumpTarget(),
392          BranchProfileOperand.unlikely())));
393      testBB.insertOut(f2lBB);
394      testBB.insertOut(nanTestBB);
395
396      // Convert float to long knowing that if the value is < min long the Intel
397      // unspecified result is min long
398      // TODO: this would be a lot simpler and faster with SSE3's FISTTP instruction
399      f2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FNSTCW, scratchLo.copy())));
400      f2lBB.appendInstruction(CPOS(s, MIR_Unary.create(IA32_MOVZX__W, cw, scratchLo.copy())));
401      f2lBB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_OR, cw, IC(0xC00))));
402      f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, scratchHi, cw.copyRO())));
403      f2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchHi.copy())));
404      f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FISTP, sl, st0.copyRO())));
405      f2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchLo.copy())));
406      f2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, result, sl.copy())));
407      f2lBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
408          nextBB.makeJumpTarget())));
409      f2lBB.insertOut(nextBB);
410
411      // Did the compare find a NaN or a maximum integer?
412      nanTestBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FSTP, st0.copyRO(), st0.copyRO())));
413      nanTestBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
414          IA32ConditionOperand.PE(),
415          nanBB.makeJumpTarget(),
416          BranchProfileOperand.unlikely())));
417      nanTestBB.insertOut(nanBB);
418      nanTestBB.insertOut(maxintBB);
419
420      // Value was >= max long
421      maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
422          result.copyRO(),
423          LC(Long.MAX_VALUE))));
424      maxintBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
425          nextBB.makeJumpTarget())));
426      maxintBB.insertOut(nextBB);
427
428      // In case of NaN result is 0
429      nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
430          result.copyRO(),
431          LC(0))));
432      nanBB.insertOut(nextBB);
433    }
434    return nextInstr;
435  }
436
437  private static Instruction double_2int(Instruction s, IR ir) {
438    Instruction nextInstr = s.nextInstructionInCodeOrder();
439    while (Label.conforms(nextInstr) || BBend.conforms(nextInstr))  {
440      nextInstr = nextInstr.nextInstructionInCodeOrder();
441    }
442    // we need 6 basic blocks (in code order)
443    // 1: the current block that does a test to see if this is a regular d2i or
444    //    branches to the maxint/NaN case
445    // 2: a block to perform a regular d2i
446    // 3: a block to test for NaN
447    // 4: a block to perform give maxint
448    // 5: a block to perform NaN
449    // 6: the next basic block
450    BasicBlock testBB = s.getBasicBlock();
451    BasicBlock nextBB = testBB.splitNodeAt(s,ir);
452    ir.cfg.linkInCodeOrder(testBB, nextBB);
453    BasicBlock nanBB = testBB.splitNodeAt(s,ir);
454    ir.cfg.linkInCodeOrder(testBB, nanBB);
455    BasicBlock maxintBB = testBB.splitNodeAt(s,ir);
456    ir.cfg.linkInCodeOrder(testBB, maxintBB);
457    BasicBlock nanTestBB = testBB.splitNodeAt(s,ir);
458    ir.cfg.linkInCodeOrder(testBB, nanTestBB);
459    BasicBlock d2iBB = testBB.splitNodeAt(s,ir);
460    ir.cfg.linkInCodeOrder(testBB, d2iBB);
461
462    // Move the maxint value and the value into registers and compare and
463    // branch if they are <= or unordered. NB we don't use a memory operand as
464    // that would require 2 jccs
465    RegisterOperand result = Unary.getResult(s);
466    RegisterOperand value = Unary.getVal(s).asRegister();
467    MemoryOperand maxint = BURS_Helpers.loadFromJTOC(Entrypoints.maxintField.getOffset(), (byte)8);
468    RegisterOperand maxintReg = ir.regpool.makeTempFloat();
469    s.insertBefore(CPOS(s,MIR_Move.create(IA32_MOVSD, maxintReg, maxint)));
470    MIR_Compare.mutate(s, IA32_UCOMISD, maxintReg.copyRO(), value);
471    testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
472        IA32ConditionOperand.LLE(),
473        nanTestBB.makeJumpTarget(),
474        BranchProfileOperand.unlikely())));
475    testBB.insertOut(d2iBB);
476    testBB.insertOut(nanTestBB);
477
478    // Convert float to int knowing that if the value is < min int the Intel
479    // unspecified result is min int
480    d2iBB.appendInstruction(CPOS(s, MIR_Unary.create(IA32_CVTTSD2SI, result, value.copy())));
481    d2iBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
482        nextBB.makeJumpTarget())));
483    d2iBB.insertOut(nextBB);
484
485    // Did the compare find a NaN or a maximum integer?
486    nanTestBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
487        IA32ConditionOperand.PE(),
488        nanBB.makeJumpTarget(),
489        BranchProfileOperand.unlikely())));
490    nanTestBB.insertOut(nanBB);
491    nanTestBB.insertOut(maxintBB);
492
493    // Value was >= max integer
494    maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
495                                                       result.copyRO(),
496                                                       IC(Integer.MAX_VALUE))));
497    maxintBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
498        nextBB.makeJumpTarget())));
499    maxintBB.insertOut(nextBB);
500
501    // In case of NaN result is 0
502    nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
503                                                    result.copyRO(),
504                                                    IC(0))));
505    nanBB.insertOut(nextBB);
506    return nextInstr;
507  }
508
509  private static Instruction double_2long(Instruction s, IR ir) {
510    Instruction nextInstr = s.nextInstructionInCodeOrder();
511    while (Label.conforms(nextInstr) || BBend.conforms(nextInstr))  {
512      nextInstr = nextInstr.nextInstructionInCodeOrder();
513    }
514    // we need 6 basic blocks (in code order)
515    // 1: the current block that does a test to see if this is a regular f2l or
516    //    branches to the maxint/NaN case
517    // 2: a block to perform a regular f2l
518    // 3: a block to test for NaN
519    // 4: a block to perform give maxint
520    // 5: a block to perform NaN
521    // 6: the next basic block
522    BasicBlock testBB = s.getBasicBlock();
523    BasicBlock nextBB = testBB.splitNodeAt(s,ir);
524    ir.cfg.linkInCodeOrder(testBB, nextBB);
525    BasicBlock nanBB = testBB.splitNodeAt(s,ir);
526    ir.cfg.linkInCodeOrder(testBB, nanBB);
527    BasicBlock maxintBB = testBB.splitNodeAt(s,ir);
528    ir.cfg.linkInCodeOrder(testBB, maxintBB);
529    BasicBlock nanTestBB = testBB.splitNodeAt(s,ir);
530    ir.cfg.linkInCodeOrder(testBB, nanTestBB);
531    BasicBlock d2lBB = testBB.splitNodeAt(s,ir);
532    ir.cfg.linkInCodeOrder(testBB, d2lBB);
533
534    // Move the maxlongFloat value and the value into x87 registers and compare and
535    // branch if they are <= or unordered.
536    if (VM.BuildFor32Addr) {
537      RegisterOperand resultHi = Unary.getResult(s);
538      resultHi.setType(TypeReference.Int);
539      RegisterOperand resultLo = new RegisterOperand(ir.regpool.getSecondReg(resultHi.getRegister()),
540          TypeReference.Int);
541      RegisterOperand value = Unary.getVal(s).asRegister();
542      RegisterOperand cw = ir.regpool.makeTempInt();
543      MemoryOperand maxlong = BURS_Helpers.loadFromJTOC(Entrypoints.maxlongField.getOffset(), (byte)8);
544      RegisterOperand st0 = new RegisterOperand(phys(ir).getST0(),
545          TypeReference.Double);
546      RegisterOperand st1 = new RegisterOperand(phys(ir).getST1(),
547          TypeReference.Double);
548      int offset = -ir.stackManager.allocateSpaceForConversion();
549      StackLocationOperand slLo = new StackLocationOperand(true, offset, 4);
550      StackLocationOperand slHi = new StackLocationOperand(true, offset + 4, 4);
551      StackLocationOperand sl = new StackLocationOperand(true, offset, 8);
552      MemoryOperand scratchLo = new MemoryOperand(ir.regpool.makeTROp(), null, (byte)0,
553          Entrypoints.scratchStorageField.getOffset(), (byte)4,
554          new LocationOperand(Entrypoints.scratchStorageField), null);
555      MemoryOperand scratchHi = new MemoryOperand(ir.regpool.makeTROp(), null, (byte)0,
556          Entrypoints.scratchStorageField.getOffset().plus(4), (byte)4,
557          new LocationOperand(Entrypoints.scratchStorageField), null);
558
559      s.insertBefore(CPOS(s, MIR_Move.create(IA32_MOVSD, sl, value)));
560      s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0, sl.copy())));
561      s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0.copyRO(), maxlong)));
562      MIR_Compare.mutate(s, IA32_FUCOMIP, st0.copyRO(), st1);
563      testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
564          IA32ConditionOperand.LLE(),
565          nanTestBB.makeJumpTarget(),
566          BranchProfileOperand.unlikely())));
567      testBB.insertOut(d2lBB);
568      testBB.insertOut(nanTestBB);
569
570      // Convert double to long knowing that if the value is < min long the Intel
571      // unspecified result is min long
572      // TODO: this would be a lot simpler and faster with SSE3's FISTTP instruction
573      d2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FNSTCW, scratchLo.copy())));
574      d2lBB.appendInstruction(CPOS(s, MIR_Unary.create(IA32_MOVZX__W, cw, scratchLo.copy())));
575      d2lBB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_OR, cw, IC(0xC00))));
576      d2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, scratchHi, cw.copyRO())));
577      d2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchHi.copy())));
578      d2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FISTP, sl.copy(), st0.copyRO())));
579      d2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchLo.copy())));
580      d2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultLo, slLo)));
581      d2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, resultHi, slHi)));
582      d2lBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
583          nextBB.makeJumpTarget())));
584      d2lBB.insertOut(nextBB);
585
586      // Did the compare find a NaN or a maximum integer?
587      nanTestBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FSTP, st0.copyRO(), st0.copyRO())));
588      nanTestBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
589          IA32ConditionOperand.PE(),
590          nanBB.makeJumpTarget(),
591          BranchProfileOperand.unlikely())));
592      nanTestBB.insertOut(nanBB);
593      nanTestBB.insertOut(maxintBB);
594
595      // Value was >= max long
596      maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
597          resultLo.copyRO(),
598          IC((int)Long.MAX_VALUE))));
599      maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
600          resultHi.copyRO(),
601          IC((int)(Long.MAX_VALUE >>> 32)))));
602      maxintBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
603          nextBB.makeJumpTarget())));
604      maxintBB.insertOut(nextBB);
605
606      // In case of NaN result is 0
607      nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
608          resultLo.copyRO(),
609          IC(0))));
610      nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
611          resultHi.copyRO(),
612          IC(0))));
613      nanBB.insertOut(nextBB);
614      return nextInstr;
615    } else {
616      RegisterOperand result = Unary.getResult(s);
617      RegisterOperand value = Unary.getVal(s).asRegister();
618      RegisterOperand cw = ir.regpool.makeTempInt();
619      MemoryOperand maxlong = BURS_Helpers.loadFromJTOC(Entrypoints.maxlongField.getOffset(), (byte)8);
620      RegisterOperand st0 = new RegisterOperand(phys(ir).getST0(),
621          TypeReference.Double);
622      RegisterOperand st1 = new RegisterOperand(phys(ir).getST1(),
623          TypeReference.Double);
624      int offset = -ir.stackManager.allocateSpaceForConversion();
625      StackLocationOperand sl = new StackLocationOperand(true, offset, 8);
626      MemoryOperand scratchLo = new MemoryOperand(ir.regpool.makeTROp(), null, (byte)0,
627              Entrypoints.scratchStorageField.getOffset(), (byte)4,
628              new LocationOperand(Entrypoints.scratchStorageField), null);
629      MemoryOperand scratchHi = new MemoryOperand(ir.regpool.makeTROp(), null, (byte)0,
630              Entrypoints.scratchStorageField.getOffset().plus(4), (byte)4,
631              new LocationOperand(Entrypoints.scratchStorageField), null);
632
633      s.insertBefore(CPOS(s, MIR_Move.create(IA32_MOVSD, sl, value)));
634      s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0, sl.copy())));
635      s.insertBefore(CPOS(s, MIR_Move.create(IA32_FLD, st0.copyRO(), maxlong)));
636      MIR_Compare.mutate(s, IA32_FUCOMIP, st0.copyRO(), st1);
637      testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
638          IA32ConditionOperand.LLE(),
639          nanTestBB.makeJumpTarget(),
640          BranchProfileOperand.unlikely())));
641      testBB.insertOut(d2lBB);
642      testBB.insertOut(nanTestBB);
643
644      // Convert double to long knowing that if the value is < min long the Intel
645      // unspecified result is min long
646      // TODO: this would be a lot simpler and faster with SSE3's FISTTP instruction
647      d2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FNSTCW, scratchLo.copy())));
648      d2lBB.appendInstruction(CPOS(s, MIR_Unary.create(IA32_MOVZX__W, cw, scratchLo.copy())));
649      d2lBB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_OR, cw, IC(0xC00))));
650      d2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, scratchHi, cw.copyRO())));
651      d2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchHi.copy())));
652      d2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FISTP, sl.copy(), st0.copyRO())));
653      d2lBB.appendInstruction(CPOS(s, MIR_UnaryNoRes.create(IA32_FLDCW, scratchLo.copy())));
654      d2lBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV, result, sl)));
655      d2lBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
656          nextBB.makeJumpTarget())));
657      d2lBB.insertOut(nextBB);
658
659      // Did the compare find a NaN or a maximum integer?
660      nanTestBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_FSTP, st0.copyRO(), st0.copyRO())));
661      nanTestBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
662          IA32ConditionOperand.PE(),
663          nanBB.makeJumpTarget(),
664          BranchProfileOperand.unlikely())));
665      nanTestBB.insertOut(nanBB);
666      nanTestBB.insertOut(maxintBB);
667
668      // Value was >= max long
669      maxintBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
670          result.copyRO(),
671          LC((int)Long.MAX_VALUE))));
672      maxintBB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
673          nextBB.makeJumpTarget())));
674      maxintBB.insertOut(nextBB);
675
676      // In case of NaN result is 0
677      nanBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
678          result.copyRO(),
679          LC(0))));
680      nanBB.insertOut(nextBB);
681      return nextInstr;
682    }
683  }
684
685  private static Instruction long_shl(Instruction s, IR ir) {
686    Instruction nextInstr = s.nextInstructionInCodeOrder();
687    while (Label.conforms(nextInstr) || BBend.conforms(nextInstr))  {
688      nextInstr = nextInstr.nextInstructionInCodeOrder();
689    }
690    // we need 4 basic blocks
691    // 1: the current block that does a test if the shift is > 32
692    // 2: a block to perform a shift in the range 32 to 63
693    // 3: a block to perform a shift in the range 0 to 31
694    // 4: the next basic block
695    BasicBlock testBB = s.getBasicBlock();
696    BasicBlock nextBB = testBB.splitNodeAt(s,ir);
697    ir.cfg.linkInCodeOrder(testBB, nextBB);
698    BasicBlock shift32BB = testBB.splitNodeAt(s,ir);
699    ir.cfg.linkInCodeOrder(testBB, shift32BB);
700    BasicBlock shift64BB = testBB.splitNodeAt(s,ir);
701    ir.cfg.linkInCodeOrder(testBB, shift64BB);
702
703    // Source registers
704    Register lhsReg = Binary.getResult(s).getRegister();
705    Register lowlhsReg = ir.regpool.getSecondReg(lhsReg);
706    Operand val1 = Binary.getVal1(s);
707    Register rhsReg;
708    Register lowrhsReg;
709    if (val1.isRegister()) {
710      rhsReg = val1.asRegister().getRegister();
711      lowrhsReg = ir.regpool.getSecondReg(rhsReg);
712    } else {
713      // shift is of a constant so set up registers
714      int low = val1.asLongConstant().lower32();
715      int high = val1.asLongConstant().upper32();
716
717      testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
718          new RegisterOperand(lowlhsReg, TypeReference.Int),
719          IC(low))));
720      testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
721          new RegisterOperand(lhsReg, TypeReference.Int),
722          IC(high))));
723      rhsReg = lhsReg;
724      lowrhsReg = lowlhsReg;
725    }
726
727    // ecx = shift amount
728    Register ecx = phys(ir).getECX();
729    testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
730        new RegisterOperand(ecx, TypeReference.Int),
731        Binary.getVal2(s))));
732
733    // Determine shift of 32 to 63 or 0 to 31
734    testBB.appendInstruction(CPOS(s, MIR_Test.create(IA32_TEST,
735        new RegisterOperand(ecx, TypeReference.Int),
736        IC(32))));
737
738    // if (ecx & 32 == 0) goto shift32BB
739    testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
740        IA32ConditionOperand.EQ(),
741        shift32BB.makeJumpTarget(),
742        BranchProfileOperand.likely())));
743
744    testBB.insertOut(shift32BB);
745    testBB.insertOut(shift64BB); // fall-through
746
747    // Perform shift in the range 32 to 63
748    shift64BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
749        new RegisterOperand(lhsReg, TypeReference.Int),
750        new RegisterOperand(lowrhsReg, TypeReference.Int))));
751    shift64BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_SHL,
752        new RegisterOperand(lhsReg, TypeReference.Int),
753        new RegisterOperand(ecx, TypeReference.Int))));
754    shift64BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
755        new RegisterOperand(lowlhsReg, TypeReference.Int),
756        IC(0))));
757
758    shift64BB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
759        nextBB.makeJumpTarget())));
760    shift64BB.insertOut(nextBB);
761
762    // Perform shift in the range 0 to 31
763    if (lhsReg != rhsReg) {
764      shift32BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
765          new RegisterOperand(lhsReg, TypeReference.Int),
766          new RegisterOperand(rhsReg, TypeReference.Int))));
767      shift32BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
768          new RegisterOperand(lowlhsReg, TypeReference.Int),
769          new RegisterOperand(lowrhsReg, TypeReference.Int))));
770    }
771    shift32BB.appendInstruction(CPOS(s, MIR_DoubleShift.create(IA32_SHLD,
772        new RegisterOperand(lhsReg, TypeReference.Int),
773        new RegisterOperand(lowlhsReg, TypeReference.Int),
774        new RegisterOperand(ecx, TypeReference.Int))));
775    shift32BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_SHL,
776        new RegisterOperand(lowlhsReg, TypeReference.Int),
777        new RegisterOperand(ecx, TypeReference.Int))));
778
779    shift32BB.insertOut(nextBB);
780
781    s.remove();
782    return nextInstr;
783  }
784
785  private static Instruction long_shr(Instruction s, IR ir) {
786    Instruction nextInstr = s.nextInstructionInCodeOrder();
787    while (Label.conforms(nextInstr) || BBend.conforms(nextInstr))  {
788      nextInstr = nextInstr.nextInstructionInCodeOrder();
789    }
790    // we need 4 basic blocks
791    // 1: the current block that does a test if the shift is > 32
792    // 2: a block to perform a shift in the range 32 to 63
793    // 3: a block to perform a shift in the range 0 to 31
794    // 4: the next basic block
795    BasicBlock testBB = s.getBasicBlock();
796    BasicBlock nextBB = testBB.splitNodeAt(s,ir);
797    ir.cfg.linkInCodeOrder(testBB, nextBB);
798    BasicBlock shift32BB = testBB.splitNodeAt(s,ir);
799    ir.cfg.linkInCodeOrder(testBB, shift32BB);
800    BasicBlock shift64BB = testBB.splitNodeAt(s,ir);
801    ir.cfg.linkInCodeOrder(testBB, shift64BB);
802
803    // Source registers
804    Register lhsReg = Binary.getResult(s).getRegister();
805    Register lowlhsReg = ir.regpool.getSecondReg(lhsReg);
806    Operand val1 = Binary.getVal1(s);
807    Register rhsReg;
808    Register lowrhsReg;
809    if (val1.isRegister()) {
810      rhsReg = val1.asRegister().getRegister();
811      lowrhsReg = ir.regpool.getSecondReg(rhsReg);
812    } else {
813      // shift is of a constant so set up registers
814      int low = val1.asLongConstant().lower32();
815      int high = val1.asLongConstant().upper32();
816
817      testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
818          new RegisterOperand(lowlhsReg, TypeReference.Int),
819          IC(low))));
820      testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
821          new RegisterOperand(lhsReg, TypeReference.Int),
822          IC(high))));
823      rhsReg = lhsReg;
824      lowrhsReg = lowlhsReg;
825    }
826
827    // ecx = shift amount
828    Register ecx = phys(ir).getECX();
829    testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
830        new RegisterOperand(ecx, TypeReference.Int),
831        Binary.getVal2(s))));
832
833    // Determine shift of 32 to 63 or 0 to 31
834    testBB.appendInstruction(CPOS(s, MIR_Test.create(IA32_TEST,
835        new RegisterOperand(ecx, TypeReference.Int),
836        IC(32))));
837
838    // if (ecx & 32 == 0) goto shift32BB
839    testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
840        IA32ConditionOperand.EQ(),
841        shift32BB.makeJumpTarget(),
842        BranchProfileOperand.likely())));
843
844    testBB.insertOut(shift32BB);
845    testBB.insertOut(shift64BB); // fall-through
846
847    // Perform shift in the range 32 to 63
848    shift64BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
849        new RegisterOperand(lowlhsReg, TypeReference.Int),
850        new RegisterOperand(rhsReg, TypeReference.Int))));
851    if (lhsReg != rhsReg) {
852      shift64BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
853          new RegisterOperand(lhsReg, TypeReference.Int),
854          new RegisterOperand(rhsReg, TypeReference.Int))));
855    }
856    shift64BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_SAR,
857        new RegisterOperand(lowlhsReg, TypeReference.Int),
858        new RegisterOperand(ecx, TypeReference.Int))));
859    shift64BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_SAR,
860        new RegisterOperand(lhsReg, TypeReference.Int),
861        IC(31))));
862
863    shift64BB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
864        nextBB.makeJumpTarget())));
865    shift64BB.insertOut(nextBB);
866
867    // Perform shift in the range 0 to 31
868    if (lhsReg != rhsReg) {
869      shift32BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
870          new RegisterOperand(lhsReg, TypeReference.Int),
871          new RegisterOperand(rhsReg, TypeReference.Int))));
872      shift32BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
873          new RegisterOperand(lowlhsReg, TypeReference.Int),
874          new RegisterOperand(lowrhsReg, TypeReference.Int))));
875    }
876    shift32BB.appendInstruction(CPOS(s, MIR_DoubleShift.create(IA32_SHRD,
877        new RegisterOperand(lowlhsReg, TypeReference.Int),
878        new RegisterOperand(lhsReg, TypeReference.Int),
879        new RegisterOperand(ecx, TypeReference.Int))));
880    shift32BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_SAR,
881        new RegisterOperand(lhsReg, TypeReference.Int),
882        new RegisterOperand(ecx, TypeReference.Int))));
883
884    shift32BB.insertOut(nextBB);
885
886    s.remove();
887    return nextInstr;
888  }
889
890  private static Instruction long_ushr(Instruction s, IR ir) {
891    Instruction nextInstr = s.nextInstructionInCodeOrder();
892    while (Label.conforms(nextInstr) || BBend.conforms(nextInstr))  {
893      nextInstr = nextInstr.nextInstructionInCodeOrder();
894    }
895    // we need 4 basic blocks
896    // 1: the current block that does a test if the shift is > 32
897    // 2: a block to perform a shift in the range 32 to 63
898    // 3: a block to perform a shift in the range 0 to 31
899    // 4: the next basic block
900    BasicBlock testBB = s.getBasicBlock();
901    BasicBlock nextBB = testBB.splitNodeAt(s,ir);
902    ir.cfg.linkInCodeOrder(testBB, nextBB);
903    BasicBlock shift32BB = testBB.splitNodeAt(s,ir);
904    ir.cfg.linkInCodeOrder(testBB, shift32BB);
905    BasicBlock shift64BB = testBB.splitNodeAt(s,ir);
906    ir.cfg.linkInCodeOrder(testBB, shift64BB);
907
908    // Source registers
909    Register lhsReg = Binary.getResult(s).getRegister();
910    Register lowlhsReg = ir.regpool.getSecondReg(lhsReg);
911    Operand val1 = Binary.getVal1(s);
912    Register rhsReg;
913    Register lowrhsReg;
914    if (val1.isRegister()) {
915      rhsReg = val1.asRegister().getRegister();
916      lowrhsReg = ir.regpool.getSecondReg(rhsReg);
917    } else {
918      // shift is of a constant so set up registers
919      int low = val1.asLongConstant().lower32();
920      int high = val1.asLongConstant().upper32();
921
922      testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
923          new RegisterOperand(lowlhsReg, TypeReference.Int),
924          IC(low))));
925      testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
926          new RegisterOperand(lhsReg, TypeReference.Int),
927          IC(high))));
928      rhsReg = lhsReg;
929      lowrhsReg = lowlhsReg;
930    }
931
932    // ecx = shift amount
933    Register ecx = phys(ir).getECX();
934    testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
935        new RegisterOperand(ecx, TypeReference.Int),
936        Binary.getVal2(s))));
937
938    // Determine shift of 32 to 63 or 0 to 31
939    testBB.appendInstruction(CPOS(s, MIR_Test.create(IA32_TEST,
940        new RegisterOperand(ecx, TypeReference.Int),
941        IC(32))));
942
943    // if (ecx & 32 == 0) goto shift32BB
944    testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
945        IA32ConditionOperand.EQ(),
946        shift32BB.makeJumpTarget(),
947        BranchProfileOperand.likely())));
948
949    testBB.insertOut(shift32BB);
950    testBB.insertOut(shift64BB); // fall-through
951
952    // Perform shift in the range 32 to 63
953    shift64BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
954        new RegisterOperand(lowlhsReg, TypeReference.Int),
955        new RegisterOperand(rhsReg, TypeReference.Int))));
956    shift64BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_SHR,
957        new RegisterOperand(lowlhsReg, TypeReference.Int),
958        new RegisterOperand(ecx, TypeReference.Int))));
959    shift64BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
960        new RegisterOperand(lhsReg, TypeReference.Int),
961        IC(0))));
962
963    shift64BB.appendInstruction(CPOS(s, MIR_Branch.create(IA32_JMP,
964        nextBB.makeJumpTarget())));
965    shift64BB.insertOut(nextBB);
966
967    // Perform shift in the range 0 to 31
968    if (lhsReg != rhsReg) {
969      shift32BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
970          new RegisterOperand(lhsReg, TypeReference.Int),
971          new RegisterOperand(rhsReg, TypeReference.Int))));
972      shift32BB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
973          new RegisterOperand(lowlhsReg, TypeReference.Int),
974          new RegisterOperand(lowrhsReg, TypeReference.Int))));
975    }
976    shift32BB.appendInstruction(CPOS(s, MIR_DoubleShift.create(IA32_SHRD,
977        new RegisterOperand(lowlhsReg, TypeReference.Int),
978        new RegisterOperand(lhsReg, TypeReference.Int),
979        new RegisterOperand(ecx, TypeReference.Int))));
980    shift32BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_SHR,
981        new RegisterOperand(lhsReg, TypeReference.Int),
982        new RegisterOperand(ecx, TypeReference.Int))));
983
984    shift32BB.insertOut(nextBB);
985
986    s.remove();
987    return nextInstr;
988  }
989
990  private static Instruction long_mul(Instruction s, IR ir) {
991    Instruction nextInstr = s.nextInstructionInCodeOrder();
992    while (Label.conforms(nextInstr) || BBend.conforms(nextInstr))  {
993      nextInstr = nextInstr.nextInstructionInCodeOrder();
994    }
995    // we need 4 basic blocks
996    // 1: the current block and a test for 32bit or 64bit multiply
997    // 2: 32bit multiply block
998    // 3: 64bit multiply block
999    // 4: the next basic block
1000    BasicBlock testBB = s.getBasicBlock();
1001    BasicBlock nextBB = testBB.splitNodeAt(s,ir);
1002    ir.cfg.linkInCodeOrder(testBB, nextBB);
1003    BasicBlock mul64BB = testBB.splitNodeAt(s,ir);
1004    ir.cfg.linkInCodeOrder(testBB, mul64BB);
1005    BasicBlock mul32BB = testBB.splitNodeAt(s,ir);
1006    ir.cfg.linkInCodeOrder(testBB, mul32BB);
1007
1008    // Source registers
1009    Register lhsReg = Binary.getResult(s).getRegister();
1010    Register lowlhsReg = ir.regpool.getSecondReg(lhsReg);
1011    Register rhsReg1 = Binary.getVal1(s).asRegister().getRegister();
1012    Register lowrhsReg1 = ir.regpool.getSecondReg(rhsReg1);
1013    Register rhsReg2 = Binary.getVal2(s).asRegister().getRegister();
1014    Register lowrhsReg2 = ir.regpool.getSecondReg(rhsReg2);
1015
1016    // Working registers
1017    Register edx = phys(ir).getEDX();
1018    Register eax = phys(ir).getEAX();
1019    Register tmp = ir.regpool.getInteger();
1020
1021    // The general form of the multiply is
1022    // (a,b) * (c,d) = (l(a imul d)+l(b imul c)+u(b mul d), l(b mul d))
1023
1024    // Determine whether we need a 32bit or 64bit multiply
1025    // edx, flags = a | c
1026    // edx = d
1027    // eax = b
1028    // if ((a | c) != 0) goto mul64BB
1029    testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
1030        new RegisterOperand(edx, TypeReference.Int),
1031        new RegisterOperand(rhsReg2, TypeReference.Int))));
1032    testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
1033        new RegisterOperand(tmp, TypeReference.Int),
1034        new RegisterOperand(rhsReg1, TypeReference.Int))));
1035    testBB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_OR,
1036        new RegisterOperand(edx, TypeReference.Int),
1037        new RegisterOperand(tmp, TypeReference.Int))));
1038    testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
1039        new RegisterOperand(edx, TypeReference.Int),
1040        new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1041    testBB.appendInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
1042        new RegisterOperand(eax, TypeReference.Int),
1043        new RegisterOperand(lowrhsReg2, TypeReference.Int))));
1044    testBB.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
1045        IA32ConditionOperand.NE(),
1046        mul64BB.makeJumpTarget(),
1047        BranchProfileOperand.unlikely())));
1048    testBB.insertOut(mul64BB);
1049    testBB.insertOut(mul32BB);
1050
1051    // multiply 32: on entry EAX = d, EDX = b, tmp = a
1052    // edx:eax = b * d
1053    mul32BB.appendInstruction(CPOS(s, MIR_Multiply.create(IA32_MUL,
1054        new RegisterOperand(edx, TypeReference.Int),
1055        new RegisterOperand(eax, TypeReference.Int),
1056        new RegisterOperand(edx, TypeReference.Int))));
1057    mul32BB.appendInstruction(MIR_Branch.create(IA32_JMP, nextBB.makeJumpTarget()));
1058    mul32BB.insertOut(nextBB);
1059
1060    // multiply 64: on entry EAX = d, EDX = b, tmp = a
1061    // edx = b imul c
1062    // tmp = a imul d
1063    // tmp1 = (a imul d) + (b imul c)
1064    // edx:eax = b * d
1065    // edx = u(b mul d) + l(a imul d) + l(b imul c)
1066    mul64BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1067        new RegisterOperand(edx, TypeReference.Int),
1068        new RegisterOperand(rhsReg2, TypeReference.Int))));
1069    mul64BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_IMUL2,
1070        new RegisterOperand(tmp, TypeReference.Int),
1071        new RegisterOperand(eax, TypeReference.Int))));
1072    mul64BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1073        new RegisterOperand(tmp, TypeReference.Int),
1074        new RegisterOperand(edx, TypeReference.Int))));
1075    mul64BB.appendInstruction(CPOS(s, MIR_Multiply.create(IA32_MUL,
1076        new RegisterOperand(edx, TypeReference.Int),
1077        new RegisterOperand(eax, TypeReference.Int),
1078        new RegisterOperand(lowrhsReg1, TypeReference.Int))));
1079    mul64BB.appendInstruction(CPOS(s, MIR_BinaryAcc.create(IA32_ADD,
1080        new RegisterOperand(edx, TypeReference.Int),
1081        new RegisterOperand(tmp, TypeReference.Int))));
1082    mul64BB.insertOut(nextBB);
1083
1084    // move result from edx:eax to lhsReg:lowlhsReg
1085    nextBB.prependInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
1086        new RegisterOperand(lhsReg, TypeReference.Int),
1087        new RegisterOperand(edx, TypeReference.Int))));
1088    nextBB.prependInstruction(CPOS(s, MIR_Move.create(IA32_MOV,
1089        new RegisterOperand(lowlhsReg, TypeReference.Int),
1090        new RegisterOperand(eax, TypeReference.Int))));
1091    s.remove();
1092    return nextInstr;
1093  }
1094
1095  private static Instruction long_ifcmp(Instruction s, IR ir) {
1096    Instruction nextInstr = s.nextInstructionInCodeOrder();
1097    ConditionOperand cond = IfCmp.getCond(s);
1098    Register xh = ((RegisterOperand) IfCmp.getVal1(s)).getRegister();
1099    Register xl = ir.regpool.getSecondReg(xh);
1100    RegisterOperand yh = (RegisterOperand) IfCmp.getClearVal2(s);
1101    yh.setType(TypeReference.Int);
1102    RegisterOperand yl = new RegisterOperand(ir.regpool.getSecondReg(yh.getRegister()), TypeReference.Int);
1103    basic_long_ifcmp(s, ir, cond, xh, xl, yh, yl);
1104    return nextInstr;
1105  }
1106
1107  private static Instruction long_ifcmp_imm(Instruction s, IR ir) {
1108    Instruction nextInstr = s.nextInstructionInCodeOrder();
1109    ConditionOperand cond = IfCmp.getCond(s);
1110    Register xh = ((RegisterOperand) IfCmp.getVal1(s)).getRegister();
1111    Register xl = ir.regpool.getSecondReg(xh);
1112    LongConstantOperand rhs = (LongConstantOperand) IfCmp.getVal2(s);
1113    int low = rhs.lower32();
1114    int high = rhs.upper32();
1115    IntConstantOperand yh = IC(high);
1116    IntConstantOperand yl = IC(low);
1117
1118    if (cond.isEQUAL() || cond.isNOT_EQUAL()) {
1119      // tricky... ((xh^yh)|(xl^yl) == 0) <==> (lhll == rhrl)!!
1120      Register th = ir.regpool.getInteger();
1121      Register tl = ir.regpool.getInteger();
1122      if (high == 0) {
1123        if (low == 0) { // 0,0
1124          s.insertBefore(MIR_Move.create(IA32_MOV,
1125                                         new RegisterOperand(th, TypeReference.Int),
1126                                         new RegisterOperand(xh, TypeReference.Int)));
1127          s.insertBefore(MIR_BinaryAcc.create(IA32_OR,
1128                                              new RegisterOperand(th, TypeReference.Int),
1129                                              new RegisterOperand(xl, TypeReference.Int)));
1130        } else if (low == -1) { // 0,-1
1131          s.insertBefore(MIR_Move.create(IA32_MOV,
1132                                         new RegisterOperand(tl, TypeReference.Int),
1133                                         new RegisterOperand(xl, TypeReference.Int)));
1134          s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(tl, TypeReference.Int)));
1135          s.insertBefore(MIR_BinaryAcc.create(IA32_OR,
1136                                              new RegisterOperand(tl, TypeReference.Int),
1137                                              new RegisterOperand(xh, TypeReference.Int)));
1138        } else { // 0,*
1139          s.insertBefore(MIR_Move.create(IA32_MOV,
1140                                         new RegisterOperand(tl, TypeReference.Int),
1141                                         new RegisterOperand(xl, TypeReference.Int)));
1142          s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(tl, TypeReference.Int), yl));
1143          s.insertBefore(MIR_BinaryAcc.create(IA32_OR,
1144                                              new RegisterOperand(tl, TypeReference.Int),
1145                                              new RegisterOperand(xh, TypeReference.Int)));
1146        }
1147      } else if (high == -1) {
1148        if (low == 0) { // -1,0
1149          s.insertBefore(MIR_Move.create(IA32_MOV,
1150                                         new RegisterOperand(th, TypeReference.Int),
1151                                         new RegisterOperand(xh, TypeReference.Int)));
1152          s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(th, TypeReference.Int)));
1153          s.insertBefore(MIR_BinaryAcc.create(IA32_OR,
1154                                              new RegisterOperand(th, TypeReference.Int),
1155                                              new RegisterOperand(xl, TypeReference.Int)));
1156        } else if (low == -1) { // -1,-1
1157          s.insertBefore(MIR_Move.create(IA32_MOV,
1158                                         new RegisterOperand(th, TypeReference.Int),
1159                                         new RegisterOperand(xh, TypeReference.Int)));
1160          s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(th, TypeReference.Int)));
1161          s.insertBefore(MIR_Move.create(IA32_MOV,
1162                                         new RegisterOperand(tl, TypeReference.Int),
1163                                         new RegisterOperand(xl, TypeReference.Int)));
1164          s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(tl, TypeReference.Int)));
1165          s.insertBefore(MIR_BinaryAcc.create(IA32_OR,
1166                                              new RegisterOperand(th, TypeReference.Int),
1167                                              new RegisterOperand(tl, TypeReference.Int)));
1168        } else { // -1,*
1169          s.insertBefore(MIR_Move.create(IA32_MOV,
1170                                         new RegisterOperand(th, TypeReference.Int),
1171                                         new RegisterOperand(xh, TypeReference.Int)));
1172          s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(th, TypeReference.Int)));
1173          s.insertBefore(MIR_Move.create(IA32_MOV,
1174                                         new RegisterOperand(tl, TypeReference.Int),
1175                                         new RegisterOperand(xl, TypeReference.Int)));
1176          s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(tl, TypeReference.Int), yl));
1177          s.insertBefore(MIR_BinaryAcc.create(IA32_OR,
1178                                              new RegisterOperand(th, TypeReference.Int),
1179                                              new RegisterOperand(tl, TypeReference.Int)));
1180        }
1181      } else {
1182        if (low == 0) { // *,0
1183          s.insertBefore(MIR_Move.create(IA32_MOV,
1184                                         new RegisterOperand(th, TypeReference.Int),
1185                                         new RegisterOperand(xh, TypeReference.Int)));
1186          s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(th, TypeReference.Int), yh));
1187          s.insertBefore(MIR_BinaryAcc.create(IA32_OR,
1188                                              new RegisterOperand(th, TypeReference.Int),
1189                                              new RegisterOperand(xl, TypeReference.Int)));
1190        } else if (low == -1) { // *,-1
1191          s.insertBefore(MIR_Move.create(IA32_MOV,
1192                                         new RegisterOperand(th, TypeReference.Int),
1193                                         new RegisterOperand(xh, TypeReference.Int)));
1194          s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(th, TypeReference.Int), yh));
1195          s.insertBefore(MIR_Move.create(IA32_MOV,
1196                                         new RegisterOperand(tl, TypeReference.Int),
1197                                         new RegisterOperand(xl, TypeReference.Int)));
1198          s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(tl, TypeReference.Int)));
1199          s.insertBefore(MIR_BinaryAcc.create(IA32_OR,
1200                                              new RegisterOperand(th, TypeReference.Int),
1201                                              new RegisterOperand(tl, TypeReference.Int)));
1202        } else { // neither high nor low is special
1203          s.insertBefore(MIR_Move.create(IA32_MOV,
1204                                         new RegisterOperand(th, TypeReference.Int),
1205                                         new RegisterOperand(xh, TypeReference.Int)));
1206          s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(th, TypeReference.Int), yh));
1207          s.insertBefore(MIR_Move.create(IA32_MOV,
1208                                         new RegisterOperand(tl, TypeReference.Int),
1209                                         new RegisterOperand(xl, TypeReference.Int)));
1210          s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(tl, TypeReference.Int), yl));
1211          s.insertBefore(MIR_BinaryAcc.create(IA32_OR,
1212                                              new RegisterOperand(th, TypeReference.Int),
1213                                              new RegisterOperand(tl, TypeReference.Int)));
1214        }
1215      }
1216      MIR_CondBranch.mutate(s,
1217                            IA32_JCC,
1218                            new IA32ConditionOperand(cond),
1219                            IfCmp.getTarget(s),
1220                            IfCmp.getBranchProfile(s));
1221      return nextInstr;
1222    } else {
1223      // pick up a few special cases where the sign of xh is sufficient
1224      if (rhs.value == 0L) {
1225        if (cond.isLESS()) {
1226          // xh < 0 implies true
1227          s.insertBefore(MIR_Compare.create(IA32_CMP, new RegisterOperand(xh, TypeReference.Int), IC(0)));
1228          MIR_CondBranch.mutate(s,
1229                                IA32_JCC,
1230                                IA32ConditionOperand.LT(),
1231                                IfCmp.getTarget(s),
1232                                IfCmp.getBranchProfile(s));
1233          return nextInstr;
1234        } else if (cond.isGREATER_EQUAL()) {
1235          s.insertBefore(MIR_Compare.create(IA32_CMP, new RegisterOperand(xh, TypeReference.Int), IC(0)));
1236          MIR_CondBranch.mutate(s,
1237                                IA32_JCC,
1238                                IA32ConditionOperand.GE(),
1239                                IfCmp.getTarget(s),
1240                                IfCmp.getBranchProfile(s));
1241          return nextInstr;
1242        }
1243      } else if (rhs.value == -1L) {
1244        if (cond.isLESS_EQUAL()) {
1245          s.insertBefore(MIR_Compare.create(IA32_CMP, new RegisterOperand(xh, TypeReference.Int), IC(-1)));
1246          MIR_CondBranch.mutate(s,
1247                                IA32_JCC,
1248                                IA32ConditionOperand.LE(),
1249                                IfCmp.getTarget(s),
1250                                IfCmp.getBranchProfile(s));
1251          return nextInstr;
1252        } else if (cond.isGREATER()) {
1253          s.insertBefore(MIR_Compare.create(IA32_CMP, new RegisterOperand(xh, TypeReference.Int), IC(0)));
1254          MIR_CondBranch.mutate(s,
1255                                IA32_JCC,
1256                                IA32ConditionOperand.GE(),
1257                                IfCmp.getTarget(s),
1258                                IfCmp.getBranchProfile(s));
1259          return nextInstr;
1260        }
1261      }
1262
1263      basic_long_ifcmp(s, ir, cond, xh, xl, yh, yl);
1264      return nextInstr;
1265    }
1266  }
1267
1268  private static void basic_long_ifcmp(Instruction s, IR ir, ConditionOperand cond, Register xh,
1269                                       Register xl, Operand yh, Operand yl) {
1270    if (cond.isEQUAL() || cond.isNOT_EQUAL()) {
1271      RegisterOperand th = ir.regpool.makeTempInt();
1272      RegisterOperand tl = ir.regpool.makeTempInt();
1273      // tricky... ((xh^yh)|(xl^yl) == 0) <==> (lhll == rhrl)!!
1274      s.insertBefore(MIR_Move.create(IA32_MOV, th, new RegisterOperand(xh, TypeReference.Int)));
1275      s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, th.copyD2D(), yh));
1276      s.insertBefore(MIR_Move.create(IA32_MOV, tl, new RegisterOperand(xl, TypeReference.Int)));
1277      s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, tl.copyD2D(), yl));
1278      s.insertBefore(MIR_BinaryAcc.create(IA32_OR, th.copyD2D(), tl.copyD2U()));
1279      MIR_CondBranch.mutate(s,
1280                            IA32_JCC,
1281                            new IA32ConditionOperand(cond),
1282                            IfCmp.getTarget(s),
1283                            IfCmp.getBranchProfile(s));
1284    } else {
1285      // Do the naive thing and generate multiple compare/branch implementation.
1286      IA32ConditionOperand cond1;
1287      IA32ConditionOperand cond2;
1288      IA32ConditionOperand cond3;
1289      if (cond.isLESS()) {
1290        cond1 = IA32ConditionOperand.LT();
1291        cond2 = IA32ConditionOperand.GT();
1292        cond3 = IA32ConditionOperand.LLT();
1293      } else if (cond.isGREATER()) {
1294        cond1 = IA32ConditionOperand.GT();
1295        cond2 = IA32ConditionOperand.LT();
1296        cond3 = IA32ConditionOperand.LGT();
1297      } else if (cond.isLESS_EQUAL()) {
1298        cond1 = IA32ConditionOperand.LT();
1299        cond2 = IA32ConditionOperand.GT();
1300        cond3 = IA32ConditionOperand.LLE();
1301      } else if (cond.isGREATER_EQUAL()) {
1302        cond1 = IA32ConditionOperand.GT();
1303        cond2 = IA32ConditionOperand.LT();
1304        cond3 = IA32ConditionOperand.LGE();
1305      } else {
1306        // I don't think we use the unsigned compares for longs,
1307        // so defer actually implementing them until we find a test case. --dave
1308        cond1 = cond2 = cond3 = null;
1309        OptimizingCompilerException.TODO();
1310      }
1311
1312      BasicBlock myBlock = s.getBasicBlock();
1313      BasicBlock test2Block = myBlock.createSubBlock(s.bcIndex, ir, 0.25f);
1314      BasicBlock falseBlock = myBlock.splitNodeAt(s, ir);
1315      BasicBlock trueBlock = IfCmp.getTarget(s).target.getBasicBlock();
1316
1317      falseBlock.recomputeNormalOut(ir);
1318      myBlock.insertOut(test2Block);
1319      myBlock.insertOut(falseBlock);
1320      myBlock.insertOut(trueBlock);
1321      test2Block.insertOut(falseBlock);
1322      test2Block.insertOut(trueBlock);
1323      ir.cfg.linkInCodeOrder(myBlock, test2Block);
1324      ir.cfg.linkInCodeOrder(test2Block, falseBlock);
1325
1326      s.remove();
1327
1328      myBlock.appendInstruction(CPOS(s, MIR_Compare.create(IA32_CMP, new RegisterOperand(xh, TypeReference.Int), yh)));
1329      myBlock.appendInstruction(CPOS(s, MIR_CondBranch2.create(IA32_JCC2,
1330                                                       cond1,
1331                                                       trueBlock.makeJumpTarget(),
1332                                                       new BranchProfileOperand(),
1333                                                       cond2,
1334                                                       falseBlock.makeJumpTarget(),
1335                                                       new BranchProfileOperand())));
1336      test2Block.appendInstruction(CPOS(s, MIR_Compare.create(IA32_CMP, new RegisterOperand(xl, TypeReference.Int), yl)));
1337      test2Block.appendInstruction(CPOS(s, MIR_CondBranch.create(IA32_JCC,
1338                                                         cond3,
1339                                                         trueBlock.makeJumpTarget(),
1340                                                         new BranchProfileOperand())));
1341    }
1342  }
1343
1344  // the fcmoi/fcmoip was generated by burs
1345  // we do the rest of the expansion here because in some
1346  // cases we must remove a trailing goto, and we
1347  // can't do that in burs!
1348  private static Instruction fp_ifcmp(Instruction s) {
1349    Instruction nextInstr = s.nextInstructionInCodeOrder();
1350    BranchOperand testFailed;
1351    BasicBlock bb = s.getBasicBlock();
1352    Instruction lastInstr = bb.lastRealInstruction();
1353    if (lastInstr.operator() == IA32_JMP) {
1354      // We're in trouble if there is another instruction between s and lastInstr!
1355      if (VM.VerifyAssertions) VM._assert(s.nextInstructionInCodeOrder() == lastInstr);
1356      // Set testFailed to target of GOTO
1357      testFailed = MIR_Branch.getTarget(lastInstr);
1358      nextInstr = lastInstr.nextInstructionInCodeOrder();
1359      lastInstr.remove();
1360    } else {
1361      // Set testFailed to label of next (fallthrough basic block)
1362      testFailed = bb.nextBasicBlockInCodeOrder().makeJumpTarget();
1363    }
1364
1365    // Translate condition operand respecting IA32 FCOMI/COMISS/COMISD
1366    Instruction fcomi = s.prevInstructionInCodeOrder();
1367    Operand val1 = MIR_Compare.getVal1(fcomi);
1368    Operand val2 = MIR_Compare.getVal2(fcomi);
1369    ConditionOperand c = IfCmp.getCond(s);
1370    BranchOperand target = IfCmp.getTarget(s);
1371    BranchProfileOperand branchProfile = IfCmp.getBranchProfile(s);
1372
1373    // FCOMI sets ZF, PF, and CF as follows:
1374    // Compare Results      ZF     PF      CF
1375    // left > right          0      0       0
1376    // left < right          0      0       1
1377    // left == right         1      0       0
1378    // UNORDERED             1      1       1
1379
1380    // Propagate branch probabilities as follows: assume the
1381    // probability of unordered (first condition) is zero, and
1382    // propagate the original probability to the second condition.
1383    switch (c.value) {
1384      // Branches that WON'T be taken after unordered comparison
1385      // (i.e. UNORDERED is a goto to testFailed)
1386      case ConditionOperand.CMPL_EQUAL:
1387        if (VM.VerifyAssertions) VM._assert(!c.branchIfUnordered());
1388        // Check whether val1 and val2 operands are the same
1389        if (!val1.similar(val2)) {
1390          s.insertBefore(MIR_CondBranch2.create(IA32_JCC2,
1391                                                IA32ConditionOperand.PE(),
1392                                                // PF == 1
1393                                                testFailed,
1394                                                new BranchProfileOperand(0f),
1395                                                IA32ConditionOperand.EQ(),
1396                                                // ZF == 1
1397                                                target,
1398                                                branchProfile));
1399          s.insertBefore(MIR_Branch.create(IA32_JMP, (BranchOperand) (testFailed.copy())));
1400        } else {
1401          // As val1 == val2 result of compare must be == or UNORDERED
1402          s.insertBefore(MIR_CondBranch.create(IA32_JCC, IA32ConditionOperand.PO(),  // PF == 0
1403                                               target, branchProfile));
1404          s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
1405        }
1406        break;
1407      case ConditionOperand.CMPL_GREATER:
1408        if (VM.VerifyAssertions) VM._assert(!c.branchIfUnordered());
1409        s.insertBefore(MIR_CondBranch.create(IA32_JCC, IA32ConditionOperand.LGT(), // CF == 0 and ZF == 0
1410                                             target, branchProfile));
1411        s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
1412        break;
1413      case ConditionOperand.CMPG_LESS:
1414        if (VM.VerifyAssertions) VM._assert(!c.branchIfUnordered());
1415        s.insertBefore(MIR_CondBranch2.create(IA32_JCC2,
1416                                              IA32ConditionOperand.PE(),
1417                                              // PF == 1
1418                                              testFailed,
1419                                              new BranchProfileOperand(0f),
1420                                              IA32ConditionOperand.LLT(),
1421                                              // CF == 1
1422                                              target,
1423                                              branchProfile));
1424        s.insertBefore(MIR_Branch.create(IA32_JMP, (BranchOperand) (testFailed.copy())));
1425        break;
1426      case ConditionOperand.CMPL_GREATER_EQUAL:
1427        if (VM.VerifyAssertions) VM._assert(!c.branchIfUnordered());
1428        s.insertBefore(MIR_CondBranch.create(IA32_JCC, IA32ConditionOperand.LGE(), // CF == 0
1429                                             target, branchProfile));
1430        s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
1431        break;
1432      case ConditionOperand.CMPG_LESS_EQUAL:
1433        s.insertBefore(MIR_CondBranch2.create(IA32_JCC2,
1434                                              IA32ConditionOperand.PE(),
1435                                              // PF == 1
1436                                              testFailed,
1437                                              new BranchProfileOperand(0f),
1438                                              IA32ConditionOperand.LGT(),
1439                                              // ZF == 0 and CF == 0
1440                                              (BranchOperand) (testFailed.copy()),
1441                                              branchProfile));
1442        s.insertBefore(MIR_Branch.create(IA32_JMP, target));
1443        break;
1444        // Branches that WILL be taken after unordered comparison
1445        // (i.e. UNORDERED is a goto to target)
1446      case ConditionOperand.CMPL_NOT_EQUAL:
1447        if (VM.VerifyAssertions) VM._assert(c.branchIfUnordered());
1448        // Check whether val1 and val2 operands are the same
1449        if (!val1.similar(val2)) {
1450          s.insertBefore(MIR_CondBranch2.create(IA32_JCC2,
1451                                                IA32ConditionOperand.PE(),
1452                                                // PF == 1
1453                                                target,
1454                                                new BranchProfileOperand(0f),
1455                                                IA32ConditionOperand.NE(),
1456                                                // ZF == 0
1457                                                (BranchOperand) (target.copy()),
1458                                                branchProfile));
1459          s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
1460        } else {
1461          // As val1 == val2 result of compare must be == or UNORDERED
1462          s.insertBefore(MIR_CondBranch.create(IA32_JCC, IA32ConditionOperand.PE(),  // PF == 1
1463                                               target, branchProfile));
1464          s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
1465        }
1466        break;
1467      case ConditionOperand.CMPL_LESS:
1468        if (VM.VerifyAssertions) VM._assert(c.branchIfUnordered());
1469        s.insertBefore(MIR_CondBranch.create(IA32_JCC, IA32ConditionOperand.LLT(),   // CF == 1
1470                                             target, branchProfile));
1471        s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
1472        break;
1473      case ConditionOperand.CMPG_GREATER_EQUAL:
1474        if (VM.VerifyAssertions) VM._assert(c.branchIfUnordered());
1475        s.insertBefore(MIR_CondBranch2.create(IA32_JCC2,
1476                                              IA32ConditionOperand.PE(),
1477                                              // PF == 1
1478                                              target,
1479                                              new BranchProfileOperand(0f),
1480                                              IA32ConditionOperand.LLT(),
1481                                              // CF == 1
1482                                              testFailed,
1483                                              branchProfile));
1484        s.insertBefore(MIR_Branch.create(IA32_JMP, (BranchOperand) (target.copy())));
1485        break;
1486      case ConditionOperand.CMPG_GREATER:
1487        if (VM.VerifyAssertions) VM._assert(c.branchIfUnordered());
1488        s.insertBefore(MIR_CondBranch2.create(IA32_JCC2,
1489                                              IA32ConditionOperand.PE(),
1490                                              // PF == 1
1491                                              target,
1492                                              new BranchProfileOperand(0f),
1493                                              IA32ConditionOperand.LGT(),
1494                                              // ZF == 0 and CF == 0
1495                                              (BranchOperand) (target.copy()),
1496                                              branchProfile));
1497        s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
1498        break;
1499      case ConditionOperand.CMPL_LESS_EQUAL:
1500        if (VM.VerifyAssertions) VM._assert(c.branchIfUnordered());
1501        s.insertBefore(MIR_CondBranch.create(IA32_JCC, IA32ConditionOperand.LLE(), // CF == 1 or ZF == 1
1502                                             target, branchProfile));
1503        s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
1504        break;
1505      default:
1506        OptimizingCompilerException.UNREACHABLE();
1507    }
1508    s.remove();
1509    return nextInstr;
1510  }
1511
1512  public static void process64BitImmediateValues(IR ir) {
1513    for (Instruction s = ir.firstInstructionInCodeOrder(); s != null;
1514        s = s.nextInstructionInCodeOrder()) {
1515      char opcode = s.getOpcode();
1516      if (opcode != IMMQ_MOV_opcode) {
1517        if (MIR_Move.conforms(s)) {
1518          Operand moveResult = MIR_Move.getResult(s);
1519          if (opcode == IA32_MOV_opcode && moveResult.isRegister()) {
1520            Operand value = MIR_Move.getValue(s);
1521            if (value.isLongConstant()) {
1522              LongConstantOperand lc = (LongConstantOperand)value;
1523              if (!Bits.fits(lc.value, 32)) {
1524                MIR_Move.mutate(s, IMMQ_MOV, moveResult, value);
1525                continue;
1526              }
1527            }
1528          }
1529        }
1530        for (Enumeration<Operand> ops = s.getOperands(); ops.hasMoreElements();) {
1531          Operand op = ops.nextElement();
1532          if (op.isLongConstant()) {
1533            LongConstantOperand lc = (LongConstantOperand)op;
1534            if (!Bits.fits(lc.value, 32)) {
1535              RegisterOperand temp = ir.regpool.makeTempLong();
1536              if (lc.convertedFromRef()) {
1537                temp.flagAsConvertedFromRef();
1538              }
1539              s.insertBefore(MIR_Move.create(IMMQ_MOV, temp, lc));
1540              s.replaceOperand(lc, temp.copyD2U());
1541            }
1542          }
1543        }
1544      }
1545    }
1546  }
1547
1548}