/*
* 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.model;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import com.oracle.truffle.llvm.parser.model.attributes.AttributesCodeEntry;
import com.oracle.truffle.llvm.parser.model.functions.FunctionDeclaration;
import com.oracle.truffle.llvm.parser.model.functions.FunctionDefinition;
import com.oracle.truffle.llvm.parser.model.generators.FunctionGenerator;
import com.oracle.truffle.llvm.parser.model.generators.ModuleGenerator;
import com.oracle.truffle.llvm.parser.model.globals.GlobalAlias;
import com.oracle.truffle.llvm.parser.model.globals.GlobalConstant;
import com.oracle.truffle.llvm.parser.model.globals.GlobalValueSymbol;
import com.oracle.truffle.llvm.parser.model.globals.GlobalVariable;
import com.oracle.truffle.llvm.parser.model.symbols.Symbols;
import com.oracle.truffle.llvm.parser.model.symbols.constants.BinaryOperationConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.BlockAddressConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.CastConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.CompareConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.Constant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.GetElementPointerConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.InlineAsmConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.NullConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.StringConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.UndefinedConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.floatingpoint.FloatingPointConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.integer.BigIntegerConstant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.integer.IntegerConstant;
import com.oracle.truffle.llvm.parser.model.target.TargetDataLayout;
import com.oracle.truffle.llvm.parser.model.visitors.ModelVisitor;
import com.oracle.truffle.llvm.runtime.types.FunctionType;
import com.oracle.truffle.llvm.runtime.types.Type;
import com.oracle.truffle.llvm.parser.metadata.MetadataList;
import com.oracle.truffle.llvm.runtime.types.symbols.LLVMIdentifier;
import com.oracle.truffle.llvm.runtime.types.symbols.Symbol;
public final class ModelModule implements ModuleGenerator {
private final List<Type> types = new ArrayList<>();
private final List<GlobalValueSymbol> globals = new ArrayList<>();
private final List<FunctionDeclaration> declares = new ArrayList<>();
private final List<FunctionDefinition> defines = new ArrayList<>();
private final Symbols symbols = new Symbols();
private final MetadataList metadata;
private int currentFunction = -1;
private TargetDataLayout targetDataLayout = null;
// when running with Polyglot it can be that there is no layout available - we fall back to this
// one.
private static final TargetDataLayout defaultLayout = TargetDataLayout.fromString("e-m:e-i64:64-f80:128-n8:16:32:64-S128");
@Override
public void createTargetDataLayout(TargetDataLayout layout) {
targetDataLayout = layout;
}
public TargetDataLayout getTargetDataLayout() {
return targetDataLayout == null ? defaultLayout : targetDataLayout;
}
public ModelModule() {
metadata = new MetadataList();
}
public void accept(ModelVisitor visitor) {
if (targetDataLayout != null) {
visitor.visit(targetDataLayout);
}
types.forEach(visitor::visit);
for (GlobalValueSymbol variable : globals) {
variable.accept(visitor);
}
defines.forEach(visitor::visit);
declares.forEach(visitor::visit);
}
@Override
public void createAlias(Type type, int aliasedValue, long linkage, long visibility) {
GlobalAlias alias = GlobalAlias.create(type, aliasedValue, linkage, visibility);
symbols.addSymbol(alias);
globals.add(alias);
}
@Override
public void createBinaryOperationExpression(Type type, int opcode, int lhs, int rhs) {
symbols.addSymbol(BinaryOperationConstant.fromSymbols(symbols, type, opcode, lhs, rhs));
}
@Override
public void createBlockAddress(Type type, int function, int block) {
symbols.addSymbol(BlockAddressConstant.fromSymbols(symbols, type, function, block));
}
@Override
public void createCastExpression(Type type, int opcode, int value) {
symbols.addSymbol(CastConstant.fromSymbols(symbols, type, opcode, value));
}
@Override
public void createCompareExpression(Type type, int opcode, int lhs, int rhs) {
symbols.addSymbol(CompareConstant.fromSymbols(symbols, type, opcode, lhs, rhs));
}
@Override
public void createFloatingPoint(Type type, long[] value) {
symbols.addSymbol(FloatingPointConstant.create(type, value));
}
@Override
public void createFromData(Type type, long[] data) {
symbols.addSymbol(Constant.createFromData(type, data));
}
@Override
public void creatFromString(Type type, String string, boolean isCString) {
symbols.addSymbol(new StringConstant(type, string, isCString));
}
@Override
public void createFromValues(Type type, int[] values) {
symbols.addSymbol(Constant.createFromValues(type, symbols, values));
}
@Override
public void createGetElementPointerExpression(Type type, int pointer, int[] indices, boolean isInbounds) {
symbols.addSymbol(GetElementPointerConstant.fromSymbols(symbols, type, pointer, indices, isInbounds));
}
@Override
public void createInlineASM(Type type, long[] args) {
symbols.addSymbol(InlineAsmConstant.generate(type, args));
}
@Override
public void createInteger(Type type, long value) {
symbols.addSymbol(new IntegerConstant(type, value));
}
@Override
public void createInteger(Type type, BigInteger value) {
symbols.addSymbol(new BigIntegerConstant(type, value));
}
@Override
public void createFunction(FunctionType type, boolean isPrototype, AttributesCodeEntry paramAttr) {
if (isPrototype) {
final FunctionDeclaration function = new FunctionDeclaration(type, paramAttr);
symbols.addSymbol(function);
declares.add(function);
} else {
final FunctionDefinition method = new FunctionDefinition(type, metadata.instantiate(), paramAttr);
symbols.addSymbol(method);
defines.add(method);
}
}
@Override
public void createNull(Type type) {
symbols.addSymbol(new NullConstant(type));
}
@Override
public void createType(Type type) {
types.add(type);
}
@Override
public void createUndefined(Type type) {
symbols.addSymbol(new UndefinedConstant(type));
}
@Override
public void createGlobal(Type type, boolean isConstant, int initialiser, int align, long linkage, long visibility) {
final GlobalValueSymbol global;
if (isConstant) {
global = GlobalConstant.create(type, initialiser, align, linkage, visibility);
} else {
global = GlobalVariable.create(type, initialiser, align, linkage, visibility);
}
symbols.addSymbol(global);
globals.add(global);
}
@Override
public void exitModule() {
int globalIndex = 0;
for (GlobalValueSymbol variable : globals) {
if (variable.getName().equals(LLVMIdentifier.UNKNOWN)) {
variable.setName(String.valueOf(globalIndex++));
}
variable.initialise(symbols);
}
}
@Override
public FunctionGenerator generateFunction() {
while (++currentFunction < symbols.getSize()) {
Symbol symbol = symbols.getSymbol(currentFunction);
if (symbol instanceof FunctionDefinition) {
FunctionDefinition function = (FunctionDefinition) symbol;
function.getSymbols().addSymbols(symbols);
return function;
}
}
throw new RuntimeException("Trying to generate undefined function");
}
@Override
public MetadataList getMetadata() {
return metadata;
}
@Override
public void nameBlock(int index, String name) {
}
@Override
public void nameEntry(int index, String name) {
symbols.setSymbolName(index, name);
}
@Override
public void nameFunction(int index, int offset, String name) {
symbols.setSymbolName(index, name);
}
@Override
public Symbols getSymbols() {
return symbols;
}
@Override
public String toString() {
return "ModelModule [types=" + types + ", globals=" + globals + ", declares=" + declares + ", defines=" + defines + ", symbols=" + symbols + ", currentFunction=" + currentFunction + "]";
}
}