1 /* 2 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.core.common; 26 27 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; 28 29 import jdk.vm.ci.code.Architecture; 30 import jdk.vm.ci.meta.AllocatableValue; 31 import jdk.vm.ci.meta.JavaKind; 32 import jdk.vm.ci.meta.PlatformKind; 33 import jdk.vm.ci.meta.Value; 34 import jdk.vm.ci.meta.ValueKind; 35 36 /** 37 * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the 38 * low level representation of the value, a {@link #referenceMask} that describes the location of 39 * object references in the value, a {@link #referenceCompressionMask} that indicates which of these 40 * references are compressed references, and for derived references a {@link #derivedReferenceBase}. 41 * 42 * <h2>Constructing {@link LIRKind} instances</h2> 43 * 44 * During LIR generation, every new {@link Value} should get a {@link LIRKind} of the correct 45 * {@link PlatformKind} that also contains the correct reference information. {@linkplain LIRKind 46 * LIRKinds} should be created as follows: 47 * 48 * <p> 49 * If the result value is created from one or more input values, the {@link LIRKind} should be 50 * created with {@link LIRKind#combine}(inputs). If the result has a different {@link PlatformKind} 51 * than the inputs, {@link LIRKind#combine}(inputs).{@link #changeType}(resultKind) should be used. 52 * <p> 53 * If the result is an exact copy of one of the inputs, {@link Value#getValueKind()} can be used. 54 * Note that this is only correct for move-like operations, like conditional move or 55 * compare-and-swap. For convert operations, {@link LIRKind#combine} should be used. 56 * <p> 57 * If it is known that the result will be a reference (e.g. pointer arithmetic where the end result 58 * is a valid oop), {@link #reference} or {@link LIRKind#compressedReference} should be used. 59 * <p> 60 * If it is known that the result will neither be a reference nor be derived from a reference, 61 * {@link LIRKind#value} can be used. If the operation producing this value has inputs, this is very 62 * likely wrong, and {@link LIRKind#combine} should be used instead. 63 * <p> 64 * If it is known that the result is derived from a reference in a way that the garbage collector 65 * can not track, {@link LIRKind#unknownReference} can be used. In most cases, 66 * {@link LIRKind#combine} should be used instead, since it is able to detect this automatically. 67 */ 68 public final class LIRKind extends ValueKind<LIRKind> { 69 70 /** 71 * The location of object references in the value. If the value is a vector type, each bit 72 * represents one component of the vector. 73 */ 74 private final int referenceMask; 75 76 /** Mask with 1-bits indicating which references in {@link #referenceMask} are compressed. */ 77 private final int referenceCompressionMask; 78 79 private AllocatableValue derivedReferenceBase; 80 81 private static final int UNKNOWN_REFERENCE = -1; 82 83 public static final LIRKind Illegal = unknownReference(ValueKind.Illegal.getPlatformKind()); 84 85 private LIRKind(PlatformKind platformKind, int referenceMask, int referenceCompressionMask, AllocatableValue derivedReferenceBase) { 86 super(platformKind); 87 this.referenceMask = referenceMask; 88 this.referenceCompressionMask = referenceCompressionMask; 89 this.derivedReferenceBase = derivedReferenceBase; 90 91 assert this.referenceCompressionMask == 0 || this.referenceMask == this.referenceCompressionMask : "mixing compressed and uncompressed references is untested"; 92 assert derivedReferenceBase == null || !derivedReferenceBase.getValueKind(LIRKind.class).isDerivedReference() : "derived reference can't have another derived reference as base"; 93 } 94 95 /** 96 * Create a {@link LIRKind} of type {@code platformKind} that contains a primitive value. Should 97 * be only used when it's guaranteed that the value is not even indirectly derived from a 98 * reference. Otherwise, {@link #combine(Value...)} should be used instead. 99 */ 100 public static LIRKind value(PlatformKind platformKind) { 101 return new LIRKind(platformKind, 0, 0, null); 102 } 103 104 /** 105 * Create a {@link LIRKind} of type {@code platformKind} that contains a single, tracked, 106 * uncompressed oop reference. 107 */ 108 public static LIRKind reference(PlatformKind platformKind) { 109 return derivedReference(platformKind, null, false); 110 } 111 112 /** 113 * Create a {@link LIRKind} of type {@code platformKind} that contains a single, tracked, 114 * compressed oop reference. 115 */ 116 public static LIRKind compressedReference(PlatformKind platformKind) { 117 return derivedReference(platformKind, null, true); 118 } 119 120 /** 121 * Create the correct {@link LIRKind} for a given {@link Architecture} and {@link JavaKind}. 122 */ 123 public static LIRKind fromJavaKind(Architecture arch, JavaKind javaKind) { 124 PlatformKind platformKind = arch.getPlatformKind(javaKind); 125 if (javaKind.isObject()) { 126 return LIRKind.reference(platformKind); 127 } else { 128 return LIRKind.value(platformKind); 129 } 130 } 131 132 /** 133 * Create a {@link LIRKind} of type {@code platformKind} that contains a derived reference. 134 */ 135 public static LIRKind derivedReference(PlatformKind platformKind, AllocatableValue base, boolean compressed) { 136 int length = platformKind.getVectorLength(); 137 assert 0 < length && length < 32 : "vector of " + length + " references not supported"; 138 int referenceMask = (1 << length) - 1; 139 int referenceCompressionMask = (compressed ? referenceMask : 0); 140 return new LIRKind(platformKind, referenceMask, referenceCompressionMask, base); 141 } 142 143 /** 144 * Create a {@link LIRKind} of type {@code platformKind} that contains a value that is derived 145 * from a reference in a non-linear way. Values of this {@link LIRKind} can not be live at 146 * safepoints. In most cases, this should not be called directly. {@link #combine} should be 147 * used instead to automatically propagate this information. 148 */ 149 public static LIRKind unknownReference(PlatformKind platformKind) { 150 return new LIRKind(platformKind, UNKNOWN_REFERENCE, UNKNOWN_REFERENCE, null); 151 } 152 153 /** 154 * Create a derived reference. 155 * 156 * @param base An {@link AllocatableValue} containing the base pointer of the derived reference. 157 */ 158 public LIRKind makeDerivedReference(AllocatableValue base) { 159 assert !isUnknownReference() && derivedReferenceBase == null; 160 if (Value.ILLEGAL.equals(base)) { 161 return makeUnknownReference(); 162 } else { 163 if (isValue()) { 164 return derivedReference(getPlatformKind(), base, false); 165 } else { 166 return new LIRKind(getPlatformKind(), referenceMask, referenceCompressionMask, base); 167 } 168 } 169 } 170 171 /** 172 * Derive a new type from inputs. The result will have the {@link PlatformKind} of one of the 173 * inputs. If all inputs are values, the result is a value. Otherwise, the result is an unknown 174 * reference. 175 * 176 * This method should be used to construct the result {@link LIRKind} of any operation that 177 * modifies values (e.g. arithmetics). 178 */ 179 public static LIRKind combine(Value... inputs) { 180 assert inputs.length > 0; 181 for (Value input : inputs) { 182 LIRKind kind = input.getValueKind(LIRKind.class); 183 if (kind.isUnknownReference()) { 184 return kind; 185 } else if (!kind.isValue()) { 186 return kind.makeUnknownReference(); 187 } 188 } 189 190 // all inputs are values, just return one of them 191 return inputs[0].getValueKind(LIRKind.class); 192 } 193 194 /** 195 * Helper method to construct derived reference kinds. Returns the base value of a reference or 196 * derived reference. For values it returns {@code null}, and for unknown references it returns 197 * {@link Value#ILLEGAL}. 198 */ 199 public static AllocatableValue derivedBaseFromValue(AllocatableValue value) { 200 ValueKind<?> valueKind = value.getValueKind(); 201 if (valueKind instanceof LIRKind) { 202 LIRKind kind = value.getValueKind(LIRKind.class); 203 if (kind.isValue()) { 204 return null; 205 } else if (kind.isDerivedReference()) { 206 return kind.getDerivedReferenceBase(); 207 } else if (kind.isUnknownReference()) { 208 return Value.ILLEGAL; 209 } else { 210 // kind is a reference 211 return value; 212 } 213 } else { 214 return Value.ILLEGAL; 215 } 216 } 217 218 /** 219 * Helper method to construct derived reference kinds. If one of {@code base1} or {@code base2} 220 * are set, it creates a derived reference using it as the base. If both are set, the result is 221 * an unknown reference. 222 */ 223 public static LIRKind combineDerived(LIRKind kind, AllocatableValue base1, AllocatableValue base2) { 224 if (base1 == null && base2 == null) { 225 return kind; 226 } else if (base1 == null) { 227 return kind.makeDerivedReference(base2); 228 } else if (base2 == null) { 229 return kind.makeDerivedReference(base1); 230 } else { 231 return kind.makeUnknownReference(); 232 } 233 } 234 235 /** 236 * Merges the reference information of the inputs. The result will have the {@link PlatformKind} 237 * of {@code mergeKind}. If all inputs are values (references), the result is a value 238 * (reference). Otherwise, the result is an unknown reference. 239 * 240 * The correctness of the {@link PlatformKind} is not verified. 241 */ 242 public static LIRKind mergeReferenceInformation(LIRKind mergeKind, LIRKind inputKind) { 243 assert mergeKind != null; 244 assert inputKind != null; 245 246 if (mergeKind.isUnknownReference()) { 247 /** 248 * {@code mergeKind} is an unknown reference, therefore the result can only be also an 249 * unknown reference. 250 */ 251 return mergeKind; 252 } 253 254 if (mergeKind.isValue()) { 255 /* {@code mergeKind} is a value. */ 256 if (!inputKind.isValue()) { 257 /* 258 * Inputs consists of values and references. Make the result an unknown reference. 259 */ 260 return mergeKind.makeUnknownReference(); 261 } 262 return mergeKind; 263 } 264 /* {@code mergeKind} is a reference. */ 265 if (mergeKind.referenceMask != inputKind.referenceMask || mergeKind.referenceCompressionMask != inputKind.referenceCompressionMask) { 266 /* 267 * Reference masks do not match so the result can only be an unknown reference. 268 */ 269 return mergeKind.makeUnknownReference(); 270 } 271 272 /* Both are references. */ 273 if (mergeKind.isDerivedReference()) { 274 if (inputKind.isDerivedReference() && mergeKind.getDerivedReferenceBase().equals(inputKind.getDerivedReferenceBase())) { 275 /* Same reference base so they must be equal. */ 276 return mergeKind; 277 } 278 /* Base pointers differ. Make the result an unknown reference. */ 279 return mergeKind.makeUnknownReference(); 280 } 281 if (inputKind.isDerivedReference()) { 282 /* 283 * {@code mergeKind} is not derived but {@code inputKind} is. Make the result an unknown 284 * reference. 285 */ 286 return mergeKind.makeUnknownReference(); 287 } 288 /* Both are not derived references so they must be equal. */ 289 return mergeKind; 290 } 291 292 /** 293 * Create a new {@link LIRKind} with the same reference information and a new 294 * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this, 295 * the new elements are marked as untracked values. 296 */ 297 @Override 298 public LIRKind changeType(PlatformKind newPlatformKind) { 299 if (newPlatformKind == getPlatformKind()) { 300 return this; 301 } else if (isUnknownReference()) { 302 return unknownReference(newPlatformKind); 303 } else if (referenceMask == 0) { 304 // value type 305 return LIRKind.value(newPlatformKind); 306 } else { 307 // reference type 308 int newLength = Math.min(32, newPlatformKind.getVectorLength()); 309 int lengthMask = 0xFFFFFFFF >>> (32 - newLength); 310 int newReferenceMask = referenceMask & lengthMask; 311 int newReferenceCompressionMask = referenceCompressionMask & lengthMask; 312 assert newReferenceMask != UNKNOWN_REFERENCE; 313 return new LIRKind(newPlatformKind, newReferenceMask, newReferenceCompressionMask, derivedReferenceBase); 314 } 315 } 316 317 /** 318 * Create a new {@link LIRKind} with a new {@linkplain #getPlatformKind platform kind}. If the 319 * new kind is longer than this, the reference positions are repeated to fill the vector. 320 */ 321 public LIRKind repeat(PlatformKind newPlatformKind) { 322 if (isUnknownReference()) { 323 return unknownReference(newPlatformKind); 324 } else if (referenceMask == 0) { 325 // value type 326 return LIRKind.value(newPlatformKind); 327 } else { 328 // reference type 329 int oldLength = getPlatformKind().getVectorLength(); 330 int newLength = newPlatformKind.getVectorLength(); 331 assert oldLength <= newLength && newLength < 32 && (newLength % oldLength) == 0; 332 333 // repeat reference mask to fill new kind 334 int newReferenceMask = 0; 335 int newReferenceCompressionMask = 0; 336 for (int i = 0; i < newLength; i += getPlatformKind().getVectorLength()) { 337 newReferenceMask |= referenceMask << i; 338 newReferenceCompressionMask |= referenceCompressionMask << i; 339 } 340 341 assert newReferenceMask != UNKNOWN_REFERENCE; 342 return new LIRKind(newPlatformKind, newReferenceMask, newReferenceCompressionMask, derivedReferenceBase); 343 } 344 } 345 346 /** 347 * Create a new {@link LIRKind} with the same type, but marked as containing an 348 * {@link LIRKind#unknownReference}. 349 */ 350 public LIRKind makeUnknownReference() { 351 return new LIRKind(getPlatformKind(), UNKNOWN_REFERENCE, UNKNOWN_REFERENCE, null); 352 } 353 354 /** 355 * Check whether this value is a derived reference. 356 */ 357 public boolean isDerivedReference() { 358 return getDerivedReferenceBase() != null; 359 } 360 361 /** 362 * Get the base value of a derived reference. 363 */ 364 public AllocatableValue getDerivedReferenceBase() { 365 return derivedReferenceBase; 366 } 367 368 /** 369 * Change the base value of a derived reference. This must be called on derived references only. 370 */ 371 public void setDerivedReferenceBase(AllocatableValue derivedReferenceBase) { 372 assert isDerivedReference(); 373 this.derivedReferenceBase = derivedReferenceBase; 374 } 375 376 /** 377 * Check whether this value is derived from a reference in a non-linear way. If this returns 378 * {@code true}, this value must not be live at safepoints. 379 */ 380 public boolean isUnknownReference() { 381 return referenceMask == UNKNOWN_REFERENCE; 382 } 383 384 public static boolean isUnknownReference(ValueKind<?> kind) { 385 if (kind instanceof LIRKind) { 386 return ((LIRKind) kind).isUnknownReference(); 387 } else { 388 return true; 389 } 390 } 391 392 public static boolean isUnknownReference(Value value) { 393 return isUnknownReference(value.getValueKind()); 394 } 395 396 public int getReferenceCount() { 397 assert !isUnknownReference(); 398 return Integer.bitCount(referenceMask); 399 } 400 401 /** 402 * Check whether the {@code idx}th part of this value is a reference that must be tracked at 403 * safepoints. 404 * 405 * @param idx The index into the vector if this is a vector kind. Must be 0 if this is a scalar 406 * kind. 407 */ 408 public boolean isReference(int idx) { 409 assert 0 <= idx && idx < getPlatformKind().getVectorLength() : "invalid index " + idx + " in " + this; 410 return !isUnknownReference() && (referenceMask & 1 << idx) != 0; 411 } 412 413 /** 414 * Check whether the {@code idx}th part of this value is a <b>compressed</b> reference. 415 * 416 * @param idx The index into the vector if this is a vector kind. Must be 0 if this is a scalar 417 * kind. 418 */ 419 public boolean isCompressedReference(int idx) { 420 assert 0 <= idx && idx < getPlatformKind().getVectorLength() : "invalid index " + idx + " in " + this; 421 return !isUnknownReference() && (referenceCompressionMask & (1 << idx)) != 0; 422 } 423 424 /** 425 * Check whether this kind is a value type that doesn't need to be tracked at safepoints. 426 */ 427 public boolean isValue() { 428 return referenceMask == 0; 429 } 430 431 public static boolean isValue(ValueKind<?> kind) { 432 if (kind instanceof LIRKind) { 433 return ((LIRKind) kind).isValue(); 434 } else { 435 return false; 436 } 437 } 438 439 public static boolean isValue(Value value) { 440 return isValue(value.getValueKind()); 441 } 442 443 @Override 444 public String toString() { 445 if (isValue()) { 446 return getPlatformKind().name(); 447 } else if (isUnknownReference()) { 448 return getPlatformKind().name() + "[*]"; 449 } else { 450 StringBuilder ret = new StringBuilder(); 451 ret.append(getPlatformKind().name()); 452 ret.append('['); 453 for (int i = 0; i < getPlatformKind().getVectorLength(); i++) { 454 if (isReference(i)) { 455 ret.append('.'); 456 } else { 457 ret.append(' '); 458 } 459 } 460 ret.append(']'); 461 return ret.toString(); 462 } 463 } 464 465 @Override 466 public int hashCode() { 467 final int prime = 31; 468 int result = 1; 469 result = prime * result + ((getPlatformKind() == null) ? 0 : getPlatformKind().hashCode()); 470 result = prime * result + ((getDerivedReferenceBase() == null) ? 0 : getDerivedReferenceBase().hashCode()); 471 result = prime * result + referenceMask; 472 result = prime * result + referenceCompressionMask; 473 return result; 474 } 475 476 @Override 477 public boolean equals(Object obj) { 478 if (this == obj) { 479 return true; 480 } 481 if (!(obj instanceof LIRKind)) { 482 return false; 483 } 484 485 LIRKind other = (LIRKind) obj; 486 if (getPlatformKind() != other.getPlatformKind() || referenceMask != other.referenceMask || referenceCompressionMask != other.referenceCompressionMask) { 487 return false; 488 } 489 if (isDerivedReference()) { 490 if (!other.isDerivedReference()) { 491 return false; 492 } 493 return getDerivedReferenceBase().equals(other.getDerivedReferenceBase()); 494 } 495 // `this` is not a derived reference 496 if (other.isDerivedReference()) { 497 return false; 498 } 499 return true; 500 } 501 502 public static boolean verifyMoveKinds(ValueKind<?> dst, ValueKind<?> src, RegisterAllocationConfig config) { 503 if (src.equals(dst)) { 504 return true; 505 } 506 if (isUnknownReference(dst) || isValue(dst) && isValue(src)) { 507 PlatformKind srcPlatformKind = src.getPlatformKind(); 508 PlatformKind dstPlatformKind = dst.getPlatformKind(); 509 if (srcPlatformKind.equals(dstPlatformKind)) { 510 return true; 511 } 512 // if the register category matches it should be fine, although the kind is different 513 return config.getRegisterCategory(srcPlatformKind).equals(config.getRegisterCategory(dstPlatformKind)); 514 } 515 // reference information mismatch 516 return false; 517 } 518 519 }