001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt.ir.operand; 014 015import org.jikesrvm.VM; 016import org.jikesrvm.classloader.RVMClass; 017import org.jikesrvm.classloader.TypeReference; 018import org.jikesrvm.compilers.opt.ir.Register; 019import org.jikesrvm.compilers.opt.OptimizingCompilerException; 020 021/** 022 * A symbolic or physical register. 023 * A wrapper around an Register that may contain program-point specific 024 * information about the value denoted by the Register. 025 * <p> 026 * TODO: This class is due for a refactor into subclasses 027 * to split out the symbolic & physical registers and to create 028 * special behavior for symbolic registers used as phi operands and 029 * as validation (guard) operands. 030 * 031 * @see Operand 032 */ 033public final class RegisterOperand extends Operand { 034 035 /** 036 * Converted from a reference? 037 */ 038 private boolean convertedFromRef = false; 039 040 /** 041 * Register object that this operand uses. 042 */ 043 private Register register; 044 045 /** 046 * Inferred data type of the contents of the register. 047 */ 048 private TypeReference type; 049 050 /** 051 * Used to maintain def and use lists. 052 */ 053 private RegisterOperand nextInDefUseList; 054 055 /** 056 * The guard associated with a RegisterOperand. 057 * <p> 058 * Used in the construction of the high-level intermediate representation. 059 */ 060 private Operand guard; 061 062 /** 063 * Type of a RegisterOperand can be in one of three states: 064 * 065 * <ol> 066 * <li>a- declared: the type obtained from a 067 * getfield,getstatic,putfield,putstatic,array load</li> 068 * <li>b- precise: obtained from a NEW.</li> 069 * <li>c- computed: (default) computed from propagating types.</li> 070 * </ol> 071 * 072 * If the register is holding an int-like type it can be holding 073 * just positive values. 074 * 075 * For calling conventions registers can be for parameters or 076 * volatile/non-volatile. The value in the register can also be 077 * extant - that is a definite non-null value (e.g. this pointer). 078 */ 079 private byte flags; 080 081 /** 082 * The type has been declared as obtained from a getfield, 083 * getstatic, putfield, putstatic, array load 084 */ 085 private static final int DECLARED_TYPE = 0x01; 086 /** We know precisely the type as it was create by a NEW */ 087 private static final int PRECISE_TYPE = 0x02; 088 /** Is the contents of the int-like register always positive? */ 089 private static final int POSITIVE = 0x04; 090 091 /** the register operand is for a parameter */ 092 private static final byte PARAMETER = 0x10; 093 /** is this a non-volatile physical register? */ 094 private static final byte NON_VOLATILE = 0x20; 095 /** is this an extant object? */ 096 private static final byte EXTANT = 0x40; 097 098 /** 099 * Some bits used to characterize guards. TODO: Maybe declare a 100 * new type GuardOperand extends RegisterOperand, and save 101 * this state there? 102 */ 103 private byte flags2; 104 105 /** guard operand that represents a taken branch */ 106 private static final byte TAKEN = 0x01; 107 /** guard operand that represents a not taken branch */ 108 private static final byte NOT_TAKEN = 0x02; 109 /** Guard operand that originates from a bounds-check */ 110 private static final byte BOUNDS_CHECK = 0x04; 111 /** Guard operand that originates from a null-check */ 112 private static final byte NULL_CHECK = 0x08; 113 114 /** 115 * Constructs a new register operand with the given register and data type. 116 * 117 * @param reg register object 118 * @param typ data type 119 */ 120 public RegisterOperand(Register reg, TypeReference typ) { 121 setRegister(reg); 122 setType(typ); 123 } 124 125 /** 126 * Constructs a new register operand with the given register, data type and flags. 127 * 128 * @param reg register object 129 * @param typ data type 130 * @param inFlags to set for this register 131 * @param isPrecise is this a precise type 132 * @param isDeclared is this a declared type 133 */ 134 public RegisterOperand(Register reg, TypeReference typ, byte inFlags, 135 boolean isPrecise, boolean isDeclared) { 136 setRegister(reg); 137 flags = inFlags; 138 if (isPrecise) { 139 setPreciseType(typ); 140 } else { 141 clearPreciseType(); 142 setType(typ); 143 } 144 if (isDeclared) { 145 setDeclaredType(); 146 } else { 147 clearDeclaredType(); 148 } 149 } 150 151 /** 152 * Returns a copy of this register operand as an operand 153 */ 154 @Override 155 public Operand copy() { 156 return copyRO(); 157 } 158 159 /** 160 * Returns a copy of this register operand as a register operand.<p> 161 * 162 * NOTE: preserves the flags, guards and def/use lists. 163 * 164 * @return a copy of this register operand 165 */ 166 public RegisterOperand copyRO() { 167 RegisterOperand temp = new RegisterOperand(register, type); 168 temp.flags = flags; 169 temp.flags2 = flags2; 170 temp.nextInDefUseList = nextInDefUseList; 171 temp.convertedFromRef = convertedFromRef; 172 temp.guard = guard; 173 if (VM.VerifyAssertions) verifyPreciseType(); 174 return temp; 175 } 176 177 /** 178 * @return a copy of this use register operand as another use reg operand. 179 */ 180 public RegisterOperand copyU2U() { 181 return copyRO(); 182 } 183 184 /** 185 * @return a copy of this def register operand as a use. 186 */ 187 public RegisterOperand copyD2U() { 188 return copyRO(); 189 } 190 191 /** 192 * @return a copy of this use register operand as a def. 193 */ 194 public RegisterOperand copyU2D() { 195 return copyRO(); 196 } 197 198 /** 199 * @return a copy of this def register operand as a def. 200 */ 201 public RegisterOperand copyD2D() { 202 return copyRO(); 203 } 204 205 /** 206 * @param op operand to compare against 207 * @return whether the given operand is a register operand and has the same 208 * register object. 209 */ 210 @Override 211 public boolean similar(Operand op) { 212 return (op instanceof RegisterOperand) && (register == ((RegisterOperand) op).getRegister()); 213 } 214 215 /** 216 * Copy type information from the given operand into this one 217 * including flag information on whether this is a precise type or 218 * not 219 * @param rhs the type to copy information from 220 */ 221 public void copyTypeFrom(RegisterOperand rhs) { 222 this.flags = rhs.flags; 223 this.setType(rhs.getType()); // setting type this way will force checking of precision 224 } 225 226 @Override 227 public boolean isIntLike() { 228 return type.isIntLikeType(); 229 } 230 231 @Override 232 public boolean isInt() { 233 return type.isIntType(); 234 } 235 236 @Override 237 public boolean isLong() { 238 return type.isLongType(); 239 } 240 241 @Override 242 public boolean isFloat() { 243 return type.isFloatType(); 244 } 245 246 @Override 247 public boolean isDouble() { 248 return type.isDoubleType(); 249 } 250 251 @Override 252 public boolean isRef() { 253 return type.isReferenceType(); 254 } 255 256 @Override 257 public boolean isAddress() { 258 return type.isWordLikeType(); 259 } 260 261 @Override 262 public boolean isDefinitelyNull() { 263 return type == TypeReference.NULL_TYPE; 264 } 265 266 public boolean isParameter() { 267 return (flags & PARAMETER) != 0; 268 } 269 270 public void setParameter() { 271 flags |= PARAMETER; 272 } 273 274 public void clearParameter() { 275 flags &= ~PARAMETER; 276 } 277 278 public boolean isNonVolatile() { 279 return (flags & NON_VOLATILE) != 0; 280 } 281 282 public void setNonVolatile() { 283 flags |= NON_VOLATILE; 284 } 285 286 public void clearNonVolatile() { 287 flags &= ~NON_VOLATILE; 288 } 289 290 /** 291 * Is this register known to contain either NULL or an object whose class was fully loaded 292 * before the current method was called? 293 * This fact is used to determine whether we can optimize away inline guards 294 * based on pre-existence based inlining. 295 * 296 * @return {@code true} if this register is extant (see above) 297 */ 298 public boolean isExtant() { 299 return (flags & EXTANT) != 0; 300 } 301 302 /** 303 * Sets this register as holding an extant object (or NULL) 304 * (ie, an object whose class was fully loaded before the current method was called). 305 * This fact is used to determine whether we can optimize away inline guards based on pre-existence 306 * based inlining. 307 */ 308 public void setExtant() { 309 flags |= EXTANT; 310 } 311 312 public void clearExtant() { 313 flags &= ~EXTANT; 314 } 315 316 public boolean isDeclaredType() { 317 return (flags & DECLARED_TYPE) != 0; 318 } 319 320 public void setDeclaredType() { 321 flags |= DECLARED_TYPE; 322 } 323 324 public void clearDeclaredType() { 325 flags &= ~DECLARED_TYPE; 326 } 327 328 private void verifyPreciseType() { 329 if (!VM.VerifyAssertions) { 330 VM.sysFail("Calls to verifyPreciseType must always be guarded by if \"(VM.VerifyAssertions)\"!"); 331 } else { 332 if (isPreciseType() && type != null && 333 type.isClassType() && type.isResolved()) { 334 RVMClass preciseClass = type.resolve().asClass(); 335 if (preciseClass.isInterface() || preciseClass.isAbstract()) { 336 VM.sysWriteln("Error processing instruction: ", this.instruction.toString()); 337 throw new OptimizingCompilerException("Unable to set type as it would make this interface/abstract class precise " + preciseClass); 338 } 339 } 340 } 341 } 342 343 public boolean isPreciseType() { 344 return (flags & PRECISE_TYPE) != 0; 345 } 346 347 public void setPreciseType() { 348 flags |= PRECISE_TYPE; 349 if (VM.VerifyAssertions) verifyPreciseType(); 350 } 351 352 public void clearPreciseType() { 353 flags &= ~PRECISE_TYPE; 354 } 355 356 public boolean isDeclaredOrPreciseType() { 357 return (flags & (DECLARED_TYPE | PRECISE_TYPE)) != 0; 358 } 359 360 public boolean isPositiveInt() { 361 return (flags & POSITIVE) != 0; 362 } 363 364 public void setPositiveInt() { 365 flags |= POSITIVE; 366 } 367 368 /** @return a byte encoding register flags */ 369 public byte getFlags() { 370 return flags; 371 } 372 373 public void clearFlags() { 374 flags = 0; 375 } 376 377 /** 378 * Merges two sets of register flags. 379 * @param inFlag the flags to merge to this register's flags 380 */ 381 public void addFlags(byte inFlag) { 382 flags |= inFlag; 383 if (VM.VerifyAssertions) verifyPreciseType(); 384 } 385 386 /** 387 * Currently all flags are inheritable, so copy all flags from src. 388 * @param src the operand to copy the flags from 389 */ 390 public void setInheritableFlags(RegisterOperand src) { 391 flags = src.getFlags(); 392 if (VM.VerifyAssertions) verifyPreciseType(); 393 } 394 395 /** 396 * Currently all flags are "meetable", so mask flags together. 397 * @param other the operand to use for computing the meet 398 */ 399 public void meetInheritableFlags(RegisterOperand other) { 400 flags &= other.flags; 401 } 402 403 /** 404 * @param other operand to compare with 405 * @return {@code true} if we have any bits set (flag true) that other 406 * doesn't. It's ok for other to have bits set true that we have set 407 * to false. 408 */ 409 public boolean hasLessConservativeFlags(RegisterOperand other) { 410 return other.getFlags() != (getFlags() | other.getFlags()); 411 } 412 413 /** @return {@code true} if this is a guard operand from a taken branch */ 414 public boolean isTaken() { 415 return (flags2 & TAKEN) != 0; 416 } 417 418 /** Set this a guard operand from a taken branch */ 419 public void setTaken() { 420 flags2 |= TAKEN; 421 } 422 423 /** Clear this from being a guard operand from a taken branch */ 424 public void clearTaken() { 425 flags2 &= ~TAKEN; 426 } 427 428 /** @return {@code true} if this is a guard operand from a not taken branch */ 429 public boolean isNotTaken() { 430 return (flags2 & NOT_TAKEN) != 0; 431 } 432 433 /** Set this a guard operand from a not taken branch */ 434 public void setNotTaken() { 435 flags2 |= NOT_TAKEN; 436 } 437 438 /** Clear this from being a guard operand from a not taken branch */ 439 public void clearNotTaken() { 440 flags2 &= ~NOT_TAKEN; 441 } 442 443 public boolean isBoundsCheck() { 444 return (flags2 & BOUNDS_CHECK) != 0; 445 } 446 447 public void setBoundsCheck() { 448 flags2 |= BOUNDS_CHECK; 449 } 450 451 public void clearBoundsCheck() { 452 flags2 &= ~BOUNDS_CHECK; 453 } 454 455 public boolean isNullCheck() { 456 return (flags2 & NULL_CHECK) != 0; 457 } 458 459 public void setNullCheck() { 460 flags2 |= NULL_CHECK; 461 } 462 463 public void clearNullCheck() { 464 flags2 &= ~NULL_CHECK; 465 } 466 467 /** 468 * Sets the next register operand in the def/use list. 469 * 470 * @param next next register operand in the list 471 */ 472 public void setNext(RegisterOperand next) { 473 nextInDefUseList = next; 474 } 475 476 /** 477 * @return the next operand in the def/use list 478 */ 479 public RegisterOperand getNext() { 480 return nextInDefUseList; 481 } 482 483 @Override 484 public String toString() { 485 String s = register.toString(); 486 if (type != null) { 487 if (type != TypeReference.VALIDATION_TYPE) { 488 s = s + "(" + type.getName(); 489 if (isExtant()) s += ",x"; 490 if (isDeclaredType()) s += ",d"; 491 if (isPreciseType()) s += ",p"; 492 if (isPositiveInt()) s += ",+"; 493 s += ")"; 494 } else { 495 s += "(GUARD)"; 496 } 497 } 498 return s; 499 } 500 501 public void setRegister(Register register) { 502 this.register = register; 503 } 504 505 public Register getRegister() { 506 return register; 507 } 508 509 /** 510 * Set the {@link TypeReference} of the value represented by the operand. 511 * 512 * @param t the inferred data type of the contents of the register 513 */ 514 public void setType(TypeReference t) { 515 type = t; 516 if (VM.VerifyAssertions) verifyPreciseType(); 517 } 518 519 /** 520 * Set the {@link TypeReference} of the value represented by the operand and 521 * make the type precise. 522 * 523 * @param t the inferred data type of the contents of the register 524 */ 525 public void setPreciseType(TypeReference t) { 526 setType(t); 527 flags |= PRECISE_TYPE; 528 if (VM.VerifyAssertions) verifyPreciseType(); 529 } 530 531 /** 532 * Return the {@link TypeReference} of the value represented by the operand. 533 * 534 * @return the inferred data type of the contents of the register 535 */ 536 @Override 537 public TypeReference getType() { 538 return type; 539 } 540 541 public void flagAsConvertedFromRef() { 542 convertedFromRef = true; 543 } 544 545 public boolean convertedFromRef() { 546 return convertedFromRef; 547 } 548 549 /** 550 * Refine the type of the register to t if t is a more precise type than the 551 * register currently holds 552 * 553 * @param t type to try to refine to 554 */ 555 public void refine(TypeReference t) { 556 // TODO: see JIRA RVM-137 557 if (!isPreciseType()) { 558 setType(t); 559 } 560 } 561 562 /** 563 * Note: This method is currently used only by test cases.<p> 564 * 565 * Does this operand have the same properties as the given Operand? This method 566 * checks only the properties specific to RegisterOperand. 567 * 568 * @param other the operand to compare with 569 * @return whether the given RegisterOperand could be seen as a copy of this one 570 */ 571 public boolean sameRegisterPropertiesAs(RegisterOperand other) { 572 return this.register == other.register && this.flags == other.flags && 573 this.flags2 == other.flags2 && this.guard == other.guard && 574 this.nextInDefUseList == other.nextInDefUseList; 575 } 576 577 /** 578 * Note: This method is currently used only by test cases.<p> 579 * 580 * Does this operand have the same properties as the given Operand? This method 581 * checks only the properties specific to RegisterOperand. For guards, similarity 582 * of operands is sufficient. 583 * 584 * @param other the operand to compare with 585 * @return whether the given RegisterOperand could be seen as a copy of this one 586 */ 587 public boolean sameRegisterPropertiesAsExceptForGuardWhichIsSimilar(RegisterOperand other) { 588 boolean guardsSimilar = this.guard == other.guard || 589 this.guard != null && this.guard.similar(other.guard); 590 return this.register == other.register && this.flags == other.flags && 591 this.flags2 == other.flags2 && this.nextInDefUseList == other.nextInDefUseList && 592 guardsSimilar; 593 } 594 595 public Operand getGuard() { 596 return guard; 597 } 598 599 public void setGuard(Operand guard) { 600 this.guard = guard; 601 } 602}