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