/*
* Copyright (c) 2016, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.parser.datalayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
final class DataLayoutParser {
static final class DataTypeSpecification {
private final DataLayoutType type;
private final int[] values;
private DataTypeSpecification(DataLayoutType type, int[] values) {
this.type = type;
this.values = values;
}
DataLayoutType getType() {
return type;
}
int[] getValues() {
return values;
}
@Override
public String toString() {
return getType() + " " + Arrays.toString(getValues());
}
}
private static void addIfMissing(List<DataTypeSpecification> specs, DataTypeSpecification newSpec) {
for (DataTypeSpecification spec : specs) {
if (spec.type == newSpec.type && spec.values[0] == newSpec.values[0]) {
return;
}
}
specs.add(newSpec);
}
static List<DataTypeSpecification> parseDataLayout(String layout) {
String[] layoutSpecs = layout.split("-");
assertNoNullElement(layoutSpecs);
List<DataTypeSpecification> specs = new ArrayList<>();
for (String spec : layoutSpecs) {
if (spec.equals("e") || spec.equals("E") || spec.equals("m:e") || spec.equals("m:o")) {
// ignore for the moment
} else {
String type = spec.substring(0, 1);
DataLayoutType baseType = getDataType(type);
int[] values = getTypeWidths(spec);
specs.add(new DataTypeSpecification(baseType, values));
if (type.equals("n")) {
for (int value : values) {
addIfMissing(specs, new DataTypeSpecification(DataLayoutType.INTEGER, new int[]{value, value}));
}
}
}
}
// Add specs for 32 bit float and 64 bit double which are supported on all targets
// http://releases.llvm.org/3.9.0/docs/LangRef.html#data-layout
addIfMissing(specs, new DataTypeSpecification(DataLayoutType.FLOAT, new int[]{Float.SIZE, Float.SIZE}));
addIfMissing(specs, new DataTypeSpecification(DataLayoutType.FLOAT, new int[]{Double.SIZE, Double.SIZE}));
// FIXME:work around to handle pointer type in LLVM 3.9.0 bitcode format
checkPointerType(specs);
return specs;
}
private static void checkPointerType(List<DataTypeSpecification> specs) {
boolean isPointerTypeFound = false;
for (DataTypeSpecification spec : specs) {
if (spec.type == DataLayoutType.POINTER) {
isPointerTypeFound = true;
break;
}
}
if (!isPointerTypeFound) {
// Add a pointer datatype with size = largest integer size
int largestIntegerTypeSize = -1;
for (DataTypeSpecification spec : specs) {
if (spec.type == DataLayoutType.INTEGER && spec.values[0] > largestIntegerTypeSize) {
largestIntegerTypeSize = spec.values[0];
}
}
if (largestIntegerTypeSize > 0) {
specs.add(new DataTypeSpecification(DataLayoutType.POINTER, new int[]{largestIntegerTypeSize, largestIntegerTypeSize}));
}
}
}
private static int[] getTypeWidths(String spec) {
String typeWidths = spec.substring(1);
if (typeWidths.startsWith(":")) {
typeWidths = typeWidths.substring(1);
}
String[] components = typeWidths.split(":");
assertNoNullElement(components);
int[] values = new int[components.length];
for (int i = 0; i < values.length; i++) {
values[i] = Integer.parseInt(components[i]);
}
return values;
}
private static DataLayoutType getDataType(String string) {
switch (string) {
case "i":
return DataLayoutType.INTEGER;
case "f":
return DataLayoutType.FLOAT;
case "v":
return DataLayoutType.VECTOR;
case "p":
return DataLayoutType.POINTER;
case "a":
return DataLayoutType.AGGREGATE;
case "s":
return DataLayoutType.STACK_OBJECT;
case "S":
return DataLayoutType.STACK;
case "n":
return DataLayoutType.INTEGER_WIDTHS;
default:
throw new AssertionError(string);
}
}
private static Object[] assertNoNullElement(Object[] objects) {
for (Object o : objects) {
if (o == null) {
throw new AssertionError(Arrays.toString(objects));
}
}
return objects;
}
}