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