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