/*
* Copyright (C) 2012 RoboVM AB
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
*/
package org.robovm.compiler.llvm;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @version $Id$
*/
public class Function {
private final String name;
private final Linkage linkage;
private final FunctionAttribute[] attributes;
private final ParameterAttribute[][] parameterAttributes;
private final String section;
private final FunctionType type;
private final Map<Label, BasicBlock> basicBlockMap = new HashMap<Label, BasicBlock>();
private final List<BasicBlock> basicBlockList = new ArrayList<BasicBlock>();
private final Map<String, Variable> variablesMap = new HashMap<String, Variable>();
private int counter = 0;
private final String[] parameterNames;
public Function(Linkage linkage, FunctionAttribute[] attributes, String section, String name, FunctionType type, String ... parameterNames) {
this.linkage = linkage;
this.attributes = attributes;
this.section = section;
this.name = name;
this.type = type;
if (parameterNames == null || parameterNames.length == 0 && type.getParameterTypes().length > 0) {
parameterNames = new String[type.getParameterTypes().length];
for (int i = 0; i < parameterNames.length; i++) {
parameterNames[i] = "p" + i;
}
}
this.parameterNames = parameterNames;
this.parameterAttributes = new ParameterAttribute[type.getParameterTypes().length][];
}
public FunctionRef ref() {
return new FunctionRef(this);
}
public String getName() {
return name;
}
public FunctionType getType() {
return type;
}
public VariableRef getParameterRef(int index) {
return new VariableRef(parameterNames[index], type.getParameterTypes()[index]);
}
public VariableRef[] getParameterRefs() {
VariableRef[] result = new VariableRef[parameterNames.length];
for (int i = 0; i < result.length; i++) {
result[i] = getParameterRef(i);
}
return result;
}
public String[] getParameterNames() {
return parameterNames.clone();
}
public void setParameterAttributes(int paramIndex, ParameterAttribute ... attributes) {
parameterAttributes[paramIndex] = attributes.clone();
}
String getLabel(BasicBlock bb) {
return "label" + basicBlockList.indexOf(bb);
}
String getLabel(BasicBlockRef ref) {
return getLabel(basicBlockMap.get(ref.getLabel()));
}
public BasicBlock newBasicBlock(Label label) {
BasicBlock block = basicBlockMap.get(label);
if (block != null) {
throw new IllegalArgumentException("BasicBlock with label " + label + " already exists");
}
block = new BasicBlock(this, label);
basicBlockMap.put(label, block);
basicBlockList.add(block);
return block;
}
public BasicBlockRef newBasicBlockRef(Label label) {
return new BasicBlockRef(this, label);
}
public BasicBlock getCurrentBasicBlock() {
if (basicBlockList.isEmpty()) {
return newBasicBlock(new Label());
}
return basicBlockList.get(basicBlockList.size() - 1);
}
public List<BasicBlock> getBasicBlocks() {
return basicBlockList;
}
public BasicBlock getBasicBlock(Label label) {
return basicBlockMap.get(label);
}
public Variable newVariable(Type type) {
return newVariable("t" + (counter++), type);
}
public Variable newVariable(String name, Type type) {
if (variablesMap.containsKey(name)) {
throw new IllegalArgumentException("Variable with name '" + name + "' already exists");
}
Variable v = new Variable(name, type);
variablesMap.put(name, v);
return v;
}
public BasicBlock getDefinedIn(VariableRef ref) {
Variable var = new Variable(ref);
for (BasicBlock bb : basicBlockList) {
if (bb.getWritesTo().contains(var)) {
return bb;
}
}
throw new IllegalStateException("Variable " + var + " not defined");
}
public Instruction add(Instruction instruction) {
getCurrentBasicBlock().add(instruction);
return instruction;
}
public void write(Writer writer) throws IOException {
Type returnType = type.getReturnType();
Type[] parameterTypes = type.getParameterTypes();
writer.write("define ");
if (linkage != null) {
writer.write(linkage.toString());
writer.write(' ');
}
writer.write(returnType.toString());
writer.write(" @\"");
writer.write(name);
writer.write("\"(");
for (int i = 0; i < parameterTypes.length; i++) {
if (i > 0) {
writer.write(", ");
}
writer.write(parameterTypes[i].toString());
if (parameterAttributes[i] != null) {
for (ParameterAttribute attrib : parameterAttributes[i]) {
writer.write(' ');
writer.write(attrib.toString());
}
}
writer.write(" %");
writer.write(parameterNames[i]);
}
if (type.isVarargs()) {
writer.write(", ...");
}
writer.write(")");
if (attributes != null && attributes.length > 0) {
for (FunctionAttribute attr : attributes) {
writer.write(' ');
writer.write(attr.toString());
}
}
if (section != null) {
writer.write(" section \"");
writer.write(section);
writer.write('"');
}
writer.write(" {\n");
for (BasicBlock bb : basicBlockList) {
writer.write(bb.toString());
}
writer.write("}\n");
}
@Override
public String toString() {
StringWriter sw = new StringWriter();
try {
write(sw);
} catch (IOException e) {
throw new RuntimeException(e);
}
return sw.toString();
}
}