comparison graal/com.oracle.jvmci.meta/src/com/oracle/jvmci/meta/LIRKind.java @ 21556:48c1ebd24120

renamed com.oracle.graal.api[meta|code] modules to com.oracle.jvmci.[meta|code] (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Wed, 27 May 2015 00:36:16 +0200
parents graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LIRKind.java@0ad4c6aa8063
children
comparison
equal deleted inserted replaced
21555:d12eaef9af72 21556:48c1ebd24120
1 /*
2 * Copyright (c) 2014, 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 com.oracle.jvmci.meta;
24
25 import java.util.*;
26
27 /**
28 * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the
29 * low level representation of the value, and a {@link #referenceMask} that describes the location
30 * of object references in the value.
31 *
32 * <h2>Constructing {@link LIRKind} instances</h2>
33 *
34 * During LIR generation, every new {@link Value} should get a {@link LIRKind} of the correct
35 * {@link PlatformKind} that also contains the correct reference information. {@linkplain LIRKind
36 * LIRKinds} should be created as follows:
37 *
38 * <p>
39 * If the result value is created from one or more input values, the {@link LIRKind} should be
40 * created with {@link LIRKind#derive}(inputs). If the result has a different {@link PlatformKind}
41 * than the inputs, {@link LIRKind#derive}(inputs).{@link #changeType}(resultKind) should be used.
42 * <p>
43 * If the result is an exact copy of one of the inputs, {@link Value#getLIRKind()} can be used. Note
44 * that this is only correct for move-like operations, like conditional move or compare-and-swap.
45 * For convert operations, {@link LIRKind#derive} should be used.
46 * <p>
47 * If it is known that the result will be a reference (e.g. pointer arithmetic where the end result
48 * is a valid oop), {@link LIRKind#reference} should be used.
49 * <p>
50 * If it is known that the result will neither be a reference nor be derived from a reference,
51 * {@link LIRKind#value} can be used. If the operation producing this value has inputs, this is very
52 * likely wrong, and {@link LIRKind#derive} should be used instead.
53 * <p>
54 * If it is known that the result is derived from a reference, {@link LIRKind#derivedReference} can
55 * be used. In most cases, {@link LIRKind#derive} should be used instead, since it is able to detect
56 * this automatically.
57 */
58 public final class LIRKind {
59
60 /**
61 * The non-type. This uses {@link #derivedReference}, so it can never be part of an oop map.
62 */
63 public static final LIRKind Illegal = derivedReference(Kind.Illegal);
64
65 private final PlatformKind platformKind;
66 private final int referenceMask;
67
68 private static final int DERIVED_REFERENCE = -1;
69
70 private LIRKind(PlatformKind platformKind, int referenceMask) {
71 this.platformKind = platformKind;
72 this.referenceMask = referenceMask;
73 }
74
75 /**
76 * Create a {@link LIRKind} of type {@code platformKind} that contains a primitive value. Should
77 * be only used when it's guaranteed that the value is not even indirectly derived from a
78 * reference. Otherwise, {@link #derive(Value...)} should be used instead.
79 */
80 public static LIRKind value(PlatformKind platformKind) {
81 assert platformKind != Kind.Object : "Object should always be used as reference type";
82 return new LIRKind(platformKind, 0);
83 }
84
85 /**
86 * Create a {@link LIRKind} of type {@code platformKind} that contains a single tracked oop
87 * reference.
88 */
89 public static LIRKind reference(PlatformKind platformKind) {
90 int length = platformKind.getVectorLength();
91 assert 0 < length && length < 32 : "vector of " + length + " references not supported";
92 return new LIRKind(platformKind, (1 << length) - 1);
93 }
94
95 /**
96 * Create a {@link LIRKind} of type {@code platformKind} that contains a value that is derived
97 * from a reference. Values of this {@link LIRKind} can not be live at safepoints. In most
98 * cases, this should not be called directly. {@link #derive} should be used instead to
99 * automatically propagate this information.
100 */
101 public static LIRKind derivedReference(PlatformKind platformKind) {
102 return new LIRKind(platformKind, DERIVED_REFERENCE);
103 }
104
105 /**
106 * Derive a new type from inputs. The result will have the {@link PlatformKind} of one of the
107 * inputs. If all inputs are values, the result is a value. Otherwise, the result is a derived
108 * reference.
109 *
110 * This method should be used to construct the result {@link LIRKind} of any operation that
111 * modifies values (e.g. arithmetics).
112 */
113 public static LIRKind derive(Value... inputs) {
114 assert inputs.length > 0;
115 for (Value input : inputs) {
116 LIRKind kind = input.getLIRKind();
117 if (kind.isDerivedReference()) {
118 return kind;
119 } else if (!kind.isValue()) {
120 return kind.makeDerivedReference();
121 }
122 }
123
124 // all inputs are values, just return one of them
125 return inputs[0].getLIRKind();
126 }
127
128 /**
129 * Merge the types of the inputs. The result will have the {@link PlatformKind} of one of the
130 * inputs. If all inputs are values (references), the result is a value (reference). Otherwise,
131 * the result is a derived reference.
132 *
133 * This method should be used to construct the result {@link LIRKind} of merge operation that do
134 * not modify values (e.g. phis).
135 */
136 public static LIRKind merge(Value... inputs) {
137 assert inputs.length > 0;
138 ArrayList<LIRKind> kinds = new ArrayList<>(inputs.length);
139 for (int i = 0; i < inputs.length; i++) {
140 kinds.add(inputs[i].getLIRKind());
141 }
142 return merge(kinds);
143 }
144
145 /**
146 * @see #merge(Value...)
147 */
148 public static LIRKind merge(Iterable<LIRKind> kinds) {
149 LIRKind mergeKind = null;
150
151 for (LIRKind kind : kinds) {
152
153 assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind);
154
155 if (kind.isDerivedReference()) {
156 /**
157 * Kind is a derived reference therefore the result can only be also a derived
158 * reference.
159 */
160 return kind;
161 }
162 if (mergeKind == null) {
163 mergeKind = kind;
164 continue;
165 }
166
167 if (kind.isValue()) {
168 /* Kind is a value. */
169 if (mergeKind.referenceMask != 0) {
170 /*
171 * Inputs consists of values and references. Make the result a derived
172 * reference.
173 */
174 return mergeKind.makeDerivedReference();
175 }
176 /* Check that other inputs are also values. */
177 } else {
178 /* Kind is a reference. */
179 if (mergeKind.referenceMask != kind.referenceMask) {
180 /*
181 * Reference maps do not match so the result can only be a derived reference.
182 */
183 return mergeKind.makeDerivedReference();
184 }
185 }
186
187 }
188 assert mergeKind != null;
189
190 // all inputs are values or references, just return one of them
191 return mergeKind;
192 }
193
194 /**
195 * Create a new {@link LIRKind} with the same reference information and a new
196 * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this,
197 * the new elements are marked as untracked values.
198 */
199 public LIRKind changeType(PlatformKind newPlatformKind) {
200 if (newPlatformKind == platformKind) {
201 return this;
202 } else if (isDerivedReference()) {
203 return derivedReference(newPlatformKind);
204 } else if (referenceMask == 0) {
205 // value type
206 return new LIRKind(newPlatformKind, 0);
207 } else {
208 // reference type
209 int newLength = Math.min(32, newPlatformKind.getVectorLength());
210 int newReferenceMask = referenceMask & (0xFFFFFFFF >>> (32 - newLength));
211 assert newReferenceMask != DERIVED_REFERENCE;
212 return new LIRKind(newPlatformKind, newReferenceMask);
213 }
214 }
215
216 /**
217 * Create a new {@link LIRKind} with a new {@linkplain #getPlatformKind platform kind}. If the
218 * new kind is longer than this, the reference positions are repeated to fill the vector.
219 */
220 public LIRKind repeat(PlatformKind newPlatformKind) {
221 if (isDerivedReference()) {
222 return derivedReference(newPlatformKind);
223 } else if (referenceMask == 0) {
224 // value type
225 return new LIRKind(newPlatformKind, 0);
226 } else {
227 // reference type
228 int oldLength = platformKind.getVectorLength();
229 int newLength = newPlatformKind.getVectorLength();
230 assert oldLength <= newLength && newLength < 32 && (newLength % oldLength) == 0;
231
232 // repeat reference mask to fill new kind
233 int newReferenceMask = 0;
234 for (int i = 0; i < newLength; i += platformKind.getVectorLength()) {
235 newReferenceMask |= referenceMask << i;
236 }
237
238 assert newReferenceMask != DERIVED_REFERENCE;
239 return new LIRKind(newPlatformKind, newReferenceMask);
240 }
241 }
242
243 /**
244 * Create a new {@link LIRKind} with the same type, but marked as containing a derivedReference.
245 */
246 public LIRKind makeDerivedReference() {
247 return new LIRKind(platformKind, DERIVED_REFERENCE);
248 }
249
250 /**
251 * Get the low level type that is used in code generation.
252 */
253 public PlatformKind getPlatformKind() {
254 return platformKind;
255 }
256
257 /**
258 * Check whether this value is derived from a reference. If this returns {@code true}, this
259 * value must not be live at safepoints.
260 */
261 public boolean isDerivedReference() {
262 return referenceMask == DERIVED_REFERENCE;
263 }
264
265 /**
266 * Check whether the {@code idx}th part of this value is a reference that must be tracked at
267 * safepoints.
268 *
269 * @param idx The index into the vector if this is a vector kind. Must be 0 if this is a scalar
270 * kind.
271 */
272 public boolean isReference(int idx) {
273 assert 0 <= idx && idx < platformKind.getVectorLength() : "invalid index " + idx + " in " + this;
274 return !isDerivedReference() && (referenceMask & 1 << idx) != 0;
275 }
276
277 /**
278 * Check whether this kind is a value type that doesn't need to be tracked at safepoints.
279 */
280 public boolean isValue() {
281 return referenceMask == 0;
282 }
283
284 @Override
285 public String toString() {
286 if (isValue()) {
287 return platformKind.name();
288 } else if (isDerivedReference()) {
289 return platformKind.name() + "[*]";
290 } else {
291 StringBuilder ret = new StringBuilder();
292 ret.append(platformKind.name());
293 ret.append('[');
294 for (int i = 0; i < platformKind.getVectorLength(); i++) {
295 if (isReference(i)) {
296 ret.append('.');
297 } else {
298 ret.append(' ');
299 }
300 }
301 ret.append(']');
302 return ret.toString();
303 }
304 }
305
306 @Override
307 public int hashCode() {
308 final int prime = 31;
309 int result = 1;
310 result = prime * result + ((platformKind == null) ? 0 : platformKind.hashCode());
311 result = prime * result + referenceMask;
312 return result;
313 }
314
315 @Override
316 public boolean equals(Object obj) {
317 if (this == obj) {
318 return true;
319 }
320 if (!(obj instanceof LIRKind)) {
321 return false;
322 }
323
324 LIRKind other = (LIRKind) obj;
325 return platformKind == other.platformKind && referenceMask == other.referenceMask;
326 }
327
328 public static boolean verifyMoveKinds(LIRKind dst, LIRKind src) {
329 if (src.equals(dst)) {
330 return true;
331 }
332 /*
333 * TODO(je,rs) What we actually want is toStackKind(src.getPlatformKind()).equals(
334 * dst.getPlatformKind()) but due to the handling of sub-integer at the current point
335 * (phi-)moves from e.g. integer to short can happen. Therefore we compare stack kinds.
336 */
337 if (toStackKind(src.getPlatformKind()).equals(toStackKind(dst.getPlatformKind()))) {
338 return !src.isDerivedReference() || dst.isDerivedReference();
339 }
340 return false;
341 }
342
343 private static PlatformKind toStackKind(PlatformKind platformKind) {
344 if (platformKind instanceof Kind) {
345 return ((Kind) platformKind).getStackKind();
346 }
347 return platformKind;
348 }
349 }