Mercurial > hg > graal-compiler
diff graal/Compiler/src/com/sun/c1x/util/Util.java @ 2507:9ec15d6914ca
Pull over of compiler from maxine repository.
author | Thomas Wuerthinger <thomas@wuerthinger.net> |
---|---|
date | Wed, 27 Apr 2011 11:43:22 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/Compiler/src/com/sun/c1x/util/Util.java Wed Apr 27 11:43:22 2011 +0200 @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.c1x.util; + +import java.util.*; + +import com.sun.c1x.*; +import com.sun.c1x.debug.*; +import com.sun.c1x.ir.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code Util} class contains a motley collection of utility methods used throughout the compiler. + * + * @author Ben L. Titzer + * @author Doug Simon + */ +public class Util { + + public static final int PRINTING_LINE_WIDTH = 40; + public static final char SECTION_CHARACTER = '*'; + public static final char SUB_SECTION_CHARACTER = '='; + public static final char SEPERATOR_CHARACTER = '-'; + + public static RuntimeException unimplemented() { + throw new InternalError("unimplemented"); + } + + public static RuntimeException unimplemented(String msg) { + throw new InternalError("unimplemented:" + msg); + } + + public static RuntimeException shouldNotReachHere() { + throw new InternalError("should not reach here"); + } + + public static RuntimeException shouldNotReachHere(String msg) { + throw new InternalError("Should not reach here: " + msg); + } + + public static <T> boolean replaceInList(T a, T b, List<T> list) { + final int max = list.size(); + for (int i = 0; i < max; i++) { + if (list.get(i) == a) { + list.set(i, b); + return true; + } + } + return false; + } + + public static <T> boolean replaceAllInList(T a, T b, List<T> list) { + final int max = list.size(); + for (int i = 0; i < max; i++) { + if (list.get(i) == a) { + list.set(i, b); + } + } + return false; + } + + /** + * Statically cast an object to an arbitrary Object type. Dynamically checked. + */ + @SuppressWarnings("unchecked") + public static <T> T uncheckedCast(Class<T> type, Object object) { + return (T) object; + } + + /** + * Statically cast an object to an arbitrary Object type. Dynamically checked. + */ + @SuppressWarnings("unchecked") + public static <T> T uncheckedCast(Object object) { + return (T) object; + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the object to add to the hash + * @return the combined hash + */ + public static int hash1(int hash, Object x) { + // always set at least one bit in case the hash wraps to zero + return 0x10000000 | (hash + 7 * System.identityHashCode(x)); + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the first object to add to the hash + * @param y the second object to add to the hash + * @return the combined hash + */ + public static int hash2(int hash, Object x, Object y) { + // always set at least one bit in case the hash wraps to zero + return 0x20000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y)); + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the first object to add to the hash + * @param y the second object to add to the hash + * @param z the third object to add to the hash + * @return the combined hash + */ + public static int hash3(int hash, Object x, Object y, Object z) { + // always set at least one bit in case the hash wraps to zero + return 0x30000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z)); + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the first object to add to the hash + * @param y the second object to add to the hash + * @param z the third object to add to the hash + * @param w the fourth object to add to the hash + * @return the combined hash + */ + public static int hash4(int hash, Object x, Object y, Object z, Object w) { + // always set at least one bit in case the hash wraps to zero + return 0x40000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z) + 17 * System.identityHashCode(w)); + } + + static { + assert CiUtil.log2(2) == 1; + assert CiUtil.log2(4) == 2; + assert CiUtil.log2(8) == 3; + assert CiUtil.log2(16) == 4; + assert CiUtil.log2(32) == 5; + assert CiUtil.log2(0x40000000) == 30; + + assert CiUtil.log2(2L) == 1; + assert CiUtil.log2(4L) == 2; + assert CiUtil.log2(8L) == 3; + assert CiUtil.log2(16L) == 4; + assert CiUtil.log2(32L) == 5; + assert CiUtil.log2(0x4000000000000000L) == 62; + + assert !CiUtil.isPowerOf2(3); + assert !CiUtil.isPowerOf2(5); + assert !CiUtil.isPowerOf2(7); + assert !CiUtil.isPowerOf2(-1); + + assert CiUtil.isPowerOf2(2); + assert CiUtil.isPowerOf2(4); + assert CiUtil.isPowerOf2(8); + assert CiUtil.isPowerOf2(16); + assert CiUtil.isPowerOf2(32); + assert CiUtil.isPowerOf2(64); + } + + /** + * Sets the element at a given position of a list and ensures that this position exists. If the list is current + * shorter than the position, intermediate positions are filled with a given value. + * + * @param list the list to put the element into + * @param pos the position at which to insert the element + * @param x the element that should be inserted + * @param filler the filler element that is used for the intermediate positions in case the list is shorter than pos + */ + public static <T> void atPutGrow(List<T> list, int pos, T x, T filler) { + if (list.size() < pos + 1) { + while (list.size() < pos + 1) { + list.add(filler); + } + assert list.size() == pos + 1; + } + + assert list.size() >= pos + 1; + list.set(pos, x); + } + + public static void breakpoint() { + // do nothing. + } + + public static void guarantee(boolean b, String string) { + if (!b) { + throw new CiBailout(string); + } + } + + public static void warning(String string) { + TTY.println("WARNING: " + string); + } + + public static int safeToInt(long l) { + assert (int) l == l; + return (int) l; + } + + public static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + public static void truncate(List<?> list, int length) { + while (list.size() > length) { + list.remove(list.size() - 1); + } + } + + public static void printSection(String name, char sectionCharacter) { + + String header = " " + name + " "; + int remainingCharacters = PRINTING_LINE_WIDTH - header.length(); + int leftPart = remainingCharacters / 2; + int rightPart = remainingCharacters - leftPart; + for (int i = 0; i < leftPart; i++) { + TTY.print(sectionCharacter); + } + + TTY.print(header); + + for (int i = 0; i < rightPart; i++) { + TTY.print(sectionCharacter); + } + + TTY.println(); + } + + /** + * Prints entries in a byte array as space separated hex values to {@link TTY}. + * + * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. + * @param array the array containing all the bytes to print + * @param bytesPerLine the number of values to print per line of output + */ + public static void printBytes(long address, byte[] array, int bytesPerLine) { + printBytes(address, array, 0, array.length, bytesPerLine); + } + + /** + * Prints entries in a byte array as space separated hex values to {@link TTY}. + * + * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. + * @param array the array containing the bytes to print + * @param offset the offset in {@code array} of the values to print + * @param length the number of values from {@code array} print + * @param bytesPerLine the number of values to print per line of output + */ + public static void printBytes(long address, byte[] array, int offset, int length, int bytesPerLine) { + assert bytesPerLine > 0; + boolean newLine = true; + for (int i = 0; i < length; i++) { + if (newLine) { + TTY.print("%08x: ", address + i); + newLine = false; + } + TTY.print("%02x ", array[i]); + if (i % bytesPerLine == bytesPerLine - 1) { + TTY.println(); + newLine = true; + } + } + + if (length % bytesPerLine != bytesPerLine) { + TTY.println(); + } + } + + public static CiKind[] signatureToKinds(RiSignature signature, CiKind receiverKind) { + int args = signature.argumentCount(false); + CiKind[] result; + int i = 0; + if (receiverKind != null) { + result = new CiKind[args + 1]; + result[0] = receiverKind; + i = 1; + } else { + result = new CiKind[args]; + } + for (int j = 0; j < args; j++) { + result[i + j] = signature.argumentKindAt(j); + } + return result; + } + + public static <T> T nonFatalUnimplemented(T val) { + if (C1XOptions.FatalUnimplemented) { + throw new Error("unimplemented"); + } + return val; + } + + public static void nonFatalUnimplemented() { + if (C1XOptions.FatalUnimplemented) { + throw new Error("unimplemented"); + } + } + + public static boolean isShiftCount(int x) { + return 0 <= x && x < 32; + } + + /** + * Determines if a given {@code int} value is the range of unsigned byte values. + */ + public static boolean isUByte(int x) { + return (x & 0xff) == x; + } + + /** + * Determines if a given {@code int} value is the range of signed byte values. + */ + public static boolean isByte(int x) { + return (byte) x == x; + } + + /** + * Determines if a given {@code long} value is the range of unsigned byte values. + */ + public static boolean isUByte(long x) { + return (x & 0xffL) == x; + } + + /** + * Determines if a given {@code long} value is the range of signed byte values. + */ + public static boolean isByte(long l) { + return (byte) l == l; + } + + /** + * Determines if a given {@code long} value is the range of unsigned int values. + */ + public static boolean isUInt(long x) { + return (x & 0xffffffffL) == x; + } + + /** + * Determines if a given {@code long} value is the range of signed int values. + */ + public static boolean isInt(long l) { + return (int) l == l; + } + /** + * Determines if a given {@code int} value is the range of signed short values. + */ + public static boolean isShort(int x) { + return (short) x == x; + } + + public static boolean is32bit(long x) { + return -0x80000000L <= x && x < 0x80000000L; + } + + public static short safeToShort(int v) { + assert isShort(v); + return (short) v; + } + + /** + * Determines if the kinds of two given IR nodes are equal at the {@linkplain #archKind(CiKind) architecture} + * level in the context of the {@linkplain C1XCompilation#compilation()} compilation. + */ + public static boolean archKindsEqual(Value i, Value other) { + return archKindsEqual(i.kind, other.kind); + } + + /** + * Determines if two given kinds are equal at the {@linkplain #archKind(CiKind) architecture} level + * in the context of the {@linkplain C1XCompilation#compilation()} compilation. + */ + public static boolean archKindsEqual(CiKind k1, CiKind k2) { + C1XCompilation compilation = C1XCompilation.compilation(); + assert compilation != null : "missing compilation context"; + return compilation.archKindsEqual(k1, k2); + } + + /** + * Translates a given kind to a {@linkplain C1XCompilation#archKind(CiKind) canonical architecture} + * kind in the context of the {@linkplain C1XCompilation#compilation() current} compilation. + */ + public static CiKind archKind(CiKind kind) { + C1XCompilation compilation = C1XCompilation.compilation(); + assert compilation != null : "missing compilation context"; + return compilation.archKind(kind); + } + + + /** + * Checks that two instructions are equivalent, optionally comparing constants. + * @param x the first instruction + * @param y the second instruction + * @param compareConstants {@code true} if equivalent constants should be considered equivalent + * @return {@code true} if the instructions are equivalent; {@code false} otherwise + */ + public static boolean equivalent(Instruction x, Instruction y, boolean compareConstants) { + if (x == y) { + return true; + } + if (compareConstants && x != null && y != null) { + if (x.isConstant() && x.asConstant().equivalent(y.asConstant())) { + return true; + } + } + return false; + } + + /** + * Converts a given instruction to a value string. The representation of an instruction as + * a value is formed by concatenating the {@linkplain com.sun.cri.ci.CiKind#typeChar character} denoting its + * {@linkplain Value#kind kind} and its {@linkplain Value#id()}. For example, {@code "i13"}. + * + * @param value the instruction to convert to a value string. If {@code value == null}, then "-" is returned. + * @return the instruction representation as a string + */ + public static String valueString(Value value) { + return value == null ? "-" : "" + value.kind.typeChar + value.id(); + } +}