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