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 }