/*
* 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.listeners;
import java.util.ArrayList;
import java.util.List;
import com.oracle.truffle.llvm.parser.model.attributes.AttributesCodeEntry;
import com.oracle.truffle.llvm.parser.model.enums.Visibility;
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.target.TargetDataLayout;
import com.oracle.truffle.llvm.parser.model.target.TargetInformation;
import com.oracle.truffle.llvm.parser.model.target.TargetTriple;
import com.oracle.truffle.llvm.parser.records.ModuleRecord;
import com.oracle.truffle.llvm.parser.records.Records;
import com.oracle.truffle.llvm.parser.scanner.Block;
import com.oracle.truffle.llvm.runtime.LLVMLogger;
import com.oracle.truffle.llvm.runtime.types.FunctionType;
import com.oracle.truffle.llvm.runtime.types.PointerType;
import com.oracle.truffle.llvm.runtime.types.Type;
public final class Module implements ParserListener {
private final ModuleGenerator generator;
private final ParameterAttributes paramAttributes = new ParameterAttributes();
private int mode = 1;
protected final Types types;
private final List<TargetInformation> info = new ArrayList<>();
protected final List<FunctionType> functions = new ArrayList<>();
protected final List<Type> symbols = new ArrayList<>();
public Module(ModuleGenerator generator) {
this.generator = generator;
types = new Types(generator);
}
private static final int FUNCTION_TYPE = 0;
private static final int FUNCTION_ISPROTOTYPE = 2;
private static final int FUNCTION_PARAMATTR = 4;
private void createFunction(long[] args) {
Type type = types.get(args[FUNCTION_TYPE]);
if (type instanceof PointerType) {
type = ((PointerType) type).getPointeeType();
}
final FunctionType functionType = (FunctionType) type;
final boolean isPrototype = args[FUNCTION_ISPROTOTYPE] != 0;
final AttributesCodeEntry paramAttr = paramAttributes.getCodeEntry(args[FUNCTION_PARAMATTR]);
generator.createFunction(functionType, isPrototype, paramAttr);
symbols.add(functionType);
if (!isPrototype) {
functions.add(functionType);
}
}
private static final int GLOBALVAR_TYPE = 0;
private static final int GLOBALVAR_FLAGS = 1;
private static final long GLOBALVAR_EXPLICICTTYPE_MASK = 0x2;
private static final long GLOBALVAR_ISCONSTANT_MASK = 0x1;
private static final int GLOBALVAR_INTITIALIZER = 2;
private static final int GLOBALVAR_LINKAGE = 3;
private static final int GLOBALVAR_ALIGN = 4;
private static final int GLOBALVAR_VISIBILITY = 6;
private void createGlobalVariable(long[] args) {
final long typeField = args[GLOBALVAR_TYPE];
final long flagField = args[GLOBALVAR_FLAGS];
Type type = types.get(typeField);
if ((flagField & GLOBALVAR_EXPLICICTTYPE_MASK) != 0) {
type = new PointerType(type);
}
final boolean isConstant = (flagField & GLOBALVAR_ISCONSTANT_MASK) != 0;
final int initialiser = (int) args[GLOBALVAR_INTITIALIZER];
final long linkage = args[GLOBALVAR_LINKAGE];
final int align = (int) args[GLOBALVAR_ALIGN];
long visibility = Visibility.DEFAULT.getEncodedValue();
if (GLOBALVAR_VISIBILITY < args.length) {
visibility = args[GLOBALVAR_VISIBILITY];
}
generator.createGlobal(type, isConstant, initialiser, align, linkage, visibility);
symbols.add(type);
}
private static final int GLOBALALIAS_TYPE = 0;
private static final int GLOBALALIAS_NEW_VALUE = 2;
private static final int GLOBALALIAS_NEW_LINKAGE = 3;
private void createGlobalAliasNew(long[] args) {
final Type type = new PointerType(types.get(args[GLOBALALIAS_TYPE]));
// idx = 1 is address space information
final int value = (int) args[GLOBALALIAS_NEW_VALUE];
final long linkage = args[GLOBALALIAS_NEW_LINKAGE];
generator.createAlias(type, value, linkage, Visibility.DEFAULT.ordinal());
symbols.add(type);
}
private static final int GLOBALALIAS_OLD_VALUE = 1;
private static final int GLOBALALIAS_OLD_LINKAGE = 2;
private void createGlobalAliasOld(long[] args) {
final Type type = types.get(args[GLOBALALIAS_TYPE]);
int value = (int) args[GLOBALALIAS_OLD_VALUE];
long linkage = args[GLOBALALIAS_OLD_LINKAGE];
generator.createAlias(type, value, linkage, Visibility.DEFAULT.ordinal());
symbols.add(type);
}
@Override
public ParserListener enter(Block block) {
switch (block) {
case MODULE:
return this; // Entering from root
case PARAMATTR:
return paramAttributes;
case PARAMATTR_GROUP:
return paramAttributes;
case CONSTANTS:
return new Constants(types, symbols, generator);
case FUNCTION: {
FunctionType function = functions.remove(0);
FunctionGenerator gen = generator.generateFunction();
List<Type> sym = new ArrayList<>(symbols);
for (Type arg : function.getArgumentTypes()) {
gen.createParameter(arg);
sym.add(arg);
}
return new Function(types, sym, gen, mode);
}
case TYPE:
return types;
case VALUE_SYMTAB:
return new ValueSymbolTable(generator);
case METADATA:
case METADATA_KIND:
return new Metadata(types, generator);
default:
LLVMLogger.info("Entering Unknown Block inside Module: " + block);
return ParserListener.DEFAULT;
}
}
@Override
public void exit() {
generator.exitModule();
}
@Override
public void record(long id, long[] args) {
final ModuleRecord record = ModuleRecord.decode(id);
switch (record) {
case VERSION:
mode = (int) args[0];
break;
case TARGET_TRIPLE:
info.add(new TargetTriple(Records.toString(args)));
break;
case TARGET_DATALAYOUT:
final TargetDataLayout layout = TargetDataLayout.fromString(Records.toString(args));
info.add(layout);
generator.createTargetDataLayout(layout);
break;
case GLOBAL_VARIABLE:
createGlobalVariable(args);
break;
case FUNCTION:
createFunction(args);
break;
case ALIAS:
createGlobalAliasNew(args);
break;
case ALIAS_OLD:
createGlobalAliasOld(args);
break;
default:
LLVMLogger.info("Unknown Top-Level Record: " + Records.describe(id, args));
break;
}
}
}