/* * 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.functions; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.llvm.parser.model.attributes.AttributesCodeEntry; import com.oracle.truffle.llvm.parser.model.attributes.AttributesGroup; import com.oracle.truffle.llvm.parser.model.blocks.InstructionBlock; import com.oracle.truffle.llvm.parser.model.generators.FunctionGenerator; 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.symbols.instructions.Instruction; import com.oracle.truffle.llvm.parser.model.symbols.instructions.ValueInstruction; import com.oracle.truffle.llvm.parser.model.visitors.ConstantVisitor; import com.oracle.truffle.llvm.parser.model.visitors.FunctionVisitor; 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.ValueSymbol; public final class FunctionDefinition implements Constant, FunctionGenerator, ValueSymbol { private final MetadataList metadata; private final Symbols symbols = new Symbols(); private final List<FunctionParameter> parameters = new ArrayList<>(); private InstructionBlock[] blocks = new InstructionBlock[0]; private int currentBlock = 0; private final Map<String, Type> namesToTypes; private final FunctionType type; private String name; private final AttributesCodeEntry paramAttr; public FunctionDefinition(FunctionType type, String name, MetadataList metadata, AttributesCodeEntry paramAttr) { this.type = type; this.metadata = metadata; namesToTypes = new HashMap<>(); this.name = name; this.paramAttr = paramAttr; } public FunctionDefinition(FunctionType type, MetadataList metadata, AttributesCodeEntry paramAttr) { this(type, LLVMIdentifier.UNKNOWN, metadata, paramAttr); } @Override public void setName(String name) { this.name = LLVMIdentifier.toGlobalIdentifier(name); } @Override public boolean hasName() { return name != null; } @Override public String getName() { assert name != null; return name; } @Override public void accept(ConstantVisitor visitor) { visitor.visit(this); } public void accept(FunctionVisitor visitor) { for (InstructionBlock block : blocks) { visitor.visit(block); } } @Override public void allocateBlocks(int count) { blocks = new InstructionBlock[count]; for (int i = 0; i < count; i++) { blocks[i] = new InstructionBlock(this, i); } } @Override public FunctionType getType() { return type; } public AttributesGroup getFunctionAttributesGroup() { CompilerAsserts.neverPartOfCompilation(); return paramAttr.getFunctionAttributesGroup(); } public AttributesGroup getReturnAttributesGroup() { CompilerAsserts.neverPartOfCompilation(); return paramAttr.getReturnAttributesGroup(); } @Override public void createParameter(Type t) { final int index = parameters.size(); final AttributesGroup attrGroup = paramAttr.getParameterAttributesGroup(index); FunctionParameter parameter = new FunctionParameter(t, index, attrGroup); symbols.addSymbol(parameter); parameters.add(parameter); } @Override public void exitFunction() { int symbolIndex = 0; // in K&R style function declarations the parameters are not assigned names for (final FunctionParameter parameter : parameters) { if (LLVMIdentifier.UNKNOWN.equals(parameter.getName())) { parameter.setName(String.valueOf(symbolIndex++)); } namesToTypes.put(parameter.getName(), parameter.getType()); } final Set<String> explicitBlockNames = Arrays.stream(blocks).map(InstructionBlock::getName).filter(blockName -> !LLVMIdentifier.UNKNOWN.equals(blockName)).collect(Collectors.toSet()); for (final InstructionBlock block : blocks) { if (block.getName().equals(LLVMIdentifier.UNKNOWN)) { do { block.setImplicitName(symbolIndex++); // avoid name clashes } while (explicitBlockNames.contains(block.getName())); } for (int i = 0; i < block.getInstructionCount(); i++) { final Instruction instruction = block.getInstruction(i); if (instruction instanceof ValueInstruction) { final ValueInstruction value = (ValueInstruction) instruction; if (value.getName().equals(LLVMIdentifier.UNKNOWN)) { value.setName(String.valueOf(symbolIndex++)); } namesToTypes.put(value.getName(), value.getType()); } } } } @Override public InstructionBlock generateBlock() { return blocks[currentBlock++]; } public Type getType(String instructionName) { CompilerAsserts.neverPartOfCompilation(); return namesToTypes.get(instructionName); } public InstructionBlock getBlock(long idx) { CompilerAsserts.neverPartOfCompilation(); return blocks[(int) idx]; } public int getBlockCount() { CompilerAsserts.neverPartOfCompilation(); return blocks.length; } public List<InstructionBlock> getBlocks() { CompilerAsserts.neverPartOfCompilation(); return Arrays.asList(blocks); } public List<FunctionParameter> getParameters() { CompilerAsserts.neverPartOfCompilation(); return parameters; } @Override public Symbols getSymbols() { CompilerAsserts.neverPartOfCompilation(); return symbols; } @Override public void nameBlock(int index, String argName) { blocks[index].setName(argName); } @Override public void nameEntry(int index, String argName) { symbols.setSymbolName(index, argName); } @Override public void nameFunction(int index, int offset, String argName) { symbols.setSymbolName(index, argName); } @Override public void createBinaryOperationExpression(Type t, int opcode, int lhs, int rhs) { symbols.addSymbol(BinaryOperationConstant.fromSymbols(symbols, t, opcode, lhs, rhs)); } @Override public void createBlockAddress(Type t, int function, int block) { symbols.addSymbol(BlockAddressConstant.fromSymbols(symbols, t, function, block)); } @Override public void createCastExpression(Type t, int opcode, int value) { symbols.addSymbol(CastConstant.fromSymbols(symbols, t, opcode, value)); } @Override public void createCompareExpression(Type t, int opcode, int lhs, int rhs) { symbols.addSymbol(CompareConstant.fromSymbols(symbols, t, opcode, lhs, rhs)); } @Override public void createFloatingPoint(Type t, long[] bits) { symbols.addSymbol(FloatingPointConstant.create(t, bits)); } @Override public void createFromData(Type t, long[] data) { symbols.addSymbol(Constant.createFromData(t, data)); } @Override public void creatFromString(Type t, String string, boolean isCString) { symbols.addSymbol(new StringConstant(t, string, isCString)); } @Override public void createFromValues(Type t, int[] values) { symbols.addSymbol(Constant.createFromValues(t, symbols, values)); } @Override public void createGetElementPointerExpression(Type t, int pointer, int[] indices, boolean isInbounds) { symbols.addSymbol(GetElementPointerConstant.fromSymbols(symbols, t, pointer, indices, isInbounds)); } @Override public void createInlineASM(Type t, long[] asm) { symbols.addSymbol(InlineAsmConstant.generate(t, asm)); } @Override public void createInteger(Type t, long value) { symbols.addSymbol(new IntegerConstant(t, value)); } @Override public void createInteger(Type t, BigInteger value) { symbols.addSymbol(new BigIntegerConstant(t, value)); } @Override public void createNull(Type t) { symbols.addSymbol(new NullConstant(t)); } @Override public void createUndefined(Type t) { symbols.addSymbol(new UndefinedConstant(t)); } @Override public MetadataList getMetadata() { CompilerAsserts.neverPartOfCompilation(); return metadata; } @Override public int hashCode() { CompilerAsserts.neverPartOfCompilation(); int hash = super.hashCode(); hash = 43 * hash + ((parameters == null) ? 0 : parameters.hashCode()); hash = 43 * hash + ((symbols == null) ? 0 : symbols.hashCode()); return hash; } @Override public boolean equals(Object obj) { CompilerAsserts.neverPartOfCompilation(); if (obj instanceof FunctionDefinition) { FunctionDefinition other = (FunctionDefinition) obj; return super.equals(other) && Objects.equals(parameters, other.parameters) && Objects.equals(symbols, other.symbols) && Arrays.equals(blocks, other.blocks) && currentBlock == other.currentBlock; } return false; } @Override public String toString() { CompilerAsserts.neverPartOfCompilation(); return "FunctionDefinition [symbols=" + symbols + ", parameters=" + parameters + ", blocks=" + Arrays.toString(blocks) + ", currentBlock=" + currentBlock + ", name=" + name + ", paramattr=" + paramAttr + "]"; } }