001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt; 014 015import static org.jikesrvm.compilers.opt.driver.OptConstants.NO; 016import static org.jikesrvm.compilers.opt.driver.OptConstants.YES; 017import static org.jikesrvm.compilers.opt.ir.Operators.*; 018import static org.jikesrvm.runtime.JavaSizeConstants.BITS_IN_INT; 019import static org.jikesrvm.runtime.JavaSizeConstants.BITS_IN_LONG; 020import static org.jikesrvm.runtime.UnboxedSizeConstants.BITS_IN_ADDRESS; 021import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS; 022 023import java.lang.reflect.Array; 024import java.lang.reflect.Method; 025 026import org.jikesrvm.VM; 027import org.jikesrvm.classloader.RVMField; 028import org.jikesrvm.classloader.RVMMethod; 029import org.jikesrvm.classloader.RVMType; 030import org.jikesrvm.classloader.TypeReference; 031import org.jikesrvm.compilers.common.CodeArray; 032import org.jikesrvm.compilers.opt.inlining.InlineSequence; 033import org.jikesrvm.compilers.opt.ir.AbstractRegisterPool; 034import org.jikesrvm.compilers.opt.ir.Binary; 035import org.jikesrvm.compilers.opt.ir.BooleanCmp; 036import org.jikesrvm.compilers.opt.ir.BoundsCheck; 037import org.jikesrvm.compilers.opt.ir.Call; 038import org.jikesrvm.compilers.opt.ir.CondMove; 039import org.jikesrvm.compilers.opt.ir.Empty; 040import org.jikesrvm.compilers.opt.ir.GetField; 041import org.jikesrvm.compilers.opt.ir.GuardedBinary; 042import org.jikesrvm.compilers.opt.ir.GuardedUnary; 043import org.jikesrvm.compilers.opt.ir.IRTools; 044import org.jikesrvm.compilers.opt.ir.InstanceOf; 045import org.jikesrvm.compilers.opt.ir.Instruction; 046import org.jikesrvm.compilers.opt.ir.Load; 047import org.jikesrvm.compilers.opt.ir.Move; 048import org.jikesrvm.compilers.opt.ir.NullCheck; 049import org.jikesrvm.compilers.opt.ir.Operator; 050import org.jikesrvm.compilers.opt.ir.StoreCheck; 051import org.jikesrvm.compilers.opt.ir.Trap; 052import org.jikesrvm.compilers.opt.ir.TrapIf; 053import org.jikesrvm.compilers.opt.ir.TypeCheck; 054import org.jikesrvm.compilers.opt.ir.Unary; 055import org.jikesrvm.compilers.opt.ir.ZeroCheck; 056import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand; 057import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand; 058import org.jikesrvm.compilers.opt.ir.operand.CodeConstantOperand; 059import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand; 060import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand; 061import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 062import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand; 063import org.jikesrvm.compilers.opt.ir.operand.MethodOperand; 064import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand; 065import org.jikesrvm.compilers.opt.ir.operand.ObjectConstantOperand; 066import org.jikesrvm.compilers.opt.ir.operand.Operand; 067import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 068import org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand; 069import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand; 070import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand; 071import org.jikesrvm.compilers.opt.ir.operand.TypeOperand; 072import org.jikesrvm.compilers.opt.ir.operand.UnreachableOperand; 073import org.jikesrvm.objectmodel.TIB; 074import org.jikesrvm.runtime.Entrypoints; 075import org.jikesrvm.runtime.Magic; 076import org.jikesrvm.runtime.Reflection; 077import org.vmmagic.unboxed.Address; 078import org.vmmagic.unboxed.Offset; 079import org.vmmagic.unboxed.Word; 080 081/** 082 * A constant folder, strength reducer and axiomatic simplifier. 083 * 084 * <p> This module performs no analysis, it simply attempts to 085 * simplify the instruction as is. The intent is that 086 * analysis modules can call this transformation engine, allowing us to 087 * share the tedious simplification code among multiple analysis modules. 088 * 089 * <p> NOTE: For maintainability purposes, I've intentionally avoided being 090 * clever about combining 'similar' operators together into a combined case 091 * of the main switch switch statement. Also, operators are in sorted ordered 092 * within each major grouping. Please maintain this coding style. 093 * I'd rather have this module be 2000 lines of obviously correct code than 094 * 500 lines of clever code. 095 */ 096public abstract class Simplifier extends IRTools { 097 /** 098 * Effect of the simplification on Def-Use chains 099 */ 100 public enum DefUseEffect { 101 /** 102 * Enumeration value to indicate an operation is unchanged, 103 * although the order of operands may have been canonicalized and 104 * type information strengthened. 105 */ 106 UNCHANGED, 107 /** 108 * Enumeration value to indicate an operation has been replaced by 109 * a move instruction with a constant right hand side. 110 */ 111 MOVE_FOLDED, 112 /** 113 * Enumeration value to indicate an operation has been replaced by 114 * a move instruction with a non-constant right hand side. 115 */ 116 MOVE_REDUCED, 117 /** 118 * Enumeration value to indicate an operation has been replaced by 119 * an unconditional trap instruction. 120 */ 121 TRAP_REDUCED, 122 /** 123 * Enumeration value to indicate an operation has been replaced by 124 * a cheaper, but non-move instruction. 125 */ 126 REDUCED 127 } 128 129 /** 130 * Given an instruction, attempt to simplify it. 131 * The instruction will be mutated in place. 132 * 133 * <p> We don't deal with branching operations here -- 134 * doing peephole optimizations of branches 135 * is the job of a separate module. 136 * 137 * @param hir is this the HIR phase? 138 * @param regpool register pool in case simplification requires a temporary register 139 * @param opts options for this compilation 140 * @param s the instruction to simplify 141 * @return one of UNCHANGED, MOVE_FOLDED, MOVE_REDUCED, TRAP_REDUCED, REDUCED 142 */ 143 public static DefUseEffect simplify(boolean hir, AbstractRegisterPool regpool, OptOptions opts, Instruction s) { 144 DefUseEffect result; 145 char opcode = s.getOpcode(); 146 switch (opcode) { 147 //////////////////// 148 // GUARD operations 149 //////////////////// 150 case GUARD_COMBINE_opcode: 151 result = guardCombine(s, opts); 152 break; 153 //////////////////// 154 // TRAP operations 155 //////////////////// 156 case TRAP_IF_opcode: 157 result = trapIf(s, opts); 158 break; 159 case NULL_CHECK_opcode: 160 result = nullCheck(s, opts); 161 break; 162 case INT_ZERO_CHECK_opcode: 163 result = intZeroCheck(s, opts); 164 break; 165 case LONG_ZERO_CHECK_opcode: 166 result = longZeroCheck(s, opts); 167 break; 168 case CHECKCAST_opcode: 169 result = checkcast(s, opts); 170 break; 171 case CHECKCAST_UNRESOLVED_opcode: 172 result = checkcast(s, opts); 173 break; 174 case CHECKCAST_NOTNULL_opcode: 175 result = checkcastNotNull(s, opts); 176 break; 177 case INSTANCEOF_opcode: 178 result = instanceOf(s, opts); 179 break; 180 case INSTANCEOF_NOTNULL_opcode: 181 result = instanceOfNotNull(s, opts); 182 break; 183 case OBJARRAY_STORE_CHECK_opcode: 184 result = objarrayStoreCheck(s, opts); 185 break; 186 case OBJARRAY_STORE_CHECK_NOTNULL_opcode: 187 result = objarrayStoreCheckNotNull(s, opts); 188 break; 189 case MUST_IMPLEMENT_INTERFACE_opcode: 190 result = mustImplementInterface(s, opts); 191 break; 192 //////////////////// 193 // Conditional moves 194 //////////////////// 195 case INT_COND_MOVE_opcode: 196 result = intCondMove(s, opts); 197 break; 198 case LONG_COND_MOVE_opcode: 199 result = longCondMove(s, opts); 200 break; 201 case FLOAT_COND_MOVE_opcode: 202 result = floatCondMove(s, opts); 203 break; 204 case DOUBLE_COND_MOVE_opcode: 205 result = doubleCondMove(s, opts); 206 break; 207 case REF_COND_MOVE_opcode: 208 result = refCondMove(s, opts); 209 break; 210 case GUARD_COND_MOVE_opcode: 211 result = guardCondMove(s, opts); 212 break; 213 //////////////////// 214 // INT ALU operations 215 //////////////////// 216 case BOOLEAN_NOT_opcode: 217 result = booleanNot(s, opts); 218 break; 219 case BOOLEAN_CMP_INT_opcode: 220 result = booleanCmpInt(s, opts); 221 break; 222 case BOOLEAN_CMP_ADDR_opcode: 223 result = booleanCmpAddr(s, opts); 224 break; 225 case INT_ADD_opcode: 226 result = intAdd(s, opts); 227 break; 228 case INT_AND_opcode: 229 result = intAnd(s, opts); 230 break; 231 case INT_DIV_opcode: 232 result = intDiv(regpool, s, opts); 233 break; 234 case INT_MUL_opcode: 235 result = intMul(regpool, s, opts); 236 break; 237 case INT_NEG_opcode: 238 result = intNeg(s, opts); 239 break; 240 case INT_NOT_opcode: 241 result = intNot(s, opts); 242 break; 243 case INT_OR_opcode: 244 result = intOr(s, opts); 245 break; 246 case INT_REM_opcode: 247 result = intRem(s, opts); 248 break; 249 case INT_SHL_opcode: 250 result = intShl(s, opts); 251 break; 252 case INT_SHR_opcode: 253 result = intShr(s, opts); 254 break; 255 case INT_SUB_opcode: 256 result = intSub(s, opts); 257 break; 258 case INT_USHR_opcode: 259 result = intUshr(s, opts); 260 break; 261 case INT_XOR_opcode: 262 result = intXor(s, opts); 263 break; 264 //////////////////// 265 // WORD ALU operations 266 //////////////////// 267 case REF_ADD_opcode: 268 result = refAdd(s, opts); 269 break; 270 case REF_AND_opcode: 271 result = refAnd(s, opts); 272 break; 273 case REF_SHL_opcode: 274 result = refShl(s, opts); 275 break; 276 case REF_SHR_opcode: 277 result = refShr(s, opts); 278 break; 279 case REF_NEG_opcode: 280 result = refNeg(s, opts); 281 break; 282 case REF_NOT_opcode: 283 result = refNot(s, opts); 284 break; 285 case REF_OR_opcode: 286 result = refOr(s, opts); 287 break; 288 case REF_SUB_opcode: 289 result = refSub(s, opts); 290 break; 291 case REF_USHR_opcode: 292 result = refUshr(s, opts); 293 break; 294 case REF_XOR_opcode: 295 result = refXor(s, opts); 296 break; 297 //////////////////// 298 // LONG ALU operations 299 //////////////////// 300 case LONG_ADD_opcode: 301 result = longAdd(s, opts); 302 break; 303 case LONG_AND_opcode: 304 result = longAnd(s, opts); 305 break; 306 case LONG_CMP_opcode: 307 result = longCmp(s, opts); 308 break; 309 case LONG_DIV_opcode: 310 result = longDiv(s, opts); 311 break; 312 case LONG_MUL_opcode: 313 result = longMul(regpool, s, opts); 314 break; 315 case LONG_NEG_opcode: 316 result = longNeg(s, opts); 317 break; 318 case LONG_NOT_opcode: 319 result = longNot(s, opts); 320 break; 321 case LONG_OR_opcode: 322 result = longOr(s, opts); 323 break; 324 case LONG_REM_opcode: 325 result = longRem(s, opts); 326 break; 327 case LONG_SHL_opcode: 328 result = longShl(s, opts); 329 break; 330 case LONG_SHR_opcode: 331 result = longShr(s, opts); 332 break; 333 case LONG_SUB_opcode: 334 result = longSub(s, opts); 335 break; 336 case LONG_USHR_opcode: 337 result = longUshr(s, opts); 338 break; 339 case LONG_XOR_opcode: 340 result = longXor(s, opts); 341 break; 342 //////////////////// 343 // FLOAT ALU operations 344 //////////////////// 345 case FLOAT_ADD_opcode: 346 result = floatAdd(s, opts); 347 break; 348 case FLOAT_CMPG_opcode: 349 result = floatCmpg(s, opts); 350 break; 351 case FLOAT_CMPL_opcode: 352 result = floatCmpl(s, opts); 353 break; 354 case FLOAT_DIV_opcode: 355 result = floatDiv(s, opts); 356 break; 357 case FLOAT_MUL_opcode: 358 result = floatMul(s, opts); 359 break; 360 case FLOAT_NEG_opcode: 361 result = floatNeg(s, opts); 362 break; 363 case FLOAT_REM_opcode: 364 result = floatRem(s, opts); 365 break; 366 case FLOAT_SUB_opcode: 367 result = floatSub(s, opts); 368 break; 369 case FLOAT_SQRT_opcode: 370 result = floatSqrt(s, opts); 371 break; 372 //////////////////// 373 // DOUBLE ALU operations 374 //////////////////// 375 case DOUBLE_ADD_opcode: 376 result = doubleAdd(s, opts); 377 break; 378 case DOUBLE_CMPG_opcode: 379 result = doubleCmpg(s, opts); 380 break; 381 case DOUBLE_CMPL_opcode: 382 result = doubleCmpl(s, opts); 383 break; 384 case DOUBLE_DIV_opcode: 385 result = doubleDiv(s, opts); 386 break; 387 case DOUBLE_MUL_opcode: 388 result = doubleMul(s, opts); 389 break; 390 case DOUBLE_NEG_opcode: 391 result = doubleNeg(s, opts); 392 break; 393 case DOUBLE_REM_opcode: 394 result = doubleRem(s, opts); 395 break; 396 case DOUBLE_SUB_opcode: 397 result = doubleSub(s, opts); 398 break; 399 case DOUBLE_SQRT_opcode: 400 result = doubleSqrt(s, opts); 401 break; 402 //////////////////// 403 // CONVERSION operations 404 //////////////////// 405 case DOUBLE_2FLOAT_opcode: 406 result = double2Float(s, opts); 407 break; 408 case DOUBLE_2INT_opcode: 409 result = double2Int(s, opts); 410 break; 411 case DOUBLE_2LONG_opcode: 412 result = double2Long(s, opts); 413 break; 414 case DOUBLE_AS_LONG_BITS_opcode: 415 result = doubleAsLongBits(s, opts); 416 break; 417 case INT_2DOUBLE_opcode: 418 result = int2Double(s, opts); 419 break; 420 case INT_2BYTE_opcode: 421 result = int2Byte(s, opts); 422 break; 423 case INT_2USHORT_opcode: 424 result = int2UShort(s, opts); 425 break; 426 case INT_2FLOAT_opcode: 427 result = int2Float(s, opts); 428 break; 429 case INT_2LONG_opcode: 430 result = int2Long(s, opts); 431 break; 432 case INT_2ADDRSigExt_opcode: 433 result = int2AddrSigExt(s, opts); 434 break; 435 case INT_2ADDRZerExt_opcode: 436 result = int2AddrZerExt(s, opts); 437 break; 438 case LONG_2ADDR_opcode: 439 result = long2Addr(s, opts); 440 break; 441 case INT_2SHORT_opcode: 442 result = int2Short(s, opts); 443 break; 444 case INT_BITS_AS_FLOAT_opcode: 445 result = intBitsAsFloat(s, opts); 446 break; 447 case ADDR_2INT_opcode: 448 result = addr2Int(s, opts); 449 break; 450 case ADDR_2LONG_opcode: 451 result = addr2Long(s, opts); 452 break; 453 case FLOAT_2DOUBLE_opcode: 454 result = float2Double(s, opts); 455 break; 456 case FLOAT_2INT_opcode: 457 result = float2Int(s, opts); 458 break; 459 case FLOAT_2LONG_opcode: 460 result = float2Long(s, opts); 461 break; 462 case FLOAT_AS_INT_BITS_opcode: 463 result = floatAsIntBits(s, opts); 464 break; 465 case LONG_2FLOAT_opcode: 466 result = long2Float(s, opts); 467 break; 468 case LONG_2INT_opcode: 469 result = long2Int(s, opts); 470 break; 471 case LONG_2DOUBLE_opcode: 472 result = long2Double(s, opts); 473 break; 474 case LONG_BITS_AS_DOUBLE_opcode: 475 result = longBitsAsDouble(s, opts); 476 break; 477 //////////////////// 478 // Field operations 479 //////////////////// 480 case ARRAYLENGTH_opcode: 481 result = arrayLength(s, opts); 482 break; 483 case BOUNDS_CHECK_opcode: 484 result = boundsCheck(s, opts); 485 break; 486 case CALL_opcode: 487 result = call(hir, regpool, s, opts); 488 break; 489 case GETFIELD_opcode: 490 result = getField(s, opts); 491 break; 492 case GET_OBJ_TIB_opcode: 493 result = getObjTib(s, opts); 494 break; 495 case GET_CLASS_TIB_opcode: 496 result = getClassTib(s, opts); 497 break; 498 case GET_TYPE_FROM_TIB_opcode: 499 result = getTypeFromTib(s, opts); 500 break; 501 case GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode: 502 result = getArrayElementTibFromTib(s, opts); 503 break; 504 case GET_SUPERCLASS_IDS_FROM_TIB_opcode: 505 result = getSuperclassIdsFromTib(s, opts); 506 break; 507 case GET_DOES_IMPLEMENT_FROM_TIB_opcode: 508 result = getDoesImplementFromTib(s, opts); 509 break; 510 case REF_LOAD_opcode: 511 result = refLoad(s, opts); 512 break; 513 default: 514 result = DefUseEffect.UNCHANGED; 515 } 516 if (VM.VerifyAssertions) { 517 switch (result) { 518 case MOVE_FOLDED: 519 // Check move has constant RHS 520 boolean moveHasConstantRHS = Move.conforms(s) && (Move.getVal(s) instanceof ConstantOperand); 521 if (!moveHasConstantRHS) { 522 String msg = "RHS of move " + s + " should be constant during simplification of " + 523 s.operator(); 524 VM._assert(VM.NOT_REACHED, msg); 525 } 526 break; 527 case MOVE_REDUCED: 528 // Check move has non-constant RHS 529 boolean moveHasNonConstantRHS = Move.conforms(s) && !(Move.getVal(s) instanceof ConstantOperand); 530 if (!moveHasNonConstantRHS) { 531 String msg = "RHS of move " + s + " shouldn't be constant during simplification of " + 532 s.operator(); 533 VM._assert(moveHasNonConstantRHS, msg); 534 } 535 break; 536 default: 537 // Nothing to check 538 } 539 } 540 return result; 541 } 542 543 private static DefUseEffect guardCombine(Instruction s, OptOptions opts) { 544 Operand op1 = Binary.getVal1(s); 545 Operand op2 = Binary.getVal2(s); 546 if (op1.similar(op2) || (op2 instanceof TrueGuardOperand)) { 547 Move.mutate(s, GUARD_MOVE, Binary.getClearResult(s), op1); 548 if (op1 instanceof TrueGuardOperand) { 549 // BOTH true guards: FOLD 550 return DefUseEffect.MOVE_FOLDED; 551 } else { 552 // ONLY OP2 IS TrueGuard: MOVE REDUCE 553 return DefUseEffect.MOVE_REDUCED; 554 } 555 } else if (op1 instanceof TrueGuardOperand) { 556 // ONLY OP1 IS TrueGuard: MOVE REDUCE 557 Move.mutate(s, GUARD_MOVE, Binary.getClearResult(s), op2); 558 return DefUseEffect.MOVE_REDUCED; 559 } else { 560 return DefUseEffect.UNCHANGED; 561 } 562 } 563 564 private static DefUseEffect trapIf(Instruction s, OptOptions opts) { 565 { 566 Operand op1 = TrapIf.getVal1(s); 567 Operand op2 = TrapIf.getVal2(s); 568 if (op1.isConstant()) { 569 if (op2.isConstant()) { 570 int willTrap = TrapIf.getCond(s).evaluate(op1, op2); 571 if (willTrap == ConditionOperand.TRUE) { 572 Trap.mutate(s, TRAP, TrapIf.getClearGuardResult(s), TrapIf.getClearTCode(s)); 573 return DefUseEffect.TRAP_REDUCED; 574 } else if (willTrap == ConditionOperand.FALSE) { 575 Move.mutate(s, GUARD_MOVE, TrapIf.getClearGuardResult(s), TG()); 576 return DefUseEffect.MOVE_FOLDED; 577 } 578 } else { 579 // canonicalize 580 TrapIf.mutate(s, 581 TRAP_IF, 582 TrapIf.getClearGuardResult(s), 583 TrapIf.getClearVal2(s), 584 TrapIf.getClearVal1(s), 585 TrapIf.getClearCond(s).flipOperands(), 586 TrapIf.getClearTCode(s)); 587 } 588 } 589 } 590 return DefUseEffect.UNCHANGED; 591 } 592 593 private static DefUseEffect nullCheck(Instruction s, OptOptions opts) { 594 Operand ref = NullCheck.getRef(s); 595 if (ref.isNullConstant() || (ref.isAddressConstant() && ref.asAddressConstant().value.isZero())) { 596 Trap.mutate(s, TRAP, NullCheck.getClearGuardResult(s), TrapCodeOperand.NullPtr()); 597 return DefUseEffect.TRAP_REDUCED; 598 } else if (ref.isConstant()) { 599 // object, string, class or non-null address constant 600 601 // Make the slightly suspect assumption that all non-zero address 602 // constants are actually valid pointers. Not necessarily true, 603 // but unclear what else we can do. 604 Move.mutate(s, GUARD_MOVE, NullCheck.getClearGuardResult(s), TG()); 605 return DefUseEffect.MOVE_FOLDED; 606 } else { 607 return DefUseEffect.UNCHANGED; 608 } 609 } 610 611 private static DefUseEffect intZeroCheck(Instruction s, OptOptions opts) { 612 { 613 Operand op = ZeroCheck.getValue(s); 614 if (op.isIntConstant()) { 615 int val = op.asIntConstant().value; 616 if (val == 0) { 617 Trap.mutate(s, TRAP, ZeroCheck.getClearGuardResult(s), TrapCodeOperand.DivByZero()); 618 return DefUseEffect.TRAP_REDUCED; 619 } else { 620 Move.mutate(s, GUARD_MOVE, ZeroCheck.getClearGuardResult(s), TG()); 621 return DefUseEffect.MOVE_FOLDED; 622 } 623 } 624 } 625 return DefUseEffect.UNCHANGED; 626 } 627 628 private static DefUseEffect longZeroCheck(Instruction s, OptOptions opts) { 629 { 630 Operand op = ZeroCheck.getValue(s); 631 if (op.isLongConstant()) { 632 long val = op.asLongConstant().value; 633 if (val == 0L) { 634 Trap.mutate(s, TRAP, ZeroCheck.getClearGuardResult(s), TrapCodeOperand.DivByZero()); 635 return DefUseEffect.TRAP_REDUCED; 636 } else { 637 Move.mutate(s, GUARD_MOVE, ZeroCheck.getClearGuardResult(s), TG()); 638 return DefUseEffect.MOVE_FOLDED; 639 } 640 } 641 } 642 return DefUseEffect.UNCHANGED; 643 } 644 private static DefUseEffect checkcast(Instruction s, OptOptions opts) { 645 Operand ref = TypeCheck.getRef(s); 646 if (ref.isNullConstant()) { 647 Move.mutate(s, REF_MOVE, TypeCheck.getResult(s), ref); 648 if (ref.isConstant()) 649 return DefUseEffect.MOVE_FOLDED; 650 else 651 return DefUseEffect.MOVE_REDUCED; 652 } else if (ref.isConstant()) { 653 s.changeOperatorTo(CHECKCAST_NOTNULL); 654 return checkcastNotNull(s, opts); 655 } else { 656 TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); 657 TypeReference rhsType = ref.getType(); 658 byte ans = ClassLoaderProxy.includesType(lhsType, rhsType); 659 if (ans == YES) { 660 Move.mutate(s, REF_MOVE, TypeCheck.getResult(s), ref); 661 if (ref.isConstant()) 662 return DefUseEffect.MOVE_FOLDED; 663 else 664 return DefUseEffect.MOVE_REDUCED; 665 } else { 666 // NOTE: Constants.NO can't help us because (T)null always succeeds 667 return DefUseEffect.UNCHANGED; 668 } 669 } 670 } 671 672 private static DefUseEffect checkcastNotNull(Instruction s, OptOptions opts) { 673 Operand ref = TypeCheck.getRef(s); 674 TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); 675 TypeReference rhsType = ref.getType(); 676 byte ans = ClassLoaderProxy.includesType(lhsType, rhsType); 677 if (ans == YES) { 678 Move.mutate(s, REF_MOVE, TypeCheck.getResult(s), ref); 679 if (ref.isConstant()) 680 return DefUseEffect.MOVE_FOLDED; 681 else 682 return DefUseEffect.MOVE_REDUCED; 683 } else if (ans == NO) { 684 RVMType rType = rhsType.peekType(); 685 if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { 686 // only final (or precise) rhs types can be optimized since rhsType may be conservative 687 Trap.mutate(s, TRAP, null, TrapCodeOperand.CheckCast()); 688 return DefUseEffect.TRAP_REDUCED; 689 } else { 690 return DefUseEffect.UNCHANGED; 691 } 692 } else { 693 return DefUseEffect.UNCHANGED; 694 } 695 } 696 private static DefUseEffect instanceOf(Instruction s, OptOptions opts) { 697 Operand ref = InstanceOf.getRef(s); 698 if (ref.isNullConstant()) { 699 Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0)); 700 return DefUseEffect.MOVE_FOLDED; 701 } else if (ref.isConstant()) { 702 s.changeOperatorTo(INSTANCEOF_NOTNULL); 703 return instanceOfNotNull(s, opts); 704 } else { 705 TypeReference lhsType = InstanceOf.getType(s).getTypeRef(); 706 TypeReference rhsType = ref.getType(); 707 byte ans = ClassLoaderProxy.includesType(lhsType, rhsType); 708 // NOTE: Constants.YES doesn't help because ref may be null and null instanceof T is false 709 if (ans == NO) { 710 RVMType rType = rhsType.peekType(); 711 if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { 712 // only final (or precise) rhs types can be optimized since rhsType may be conservative 713 Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0)); 714 return DefUseEffect.MOVE_FOLDED; 715 } else { 716 return DefUseEffect.UNCHANGED; 717 } 718 } else { 719 return DefUseEffect.UNCHANGED; 720 } 721 } 722 } 723 724 private static DefUseEffect instanceOfNotNull(Instruction s, OptOptions opts) { 725 { 726 Operand ref = InstanceOf.getRef(s); 727 TypeReference lhsType = InstanceOf.getType(s).getTypeRef(); 728 TypeReference rhsType = ref.getType(); 729 byte ans = ClassLoaderProxy.includesType(lhsType, rhsType); 730 if (ans == YES) { 731 Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(1)); 732 return DefUseEffect.MOVE_FOLDED; 733 } else if (ans == NO) { 734 RVMType rType = rhsType.peekType(); 735 if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { 736 // only final (or precise) rhs types can be optimized since rhsType may be conservative 737 Move.mutate(s, INT_MOVE, InstanceOf.getClearResult(s), IC(0)); 738 return DefUseEffect.MOVE_FOLDED; 739 } 740 } 741 } 742 return DefUseEffect.UNCHANGED; 743 } 744 745 private static DefUseEffect objarrayStoreCheck(Instruction s, OptOptions opts) { 746 Operand val = StoreCheck.getVal(s); 747 if (val.isNullConstant()) { 748 // Writing null into an array is trivially safe 749 Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); 750 return DefUseEffect.MOVE_REDUCED; 751 } else { 752 Operand ref = StoreCheck.getRef(s); 753 TypeReference arrayTypeRef = ref.getType(); 754 if (!arrayTypeRef.isArrayType()) { 755 // Caused by inlining new and type propogation 756 return DefUseEffect.UNCHANGED; 757 } 758 RVMType typeOfIMElem = arrayTypeRef.getInnermostElementType().peekType(); 759 if (typeOfIMElem != null) { 760 RVMType typeOfVal = val.getType().peekType(); 761 if ((typeOfIMElem == typeOfVal) && 762 (typeOfIMElem.isPrimitiveType() || typeOfIMElem.isUnboxedType() || typeOfIMElem.asClass().isFinal())) { 763 // Writing something of a final type to an array of that 764 // final type is safe 765 Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); 766 return DefUseEffect.MOVE_REDUCED; 767 } 768 } 769 final boolean refIsPrecise = ref.isConstant() || (ref.isRegister() && ref.asRegister().isPreciseType()); 770 if ((arrayTypeRef == TypeReference.JavaLangObjectArray) && refIsPrecise) { 771 // We know this to be an array of objects so any store must 772 // be safe 773 Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); 774 return DefUseEffect.MOVE_REDUCED; 775 } 776 final boolean valIsPrecise = val.isConstant() || (val.isRegister() && val.asRegister().isPreciseType()); 777 if (refIsPrecise && valIsPrecise) { 778 // writing a known type of value into a known type of array 779 byte ans = ClassLoaderProxy.includesType(arrayTypeRef.getArrayElementType(), val.getType()); 780 if (ans == YES) { 781 // all stores should succeed 782 Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); 783 return DefUseEffect.MOVE_REDUCED; 784 } else if (ans == NO) { 785 // all stores will fail 786 Trap.mutate(s, TRAP, StoreCheck.getClearGuardResult(s), TrapCodeOperand.StoreCheck()); 787 return DefUseEffect.TRAP_REDUCED; 788 } 789 } 790 return DefUseEffect.UNCHANGED; 791 } 792 } 793 794 private static DefUseEffect objarrayStoreCheckNotNull(Instruction s, OptOptions opts) { 795 Operand val = StoreCheck.getVal(s); 796 Operand ref = StoreCheck.getRef(s); 797 TypeReference arrayTypeRef = ref.getType(); 798 if (!arrayTypeRef.isArrayType()) { 799 // Caused by inlining new and type propogation 800 return DefUseEffect.UNCHANGED; 801 } 802 RVMType typeOfIMElem = arrayTypeRef.getInnermostElementType().peekType(); 803 if (typeOfIMElem != null) { 804 RVMType typeOfVal = val.getType().peekType(); 805 if ((typeOfIMElem == typeOfVal) && 806 (typeOfIMElem.isPrimitiveType() || typeOfIMElem.isUnboxedType() || typeOfIMElem.asClass().isFinal())) { 807 // Writing something of a final type to an array of that 808 // final type is safe 809 Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); 810 return DefUseEffect.MOVE_REDUCED; 811 } 812 } 813 final boolean refIsPrecise = ref.isConstant() || (ref.isRegister() && ref.asRegister().isPreciseType()); 814 if ((arrayTypeRef == TypeReference.JavaLangObjectArray) && refIsPrecise) { 815 // We know this to be an array of objects so any store must 816 // be safe 817 Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); 818 return DefUseEffect.MOVE_REDUCED; 819 } 820 final boolean valIsPrecise = val.isConstant() || (val.isRegister() && val.asRegister().isPreciseType()); 821 if (refIsPrecise && valIsPrecise) { 822 // writing a known type of value into a known type of array 823 byte ans = ClassLoaderProxy.includesType(arrayTypeRef.getArrayElementType(), val.getType()); 824 if (ans == YES) { 825 // all stores should succeed 826 Move.mutate(s, GUARD_MOVE, StoreCheck.getClearGuardResult(s), StoreCheck.getClearGuard(s)); 827 return DefUseEffect.MOVE_REDUCED; 828 } else if (ans == NO) { 829 // all stores will fail 830 Trap.mutate(s, TRAP, StoreCheck.getClearGuardResult(s), TrapCodeOperand.StoreCheck()); 831 return DefUseEffect.TRAP_REDUCED; 832 } 833 } 834 return DefUseEffect.UNCHANGED; 835 } 836 837 private static DefUseEffect mustImplementInterface(Instruction s, OptOptions opts) { 838 Operand ref = TypeCheck.getRef(s); 839 if (ref.isNullConstant()) { 840 // Possible situation from constant propagation. This operation 841 // is really a nop as a null_check should have happened already 842 Trap.mutate(s, TRAP, null, TrapCodeOperand.NullPtr()); 843 return DefUseEffect.TRAP_REDUCED; 844 } else { 845 TypeReference lhsType = TypeCheck.getType(s).getTypeRef(); // the interface that must be implemented 846 TypeReference rhsType = ref.getType(); // our type 847 byte ans = ClassLoaderProxy.includesType(lhsType, rhsType); 848 if (ans == YES) { 849 RVMType rType = rhsType.peekType(); 850 if (rType != null) { 851 if (rType.isClassType() && rType.asClass().isInterface()) { 852 /* This is exactly the kind of typing that could require us to raise an IncompatibleClassChangeError */ 853 return DefUseEffect.UNCHANGED; 854 } 855 Move.mutate(s, REF_MOVE, TypeCheck.getResult(s), ref); 856 if (ref.isConstant()) 857 return DefUseEffect.MOVE_FOLDED; 858 else 859 return DefUseEffect.MOVE_REDUCED; 860 } else { 861 return DefUseEffect.UNCHANGED; 862 } 863 } else if (ans == NO) { 864 RVMType rType = rhsType.peekType(); 865 if (rType != null && rType.isClassType() && rType.asClass().isFinal()) { 866 // only final (or precise) rhs types can be optimized since rhsType may be conservative 867 Trap.mutate(s, TRAP, null, TrapCodeOperand.MustImplement()); 868 return DefUseEffect.TRAP_REDUCED; 869 } 870 } 871 return DefUseEffect.UNCHANGED; 872 } 873 } 874 875 private static DefUseEffect intCondMove(Instruction s, OptOptions opts) { 876 { 877 Operand val1 = CondMove.getVal1(s); 878 Operand val2 = CondMove.getVal2(s); 879 int cond = CondMove.getCond(s).evaluate(val1, val2); 880 if (cond != ConditionOperand.UNKNOWN) { 881 // BOTH CONSTANTS OR SIMILAR: FOLD 882 Operand val = 883 (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); 884 Move.mutate(s, INT_MOVE, CondMove.getClearResult(s), val); 885 return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 886 } 887 if (val1.isConstant() && !val2.isConstant()) { 888 // Canonicalize by switching operands and fliping code. 889 Operand tmp = CondMove.getClearVal1(s); 890 CondMove.setVal1(s, CondMove.getClearVal2(s)); 891 CondMove.setVal2(s, tmp); 892 CondMove.getCond(s).flipOperands(); 893 } 894 Operand tv = CondMove.getTrueValue(s); 895 Operand fv = CondMove.getFalseValue(s); 896 if (tv.similar(fv)) { 897 Move.mutate(s, INT_MOVE, CondMove.getClearResult(s), tv); 898 return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 899 } 900 if (tv.isIntConstant() && fv.isIntConstant() && !CondMove.getCond(s).isFLOATINGPOINT()) { 901 int itv = tv.asIntConstant().value; 902 int ifv = fv.asIntConstant().value; 903 Operator op = null; 904 if (val1.isLong()) { 905 op = BOOLEAN_CMP_LONG; 906 } else if (val1.isFloat()) { 907 op = BOOLEAN_CMP_FLOAT; 908 } else if (val1.isDouble()) { 909 op = BOOLEAN_CMP_DOUBLE; 910 } else if (val1.isRef()) { 911 op = BOOLEAN_CMP_ADDR; 912 } else { 913 op = BOOLEAN_CMP_INT; 914 } 915 if (itv == 1 && ifv == 0) { 916 BooleanCmp.mutate(s, 917 op, 918 CondMove.getClearResult(s), 919 CondMove.getClearVal1(s), 920 CondMove.getClearVal2(s), 921 CondMove.getClearCond(s), 922 new BranchProfileOperand()); 923 return DefUseEffect.REDUCED; 924 } 925 if (itv == 0 && ifv == 1) { 926 BooleanCmp.mutate(s, 927 op, 928 CondMove.getClearResult(s), 929 CondMove.getClearVal1(s), 930 CondMove.getClearVal2(s), 931 CondMove.getClearCond(s).flipCode(), 932 new BranchProfileOperand()); 933 return DefUseEffect.REDUCED; 934 } 935 } 936 } 937 return DefUseEffect.UNCHANGED; 938 } 939 940 private static DefUseEffect longCondMove(Instruction s, OptOptions opts) { 941 { 942 Operand val1 = CondMove.getVal1(s); 943 Operand val2 = CondMove.getVal2(s); 944 int cond = CondMove.getCond(s).evaluate(val1, val2); 945 if (cond != ConditionOperand.UNKNOWN) { 946 // BOTH CONSTANTS OR SIMILAR: FOLD 947 Operand val = 948 (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); 949 Move.mutate(s, LONG_MOVE, CondMove.getClearResult(s), val); 950 return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 951 } 952 if (val1.isConstant() && !val2.isConstant()) { 953 // Canonicalize by switching operands and fliping code. 954 Operand tmp = CondMove.getClearVal1(s); 955 CondMove.setVal1(s, CondMove.getClearVal2(s)); 956 CondMove.setVal2(s, tmp); 957 CondMove.getCond(s).flipOperands(); 958 } 959 Operand tv = CondMove.getTrueValue(s); 960 Operand fv = CondMove.getFalseValue(s); 961 if (tv.similar(fv)) { 962 Move.mutate(s, LONG_MOVE, CondMove.getClearResult(s), tv); 963 return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 964 } 965 if (tv.isLongConstant() && fv.isLongConstant() && !CondMove.getCond(s).isFLOATINGPOINT()) { 966 long itv = tv.asLongConstant().value; 967 long ifv = fv.asLongConstant().value; 968 Operator op = null; 969 if (val1.isLong()) { 970 op = BOOLEAN_CMP_LONG; 971 } else if (val1.isFloat()) { 972 op = BOOLEAN_CMP_FLOAT; 973 } else if (val1.isDouble()) { 974 op = BOOLEAN_CMP_DOUBLE; 975 } else { 976 op = BOOLEAN_CMP_INT; 977 } 978 if (itv == 1 && ifv == 0) { 979 BooleanCmp.mutate(s, 980 op, 981 CondMove.getClearResult(s), 982 CondMove.getClearVal1(s), 983 CondMove.getClearVal2(s), 984 CondMove.getClearCond(s), 985 new BranchProfileOperand()); 986 return DefUseEffect.REDUCED; 987 } 988 if (itv == 0 && ifv == 1) { 989 BooleanCmp.mutate(s, 990 op, 991 CondMove.getClearResult(s), 992 CondMove.getClearVal1(s), 993 CondMove.getClearVal2(s), 994 CondMove.getClearCond(s).flipCode(), 995 new BranchProfileOperand()); 996 return DefUseEffect.REDUCED; 997 } 998 } 999 } 1000 return DefUseEffect.UNCHANGED; 1001 } 1002 1003 private static DefUseEffect floatCondMove(Instruction s, OptOptions opts) { 1004 { 1005 Operand val1 = CondMove.getVal1(s); 1006 Operand val2 = CondMove.getVal2(s); 1007 int cond = CondMove.getCond(s).evaluate(val1, val2); 1008 if (cond != ConditionOperand.UNKNOWN) { 1009 // BOTH CONSTANTS OR SIMILAR: FOLD 1010 Operand val = 1011 (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); 1012 Move.mutate(s, FLOAT_MOVE, CondMove.getClearResult(s), val); 1013 return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1014 } 1015 if (val1.isConstant() && !val2.isConstant()) { 1016 // Canonicalize by switching operands and fliping code. 1017 Operand tmp = CondMove.getClearVal1(s); 1018 CondMove.setVal1(s, CondMove.getClearVal2(s)); 1019 CondMove.setVal2(s, tmp); 1020 CondMove.getCond(s).flipOperands(); 1021 } 1022 Operand tv = CondMove.getTrueValue(s); 1023 Operand fv = CondMove.getFalseValue(s); 1024 if (tv.similar(fv)) { 1025 Move.mutate(s, FLOAT_MOVE, CondMove.getClearResult(s), tv); 1026 return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1027 } 1028 } 1029 return DefUseEffect.UNCHANGED; 1030 } 1031 1032 private static DefUseEffect doubleCondMove(Instruction s, OptOptions opts) { 1033 { 1034 Operand val1 = CondMove.getVal1(s); 1035 Operand val2 = CondMove.getVal2(s); 1036 int cond = CondMove.getCond(s).evaluate(val1, val2); 1037 if (cond != ConditionOperand.UNKNOWN) { 1038 // BOTH CONSTANTS OR SIMILAR: FOLD 1039 Operand val = 1040 (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); 1041 Move.mutate(s, DOUBLE_MOVE, CondMove.getClearResult(s), val); 1042 return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1043 } 1044 if (val1.isConstant() && !val2.isConstant()) { 1045 // Canonicalize by switching operands and fliping code. 1046 Operand tmp = CondMove.getClearVal1(s); 1047 CondMove.setVal1(s, CondMove.getClearVal2(s)); 1048 CondMove.setVal2(s, tmp); 1049 CondMove.getCond(s).flipOperands(); 1050 } 1051 Operand tv = CondMove.getTrueValue(s); 1052 Operand fv = CondMove.getFalseValue(s); 1053 if (tv.similar(fv)) { 1054 Move.mutate(s, DOUBLE_MOVE, CondMove.getClearResult(s), tv); 1055 return tv.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1056 } 1057 } 1058 return DefUseEffect.UNCHANGED; 1059 } 1060 1061 private static DefUseEffect refCondMove(Instruction s, OptOptions opts) { 1062 { 1063 Operand val1 = CondMove.getVal1(s); 1064 if (val1.isConstant()) { 1065 Operand val2 = CondMove.getVal2(s); 1066 if (val2.isConstant()) { 1067 // BOTH CONSTANTS: FOLD 1068 int cond = CondMove.getCond(s).evaluate(val1, val2); 1069 if (cond != ConditionOperand.UNKNOWN) { 1070 Operand val = 1071 (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); 1072 Move.mutate(s, REF_MOVE, CondMove.getClearResult(s), val); 1073 return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1074 } 1075 } else { 1076 // Canonicalize by switching operands and fliping code. 1077 Operand tmp = CondMove.getClearVal1(s); 1078 CondMove.setVal1(s, CondMove.getClearVal2(s)); 1079 CondMove.setVal2(s, tmp); 1080 CondMove.getCond(s).flipOperands(); 1081 } 1082 } 1083 if (CondMove.getTrueValue(s).similar(CondMove.getFalseValue(s))) { 1084 Operand val = CondMove.getClearTrueValue(s); 1085 Move.mutate(s, REF_MOVE, CondMove.getClearResult(s), val); 1086 return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1087 } 1088 } 1089 return DefUseEffect.UNCHANGED; 1090 } 1091 1092 private static DefUseEffect guardCondMove(Instruction s, OptOptions opts) { 1093 { 1094 Operand val1 = CondMove.getVal1(s); 1095 if (val1.isConstant()) { 1096 Operand val2 = CondMove.getVal2(s); 1097 if (val2.isConstant()) { 1098 // BOTH CONSTANTS: FOLD 1099 int cond = CondMove.getCond(s).evaluate(val1, val2); 1100 if (cond == ConditionOperand.UNKNOWN) { 1101 Operand val = 1102 (cond == ConditionOperand.TRUE) ? CondMove.getClearTrueValue(s) : CondMove.getClearFalseValue(s); 1103 Move.mutate(s, GUARD_MOVE, CondMove.getClearResult(s), val); 1104 return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1105 } 1106 } else { 1107 // Canonicalize by switching operands and fliping code. 1108 Operand tmp = CondMove.getClearVal1(s); 1109 CondMove.setVal1(s, CondMove.getClearVal2(s)); 1110 CondMove.setVal2(s, tmp); 1111 CondMove.getCond(s).flipOperands(); 1112 } 1113 } 1114 if (CondMove.getTrueValue(s).similar(CondMove.getFalseValue(s))) { 1115 Operand val = CondMove.getClearTrueValue(s); 1116 Move.mutate(s, GUARD_MOVE, CondMove.getClearResult(s), val); 1117 return val.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1118 } 1119 } 1120 return DefUseEffect.UNCHANGED; 1121 } 1122 1123 private static DefUseEffect booleanNot(Instruction s, OptOptions opts) { 1124 if (opts.SIMPLIFY_INTEGER_OPS) { 1125 Operand op = Unary.getVal(s); 1126 if (op.isIntConstant()) { 1127 // CONSTANT: FOLD 1128 int val = op.asIntConstant().value; 1129 if (val == 0) { 1130 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(1)); 1131 } else { 1132 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(0)); 1133 } 1134 return DefUseEffect.MOVE_FOLDED; 1135 } 1136 } 1137 return DefUseEffect.UNCHANGED; 1138 } 1139 1140 private static DefUseEffect booleanCmpInt(Instruction s, OptOptions opts) { 1141 if (opts.SIMPLIFY_INTEGER_OPS) { 1142 Operand op1 = BooleanCmp.getVal1(s); 1143 Operand op2 = BooleanCmp.getVal2(s); 1144 if (op1.isConstant()) { 1145 if (op2.isConstant()) { 1146 // BOTH CONSTANTS: FOLD 1147 int cond = BooleanCmp.getCond(s).evaluate(op1, op2); 1148 if (cond != ConditionOperand.UNKNOWN) { 1149 Move.mutate(s, INT_MOVE, BooleanCmp.getResult(s), (cond == ConditionOperand.TRUE) ? IC(1) : IC(0)); 1150 return DefUseEffect.MOVE_FOLDED; 1151 } 1152 } else { 1153 // Canonicalize by switching operands and fliping code. 1154 BooleanCmp.setVal1(s, op2); 1155 BooleanCmp.setVal2(s, op1); 1156 BooleanCmp.getCond(s).flipOperands(); 1157 op2 = op1; 1158 op1 = BooleanCmp.getVal1(s); 1159 } 1160 } 1161 // try to fold boolean compares involving one boolean constant 1162 // e.g.: x = (y == true) ? true : false ==> x = y 1163 // or: x = (y == false) ? true : false ==> x = !y 1164 if (op1.getType().isBooleanType() && op2.isConstant()) { 1165 ConditionOperand cond = BooleanCmp.getCond(s); 1166 int op2value = op2.asIntConstant().value; 1167 if ((cond.isNOT_EQUAL() && (op2value == 0)) || (cond.isEQUAL() && (op2value == 1))) { 1168 Move.mutate(s, INT_MOVE, BooleanCmp.getResult(s), op1); 1169 return DefUseEffect.MOVE_REDUCED; 1170 } else if ((cond.isEQUAL() && (op2value == 0)) || (cond.isNOT_EQUAL() && (op2value == 1))) { 1171 Unary.mutate(s, BOOLEAN_NOT, BooleanCmp.getResult(s), op1); 1172 return DefUseEffect.REDUCED; 1173 } 1174 } 1175 } 1176 return DefUseEffect.UNCHANGED; 1177 } 1178 1179 private static DefUseEffect booleanCmpAddr(Instruction s, OptOptions opts) { 1180 if (opts.SIMPLIFY_REF_OPS) { 1181 Operand op1 = BooleanCmp.getVal1(s); 1182 Operand op2 = BooleanCmp.getVal2(s); 1183 if (op1.isConstant()) { 1184 if (op2.isConstant()) { 1185 // BOTH CONSTANTS: FOLD 1186 int cond = BooleanCmp.getCond(s).evaluate(op1, op2); 1187 if (cond != ConditionOperand.UNKNOWN) { 1188 Move.mutate(s, REF_MOVE, BooleanCmp.getResult(s), (cond == ConditionOperand.TRUE) ? IC(1) : IC(0)); 1189 return DefUseEffect.MOVE_FOLDED; 1190 } 1191 } else { 1192 // Canonicalize by switching operands and fliping code. 1193 Operand tmp = BooleanCmp.getClearVal1(s); 1194 BooleanCmp.setVal1(s, BooleanCmp.getClearVal2(s)); 1195 BooleanCmp.setVal2(s, tmp); 1196 BooleanCmp.getCond(s).flipOperands(); 1197 } 1198 } 1199 } 1200 return DefUseEffect.UNCHANGED; 1201 } 1202 1203 private static DefUseEffect intAdd(Instruction s, OptOptions opts) { 1204 if (opts.SIMPLIFY_INTEGER_OPS) { 1205 canonicalizeCommutativeOperator(s); 1206 Operand op2 = Binary.getVal2(s); 1207 if (op2.isIntConstant()) { 1208 int val2 = op2.asIntConstant().value; 1209 Operand op1 = Binary.getVal1(s); 1210 if (op1.isIntConstant()) { 1211 // BOTH CONSTANTS: FOLD 1212 int val1 = op1.asIntConstant().value; 1213 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 + val2)); 1214 return DefUseEffect.MOVE_FOLDED; 1215 } else { 1216 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1217 if (val2 == 0) { 1218 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1219 return DefUseEffect.MOVE_REDUCED; 1220 } 1221 } 1222 } else { 1223 Operand op1 = Binary.getVal1(s); 1224 if (op1.similar(op2)) { 1225 // Adding something to itself is the same as a multiply by 2 so 1226 // canonicalize as a shift left 1227 Binary.mutate(s, INT_SHL, Binary.getClearResult(s), op1, IC(1)); 1228 return DefUseEffect.UNCHANGED; 1229 } 1230 } 1231 } 1232 return DefUseEffect.UNCHANGED; 1233 } 1234 1235 private static DefUseEffect intAnd(Instruction s, OptOptions opts) { 1236 if (opts.SIMPLIFY_INTEGER_OPS) { 1237 canonicalizeCommutativeOperator(s); 1238 Operand op1 = Binary.getVal1(s); 1239 Operand op2 = Binary.getVal2(s); 1240 if (op1.similar(op2)) { 1241 // THE SAME OPERAND: x & x == x 1242 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1243 return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1244 } 1245 if (op2.isIntConstant()) { 1246 int val2 = op2.asIntConstant().value; 1247 if (op1.isIntConstant()) { 1248 // BOTH CONSTANTS: FOLD 1249 int val1 = op1.asIntConstant().value; 1250 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 & val2)); 1251 return DefUseEffect.MOVE_FOLDED; 1252 } else { 1253 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1254 if (val2 == 0) { // x & 0 == 0 1255 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); 1256 return DefUseEffect.MOVE_FOLDED; 1257 } 1258 if (val2 == -1) { // x & -1 == x & 0xffffffff == x 1259 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1260 return DefUseEffect.MOVE_REDUCED; 1261 } 1262 } 1263 } 1264 } 1265 return DefUseEffect.UNCHANGED; 1266 } 1267 1268 private static DefUseEffect intDiv(AbstractRegisterPool regpool, Instruction s, OptOptions opts) { 1269 if (opts.SIMPLIFY_INTEGER_OPS) { 1270 Operand op1 = GuardedBinary.getVal1(s); 1271 Operand op2 = GuardedBinary.getVal2(s); 1272 if (op1.similar(op2)) { 1273 // THE SAME OPERAND: x / x == 1 1274 Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(1)); 1275 return DefUseEffect.MOVE_FOLDED; 1276 } 1277 if (op2.isIntConstant()) { 1278 int val2 = op2.asIntConstant().value; 1279 if (val2 == 0) { 1280 // TODO: This instruction is actually unreachable. 1281 // There will be an INT_ZERO_CHECK 1282 // guarding this instruction that will result in an 1283 // ArithmeticException. We 1284 // should probabbly just remove the INT_DIV as dead code. 1285 return DefUseEffect.UNCHANGED; 1286 } 1287 if (op1.isIntConstant()) { 1288 // BOTH CONSTANTS: FOLD 1289 int val1 = op1.asIntConstant().value; 1290 Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(val1 / val2)); 1291 return DefUseEffect.MOVE_FOLDED; 1292 } else { 1293 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1294 if (val2 == 1) { // x / 1 == x; 1295 Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), GuardedBinary.getClearVal1(s)); 1296 return DefUseEffect.MOVE_REDUCED; 1297 } 1298 // x / c == (x + (((1 << c) - 1) & (x >> 31))) >> c .. if c is power of 2 1299 if (s.hasPrev()) { 1300 int power = PowerOf2(val2); 1301 if (power != -1) { 1302 RegisterOperand tempInt1 = regpool.makeTempInt(); 1303 RegisterOperand tempInt2 = regpool.makeTempInt(); 1304 RegisterOperand tempInt3 = regpool.makeTempInt(); 1305 Instruction sign = Binary.create(INT_SHR, tempInt1, GuardedBinary.getVal1(s).copy(), IC(31)); 1306 sign.copyPosition(s); 1307 s.insertBefore(sign); 1308 Instruction masked = Binary.create(INT_AND, tempInt2, tempInt1.copyRO(), IC((1 << power) - 1)); 1309 masked.copyPosition(s); 1310 s.insertBefore(masked); 1311 Instruction adjusted = Binary.create(INT_ADD, tempInt3, tempInt2.copyRO(), GuardedBinary.getClearVal1(s)); 1312 adjusted.copyPosition(s); 1313 s.insertBefore(adjusted); 1314 Binary.mutate(s, INT_SHR, GuardedBinary.getClearResult(s), tempInt3.copyRO(), IC(power)); 1315 return DefUseEffect.REDUCED; 1316 } 1317 } 1318 } 1319 } 1320 } 1321 return DefUseEffect.UNCHANGED; 1322 } 1323 1324 private static DefUseEffect intMul(AbstractRegisterPool regpool, Instruction s, OptOptions opts) { 1325 if (opts.SIMPLIFY_INTEGER_OPS) { 1326 canonicalizeCommutativeOperator(s); 1327 Operand op2 = Binary.getVal2(s); 1328 if (op2.isIntConstant()) { 1329 Operand op1 = Binary.getVal1(s); 1330 if (op1.isIntConstant()) { 1331 // BOTH CONSTANTS: FOLD 1332 int val1 = op1.asIntConstant().value; 1333 int val2 = op2.asIntConstant().value; 1334 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 * val2)); 1335 return DefUseEffect.MOVE_FOLDED; 1336 } else { 1337 // ONLY OP2 IS CONSTANT 1338 return multiplyByConstant(regpool, s, op1, op2, opts); 1339 } 1340 } 1341 } 1342 return DefUseEffect.UNCHANGED; 1343 } 1344 1345 private static DefUseEffect multiplyByConstant(AbstractRegisterPool regpool, Instruction s, Operand op1, Operand op2, OptOptions opts) { 1346 Operator addOperator, moveOperator, negateOperator, shiftLeftOperator; 1347 ConstantOperand zero; 1348 long val2; 1349 int numBits; 1350 if (op2.isIntConstant()) { 1351 val2 = op2.asIntConstant().value; 1352 addOperator = INT_ADD; 1353 moveOperator = INT_MOVE; 1354 negateOperator = INT_NEG; 1355 shiftLeftOperator = INT_SHL; 1356 zero = IntConstantOperand.zero; 1357 numBits = 32; 1358 } else { 1359 val2 = op2.asLongConstant().value; 1360 addOperator = LONG_ADD; 1361 moveOperator = LONG_MOVE; 1362 negateOperator = LONG_NEG; 1363 shiftLeftOperator = LONG_SHL; 1364 zero = LongConstantOperand.zero; 1365 numBits = 64; 1366 } 1367 // ATTEMPT TO APPLY AXIOMS 1368 if (val2 == 0) { // x * 0 == 0 1369 Move.mutate(s, moveOperator, Binary.getClearResult(s), zero.copy()); 1370 return DefUseEffect.MOVE_FOLDED; 1371 } else if (numBits == 32 && ((int)val2 == ((int)-val2))) { // x * MIN_INT == x << 31 1372 Binary.mutate(s, INT_SHL, Binary.getClearResult(s), op1, IC(31)); 1373 return DefUseEffect.REDUCED; 1374 } else if (numBits == 64 && val2 == -val2) { // x * MIN_LONG == x << 63 1375 Binary.mutate(s, LONG_SHL, Binary.getClearResult(s), op1, IC(63)); 1376 return DefUseEffect.REDUCED; 1377 } 1378 // Try to reduce x*c into shift and adds, but only if cost is cheap 1379 if (s.hasPrev()) { 1380 // don't attempt to reduce if this instruction isn't 1381 // part of a well-formed sequence 1382 1383 // Cost of shift and add replacement 1384 int cost = 0; 1385 boolean negative = val2 < 0; 1386 if (negative) { 1387 val2 = -val2; 1388 cost++; 1389 } 1390 if (VM.BuildForIA32 && numBits <= BITS_IN_ADDRESS) { 1391 int lastShift = 0; 1392 boolean lastShiftWasShort = false; 1393 for (int i = 1; i < numBits; i++) { 1394 if ((val2 & (1L << i)) != 0) { 1395 // LEA shift and add uses 1 instruction, try to determine if we can 1396 // use in favour to separate shift and adds 1397 // NB LEA shift needs to be of size 1, 2 or 3 and if the last 1398 // shift used an LEA then the add can't be merged 1399 // (so we can allow better ILP by just using a regular shift of 1400 // the original operand) 1401 if (i < 4) { 1402 // can use LEA of operand 1403 cost++; 1404 } else if ((i - lastShift) < 4 && !lastShiftWasShort) { 1405 // can use LEA of last shift 1406 cost++; 1407 lastShiftWasShort = true; 1408 } else { 1409 // need separate shift and add 1410 cost += 2; 1411 lastShiftWasShort = false; 1412 } 1413 lastShift = i; 1414 } 1415 } 1416 } else if (numBits > BITS_IN_ADDRESS) { 1417 for (int i = 1; i < BITS_IN_ADDRESS; i++) { 1418 if ((val2 & (1L << i)) != 0) { 1419 // each 1 requires a shift and add 1420 cost += 2; 1421 } 1422 } 1423 for (int i = BITS_IN_ADDRESS; i < numBits; i++) { 1424 if ((val2 & (1L << i)) != 0) { 1425 // when the shift is > than the bits in the address we can just 0 1426 // the bottom word, make the cost cheaper 1427 cost++; 1428 } 1429 } 1430 } else { 1431 for (int i = 1; i < numBits; i++) { 1432 if ((val2 & (1L << i)) != 0) { 1433 // each 1 requires a shift and add 1434 cost += 2; 1435 } 1436 } 1437 } 1438 int targetCost; 1439 if (VM.BuildForIA32) { 1440 targetCost = numBits == 64 ? 6 : 4; 1441 } else { 1442 targetCost = 2; 1443 } 1444 if (cost <= targetCost) { 1445 // generate shift and adds 1446 RegisterOperand val1Operand = op1.asRegister(); 1447 RegisterOperand resultOperand = numBits == 32 ? regpool.makeTempInt() : regpool.makeTempLong(); 1448 Instruction move; 1449 if ((val2 & 1) == 1) { 1450 // result = val1 * 1 1451 move = Move.create(moveOperator, resultOperand, val1Operand); 1452 } else { 1453 // result = 0 1454 move = Move.create(moveOperator, resultOperand, zero.copy()); 1455 } 1456 move.copyPosition(s); 1457 s.insertBefore(move); 1458 int lastShift = 0; 1459 RegisterOperand lastShiftResult = null; 1460 boolean lastShiftWasShort = false; 1461 for (int i = 1; i < numBits; i++) { 1462 if ((val2 & (1L << i)) != 0) { 1463 Instruction shift; 1464 RegisterOperand shiftResult = numBits == 32 ? regpool.makeTempInt() : regpool.makeTempLong(); 1465 if (VM.BuildForIA32 && numBits <= BITS_IN_ADDRESS && 1466 lastShiftResult != null && ((i - lastShift) <= 3) && (i > 3) && !lastShiftWasShort) { 1467 // We can produce a short shift (1, 2 or 3) using the result of the last shift 1468 shift = Binary.create(shiftLeftOperator, shiftResult, lastShiftResult.copyRO(), IC(i - lastShift)); 1469 lastShiftWasShort = true; 1470 } else { 1471 shift = Binary.create(shiftLeftOperator, shiftResult, val1Operand.copyRO(), IC(i)); 1472 lastShiftWasShort = false; 1473 } 1474 shift.copyPosition(s); 1475 s.insertBefore(shift); 1476 lastShiftResult = shiftResult; 1477 lastShift = i; 1478 RegisterOperand addResult = numBits == 32 ? regpool.makeTempInt() : regpool.makeTempLong(); 1479 Instruction add = Binary.create(addOperator, addResult, resultOperand.copyRO(), shiftResult.copyRO()); 1480 add.copyPosition(s); 1481 s.insertBefore(add); 1482 resultOperand = addResult; 1483 } 1484 } 1485 if (negative) { 1486 Unary.mutate(s, negateOperator, Binary.getClearResult(s), resultOperand.copyRO()); 1487 } else { 1488 Move.mutate(s, moveOperator, Binary.getClearResult(s), resultOperand.copyRO()); 1489 } 1490 return DefUseEffect.REDUCED; 1491 } 1492 } 1493 return DefUseEffect.UNCHANGED; 1494 } 1495 1496 private static DefUseEffect intNeg(Instruction s, OptOptions opts) { 1497 if (opts.SIMPLIFY_INTEGER_OPS) { 1498 Operand op = Unary.getVal(s); 1499 if (op.isIntConstant()) { 1500 // CONSTANT: FOLD 1501 int val = op.asIntConstant().value; 1502 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(-val)); 1503 return DefUseEffect.MOVE_FOLDED; 1504 } 1505 } 1506 return DefUseEffect.UNCHANGED; 1507 } 1508 1509 private static DefUseEffect intNot(Instruction s, OptOptions opts) { 1510 if (opts.SIMPLIFY_INTEGER_OPS) { 1511 Operand op = Unary.getVal(s); 1512 if (op.isIntConstant()) { 1513 // CONSTANT: FOLD 1514 int val = op.asIntConstant().value; 1515 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(~val)); 1516 return DefUseEffect.MOVE_FOLDED; 1517 } 1518 } 1519 return DefUseEffect.UNCHANGED; 1520 } 1521 1522 private static DefUseEffect intOr(Instruction s, OptOptions opts) { 1523 if (opts.SIMPLIFY_INTEGER_OPS) { 1524 canonicalizeCommutativeOperator(s); 1525 Operand op1 = Binary.getVal1(s); 1526 Operand op2 = Binary.getVal2(s); 1527 if (op1.similar(op2)) { 1528 // THE SAME OPERAND: x | x == x 1529 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1530 return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1531 } 1532 if (op2.isIntConstant()) { 1533 int val2 = op2.asIntConstant().value; 1534 if (op1.isIntConstant()) { 1535 // BOTH CONSTANTS: FOLD 1536 int val1 = op1.asIntConstant().value; 1537 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 | val2)); 1538 return DefUseEffect.MOVE_FOLDED; 1539 } else { 1540 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1541 if (val2 == -1) { // x | -1 == x | 0xffffffff == 0xffffffff == -1 1542 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1)); 1543 return DefUseEffect.MOVE_FOLDED; 1544 } 1545 if (val2 == 0) { // x | 0 == x 1546 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1547 return DefUseEffect.MOVE_REDUCED; 1548 } 1549 } 1550 } 1551 } 1552 return DefUseEffect.UNCHANGED; 1553 } 1554 1555 private static DefUseEffect intRem(Instruction s, OptOptions opts) { 1556 if (opts.SIMPLIFY_INTEGER_OPS) { 1557 Operand op1 = GuardedBinary.getVal1(s); 1558 Operand op2 = GuardedBinary.getVal2(s); 1559 if (op1.similar(op2)) { 1560 // THE SAME OPERAND: x % x == 0 1561 Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(0)); 1562 return DefUseEffect.MOVE_FOLDED; 1563 } 1564 if (op2.isIntConstant()) { 1565 int val2 = op2.asIntConstant().value; 1566 if (val2 == 0) { 1567 // TODO: This instruction is actually unreachable. 1568 // There will be an INT_ZERO_CHECK 1569 // guarding this instruction that will result in an 1570 // ArithmeticException. We 1571 // should probably just remove the INT_REM as dead code. 1572 return DefUseEffect.UNCHANGED; 1573 } 1574 if (op1.isIntConstant()) { 1575 // BOTH CONSTANTS: FOLD 1576 int val1 = op1.asIntConstant().value; 1577 Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(val1 % val2)); 1578 return DefUseEffect.MOVE_FOLDED; 1579 } else { 1580 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1581 if ((val2 == 1) || (val2 == -1)) { // x % 1 == 0 1582 Move.mutate(s, INT_MOVE, GuardedBinary.getClearResult(s), IC(0)); 1583 return DefUseEffect.MOVE_FOLDED; 1584 } 1585 } 1586 } 1587 } 1588 return DefUseEffect.UNCHANGED; 1589 } 1590 1591 private static DefUseEffect intShl(Instruction s, OptOptions opts) { 1592 if (opts.SIMPLIFY_INTEGER_OPS) { 1593 Operand op2 = Binary.getVal2(s); 1594 Operand op1 = Binary.getVal1(s); 1595 if (op2.isIntConstant()) { 1596 int val2 = op2.asIntConstant().value; 1597 if (op1.isIntConstant()) { 1598 // BOTH CONSTANTS: FOLD 1599 int val1 = op1.asIntConstant().value; 1600 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 << val2)); 1601 return DefUseEffect.MOVE_FOLDED; 1602 } else { 1603 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1604 if (val2 == 0) { // x << 0 == x 1605 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1606 return DefUseEffect.MOVE_REDUCED; 1607 } 1608 if ((val2 >= BITS_IN_INT) || (val2 < 0)) { // x << 32 == 0 1609 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); 1610 return DefUseEffect.MOVE_FOLDED; 1611 } 1612 } 1613 } else if (op1.isIntConstant()) { 1614 int val1 = op1.asIntConstant().value; 1615 // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1616 if (val1 == 0) { // 0 << x == 0 1617 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); 1618 return DefUseEffect.MOVE_FOLDED; 1619 } 1620 } 1621 } 1622 return DefUseEffect.UNCHANGED; 1623 } 1624 1625 private static DefUseEffect intShr(Instruction s, OptOptions opts) { 1626 if (opts.SIMPLIFY_INTEGER_OPS) { 1627 Operand op1 = Binary.getVal1(s); 1628 Operand op2 = Binary.getVal2(s); 1629 if (op2.isIntConstant()) { 1630 int val2 = op2.asIntConstant().value; 1631 if (op1.isIntConstant()) { 1632 // BOTH CONSTANTS: FOLD 1633 int val1 = op1.asIntConstant().value; 1634 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 >> val2)); 1635 return DefUseEffect.MOVE_FOLDED; 1636 } else { 1637 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1638 if (val2 == 0) { // x >> 0 == x 1639 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1640 return DefUseEffect.MOVE_REDUCED; 1641 } 1642 if ((val2 >= BITS_IN_INT) || (val2 < 0)) { // x >> 32 == x >> 31 1643 Binary.setVal2(s, IC(31)); 1644 return DefUseEffect.UNCHANGED; 1645 } 1646 } 1647 } else if (op1.isIntConstant()) { 1648 int val1 = op1.asIntConstant().value; 1649 // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1650 if ((val1 == -1) || (val1 == 0)) { // -1 >> x == -1,0 >> x == 0 1651 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), op1); 1652 return DefUseEffect.MOVE_FOLDED; 1653 } 1654 } 1655 } 1656 return DefUseEffect.UNCHANGED; 1657 } 1658 1659 private static DefUseEffect intSub(Instruction s, OptOptions opts) { 1660 if (opts.SIMPLIFY_INTEGER_OPS) { 1661 Operand op1 = Binary.getVal1(s); 1662 Operand op2 = Binary.getVal2(s); 1663 if (op1.similar(op2)) { 1664 // THE SAME OPERAND: x - x == 0 1665 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); 1666 return DefUseEffect.MOVE_FOLDED; 1667 } 1668 if (op2.isIntConstant()) { 1669 int val2 = op2.asIntConstant().value; 1670 if (op1.isIntConstant()) { 1671 // BOTH CONSTANTS: FOLD 1672 int val1 = op1.asIntConstant().value; 1673 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 - val2)); 1674 return DefUseEffect.MOVE_FOLDED; 1675 } else { 1676 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1677 if (val2 == 0) { // x - 0 == x 1678 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1679 return DefUseEffect.MOVE_REDUCED; 1680 } 1681 // x - c = x + -c 1682 // prefer adds, since some architectures have addi but not subi, also 1683 // add is commutative and gives greater flexibility to LIR/MIR phases 1684 // without possibly introducing temporary variables 1685 Binary.mutate(s, INT_ADD, Binary.getClearResult(s), Binary.getClearVal1(s), IC(-val2)); 1686 return DefUseEffect.REDUCED; 1687 } 1688 } else if (op1.isIntConstant() && (op1.asIntConstant().value == 0)) { 1689 Unary.mutate(s, INT_NEG, Binary.getClearResult(s), Binary.getClearVal2(s)); 1690 return DefUseEffect.REDUCED; 1691 } 1692 } 1693 return DefUseEffect.UNCHANGED; 1694 } 1695 1696 private static DefUseEffect intUshr(Instruction s, OptOptions opts) { 1697 if (opts.SIMPLIFY_INTEGER_OPS) { 1698 Operand op2 = Binary.getVal2(s); 1699 Operand op1 = Binary.getVal1(s); 1700 if (op2.isIntConstant()) { 1701 int val2 = op2.asIntConstant().value; 1702 if (op1.isIntConstant()) { 1703 // BOTH CONSTANTS: FOLD 1704 int val1 = op1.asIntConstant().value; 1705 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 >>> val2)); 1706 return DefUseEffect.MOVE_FOLDED; 1707 } else { 1708 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1709 if (val2 == 0) { // x >>> 0 == x 1710 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1711 return DefUseEffect.MOVE_REDUCED; 1712 } 1713 if ((val2 >= BITS_IN_INT) || (val2 < 0)) { // x >>> 32 == 0 1714 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); 1715 return DefUseEffect.MOVE_FOLDED; 1716 } 1717 } 1718 } else if (op1.isIntConstant()) { 1719 int val1 = op1.asIntConstant().value; 1720 // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1721 if (val1 == 0) { // 0 >>> x == 0 1722 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); 1723 return DefUseEffect.MOVE_FOLDED; 1724 } 1725 } 1726 } 1727 return DefUseEffect.UNCHANGED; 1728 } 1729 1730 private static DefUseEffect intXor(Instruction s, OptOptions opts) { 1731 if (opts.SIMPLIFY_INTEGER_OPS) { 1732 canonicalizeCommutativeOperator(s); 1733 Operand op1 = Binary.getVal1(s); 1734 Operand op2 = Binary.getVal2(s); 1735 if (op1.similar(op2)) { 1736 // THE SAME OPERAND: x ^ x == 0 1737 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); 1738 return DefUseEffect.MOVE_FOLDED; 1739 } 1740 if (op2.isIntConstant()) { 1741 int val2 = op2.asIntConstant().value; 1742 1743 if (op1.isIntConstant()) { 1744 // BOTH CONSTANTS: FOLD 1745 int val1 = op1.asIntConstant().value; 1746 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(val1 ^ val2)); 1747 return DefUseEffect.MOVE_FOLDED; 1748 } else { 1749 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1750 if (val2 == -1) { // x ^ -1 == x ^ 0xffffffff = ~x 1751 Unary.mutate(s, INT_NOT, Binary.getClearResult(s), Binary.getClearVal1(s)); 1752 return DefUseEffect.REDUCED; 1753 } 1754 if (val2 == 0) { // x ^ 0 == x 1755 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1756 return DefUseEffect.MOVE_REDUCED; 1757 } 1758 } 1759 } 1760 } 1761 return DefUseEffect.UNCHANGED; 1762 } 1763 1764 private static DefUseEffect refAdd(Instruction s, OptOptions opts) { 1765 if (opts.SIMPLIFY_REF_OPS) { 1766 canonicalizeCommutativeOperator(s); 1767 Operand op2 = Binary.getVal2(s); 1768 if (op2.isConstant() && !op2.isMovableObjectConstant()) { 1769 Address val2 = getAddressValue(op2); 1770 Operand op1 = Binary.getVal1(s); 1771 if (op1.isConstant() && !op1.isMovableObjectConstant()) { 1772 // BOTH CONSTANTS: FOLD 1773 Address val1 = getAddressValue(op1); 1774 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.plus(val2.toWord().toOffset()))); 1775 return DefUseEffect.MOVE_FOLDED; 1776 } else { 1777 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1778 if (val2.isZero()) { // x + 0 == x 1779 if (op1.isIntLike()) { 1780 Unary.mutate(s, INT_2ADDRSigExt, Binary.getClearResult(s), Binary.getClearVal1(s)); 1781 return DefUseEffect.REDUCED; 1782 } else { 1783 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1784 return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1785 } 1786 } 1787 } 1788 } else { 1789 Operand op1 = Binary.getVal1(s); 1790 if (op1.similar(op2)) { 1791 // Adding something to itself is the same as a multiply by 2 so 1792 // canonicalize as a shift left 1793 Binary.mutate(s, REF_SHL, Binary.getClearResult(s), op1, IC(1)); 1794 return DefUseEffect.UNCHANGED; 1795 } 1796 } 1797 } 1798 return DefUseEffect.UNCHANGED; 1799 } 1800 1801 private static DefUseEffect refAnd(Instruction s, OptOptions opts) { 1802 if (opts.SIMPLIFY_REF_OPS) { 1803 canonicalizeCommutativeOperator(s); 1804 Operand op1 = Binary.getVal1(s); 1805 Operand op2 = Binary.getVal2(s); 1806 if (op1.similar(op2)) { 1807 // THE SAME OPERAND: x & x == x 1808 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1809 return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1810 } 1811 if (op2.isConstant() && !op2.isMovableObjectConstant()) { 1812 Word val2 = getAddressValue(op2).toWord(); 1813 if (op1.isConstant() && !op1.isMovableObjectConstant()) { 1814 // BOTH CONSTANTS: FOLD 1815 Word val1 = getAddressValue(op1).toWord(); 1816 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.and(val2).toAddress())); 1817 return DefUseEffect.MOVE_FOLDED; 1818 } else { 1819 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1820 if (val2.isZero()) { // x & 0 == 0 1821 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(Address.zero())); 1822 return DefUseEffect.MOVE_FOLDED; 1823 } 1824 if (val2.isMax()) { // x & -1 == x & 0xffffffff == x 1825 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1826 return DefUseEffect.MOVE_REDUCED; 1827 } 1828 } 1829 } 1830 } 1831 return DefUseEffect.UNCHANGED; 1832 } 1833 1834 private static DefUseEffect refShl(Instruction s, OptOptions opts) { 1835 if (opts.SIMPLIFY_REF_OPS) { 1836 Operand op2 = Binary.getVal2(s); 1837 Operand op1 = Binary.getVal1(s); 1838 if (op2.isIntConstant()) { 1839 int val2 = op2.asIntConstant().value; 1840 if (op1.isConstant() && !op1.isMovableObjectConstant()) { 1841 // BOTH CONSTANTS: FOLD 1842 Word val1 = getAddressValue(op1).toWord(); 1843 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.lsh(val2).toAddress())); 1844 return DefUseEffect.MOVE_FOLDED; 1845 } else { 1846 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1847 if (val2 == 0) { // x << 0 == x 1848 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1849 return DefUseEffect.MOVE_REDUCED; 1850 } 1851 if ((val2 >= BITS_IN_ADDRESS) || (val2 < 0)) { // x << 32 == 0 1852 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), IC(0)); 1853 return DefUseEffect.MOVE_FOLDED; 1854 } 1855 } 1856 } else if (op1.isConstant() && !op1.isMovableObjectConstant()) { 1857 Word val1 = getAddressValue(op1).toWord(); 1858 // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1859 if (val1.isZero()) { // 0 << x == 0 1860 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(Address.zero())); 1861 return DefUseEffect.MOVE_FOLDED; 1862 } 1863 } 1864 } 1865 return DefUseEffect.UNCHANGED; 1866 } 1867 1868 private static DefUseEffect refShr(Instruction s, OptOptions opts) { 1869 if (opts.SIMPLIFY_REF_OPS) { 1870 Operand op1 = Binary.getVal1(s); 1871 Operand op2 = Binary.getVal2(s); 1872 if (op2.isIntConstant()) { 1873 int val2 = op2.asIntConstant().value; 1874 if (op1.isConstant() && !op1.isMovableObjectConstant()) { 1875 // BOTH CONSTANTS: FOLD 1876 Word val1 = getAddressValue(op1).toWord(); 1877 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.rsha(val2).toAddress())); 1878 return DefUseEffect.MOVE_FOLDED; 1879 } else { 1880 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1881 if (val2 == 0) { // x >> 0 == x 1882 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1883 return DefUseEffect.MOVE_REDUCED; 1884 } 1885 if ((val2 >= BITS_IN_ADDRESS) || (val2 < 0)) { // x >> 32 == x >> 31 1886 Binary.setVal2(s, IC(BITS_IN_ADDRESS - 1)); 1887 return DefUseEffect.UNCHANGED; 1888 } 1889 } 1890 } else if (op1.isConstant() && !op1.isMovableObjectConstant()) { 1891 Word val1 = getAddressValue(op1).toWord(); 1892 // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1893 // -1 >> x == -1, 0 >> x == 0 1894 if (val1.EQ(Word.zero()) || val1.EQ(Word.zero().minus(Word.one()))) { 1895 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), op1); 1896 return DefUseEffect.MOVE_FOLDED; 1897 } 1898 } 1899 } 1900 return DefUseEffect.UNCHANGED; 1901 } 1902 1903 private static DefUseEffect refNeg(Instruction s, OptOptions opts) { 1904 if (opts.SIMPLIFY_REF_OPS) { 1905 Operand op = Unary.getVal(s); 1906 if (op.isConstant() && !op.isMovableObjectConstant()) { 1907 // CONSTANT: FOLD 1908 Word val = getAddressValue(op).toWord(); 1909 Word negVal = Word.zero().minus(val); 1910 Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(negVal.toAddress())); 1911 return DefUseEffect.MOVE_FOLDED; 1912 } 1913 } 1914 return DefUseEffect.UNCHANGED; 1915 } 1916 1917 private static DefUseEffect refNot(Instruction s, OptOptions opts) { 1918 if (opts.SIMPLIFY_REF_OPS) { 1919 Operand op = Unary.getVal(s); 1920 if (op.isConstant() && !op.isMovableObjectConstant()) { 1921 // CONSTANT: FOLD 1922 Word val = getAddressValue(op).toWord(); 1923 Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(val.not().toAddress())); 1924 return DefUseEffect.MOVE_FOLDED; 1925 } 1926 } 1927 return DefUseEffect.UNCHANGED; 1928 } 1929 1930 private static DefUseEffect refOr(Instruction s, OptOptions opts) { 1931 if (opts.SIMPLIFY_REF_OPS) { 1932 canonicalizeCommutativeOperator(s); 1933 Operand op1 = Binary.getVal1(s); 1934 Operand op2 = Binary.getVal2(s); 1935 if (op1.similar(op2)) { 1936 // THE SAME OPERAND: x | x == x 1937 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1938 return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1939 } 1940 if (op2.isConstant() && !op2.isMovableObjectConstant()) { 1941 Word val2 = getAddressValue(op2).toWord(); 1942 if (op1.isAddressConstant()) { 1943 // BOTH CONSTANTS: FOLD 1944 Word val1 = getAddressValue(op1).toWord(); 1945 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.or(val2).toAddress())); 1946 return DefUseEffect.MOVE_FOLDED; 1947 } else { 1948 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1949 if (val2.isMax()) { // x | -1 == x | 0xffffffff == 0xffffffff == -1 1950 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(Address.max())); 1951 return DefUseEffect.MOVE_FOLDED; 1952 } 1953 if (val2.isZero()) { // x | 0 == x 1954 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1955 return DefUseEffect.MOVE_REDUCED; 1956 } 1957 } 1958 } 1959 } 1960 return DefUseEffect.UNCHANGED; 1961 } 1962 1963 private static DefUseEffect refSub(Instruction s, OptOptions opts) { 1964 if (opts.SIMPLIFY_REF_OPS) { 1965 Operand op1 = Binary.getVal1(s); 1966 Operand op2 = Binary.getVal2(s); 1967 if (op1.similar(op2)) { 1968 // THE SAME OPERAND: x - x == 0 1969 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), IC(0)); 1970 return DefUseEffect.MOVE_FOLDED; 1971 } 1972 if (op2.isConstant() && !op2.isMovableObjectConstant()) { 1973 Address val2 = getAddressValue(op2); 1974 if (op1.isConstant() && !op1.isMovableObjectConstant()) { 1975 // BOTH CONSTANTS: FOLD 1976 Address val1 = getAddressValue(op1); 1977 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.minus(val2.toWord().toOffset()))); 1978 return DefUseEffect.MOVE_FOLDED; 1979 } else { 1980 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 1981 if (val2.isZero()) { // x - 0 == x 1982 if (op1.isIntLike()) { 1983 Unary.mutate(s, INT_2ADDRSigExt, Binary.getClearResult(s), Binary.getClearVal1(s)); 1984 return DefUseEffect.REDUCED; 1985 } else { 1986 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 1987 return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 1988 } 1989 } 1990 // x - c = x + -c 1991 // prefer adds, since some architectures have addi but not subi 1992 Binary.mutate(s, 1993 REF_ADD, 1994 Binary.getClearResult(s), 1995 Binary.getClearVal1(s), 1996 AC(Address.zero().minus(val2.toWord().toOffset()))); 1997 return DefUseEffect.REDUCED; 1998 } 1999 } else if (op1.isConstant() && !op1.isMovableObjectConstant()) { 2000 Address val1 = getAddressValue(op1); 2001 if (val1.EQ(Address.zero())) { 2002 Unary.mutate(s, REF_NEG, Binary.getClearResult(s), Binary.getClearVal2(s)); 2003 return DefUseEffect.REDUCED; 2004 } 2005 } 2006 } 2007 return DefUseEffect.UNCHANGED; 2008 } 2009 2010 private static DefUseEffect refUshr(Instruction s, OptOptions opts) { 2011 if (opts.SIMPLIFY_REF_OPS) { 2012 Operand op2 = Binary.getVal2(s); 2013 Operand op1 = Binary.getVal1(s); 2014 if (op2.isIntConstant()) { 2015 int val2 = op2.asIntConstant().value; 2016 if (op1.isConstant() && !op1.isMovableObjectConstant()) { 2017 // BOTH CONSTANTS: FOLD 2018 Word val1 = getAddressValue(op1).toWord(); 2019 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.rshl(val2).toAddress())); 2020 return DefUseEffect.MOVE_FOLDED; 2021 } else { 2022 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2023 if (val2 == 0) { // x >>> 0 == x 2024 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2025 return DefUseEffect.MOVE_REDUCED; 2026 } 2027 if ((val2 >= BITS_IN_ADDRESS) || (val2 < 0)) { // x >>> 32 == 0 2028 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), IC(0)); 2029 return DefUseEffect.MOVE_FOLDED; 2030 } 2031 } 2032 } else if (op1.isConstant() && !op1.isMovableObjectConstant()) { 2033 Word val1 = getAddressValue(op1).toWord(); 2034 // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2035 if (val1.EQ(Word.zero())) { // 0 >>> x == 0 2036 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(Address.zero())); 2037 return DefUseEffect.MOVE_FOLDED; 2038 } 2039 } 2040 } 2041 return DefUseEffect.UNCHANGED; 2042 } 2043 2044 private static DefUseEffect refXor(Instruction s, OptOptions opts) { 2045 if (opts.SIMPLIFY_REF_OPS) { 2046 canonicalizeCommutativeOperator(s); 2047 Operand op1 = Binary.getVal1(s); 2048 Operand op2 = Binary.getVal2(s); 2049 if (op1.similar(op2)) { 2050 // THE SAME OPERAND: x ^ x == 0 2051 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), IC(0)); 2052 return DefUseEffect.MOVE_FOLDED; 2053 } 2054 if (op2.isConstant() && !op2.isMovableObjectConstant()) { 2055 Word val2 = getAddressValue(op2).toWord(); 2056 if (op1.isConstant() && !op1.isMovableObjectConstant()) { 2057 // BOTH CONSTANTS: FOLD 2058 Word val1 = getAddressValue(op1).toWord(); 2059 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), AC(val1.xor(val2).toAddress())); 2060 return DefUseEffect.MOVE_FOLDED; 2061 } else { 2062 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2063 if (val2.isMax()) { // x ^ -1 == x ^ 0xffffffff = ~x 2064 Unary.mutate(s, REF_NOT, Binary.getClearResult(s), Binary.getClearVal1(s)); 2065 return DefUseEffect.REDUCED; 2066 } 2067 if (val2.isZero()) { // x ^ 0 == x 2068 Move.mutate(s, REF_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2069 return DefUseEffect.MOVE_REDUCED; 2070 } 2071 } 2072 } 2073 } 2074 return DefUseEffect.UNCHANGED; 2075 } 2076 2077 private static DefUseEffect longAdd(Instruction s, OptOptions opts) { 2078 if (opts.SIMPLIFY_LONG_OPS) { 2079 canonicalizeCommutativeOperator(s); 2080 Operand op2 = Binary.getVal2(s); 2081 if (op2.isLongConstant()) { 2082 long val2 = op2.asLongConstant().value; 2083 Operand op1 = Binary.getVal1(s); 2084 if (op1.isLongConstant()) { 2085 // BOTH CONSTANTS: FOLD 2086 long val1 = op1.asLongConstant().value; 2087 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 + val2)); 2088 return DefUseEffect.MOVE_FOLDED; 2089 } else { 2090 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2091 if (val2 == 0L) { // x + 0 == x 2092 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2093 return DefUseEffect.MOVE_REDUCED; 2094 } 2095 } 2096 } else { 2097 Operand op1 = Binary.getVal1(s); 2098 if (op1.similar(op2)) { 2099 // Adding something to itself is the same as a multiply by 2 so 2100 // canonicalize as a shift left 2101 Binary.mutate(s, LONG_SHL, Binary.getClearResult(s), op1, IC(1)); 2102 return DefUseEffect.UNCHANGED; 2103 } 2104 } 2105 } 2106 return DefUseEffect.UNCHANGED; 2107 } 2108 2109 private static DefUseEffect longAnd(Instruction s, OptOptions opts) { 2110 if (opts.SIMPLIFY_LONG_OPS) { 2111 canonicalizeCommutativeOperator(s); 2112 Operand op1 = Binary.getVal1(s); 2113 Operand op2 = Binary.getVal2(s); 2114 if (op1.similar(op2)) { 2115 // THE SAME OPERAND: x & x == x 2116 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2117 return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 2118 } 2119 if (op2.isLongConstant()) { 2120 long val2 = op2.asLongConstant().value; 2121 if (op1.isLongConstant()) { 2122 // BOTH CONSTANTS: FOLD 2123 long val1 = op1.asLongConstant().value; 2124 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 & val2)); 2125 return DefUseEffect.MOVE_FOLDED; 2126 } else { 2127 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2128 if (val2 == 0L) { // x & 0L == 0L 2129 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(0L)); 2130 return DefUseEffect.MOVE_FOLDED; 2131 } 2132 if (val2 == -1) { // x & -1L == x & 0xff...ff == x 2133 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2134 return DefUseEffect.MOVE_REDUCED; 2135 } 2136 } 2137 } 2138 } 2139 return DefUseEffect.UNCHANGED; 2140 } 2141 2142 private static DefUseEffect longCmp(Instruction s, OptOptions opts) { 2143 if (opts.SIMPLIFY_LONG_OPS) { 2144 Operand op1 = Binary.getVal1(s); 2145 Operand op2 = Binary.getVal2(s); 2146 if (op1.similar(op2)) { 2147 // THE SAME OPERAND: op1 == op2 2148 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(0)); 2149 return DefUseEffect.MOVE_FOLDED; 2150 } 2151 if (op2.isLongConstant()) { 2152 if (op1.isLongConstant()) { 2153 // BOTH CONSTANTS: FOLD 2154 long val1 = op1.asLongConstant().value; 2155 long val2 = op2.asLongConstant().value; 2156 int result = (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1); 2157 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(result)); 2158 return DefUseEffect.MOVE_FOLDED; 2159 } 2160 } 2161 } 2162 return DefUseEffect.UNCHANGED; 2163 } 2164 2165 private static DefUseEffect longDiv(Instruction s, OptOptions opts) { 2166 if (opts.SIMPLIFY_LONG_OPS) { 2167 Operand op1 = GuardedBinary.getVal1(s); 2168 Operand op2 = GuardedBinary.getVal2(s); 2169 if (op1.similar(op2)) { 2170 // THE SAME OPERAND: x / x == 1 2171 Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(1)); 2172 return DefUseEffect.MOVE_FOLDED; 2173 } 2174 if (op2.isLongConstant()) { 2175 long val2 = op2.asLongConstant().value; 2176 if (val2 == 0L) { 2177 // TODO: This instruction is actually unreachable. 2178 // There will be a LONG_ZERO_CHECK 2179 // guarding this instruction that will result in an 2180 // ArithmeticException. We 2181 // should probably just remove the LONG_DIV as dead code. 2182 return DefUseEffect.UNCHANGED; 2183 } 2184 if (op1.isLongConstant()) { 2185 // BOTH CONSTANTS: FOLD 2186 long val1 = op1.asLongConstant().value; 2187 Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(val1 / val2)); 2188 return DefUseEffect.MOVE_FOLDED; 2189 } else { 2190 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2191 if (val2 == 1L) { // x / 1L == x 2192 Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), GuardedBinary.getClearVal1(s)); 2193 return DefUseEffect.MOVE_REDUCED; 2194 } 2195 } 2196 } 2197 } 2198 return DefUseEffect.UNCHANGED; 2199 } 2200 private static DefUseEffect longMul(AbstractRegisterPool regpool, Instruction s, OptOptions opts) { 2201 if (opts.SIMPLIFY_LONG_OPS) { 2202 canonicalizeCommutativeOperator(s); 2203 Operand op2 = Binary.getVal2(s); 2204 if (op2.isLongConstant()) { 2205 Operand op1 = Binary.getVal1(s); 2206 if (op1.isLongConstant()) { 2207 // BOTH CONSTANTS: FOLD 2208 long val1 = op1.asLongConstant().value; 2209 long val2 = op2.asLongConstant().value; 2210 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 * val2)); 2211 return DefUseEffect.MOVE_FOLDED; 2212 } else { 2213 // ONLY OP2 IS CONSTANT 2214 return multiplyByConstant(regpool, s, op1, op2, opts); 2215 } 2216 } 2217 } 2218 return DefUseEffect.UNCHANGED; 2219 } 2220 2221 private static DefUseEffect longNeg(Instruction s, OptOptions opts) { 2222 if (opts.SIMPLIFY_LONG_OPS) { 2223 Operand op = Unary.getVal(s); 2224 if (op.isLongConstant()) { 2225 // CONSTANT: FOLD 2226 long val = op.asLongConstant().value; 2227 Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(-val)); 2228 return DefUseEffect.MOVE_FOLDED; 2229 } 2230 } 2231 return DefUseEffect.UNCHANGED; 2232 } 2233 2234 private static DefUseEffect longNot(Instruction s, OptOptions opts) { 2235 if (opts.SIMPLIFY_LONG_OPS) { 2236 Operand op = Unary.getVal(s); 2237 if (op.isLongConstant()) { 2238 long val = op.asLongConstant().value; 2239 // CONSTANT: FOLD 2240 Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(~val)); 2241 return DefUseEffect.MOVE_FOLDED; 2242 } 2243 } 2244 return DefUseEffect.UNCHANGED; 2245 } 2246 2247 private static DefUseEffect longOr(Instruction s, OptOptions opts) { 2248 if (opts.SIMPLIFY_LONG_OPS) { 2249 canonicalizeCommutativeOperator(s); 2250 Operand op1 = Binary.getVal1(s); 2251 Operand op2 = Binary.getVal2(s); 2252 if (op1.similar(op2)) { 2253 // THE SAME OPERAND: x | x == x 2254 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2255 return op1.isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 2256 } 2257 if (op2.isLongConstant()) { 2258 long val2 = op2.asLongConstant().value; 2259 if (op1.isLongConstant()) { 2260 // BOTH CONSTANTS: FOLD 2261 long val1 = op1.asLongConstant().value; 2262 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 | val2)); 2263 return DefUseEffect.MOVE_FOLDED; 2264 } else { 2265 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2266 if (val2 == 0L) { // x | 0L == x 2267 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2268 return DefUseEffect.MOVE_REDUCED; 2269 } 2270 if (val2 == -1L) { // x | -1L == x | 0xff..ff == 0xff..ff == -1L 2271 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(-1L)); 2272 return DefUseEffect.MOVE_FOLDED; 2273 } 2274 } 2275 } 2276 } 2277 return DefUseEffect.UNCHANGED; 2278 } 2279 2280 private static DefUseEffect longRem(Instruction s, OptOptions opts) { 2281 if (opts.SIMPLIFY_LONG_OPS) { 2282 Operand op1 = GuardedBinary.getVal1(s); 2283 Operand op2 = GuardedBinary.getVal2(s); 2284 if (op1.similar(op2)) { 2285 // THE SAME OPERAND: x % x == 0 2286 Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(0)); 2287 return DefUseEffect.MOVE_FOLDED; 2288 } 2289 if (op2.isLongConstant()) { 2290 long val2 = op2.asLongConstant().value; 2291 if (val2 == 0L) { 2292 // TODO: This instruction is actually unreachable. 2293 // There will be a LONG_ZERO_CHECK 2294 // guarding this instruction that will result in an 2295 // ArithmeticException. We 2296 // should probably just remove the LONG_REM as dead code. 2297 return DefUseEffect.UNCHANGED; 2298 } 2299 if (op1.isLongConstant()) { 2300 // BOTH CONSTANTS: FOLD 2301 long val1 = op1.asLongConstant().value; 2302 Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(val1 % val2)); 2303 return DefUseEffect.MOVE_FOLDED; 2304 } else { 2305 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2306 if ((val2 == 1L) || (val2 == -1L)) { // x % 1L == 0 2307 Move.mutate(s, LONG_MOVE, GuardedBinary.getClearResult(s), LC(0)); 2308 return DefUseEffect.MOVE_FOLDED; 2309 } 2310 } 2311 } 2312 } 2313 return DefUseEffect.UNCHANGED; 2314 } 2315 2316 private static DefUseEffect longShl(Instruction s, OptOptions opts) { 2317 if (opts.SIMPLIFY_LONG_OPS) { 2318 Operand op2 = Binary.getVal2(s); 2319 Operand op1 = Binary.getVal1(s); 2320 if (op2.isIntConstant()) { 2321 int val2 = op2.asIntConstant().value; 2322 if (op1.isLongConstant()) { 2323 // BOTH CONSTANTS: FOLD 2324 long val1 = op1.asLongConstant().value; 2325 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 << val2)); 2326 return DefUseEffect.MOVE_FOLDED; 2327 } else { 2328 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2329 if (val2 == 0) { // x << 0 == x 2330 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2331 return DefUseEffect.MOVE_REDUCED; 2332 } 2333 if ((val2 >= BITS_IN_LONG) || (val2 < 0)) { // x << 64 == 0 2334 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), LC(0)); 2335 return DefUseEffect.MOVE_FOLDED; 2336 } 2337 } 2338 } else if (op1.isLongConstant()) { 2339 long val1 = op1.asLongConstant().value; 2340 // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2341 if (val1 == 0L) { // 0 << x == 0 2342 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), op1); 2343 return DefUseEffect.MOVE_FOLDED; 2344 } 2345 } 2346 } 2347 return DefUseEffect.UNCHANGED; 2348 } 2349 2350 private static DefUseEffect longShr(Instruction s, OptOptions opts) { 2351 if (opts.SIMPLIFY_LONG_OPS) { 2352 Operand op1 = Binary.getVal1(s); 2353 Operand op2 = Binary.getVal2(s); 2354 if (op2.isIntConstant()) { 2355 int val2 = op2.asIntConstant().value; 2356 if (op1.isLongConstant()) { 2357 // BOTH CONSTANTS: FOLD 2358 long val1 = op1.asLongConstant().value; 2359 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 >> val2)); 2360 return DefUseEffect.MOVE_FOLDED; 2361 } else { 2362 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2363 if (val2 == 0) { // x >> 0L == x 2364 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2365 return DefUseEffect.MOVE_REDUCED; 2366 } 2367 if ((val2 >= BITS_IN_LONG) || (val2 < 0)) { // x >> 64 == x >> 63 2368 Binary.setVal2(s, LC(63)); 2369 return DefUseEffect.UNCHANGED; 2370 } 2371 } 2372 } else if (op1.isLongConstant()) { 2373 long val1 = op1.asLongConstant().value; 2374 // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2375 if ((val1 == -1L) || (val1 == 0L)) { // -1 >> x == -1, 0 >> x == 0 2376 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), op1); 2377 return DefUseEffect.MOVE_FOLDED; 2378 } 2379 } 2380 } 2381 return DefUseEffect.UNCHANGED; 2382 } 2383 2384 private static DefUseEffect longSub(Instruction s, OptOptions opts) { 2385 if (opts.SIMPLIFY_LONG_OPS) { 2386 Operand op1 = Binary.getVal1(s); 2387 Operand op2 = Binary.getVal2(s); 2388 if (op1.similar(op2)) { 2389 // THE SAME OPERAND: x - x == 0 2390 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(0)); 2391 return DefUseEffect.MOVE_FOLDED; 2392 } 2393 if (op2.isLongConstant()) { 2394 long val2 = op2.asLongConstant().value; 2395 if (op1.isLongConstant()) { 2396 // BOTH CONSTANTS: FOLD 2397 long val1 = op1.asLongConstant().value; 2398 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 - val2)); 2399 return DefUseEffect.MOVE_FOLDED; 2400 } else { 2401 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2402 if (val2 == 0L) { // x - 0 == x 2403 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2404 return DefUseEffect.MOVE_REDUCED; 2405 } 2406 // x - c = x + -c 2407 // prefer adds, since some architectures have addi but not subi, also 2408 // add is commutative and gives greater flexibility to LIR/MIR phases 2409 // without possibly introducing temporary variables 2410 Binary.mutate(s, LONG_ADD, Binary.getClearResult(s), 2411 Binary.getClearVal1(s), LC(-val2)); 2412 return DefUseEffect.REDUCED; 2413 } 2414 } else if (op1.isLongConstant() && (op1.asLongConstant().value == 0)) { 2415 Unary.mutate(s, LONG_NEG, Binary.getClearResult(s), Binary.getClearVal2(s)); 2416 return DefUseEffect.REDUCED; 2417 } 2418 } 2419 return DefUseEffect.UNCHANGED; 2420 } 2421 2422 private static DefUseEffect longUshr(Instruction s, OptOptions opts) { 2423 if (opts.SIMPLIFY_LONG_OPS) { 2424 Operand op2 = Binary.getVal2(s); 2425 Operand op1 = Binary.getVal1(s); 2426 if (op2.isIntConstant()) { 2427 int val2 = op2.asIntConstant().value; 2428 if (op1.isLongConstant()) { 2429 // BOTH CONSTANTS: FOLD 2430 long val1 = op1.asLongConstant().value; 2431 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 >>> val2)); 2432 return DefUseEffect.MOVE_FOLDED; 2433 } else { 2434 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2435 if (val2 == 0) { // x >>> 0L == x 2436 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2437 return DefUseEffect.MOVE_REDUCED; 2438 } 2439 if ((val2 >= BITS_IN_LONG) || (val2 < 0)) { // x >>> 64 == 0 2440 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(0)); 2441 return DefUseEffect.MOVE_FOLDED; 2442 } 2443 } 2444 } else if (op1.isLongConstant()) { 2445 long val1 = op1.asLongConstant().value; 2446 // ONLY OP1 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2447 if (val1 == 0L) { // 0 >>> x == 0 2448 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), op1); 2449 return DefUseEffect.MOVE_FOLDED; 2450 } 2451 } 2452 } 2453 return DefUseEffect.UNCHANGED; 2454 } 2455 2456 private static DefUseEffect longXor(Instruction s, OptOptions opts) { 2457 if (opts.SIMPLIFY_LONG_OPS) { 2458 canonicalizeCommutativeOperator(s); 2459 Operand op1 = Binary.getVal1(s); 2460 Operand op2 = Binary.getVal2(s); 2461 if (op1.similar(op2)) { 2462 // THE SAME OPERAND: x ^ x == 0 2463 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(0)); 2464 return DefUseEffect.MOVE_FOLDED; 2465 } 2466 if (op2.isLongConstant()) { 2467 long val2 = op2.asLongConstant().value; 2468 if (op1.isLongConstant()) { 2469 // BOTH CONSTANTS: FOLD 2470 long val1 = op1.asLongConstant().value; 2471 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), LC(val1 ^ val2)); 2472 return DefUseEffect.MOVE_FOLDED; 2473 } else { 2474 // ONLY OP2 IS CONSTANT: ATTEMPT TO APPLY AXIOMS 2475 if (val2 == -1L) { // x ^ -1L == x ^ 0xff..ff = ~x 2476 Unary.mutate(s, LONG_NOT, Binary.getClearResult(s), Binary.getClearVal1(s)); 2477 return DefUseEffect.REDUCED; 2478 } 2479 if (val2 == 0L) { // x ^ 0L == x 2480 Move.mutate(s, LONG_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2481 return DefUseEffect.MOVE_REDUCED; 2482 } 2483 } 2484 } 2485 } 2486 return DefUseEffect.UNCHANGED; 2487 } 2488 2489 private static DefUseEffect floatAdd(Instruction s, OptOptions opts) { 2490 if (opts.SIMPLIFY_FLOAT_OPS) { 2491 canonicalizeCommutativeOperator(s); 2492 Operand op2 = Binary.getVal2(s); 2493 if (op2.isFloatConstant()) { 2494 float val2 = op2.asFloatConstant().value; 2495 Operand op1 = Binary.getVal1(s); 2496 if (op1.isFloatConstant()) { 2497 // BOTH CONSTANTS: FOLD 2498 float val1 = op1.asFloatConstant().value; 2499 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 + val2)); 2500 return DefUseEffect.MOVE_FOLDED; 2501 } 2502 if (val2 == 0.0f) { 2503 // x + 0.0 is x (even is x is a NaN). 2504 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2505 return DefUseEffect.MOVE_REDUCED; 2506 } 2507 if (Float.isNaN(val2)) { 2508 // x + NaN is NaN 2509 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN)); 2510 return DefUseEffect.MOVE_FOLDED; 2511 } 2512 } 2513 } 2514 return DefUseEffect.UNCHANGED; 2515 } 2516 2517 private static DefUseEffect floatCmpg(Instruction s, OptOptions opts) { 2518 if (opts.SIMPLIFY_FLOAT_OPS) { 2519 Operand op1 = Binary.getVal1(s); 2520 Operand op2 = Binary.getVal2(s); 2521 if (op2.isFloatConstant()) { 2522 float val2 = op2.asFloatConstant().value; 2523 if (op1.isFloatConstant()) { 2524 // BOTH CONSTANTS: FOLD 2525 float val1 = op1.asFloatConstant().value; 2526 int result = (val1 < val2) ? -1 : ((val1 == val2) ? 0 : 1); 2527 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(result)); 2528 return DefUseEffect.MOVE_FOLDED; 2529 } 2530 if (Float.isNaN(val2)) { 2531 // result is unordered => 1 2532 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(1)); 2533 return DefUseEffect.MOVE_FOLDED; 2534 } 2535 } 2536 if (op1.isFloatConstant()) { 2537 float val1 = op1.asFloatConstant().value; 2538 if (Float.isNaN(val1)) { 2539 // result is unordered => 1 2540 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(1)); 2541 return DefUseEffect.MOVE_FOLDED; 2542 } 2543 } 2544 } 2545 return DefUseEffect.UNCHANGED; 2546 } 2547 2548 private static DefUseEffect floatCmpl(Instruction s, OptOptions opts) { 2549 if (opts.SIMPLIFY_FLOAT_OPS) { 2550 Operand op1 = Binary.getVal1(s); 2551 Operand op2 = Binary.getVal2(s); 2552 if (op2.isFloatConstant()) { 2553 float val2 = op2.asFloatConstant().value; 2554 if (op1.isFloatConstant()) { 2555 // BOTH CONSTANTS: FOLD 2556 float val1 = op1.asFloatConstant().value; 2557 int result = (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1); 2558 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(result)); 2559 return DefUseEffect.MOVE_FOLDED; 2560 } 2561 if (Float.isNaN(val2)) { 2562 // result is unordered => -1 2563 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1)); 2564 return DefUseEffect.MOVE_FOLDED; 2565 } 2566 } 2567 if (op1.isFloatConstant()) { 2568 float val1 = op1.asFloatConstant().value; 2569 if (Float.isNaN(val1)) { 2570 // result is unordered => -1 2571 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1)); 2572 return DefUseEffect.MOVE_FOLDED; 2573 } 2574 } 2575 } 2576 return DefUseEffect.UNCHANGED; 2577 } 2578 2579 private static DefUseEffect floatDiv(Instruction s, OptOptions opts) { 2580 if (opts.SIMPLIFY_FLOAT_OPS) { 2581 Operand op1 = Binary.getVal1(s); 2582 Operand op2 = Binary.getVal2(s); 2583 if (op2.isFloatConstant()) { 2584 float val2 = op2.asFloatConstant().value; 2585 if (op1.isFloatConstant()) { 2586 // BOTH CONSTANTS: FOLD 2587 float val1 = op1.asFloatConstant().value; 2588 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 / val2)); 2589 return DefUseEffect.MOVE_FOLDED; 2590 } 2591 if (Float.isNaN(val2)) { 2592 // x / NaN is NaN 2593 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN)); 2594 return DefUseEffect.MOVE_FOLDED; 2595 } 2596 } 2597 if (op1.isFloatConstant()) { 2598 float val1 = op1.asFloatConstant().value; 2599 if (Float.isNaN(val1)) { 2600 // NaN / x is NaN 2601 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN)); 2602 return DefUseEffect.MOVE_FOLDED; 2603 } 2604 } 2605 } 2606 return DefUseEffect.UNCHANGED; 2607 } 2608 2609 private static DefUseEffect floatMul(Instruction s, OptOptions opts) { 2610 if (opts.SIMPLIFY_FLOAT_OPS) { 2611 canonicalizeCommutativeOperator(s); 2612 Operand op2 = Binary.getVal2(s); 2613 if (op2.isFloatConstant()) { 2614 float val2 = op2.asFloatConstant().value; 2615 Operand op1 = Binary.getVal1(s); 2616 if (op1.isFloatConstant()) { 2617 // BOTH CONSTANTS: FOLD 2618 float val1 = op1.asFloatConstant().value; 2619 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 * val2)); 2620 return DefUseEffect.MOVE_FOLDED; 2621 } 2622 if (val2 == 1.0f) { 2623 // x * 1.0 is x, even if x is a NaN 2624 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2625 return DefUseEffect.MOVE_REDUCED; 2626 } 2627 if (Float.isNaN(val2)) { 2628 // x * NaN is NaN 2629 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN)); 2630 return DefUseEffect.MOVE_FOLDED; 2631 } 2632 } 2633 } 2634 return DefUseEffect.UNCHANGED; 2635 } 2636 2637 private static DefUseEffect floatNeg(Instruction s, OptOptions opts) { 2638 if (opts.SIMPLIFY_FLOAT_OPS) { 2639 Operand op = Unary.getVal(s); 2640 if (op.isFloatConstant()) { 2641 // CONSTANT: FOLD 2642 float val = op.asFloatConstant().value; 2643 Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC(-val)); 2644 return DefUseEffect.MOVE_FOLDED; 2645 } 2646 } 2647 return DefUseEffect.UNCHANGED; 2648 } 2649 2650 private static DefUseEffect floatRem(Instruction s, OptOptions opts) { 2651 if (opts.SIMPLIFY_FLOAT_OPS) { 2652 Operand op1 = Binary.getVal1(s); 2653 Operand op2 = Binary.getVal2(s); 2654 if (op2.isFloatConstant()) { 2655 float val2 = op2.asFloatConstant().value; 2656 if (op1.isFloatConstant()) { 2657 // BOTH CONSTANTS: FOLD 2658 float val1 = op1.asFloatConstant().value; 2659 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 % val2)); 2660 return DefUseEffect.MOVE_FOLDED; 2661 } 2662 if (Float.isNaN(val2)) { 2663 // x % NaN is NaN 2664 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN)); 2665 return DefUseEffect.MOVE_FOLDED; 2666 } 2667 } 2668 if (op1.isFloatConstant()) { 2669 float val1 = op1.asFloatConstant().value; 2670 if (Float.isNaN(val1)) { 2671 // NaN % x is NaN 2672 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN)); 2673 return DefUseEffect.MOVE_FOLDED; 2674 } 2675 } 2676 } 2677 return DefUseEffect.UNCHANGED; 2678 } 2679 2680 private static DefUseEffect floatSub(Instruction s, OptOptions opts) { 2681 if (opts.SIMPLIFY_FLOAT_OPS) { 2682 Operand op1 = Binary.getVal1(s); 2683 Operand op2 = Binary.getVal2(s); 2684 if (op2.isFloatConstant()) { 2685 float val2 = op2.asFloatConstant().value; 2686 if (op1.isFloatConstant()) { 2687 // BOTH CONSTANTS: FOLD 2688 float val1 = op1.asFloatConstant().value; 2689 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(val1 - val2)); 2690 return DefUseEffect.MOVE_FOLDED; 2691 } 2692 if (val2 == 0.0f) { 2693 // x - 0.0 is x, even if x is a NaN 2694 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2695 return DefUseEffect.MOVE_REDUCED; 2696 } 2697 if (Float.isNaN(val2)) { 2698 // x - NaN is NaN 2699 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN)); 2700 return DefUseEffect.MOVE_FOLDED; 2701 } 2702 } 2703 if (op1.isFloatConstant()) { 2704 float val1 = op1.asFloatConstant().value; 2705 if (val1 == 0.0f) { 2706 // 0.0 - x is -x 2707 Unary.mutate(s, FLOAT_NEG, Binary.getClearResult(s), Binary.getClearVal2(s)); 2708 return DefUseEffect.REDUCED; 2709 } 2710 if (Float.isNaN(val1)) { 2711 // x - NaN is NaN 2712 Move.mutate(s, FLOAT_MOVE, Binary.getClearResult(s), FC(Float.NaN)); 2713 return DefUseEffect.MOVE_FOLDED; 2714 } 2715 } 2716 } 2717 return DefUseEffect.UNCHANGED; 2718 } 2719 2720 private static DefUseEffect floatSqrt(Instruction s, OptOptions opts) { 2721 if (opts.SIMPLIFY_FLOAT_OPS) { 2722 Operand op = Unary.getVal(s); 2723 if (op.isFloatConstant()) { 2724 // CONSTANT: FOLD 2725 float val = op.asFloatConstant().value; 2726 Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC((float)Math.sqrt(val))); 2727 return DefUseEffect.MOVE_FOLDED; 2728 } 2729 } 2730 return DefUseEffect.UNCHANGED; 2731 } 2732 2733 private static DefUseEffect doubleAdd(Instruction s, OptOptions opts) { 2734 if (opts.SIMPLIFY_DOUBLE_OPS) { 2735 canonicalizeCommutativeOperator(s); 2736 Operand op2 = Binary.getVal2(s); 2737 if (op2.isDoubleConstant()) { 2738 double val2 = op2.asDoubleConstant().value; 2739 Operand op1 = Binary.getVal1(s); 2740 if (op1.isDoubleConstant()) { 2741 // BOTH CONSTANTS: FOLD 2742 double val1 = op1.asDoubleConstant().value; 2743 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 + val2)); 2744 return DefUseEffect.MOVE_FOLDED; 2745 } 2746 if (val2 == 0.0) { 2747 // x + 0.0 is x, even if x is a NaN 2748 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2749 return DefUseEffect.MOVE_REDUCED; 2750 } 2751 if (Double.isNaN(val2)) { 2752 // x + NaN is NaN 2753 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN)); 2754 return DefUseEffect.MOVE_FOLDED; 2755 } 2756 } 2757 } 2758 return DefUseEffect.UNCHANGED; 2759 } 2760 2761 private static DefUseEffect doubleCmpg(Instruction s, OptOptions opts) { 2762 if (opts.SIMPLIFY_DOUBLE_OPS) { 2763 Operand op1 = Binary.getVal1(s); 2764 Operand op2 = Binary.getVal2(s); 2765 if (op2.isDoubleConstant()) { 2766 double val2 = op2.asDoubleConstant().value; 2767 if (op1.isDoubleConstant()) { 2768 // BOTH CONSTANTS: FOLD 2769 double val1 = op1.asDoubleConstant().value; 2770 int result = (val1 < val2) ? -1 : ((val1 == val2) ? 0 : 1); 2771 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(result)); 2772 return DefUseEffect.MOVE_FOLDED; 2773 } 2774 if (Double.isNaN(val2)) { 2775 // result is unordered => 1 2776 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(1)); 2777 return DefUseEffect.MOVE_FOLDED; 2778 } 2779 } 2780 if (op1.isDoubleConstant()) { 2781 double val1 = op1.asDoubleConstant().value; 2782 if (Double.isNaN(val1)) { 2783 // result is unordered => 1 2784 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(1)); 2785 return DefUseEffect.MOVE_FOLDED; 2786 } 2787 } 2788 } 2789 return DefUseEffect.UNCHANGED; 2790 } 2791 2792 private static DefUseEffect doubleCmpl(Instruction s, OptOptions opts) { 2793 if (opts.SIMPLIFY_DOUBLE_OPS) { 2794 Operand op1 = Binary.getVal1(s); 2795 Operand op2 = Binary.getVal2(s); 2796 if (op2.isDoubleConstant()) { 2797 double val2 = op2.asDoubleConstant().value; 2798 if (op1.isDoubleConstant()) { 2799 // BOTH CONSTANTS: FOLD 2800 double val1 = op1.asDoubleConstant().value; 2801 int result = (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1); 2802 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), IC(result)); 2803 return DefUseEffect.MOVE_FOLDED; 2804 } 2805 if (Double.isNaN(val2)) { 2806 // result is unordered => -1 2807 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1)); 2808 return DefUseEffect.MOVE_FOLDED; 2809 } 2810 } 2811 if (op1.isDoubleConstant()) { 2812 double val1 = op1.asDoubleConstant().value; 2813 if (Double.isNaN(val1)) { 2814 // result is unordered => -1 2815 Move.mutate(s, INT_MOVE, Binary.getClearResult(s), IC(-1)); 2816 return DefUseEffect.MOVE_FOLDED; 2817 } 2818 } 2819 } 2820 return DefUseEffect.UNCHANGED; 2821 } 2822 2823 private static DefUseEffect doubleDiv(Instruction s, OptOptions opts) { 2824 if (opts.SIMPLIFY_DOUBLE_OPS) { 2825 Operand op1 = Binary.getVal1(s); 2826 Operand op2 = Binary.getVal2(s); 2827 if (op2.isDoubleConstant()) { 2828 double val2 = op2.asDoubleConstant().value; 2829 if (op1.isDoubleConstant()) { 2830 // BOTH CONSTANTS: FOLD 2831 double val1 = op1.asDoubleConstant().value; 2832 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 / val2)); 2833 return DefUseEffect.MOVE_FOLDED; 2834 } 2835 if (Double.isNaN(val2)) { 2836 // x / NaN is NaN 2837 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN)); 2838 return DefUseEffect.MOVE_FOLDED; 2839 } 2840 } 2841 if (op1.isDoubleConstant()) { 2842 double val1 = op1.asDoubleConstant().value; 2843 if (Double.isNaN(val1)) { 2844 // x / NaN is NaN 2845 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN)); 2846 return DefUseEffect.MOVE_FOLDED; 2847 } 2848 } 2849 } 2850 return DefUseEffect.UNCHANGED; 2851 } 2852 2853 private static DefUseEffect doubleMul(Instruction s, OptOptions opts) { 2854 if (opts.SIMPLIFY_DOUBLE_OPS) { 2855 canonicalizeCommutativeOperator(s); 2856 Operand op2 = Binary.getVal2(s); 2857 if (op2.isDoubleConstant()) { 2858 double val2 = op2.asDoubleConstant().value; 2859 Operand op1 = Binary.getVal1(s); 2860 if (op1.isDoubleConstant()) { 2861 // BOTH CONSTANTS: FOLD 2862 double val1 = op1.asDoubleConstant().value; 2863 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 * val2)); 2864 return DefUseEffect.MOVE_FOLDED; 2865 } 2866 if (val2 == 1.0) { 2867 // x * 1.0 is x even if x is a NaN 2868 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2869 return DefUseEffect.MOVE_REDUCED; 2870 } 2871 if (Double.isNaN(val2)) { 2872 // x * NaN is NaN 2873 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN)); 2874 return DefUseEffect.MOVE_FOLDED; 2875 } 2876 } 2877 } 2878 return DefUseEffect.UNCHANGED; 2879 } 2880 2881 private static DefUseEffect doubleNeg(Instruction s, OptOptions opts) { 2882 if (opts.SIMPLIFY_DOUBLE_OPS) { 2883 Operand op = Unary.getVal(s); 2884 if (op.isDoubleConstant()) { 2885 // CONSTANT: FOLD 2886 double val = op.asDoubleConstant().value; 2887 Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(-val)); 2888 return DefUseEffect.MOVE_FOLDED; 2889 } 2890 } 2891 return DefUseEffect.UNCHANGED; 2892 } 2893 2894 2895 private static DefUseEffect doubleRem(Instruction s, OptOptions opts) { 2896 if (opts.SIMPLIFY_DOUBLE_OPS) { 2897 Operand op1 = Binary.getVal1(s); 2898 Operand op2 = Binary.getVal2(s); 2899 if (op2.isDoubleConstant()) { 2900 double val2 = op2.asDoubleConstant().value; 2901 if (op1.isDoubleConstant()) { 2902 // BOTH CONSTANTS: FOLD 2903 double val1 = op1.asDoubleConstant().value; 2904 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 % val2)); 2905 return DefUseEffect.MOVE_FOLDED; 2906 } 2907 if (Double.isNaN(val2)) { 2908 // x % NaN is NaN 2909 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN)); 2910 return DefUseEffect.MOVE_FOLDED; 2911 } 2912 } 2913 if (op1.isDoubleConstant()) { 2914 double val1 = op1.asDoubleConstant().value; 2915 if (Double.isNaN(val1)) { 2916 // x % NaN is NaN 2917 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN)); 2918 return DefUseEffect.MOVE_FOLDED; 2919 } 2920 } 2921 } 2922 return DefUseEffect.UNCHANGED; 2923 } 2924 2925 private static DefUseEffect doubleSub(Instruction s, OptOptions opts) { 2926 if (opts.SIMPLIFY_DOUBLE_OPS) { 2927 Operand op1 = Binary.getVal1(s); 2928 Operand op2 = Binary.getVal2(s); 2929 if (op2.isDoubleConstant()) { 2930 double val2 = op2.asDoubleConstant().value; 2931 if (op1.isDoubleConstant()) { 2932 // BOTH CONSTANTS: FOLD 2933 double val1 = op1.asDoubleConstant().value; 2934 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(val1 - val2)); 2935 return DefUseEffect.MOVE_FOLDED; 2936 } 2937 if (val2 == 0.0) { 2938 // x - 0.0 is x, even if x is a NaN 2939 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), Binary.getClearVal1(s)); 2940 return DefUseEffect.MOVE_REDUCED; 2941 } 2942 if (Double.isNaN(val2)) { 2943 // x - NaN is NaN 2944 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN)); 2945 return DefUseEffect.MOVE_FOLDED; 2946 } 2947 } 2948 if (op1.isDoubleConstant()) { 2949 double val1 = op1.asDoubleConstant().value; 2950 if (val1 == 0.0) { 2951 // 0.0 - x is -x 2952 Unary.mutate(s, DOUBLE_NEG, Binary.getClearResult(s), Binary.getClearVal2(s)); 2953 return DefUseEffect.REDUCED; 2954 } 2955 if (Double.isNaN(val1)) { 2956 // x - NaN is NaN 2957 Move.mutate(s, DOUBLE_MOVE, Binary.getClearResult(s), DC(Double.NaN)); 2958 return DefUseEffect.MOVE_FOLDED; 2959 } 2960 } 2961 } 2962 return DefUseEffect.UNCHANGED; 2963 } 2964 2965 private static DefUseEffect doubleSqrt(Instruction s, OptOptions opts) { 2966 if (opts.SIMPLIFY_DOUBLE_OPS) { 2967 Operand op = Unary.getVal(s); 2968 if (op.isDoubleConstant()) { 2969 // CONSTANT: FOLD 2970 double val = op.asDoubleConstant().value; 2971 Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(Math.sqrt(val))); 2972 return DefUseEffect.MOVE_FOLDED; 2973 } 2974 } 2975 return DefUseEffect.UNCHANGED; 2976 } 2977 2978 private static DefUseEffect double2Float(Instruction s, OptOptions opts) { 2979 if (opts.SIMPLIFY_FLOAT_OPS) { 2980 Operand op = Unary.getVal(s); 2981 if (op.isDoubleConstant()) { 2982 // CONSTANT: FOLD 2983 double val = op.asDoubleConstant().value; 2984 Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC((float) val)); 2985 return DefUseEffect.MOVE_FOLDED; 2986 } 2987 } 2988 return DefUseEffect.UNCHANGED; 2989 } 2990 2991 private static DefUseEffect double2Int(Instruction s, OptOptions opts) { 2992 if (opts.SIMPLIFY_INTEGER_OPS) { 2993 Operand op = Unary.getVal(s); 2994 if (op.isDoubleConstant()) { 2995 // CONSTANT: FOLD 2996 double val = op.asDoubleConstant().value; 2997 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((int) val)); 2998 return DefUseEffect.MOVE_FOLDED; 2999 } 3000 } 3001 return DefUseEffect.UNCHANGED; 3002 } 3003 3004 private static DefUseEffect double2Long(Instruction s, OptOptions opts) { 3005 if (opts.SIMPLIFY_LONG_OPS) { 3006 Operand op = Unary.getVal(s); 3007 if (op.isDoubleConstant()) { 3008 // CONSTANT: FOLD 3009 double val = op.asDoubleConstant().value; 3010 Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC((long) val)); 3011 return DefUseEffect.MOVE_FOLDED; 3012 } 3013 } 3014 return DefUseEffect.UNCHANGED; 3015 } 3016 3017 private static DefUseEffect doubleAsLongBits(Instruction s, OptOptions opts) { 3018 if (opts.SIMPLIFY_LONG_OPS) { 3019 Operand op = Unary.getVal(s); 3020 if (op.isDoubleConstant()) { 3021 // CONSTANT: FOLD 3022 double val = op.asDoubleConstant().value; 3023 Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(Double.doubleToLongBits(val))); 3024 return DefUseEffect.MOVE_FOLDED; 3025 } 3026 } 3027 return DefUseEffect.UNCHANGED; 3028 } 3029 3030 private static DefUseEffect int2Double(Instruction s, OptOptions opts) { 3031 if (opts.SIMPLIFY_DOUBLE_OPS) { 3032 Operand op = Unary.getVal(s); 3033 if (op.isIntConstant()) { 3034 // CONSTANT: FOLD 3035 int val = op.asIntConstant().value; 3036 Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(val)); 3037 return DefUseEffect.MOVE_FOLDED; 3038 } 3039 } 3040 return DefUseEffect.UNCHANGED; 3041 } 3042 3043 private static DefUseEffect int2Byte(Instruction s, OptOptions opts) { 3044 if (opts.SIMPLIFY_INTEGER_OPS) { 3045 Operand op = Unary.getVal(s); 3046 if (op.isIntConstant()) { 3047 // CONSTANT: FOLD 3048 int val = op.asIntConstant().value; 3049 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((byte) val)); 3050 return DefUseEffect.MOVE_FOLDED; 3051 } 3052 } 3053 return DefUseEffect.UNCHANGED; 3054 } 3055 3056 private static DefUseEffect int2UShort(Instruction s, OptOptions opts) { 3057 if (opts.SIMPLIFY_INTEGER_OPS) { 3058 Operand op = Unary.getVal(s); 3059 if (op.isIntConstant()) { 3060 // CONSTANT: FOLD 3061 int val = op.asIntConstant().value; 3062 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((char) val)); 3063 return DefUseEffect.MOVE_FOLDED; 3064 } 3065 } 3066 return DefUseEffect.UNCHANGED; 3067 } 3068 3069 private static DefUseEffect int2Float(Instruction s, OptOptions opts) { 3070 if (opts.SIMPLIFY_FLOAT_OPS) { 3071 Operand op = Unary.getVal(s); 3072 if (op.isIntConstant()) { 3073 // CONSTANT: FOLD 3074 int val = op.asIntConstant().value; 3075 Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC(val)); 3076 return DefUseEffect.MOVE_FOLDED; 3077 } 3078 } 3079 return DefUseEffect.UNCHANGED; 3080 } 3081 3082 private static DefUseEffect int2Long(Instruction s, OptOptions opts) { 3083 if (opts.SIMPLIFY_LONG_OPS) { 3084 Operand op = Unary.getVal(s); 3085 if (op.isIntConstant()) { 3086 // CONSTANT: FOLD 3087 int val = op.asIntConstant().value; 3088 Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(val)); 3089 return DefUseEffect.MOVE_FOLDED; 3090 } 3091 } 3092 return DefUseEffect.UNCHANGED; 3093 } 3094 3095 private static DefUseEffect int2AddrSigExt(Instruction s, OptOptions opts) { 3096 if (opts.SIMPLIFY_REF_OPS) { 3097 Operand op = Unary.getVal(s); 3098 if (op.isIntConstant()) { 3099 // CONSTANT: FOLD 3100 int val = op.asIntConstant().value; 3101 Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(Address.fromIntSignExtend(val))); 3102 return DefUseEffect.MOVE_FOLDED; 3103 } 3104 } 3105 return DefUseEffect.UNCHANGED; 3106 } 3107 3108 private static DefUseEffect int2AddrZerExt(Instruction s, OptOptions opts) { 3109 if (opts.SIMPLIFY_REF_OPS) { 3110 Operand op = Unary.getVal(s); 3111 if (op.isIntConstant()) { 3112 // CONSTANT: FOLD 3113 int val = op.asIntConstant().value; 3114 Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(Address.fromIntZeroExtend(val))); 3115 return DefUseEffect.MOVE_FOLDED; 3116 } 3117 } 3118 return DefUseEffect.UNCHANGED; 3119 } 3120 3121 private static DefUseEffect long2Addr(Instruction s, OptOptions opts) { 3122 if (opts.SIMPLIFY_REF_OPS) { 3123 Operand op = Unary.getVal(s); 3124 if (op.isLongConstant()) { 3125 if (VM.BuildFor64Addr) { 3126 // CONSTANT: FOLD 3127 long val = op.asLongConstant().value; 3128 Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(Address.fromLong(val))); 3129 return DefUseEffect.MOVE_FOLDED; 3130 } else { 3131 // CONSTANT: FOLD 3132 int val = (int) op.asLongConstant().value; 3133 Move.mutate(s, REF_MOVE, Unary.getClearResult(s), AC(Address.fromIntZeroExtend(val))); 3134 return DefUseEffect.MOVE_FOLDED; 3135 } 3136 } 3137 } 3138 return DefUseEffect.UNCHANGED; 3139 } 3140 3141 private static DefUseEffect int2Short(Instruction s, OptOptions opts) { 3142 if (opts.SIMPLIFY_INTEGER_OPS) { 3143 Operand op = Unary.getVal(s); 3144 if (op.isIntConstant()) { 3145 // CONSTANT: FOLD 3146 int val = op.asIntConstant().value; 3147 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((short) val)); 3148 return DefUseEffect.MOVE_FOLDED; 3149 } 3150 } 3151 return DefUseEffect.UNCHANGED; 3152 } 3153 3154 private static DefUseEffect intBitsAsFloat(Instruction s, OptOptions opts) { 3155 if (opts.SIMPLIFY_FLOAT_OPS) { 3156 Operand op = Unary.getVal(s); 3157 if (op.isIntConstant()) { 3158 // CONSTANT: FOLD 3159 int val = op.asIntConstant().value; 3160 Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC(Float.intBitsToFloat(val))); 3161 return DefUseEffect.MOVE_FOLDED; 3162 } 3163 } 3164 return DefUseEffect.UNCHANGED; 3165 } 3166 3167 private static DefUseEffect addr2Int(Instruction s, OptOptions opts) { 3168 if (opts.SIMPLIFY_INTEGER_OPS) { 3169 Operand op = Unary.getVal(s); 3170 if (op.isConstant() && !op.isMovableObjectConstant()) { 3171 // CONSTANT: FOLD 3172 Address val = getAddressValue(op); 3173 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(val.toInt())); 3174 return DefUseEffect.MOVE_FOLDED; 3175 } 3176 } 3177 return DefUseEffect.UNCHANGED; 3178 } 3179 3180 private static DefUseEffect addr2Long(Instruction s, OptOptions opts) { 3181 if (opts.SIMPLIFY_LONG_OPS) { 3182 Operand op = Unary.getVal(s); 3183 if (op.isConstant() && !op.isMovableObjectConstant()) { 3184 // CONSTANT: FOLD 3185 Address val = getAddressValue(op); 3186 Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC(val.toLong())); 3187 return DefUseEffect.MOVE_FOLDED; 3188 } 3189 } 3190 return DefUseEffect.UNCHANGED; 3191 } 3192 3193 private static DefUseEffect float2Double(Instruction s, OptOptions opts) { 3194 if (opts.SIMPLIFY_DOUBLE_OPS) { 3195 Operand op = Unary.getVal(s); 3196 if (op.isFloatConstant()) { 3197 // CONSTANT: FOLD 3198 float val = op.asFloatConstant().value; 3199 Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(val)); 3200 return DefUseEffect.MOVE_FOLDED; 3201 } 3202 } 3203 return DefUseEffect.UNCHANGED; 3204 } 3205 3206 private static DefUseEffect float2Int(Instruction s, OptOptions opts) { 3207 if (opts.SIMPLIFY_INTEGER_OPS) { 3208 Operand op = Unary.getVal(s); 3209 if (op.isFloatConstant()) { 3210 // CONSTANT: FOLD 3211 float val = op.asFloatConstant().value; 3212 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((int) val)); 3213 return DefUseEffect.MOVE_FOLDED; 3214 } 3215 } 3216 return DefUseEffect.UNCHANGED; 3217 } 3218 3219 private static DefUseEffect float2Long(Instruction s, OptOptions opts) { 3220 if (opts.SIMPLIFY_LONG_OPS) { 3221 Operand op = Unary.getVal(s); 3222 if (op.isFloatConstant()) { 3223 // CONSTANT: FOLD 3224 float val = op.asFloatConstant().value; 3225 Move.mutate(s, LONG_MOVE, Unary.getClearResult(s), LC((long) val)); 3226 return DefUseEffect.MOVE_FOLDED; 3227 } 3228 } 3229 return DefUseEffect.UNCHANGED; 3230 } 3231 3232 private static DefUseEffect floatAsIntBits(Instruction s, OptOptions opts) { 3233 if (opts.SIMPLIFY_INTEGER_OPS) { 3234 Operand op = Unary.getVal(s); 3235 if (op.isFloatConstant()) { 3236 // CONSTANT: FOLD 3237 float val = op.asFloatConstant().value; 3238 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC(Float.floatToIntBits(val))); 3239 return DefUseEffect.MOVE_FOLDED; 3240 } 3241 } 3242 return DefUseEffect.UNCHANGED; 3243 } 3244 3245 private static DefUseEffect long2Float(Instruction s, OptOptions opts) { 3246 if (opts.SIMPLIFY_FLOAT_OPS) { 3247 Operand op = Unary.getVal(s); 3248 if (op.isLongConstant()) { 3249 // CONSTANT: FOLD 3250 long val = op.asLongConstant().value; 3251 Move.mutate(s, FLOAT_MOVE, Unary.getClearResult(s), FC(val)); 3252 return DefUseEffect.MOVE_FOLDED; 3253 } 3254 } 3255 return DefUseEffect.UNCHANGED; 3256 } 3257 3258 private static DefUseEffect long2Int(Instruction s, OptOptions opts) { 3259 if (opts.SIMPLIFY_INTEGER_OPS) { 3260 Operand op = Unary.getVal(s); 3261 if (op.isLongConstant()) { 3262 // CONSTANT: FOLD 3263 long val = op.asLongConstant().value; 3264 Move.mutate(s, INT_MOVE, Unary.getClearResult(s), IC((int) val)); 3265 return DefUseEffect.MOVE_FOLDED; 3266 } 3267 } 3268 return DefUseEffect.UNCHANGED; 3269 } 3270 3271 private static DefUseEffect long2Double(Instruction s, OptOptions opts) { 3272 if (opts.SIMPLIFY_DOUBLE_OPS) { 3273 Operand op = Unary.getVal(s); 3274 if (op.isLongConstant()) { 3275 // CONSTANT: FOLD 3276 long val = op.asLongConstant().value; 3277 Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(val)); 3278 return DefUseEffect.MOVE_FOLDED; 3279 } 3280 } 3281 return DefUseEffect.UNCHANGED; 3282 } 3283 3284 private static DefUseEffect longBitsAsDouble(Instruction s, OptOptions opts) { 3285 if (opts.SIMPLIFY_DOUBLE_OPS) { 3286 Operand op = Unary.getVal(s); 3287 if (op.isLongConstant()) { 3288 // CONSTANT: FOLD 3289 long val = op.asLongConstant().value; 3290 Move.mutate(s, DOUBLE_MOVE, Unary.getClearResult(s), DC(Double.longBitsToDouble(val))); 3291 return DefUseEffect.MOVE_FOLDED; 3292 } 3293 } 3294 return DefUseEffect.UNCHANGED; 3295 } 3296 3297 private static DefUseEffect arrayLength(Instruction s, OptOptions opts) { 3298 if (opts.SIMPLIFY_FIELD_OPS) { 3299 Operand op = GuardedUnary.getVal(s); 3300 if (op.isObjectConstant()) { 3301 int length = 0; 3302 if (op.getType().getArrayElementType().isCodeType()) { 3303 length = ((CodeArray)(op.asObjectConstant().value)).length(); 3304 } else { 3305 length = Array.getLength(op.asObjectConstant().value); 3306 } 3307 Move.mutate(s, INT_MOVE, GuardedUnary.getClearResult(s), IC(length)); 3308 return DefUseEffect.MOVE_FOLDED; 3309 } else if (op.isNullConstant()) { 3310 // TODO: this arraylength operation is junk so destroy 3311 return DefUseEffect.UNCHANGED; 3312 } 3313 } 3314 return DefUseEffect.UNCHANGED; 3315 } 3316 3317 private static DefUseEffect boundsCheck(Instruction s, OptOptions opts) { 3318 if (opts.SIMPLIFY_FIELD_OPS) { 3319 Operand ref = BoundsCheck.getRef(s); 3320 Operand index = BoundsCheck.getIndex(s); 3321 if (ref.isNullConstant()) { 3322 // Should already be caught by nullcheck simplification 3323 return DefUseEffect.UNCHANGED; 3324 } else if (index.isIntConstant()) { 3325 int indexAsInt = index.asIntConstant().value; 3326 if (indexAsInt < 0) { 3327 Trap.mutate(s, TRAP, BoundsCheck.getClearGuardResult(s), TrapCodeOperand.ArrayBounds()); 3328 return DefUseEffect.TRAP_REDUCED; 3329 } else if (ref.isConstant()) { 3330 if (ref.isObjectConstant()) { 3331 int refLength = Array.getLength(ref.asObjectConstant().value); 3332 if (indexAsInt < refLength) { 3333 Move.mutate(s, GUARD_MOVE, BoundsCheck.getClearGuardResult(s), BoundsCheck.getClearGuard(s)); 3334 return Move.getVal(s).isConstant() ? DefUseEffect.MOVE_FOLDED : DefUseEffect.MOVE_REDUCED; 3335 } else { 3336 Trap.mutate(s, TRAP, BoundsCheck.getClearGuardResult(s), TrapCodeOperand.ArrayBounds()); 3337 return DefUseEffect.TRAP_REDUCED; 3338 } 3339 } 3340 } 3341 } 3342 } 3343 return DefUseEffect.UNCHANGED; 3344 } 3345 3346 private static DefUseEffect call(boolean HIR, AbstractRegisterPool regpool, Instruction s, OptOptions opts) { 3347 if (opts.SIMPLIFY_FIELD_OPS) { 3348 MethodOperand methOp = Call.getMethod(s); 3349 if (methOp == null) { 3350 return DefUseEffect.UNCHANGED; 3351 } 3352 if (methOp.isVirtual() && !methOp.hasPreciseTarget()) { 3353 Operand calleeThis = Call.getParam(s, 0); 3354 if (calleeThis.isNullConstant()) { 3355 // Should already be caught by nullcheck simplification 3356 return DefUseEffect.UNCHANGED; 3357 } else if (calleeThis.isConstant() || calleeThis.asRegister().isPreciseType()) { 3358 TypeReference calleeClass = calleeThis.getType(); 3359 if (calleeClass.isResolved()) { 3360 methOp.refine(calleeClass.peekType()); 3361 return DefUseEffect.UNCHANGED; 3362 } 3363 } 3364 } else if (methOp.isStatic() && methOp.hasPreciseTarget() && HIR) { 3365 RVMMethod method = methOp.getTarget(); 3366 // Can we remove the need for RVMClass.getClass...FromStackFrame to walk the stack? 3367 if (method == Entrypoints.getClassLoaderFromStackFrame || 3368 method == Entrypoints.getClassFromStackFrame) { 3369 Operand frameOp = Call.getParam(s, 0); 3370 if (frameOp.isIntConstant()) { 3371 int frame = frameOp.asIntConstant().value; 3372 InlineSequence currentFrame = s.position; 3373 while (frame > 0 && currentFrame != null) { 3374 currentFrame = currentFrame.caller; 3375 frame--; 3376 } 3377 if (currentFrame != null) { 3378 // we found the caller 3379 ObjectConstantOperand cop; 3380 if (method == Entrypoints.getClassLoaderFromStackFrame) { 3381 cop = new ObjectConstantOperand(currentFrame.method.getDeclaringClass().getTypeRef().getClassLoader(), Offset.zero()); 3382 } else { 3383 cop = new ObjectConstantOperand(currentFrame.method.getDeclaringClass(), Offset.zero()); 3384 } 3385 Move.mutate(s, REF_MOVE, Call.getClearResult(s), cop); 3386 return DefUseEffect.MOVE_FOLDED; 3387 } 3388 } 3389 } 3390 } 3391 if (!VM.runningVM && methOp.hasPreciseTarget() && methOp.getTarget().isRuntimePure()) { 3392 RVMMethod method = methOp.getTarget(); 3393 switch(method.getAnnotation(org.vmmagic.pragma.RuntimePure.class).value()) { 3394 case Unavailable: // not available at boot image write time 3395 return DefUseEffect.UNCHANGED; 3396 default: 3397 throw new Error("Unhandled RuntimePure value: " + 3398 method.getAnnotation(org.vmmagic.pragma.RuntimePure.class).value()); 3399 } 3400 } else if (methOp.hasPreciseTarget() && methOp.getTarget().isPure()) { 3401 // Look for a precise method call to a pure method with all constant arguments 3402 RVMMethod method = methOp.getTarget(); 3403 int n = Call.getNumberOfParams(s); 3404 for (int i = 0; i < n; i++) { 3405 Operand param = Call.getParam(s,i); 3406 if (!param.isConstant() || param.isNullConstant()) { 3407 return DefUseEffect.UNCHANGED; 3408 } 3409 } 3410 // Pure method with all constant arguments. Perform reflective method call 3411 Object thisArg = null; 3412 TypeReference[] paramTypes = method.getParameterTypes(); 3413 Object[] otherArgs; 3414 Object result = null; 3415 if (!methOp.isStatic()) { 3416 thisArg = boxConstantOperand((ConstantOperand)Call.getParam(s,0), method.getDeclaringClass().getTypeRef()); 3417 n--; 3418 otherArgs = new Object[n]; 3419 for (int i = 0; i < n; i++) { 3420 otherArgs[i] = boxConstantOperand((ConstantOperand)Call.getParam(s,i + 1),paramTypes[i]); 3421 } 3422 } else { 3423 otherArgs = new Object[n]; 3424 for (int i = 0; i < n; i++) { 3425 otherArgs[i] = boxConstantOperand((ConstantOperand)Call.getParam(s,i),paramTypes[i]); 3426 } 3427 } 3428 Throwable t = null; 3429 Method m = null; 3430 try { 3431 if (VM.runningVM) { 3432 result = Reflection.invoke(method, null, thisArg, otherArgs, false); 3433 } else { 3434 Class<?>[] argTypes = new Class<?>[n]; 3435 for (int i = 0; i < n; i++) { 3436 argTypes[i] = Call.getParam(s,i).getType().resolve().getClassForType(); 3437 } 3438 m = method.getDeclaringClass().getClassForType().getDeclaredMethod(method.getName().toString(), argTypes); 3439 result = m.invoke(thisArg, otherArgs); 3440 } 3441 } catch (Throwable e) { 3442 t = e; 3443 } 3444 if (t != null) { 3445 // Call threw exception so leave in to generate at execution time 3446 return DefUseEffect.UNCHANGED; 3447 } 3448 if (result == null) throw new OptimizingCompilerException("Method " + m + "/" + method + " returned null"); 3449 if (method.getReturnType().isVoidType()) { 3450 Empty.mutate(s, NOP); 3451 return DefUseEffect.REDUCED; 3452 } else { 3453 Operator moveOp = IRTools.getMoveOp(method.getReturnType()); 3454 Move.mutate(s,moveOp, Call.getClearResult(s), 3455 boxConstantObjectAsOperand(result, method.getReturnType())); 3456 return DefUseEffect.MOVE_FOLDED; 3457 } 3458 } 3459 } 3460 return DefUseEffect.UNCHANGED; 3461 } 3462 3463 /** 3464 * Package up a constant operand as an object 3465 * @param op the constant operand to package 3466 * @param t the type of the object (needed to differentiate primitive from numeric types..) 3467 * @return the object 3468 */ 3469 private static Object boxConstantOperand(ConstantOperand op, TypeReference t) { 3470 if (op.isObjectConstant()) { 3471 return op.asObjectConstant().value; 3472 } else if (op.isLongConstant()) { 3473 return op.asLongConstant().value; 3474 } else if (op.isFloatConstant()) { 3475 return op.asFloatConstant().value; 3476 } else if (op.isDoubleConstant()) { 3477 return op.asDoubleConstant().value; 3478 } else if (t.isIntType()) { 3479 return op.asIntConstant().value; 3480 } else if (t.isBooleanType()) { 3481 return op.asIntConstant().value == 1; 3482 } else if (t.isByteType()) { 3483 return (byte)op.asIntConstant().value; 3484 } else if (t.isCharType()) { 3485 return (char)op.asIntConstant().value; 3486 } else if (t.isShortType()) { 3487 return (short)op.asIntConstant().value; 3488 } else { 3489 throw new OptimizingCompilerException("Trying to box an VM magic unboxed type (" + op + 3490 ")for a pure method call is not possible:\n" + op.instruction + 3491 "\n at " + op.instruction.position); 3492 } 3493 } 3494 /** 3495 * Package up an object as a constant operand 3496 * @param x the object to package 3497 * @param t the type of the object (needed to differentiate primitive from numeric types..) 3498 * @return the constant operand 3499 */ 3500 private static ConstantOperand boxConstantObjectAsOperand(Object x, TypeReference t) { 3501 if (VM.VerifyAssertions) VM._assert(!t.isUnboxedType()); 3502 if (x == null) { 3503 throw new Error("Field of type: " + t + " is null"); 3504 } 3505 if (t.isIntType()) { 3506 return IC((Integer)x); 3507 } else if (t.isBooleanType()) { 3508 return IC((Boolean)x ? 1 : 0); 3509 } else if (t.isByteType()) { 3510 return IC((Byte)x); 3511 } else if (t.isCharType()) { 3512 return IC((Character)x); 3513 } else if (t.isShortType()) { 3514 return IC((Short)x); 3515 } else if (t.isLongType()) { 3516 return LC((Long)x); 3517 } else if (t.isFloatType()) { 3518 return FC((Float)x); 3519 } else if (t.isDoubleType()) { 3520 return DC((Double)x); 3521 } else if (x instanceof String) { 3522 // Handle as object constant but make sure to use interned String 3523 x = ((String)x).intern(); 3524 return new ObjectConstantOperand(x, Offset.zero()); 3525 } else if (x instanceof Class) { 3526 // Handle as object constant 3527 return new ObjectConstantOperand(x, Offset.zero()); 3528 } else { 3529 return new ObjectConstantOperand(x, Offset.zero()); 3530 } 3531 } 3532 3533 private static DefUseEffect getField(Instruction s, OptOptions opts) { 3534 if (opts.SIMPLIFY_FIELD_OPS) { 3535 Operand ref = GetField.getRef(s); 3536 if (VM.VerifyAssertions && ref.isNullConstant()) { 3537 // Simplify to an unreachable operand, this instruction is dead code 3538 // guarded by a nullcheck that should already have been simplified 3539 RegisterOperand result = GetField.getClearResult(s); 3540 Move.mutate(s, IRTools.getMoveOp(result.getType()), result, new UnreachableOperand()); 3541 return DefUseEffect.MOVE_FOLDED; 3542 } else if (opts.SIMPLIFY_CHASE_FINAL_FIELDS && ref.isObjectConstant()) { 3543 // A constant object references this field which is 3544 // final. As the reference is final the constructor 3545 // of the referred object MUST have already completed. 3546 // This also implies that the type MUST have been resolved. 3547 RVMField field = GetField.getLocation(s).getFieldRef().resolve(); 3548 if (field.isFinal() && field.getDeclaringClass().isInitialized()) { 3549 try { 3550 ConstantOperand op = StaticFieldReader.getFieldValueAsConstant(field, ref.asObjectConstant().value); 3551 Move.mutate(s, IRTools.getMoveOp(field.getType()), GetField.getClearResult(s), op); 3552 return DefUseEffect.MOVE_FOLDED; 3553 } catch (NoSuchFieldException e) { 3554 if (VM.runningVM) { 3555 // this is unexpected 3556 throw new Error("Unexpected exception", e); 3557 } else { 3558 // Field not found during bootstrap due to chasing a field 3559 // only valid in the bootstrap JVM 3560 } 3561 } 3562 } 3563 } 3564 } 3565 return DefUseEffect.UNCHANGED; 3566 } 3567 3568 private static DefUseEffect getObjTib(Instruction s, OptOptions opts) { 3569 if (opts.SIMPLIFY_TIB_OPS) { 3570 Operand op = GuardedUnary.getVal(s); 3571 if (op.isNullConstant()) { 3572 // Simplify to an unreachable operand, this instruction is dead code 3573 // guarded by a nullcheck that should already have been simplified 3574 RegisterOperand result = GetField.getClearResult(s); 3575 Move.mutate(s, IRTools.getMoveOp(result.getType()), result, new UnreachableOperand()); 3576 return DefUseEffect.MOVE_FOLDED; 3577 } else if (op.isConstant()) { 3578 final TypeReference typeRef = op.getType(); 3579 if (typeRef.isResolved()) { 3580 Move.mutate(s, REF_MOVE, GuardedUnary.getClearResult(s), new TIBConstantOperand(op.getType().peekType())); 3581 return DefUseEffect.MOVE_FOLDED; 3582 } 3583 } else { 3584 RegisterOperand rop = op.asRegister(); 3585 TypeReference typeRef = rop.getType(); 3586 // Is the type of this register only one possible type? 3587 if (typeRef.isResolved() && rop.isPreciseType() && typeRef.resolve().isInstantiated()) { 3588 // before simplifying ensure that the type is instantiated, this stops 3589 // constant propagation potentially moving the TIB constant before the 3590 // runtime call that instantiates it 3591 Move.mutate(s, 3592 REF_MOVE, 3593 GuardedUnary.getClearResult(s), 3594 new TIBConstantOperand(typeRef.peekType())); 3595 return DefUseEffect.MOVE_FOLDED; 3596 } 3597 } 3598 } 3599 return DefUseEffect.UNCHANGED; 3600 } 3601 3602 private static DefUseEffect getClassTib(Instruction s, OptOptions opts) { 3603 if (opts.SIMPLIFY_TIB_OPS) { 3604 TypeOperand typeOp = Unary.getVal(s).asType(); 3605 if (typeOp.getTypeRef().isResolved()) { 3606 Move.mutate(s, 3607 REF_MOVE, 3608 Unary.getClearResult(s), 3609 new TIBConstantOperand(typeOp.getTypeRef().peekType())); 3610 return DefUseEffect.MOVE_FOLDED; 3611 } 3612 } 3613 return DefUseEffect.UNCHANGED; 3614 } 3615 3616 private static DefUseEffect getTypeFromTib(Instruction s, OptOptions opts) { 3617 if (opts.SIMPLIFY_TIB_OPS) { 3618 Operand tibOp = Unary.getVal(s); 3619 if (tibOp.isTIBConstant()) { 3620 TIBConstantOperand tib = tibOp.asTIBConstant(); 3621 Move.mutate(s, REF_MOVE, Unary.getClearResult(s), new ObjectConstantOperand(tib.value, Offset.zero())); 3622 return DefUseEffect.MOVE_FOLDED; 3623 } 3624 } 3625 return DefUseEffect.UNCHANGED; 3626 } 3627 3628 private static DefUseEffect getArrayElementTibFromTib(Instruction s, OptOptions opts) { 3629 if (opts.SIMPLIFY_TIB_OPS) { 3630 Operand tibOp = Unary.getVal(s); 3631 if (tibOp.isTIBConstant()) { 3632 TIBConstantOperand tib = tibOp.asTIBConstant(); 3633 Move.mutate(s, 3634 REF_MOVE, 3635 Unary.getClearResult(s), 3636 new TIBConstantOperand(tib.value.asArray().getElementType())); 3637 return DefUseEffect.MOVE_FOLDED; 3638 } 3639 } 3640 return DefUseEffect.UNCHANGED; 3641 } 3642 3643 private static DefUseEffect getSuperclassIdsFromTib(Instruction s, OptOptions opts) { 3644 if (opts.SIMPLIFY_TIB_OPS) { 3645 Operand tibOp = Unary.getVal(s); 3646 if (tibOp.isTIBConstant()) { 3647 TIBConstantOperand tib = tibOp.asTIBConstant(); 3648 Move.mutate(s, 3649 REF_MOVE, 3650 Unary.getClearResult(s), 3651 new ObjectConstantOperand(tib.value.getSuperclassIds(), Offset.zero())); 3652 return DefUseEffect.MOVE_FOLDED; 3653 } 3654 } 3655 return DefUseEffect.UNCHANGED; 3656 } 3657 3658 private static DefUseEffect getDoesImplementFromTib(Instruction s, OptOptions opts) { 3659 if (opts.SIMPLIFY_TIB_OPS) { 3660 Operand tibOp = Unary.getVal(s); 3661 if (tibOp.isTIBConstant()) { 3662 TIBConstantOperand tib = tibOp.asTIBConstant(); 3663 Move.mutate(s, 3664 REF_MOVE, 3665 Unary.getClearResult(s), 3666 new ObjectConstantOperand(tib.value.getDoesImplement(), Offset.zero())); 3667 return DefUseEffect.MOVE_FOLDED; 3668 } 3669 } 3670 return DefUseEffect.UNCHANGED; 3671 } 3672 3673 private static DefUseEffect refLoad(Instruction s, OptOptions opts) { 3674 if (opts.SIMPLIFY_TIB_OPS) { 3675 Operand base = Load.getAddress(s); 3676 if (base.isTIBConstant()) { 3677 TIBConstantOperand tib = base.asTIBConstant(); 3678 Operand offset = Load.getOffset(s); 3679 if (tib.value.isInstantiated() && offset.isConstant()) { 3680 // Reading from a fixed offset from an effectively 3681 // constant array 3682 int intOffset; 3683 if (offset.isIntConstant()) { 3684 intOffset = offset.asIntConstant().value; 3685 } else { 3686 intOffset = offset.asAddressConstant().value.toInt(); 3687 } 3688 int intSlot = intOffset >> LOG_BYTES_IN_ADDRESS; 3689 3690 // Create appropriate constant operand for TIB slot 3691 ConstantOperand result; 3692 TIB tibArray = tib.value.getTypeInformationBlock(); 3693 if (tibArray.slotContainsTib(intSlot)) { 3694 RVMType typeOfTIB = ((TIB)tibArray.get(intSlot)).getType(); 3695 result = new TIBConstantOperand(typeOfTIB); 3696 } else if (tibArray.slotContainsCode(intSlot)) { 3697 // Only generate code constants when we want to make 3698 // some virtual calls go via the JTOC 3699 if (opts.H2L_CALL_VIA_JTOC) { 3700 RVMMethod method = tib.value.getTIBMethodAtSlot(intSlot); 3701 result = new CodeConstantOperand(method); 3702 } else { 3703 return DefUseEffect.UNCHANGED; 3704 } 3705 } else { 3706 if (tibArray.get(intSlot) == null) { 3707 result = new NullConstantOperand(); 3708 } else { 3709 result = new ObjectConstantOperand(tibArray.get(intSlot), Offset.zero()); 3710 } 3711 } 3712 Move.mutate(s, REF_MOVE, Load.getClearResult(s), result); 3713 return DefUseEffect.MOVE_FOLDED; 3714 } 3715 } 3716 } 3717 return DefUseEffect.UNCHANGED; 3718 } 3719 3720 /** 3721 * To reduce the number of conditions to consider, we transform all commutative 3722 * operators to a canoncial form. The following forms are considered 3723 * canonical: 3724 * <ul> 3725 * <li> <code> Reg = Reg <op> Reg </code> 3726 * <li> <code> Reg = Reg <op> Constant </code> 3727 * <li> <code> Reg = Constant <op> Constant </code> 3728 * </ul> 3729 * For object constant operands we treat movable objects like registers. 3730 * @param instr the instruction to consider 3731 */ 3732 private static void canonicalizeCommutativeOperator(Instruction instr) { 3733 Operand op1 = Binary.getVal1(instr); 3734 if (op1.isConstant() && !op1.isMovableObjectConstant()) { 3735 Operand tmp = Binary.getClearVal1(instr); 3736 Binary.setVal1(instr, Binary.getClearVal2(instr)); 3737 Binary.setVal2(instr, tmp); 3738 } 3739 } 3740 3741 private static int PowerOf2(int v) { 3742 int i = 31; 3743 int power = -1; 3744 for (; v != 0; v = v << 1, i--) { 3745 if (v < 0) { 3746 if (power == -1) { 3747 power = i; 3748 } else { 3749 return -1; 3750 } 3751 } 3752 } 3753 return power; 3754 } 3755 3756 /** 3757 * Turns the given operand encoding an address constant into an Address. 3758 * 3759 * @param op the operand 3760 * @return the address that was extracted from the operand 3761 */ 3762 private static Address getAddressValue(Operand op) { 3763 if (op instanceof NullConstantOperand) { 3764 return Address.zero(); 3765 } 3766 if (op instanceof AddressConstantOperand) { 3767 return op.asAddressConstant().value; 3768 } 3769 if (op instanceof IntConstantOperand) { 3770 return Address.fromIntSignExtend(op.asIntConstant().value); 3771 } 3772 if (op instanceof LongConstantOperand) { 3773 if (VM.BuildFor64Addr) { 3774 return Address.fromLong(op.asLongConstant().value); 3775 } else { 3776 return Address.fromIntZeroExtend((int)op.asLongConstant().value); 3777 } 3778 } 3779 if (op instanceof ObjectConstantOperand) { 3780 if (VM.VerifyAssertions) VM._assert(!op.isMovableObjectConstant()); 3781 return Magic.objectAsAddress(op.asObjectConstant().value); 3782 } 3783 throw new OptimizingCompilerException("Cannot getAddressValue from this operand " + op); 3784 } 3785}