Skip to content

Commit

Permalink
Add Julia backend
Browse files Browse the repository at this point in the history
  • Loading branch information
pjuftring committed Nov 20, 2019
1 parent 55fea47 commit 6345699
Show file tree
Hide file tree
Showing 11 changed files with 455 additions and 6 deletions.
27 changes: 27 additions & 0 deletions codegen-julia/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>gaalop</artifactId>
<groupId>de.gaalop</groupId>
<version>1.0.0</version>
</parent>
<name>Gaalop Julia Plugin</name>
<modelVersion>4.0.0</modelVersion>
<groupId>de.gaalop</groupId>
<artifactId>codegen-julia</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>de.gaalop</groupId>
<artifactId>api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>de.gaalop</groupId>
<artifactId>codegen-cpp</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package de.gaalop.julia;

import de.gaalop.CodeGenerator;
import de.gaalop.OutputFile;
import de.gaalop.cfg.ControlFlowGraph;

import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.Collections;

public enum JuliaCodeGenerator implements CodeGenerator {

INSTANCE;

@Override
public Set<OutputFile> generate(ControlFlowGraph in) {
String code = generateCode(in);

String filename = generateFilename(in);

OutputFile sourceFile = new OutputFile(filename, code, StandardCharsets.UTF_8);
return Collections.singleton(sourceFile);
}

private String generateFilename(ControlFlowGraph in) {
String filename = "gaalop.txt";
if (in.getSource() != null) {
filename = in.getSource().getName();
int lastDotIndex = filename.lastIndexOf('.');
if (lastDotIndex != -1) {
filename = filename.substring(0, lastDotIndex);
}
filename += ".txt";
}
return filename;
}

/**
* Generates source code for a control dataflow graph.
*
* @param in
* @return
*/
private String generateCode(ControlFlowGraph in) {
JuliaVisitor visitor = new JuliaVisitor();
in.accept(visitor);
return visitor.getCode();
}

}
307 changes: 307 additions & 0 deletions codegen-julia/src/main/java/de/gaalop/julia/JuliaVisitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
package de.gaalop.julia;

import de.gaalop.cfg.*;
import de.gaalop.cpp.OperatorPriority;
import de.gaalop.dfg.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;


/**
* This class implements the CFG and DFG visitor that generate Julia code.
* Heavily inspired by CppVisitor.java
*/

public class JuliaVisitor implements ControlFlowVisitor, ExpressionVisitor {

protected Log log = LogFactory.getLog(JuliaVisitor.class);

protected StringBuilder code;
private ControlFlowGraph graph;

public JuliaVisitor() {
code = new StringBuilder();
}

// Stolen from CppVisitor.java. Keeping the order of the variables deterministic is a good idea.
private List<Variable> sortVariables(Set<Variable> inputVariables) {
List<Variable> variables = new ArrayList<Variable>(inputVariables);
Comparator<Variable> comparator = new Comparator<Variable>() {

@Override
public int compare(Variable o1, Variable o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
};

Collections.sort(variables, comparator);
return variables;
}

private void not_implemented(String nodeType) {
throw new UnsupportedOperationException("The Julia backend does not support \"" + nodeType + "\"!");
}

private void macro_error() {
throw new UnsupportedOperationException("Macros should have been removed already!");
}

protected void addBinaryInfix(BinaryOperation op, String operator) {
addChild(op, op.getLeft());
code.append(operator);
addChild(op, op.getRight());
}

protected void addChild(Expression parent, Expression child) {
if (OperatorPriority.hasLowerPriority(parent, child)) {
code.append('(');
child.accept(this);
code.append(')');
} else {
child.accept(this);
}
}

@Override
public void visit(StartNode node) {
graph = node.getGraph();
int bladeCount = graph.getAlgebraDefinitionFile().getBladeCount();

List<Variable> localVariables = sortVariables(graph.getLocalVariables());
List<Variable> inputParameters = sortVariables(graph.getInputVariables());

code.append("function calculate(");

for (Variable var : inputParameters) {
code.append(var.getName());
code.append(", ");
}

for (Variable var : localVariables) {
code.append(var.getName());
code.append(", ");
}

// Remove the last ", " if we have any local variables.
if (graph.getLocalVariables().size() > 0) {
code.setLength(code.length() - 2);
}

code.append(")\n");

node.getSuccessor().accept(this);
}

@Override
public void visit(AssignmentNode node) {
code.append("\t");
node.getVariable().accept(this);
code.append(" = ");
node.getValue().accept(this);
code.append(";");

if (node.getVariable() instanceof MultivectorComponent) {
code.append(" # ");
MultivectorComponent component = (MultivectorComponent) node.getVariable();
code.append(node.getGraph().getAlgebraDefinitionFile().getBladeString(component.getBladeIndex()));
}

code.append("\n");
node.getSuccessor().accept(this);
}

@Override
public void visit(StoreResultNode node) {
node.getSuccessor().accept(this);
}

@Override
public void visit(IfThenElseNode node) {
not_implemented("IfThenElseNode");
}

@Override
public void visit(BlockEndNode node) {
not_implemented("BlockEndNode");
}

@Override
public void visit(LoopNode node) {
not_implemented("LoopNode");
}

@Override
public void visit(BreakNode node) {
not_implemented("BreakNode");
}

@Override
public void visit(Macro node) {
macro_error();
}

@Override
public void visit(ExpressionStatement node) {
not_implemented("ExpressionStatement");
}

@Override
public void visit(EndNode node) {
code.append("end\n");
}

@Override
public void visit(ColorNode node) {
node.getSuccessor().accept(this);
}

@Override
public void visit(Subtraction node) {
addBinaryInfix(node, " - ");
}

@Override
public void visit(Addition node) {
addBinaryInfix(node, " + ");
}

@Override
public void visit(Division node) {
addBinaryInfix(node, " / ");
}

@Override
public void visit(InnerProduct node) {
not_implemented("InnerProduct");
}

@Override
public void visit(Multiplication node) {
addBinaryInfix(node, " * ");
}

@Override
public void visit(MathFunctionCall node) {
String functionName = "";
switch (node.getFunction()) {
case SQRT:
functionName = "sqrt";
break;
case ABS:
functionName = "abs";
break;
case COS:
functionName = "cos";
break;
case SIN:
functionName = "sin";
break;
case EXP:
functionName = "exp";
break;
default:
not_implemented("specific MathFunctionCall");
}
code.append(functionName);
code.append("(");
node.getOperand().accept(this);
code.append(")");
}

@Override
public void visit(Variable node) {
code.append(node.getName());
}

@Override
public void visit(MultivectorComponent node) {
//code.append(node.getName().replace(suffix, ""));
code.append(node.getName());
code.append("[");
code.append(node.getBladeIndex() + 1); // Indices start at 1 in Julia
code.append("]");
}

@Override
public void visit(Exponentiation node) {
code.append("(");
node.getLeft().accept(this);
code.append(") ^ (");
node.getRight().accept(this);
code.append(")");
}

@Override
public void visit(FloatConstant node) {
code.append(Double.toString(node.getValue()));
code.append("f0");
}

@Override
public void visit(OuterProduct node) {
not_implemented("OuterProduct");
}

@Override
public void visit(BaseVector node) {
not_implemented("BaseVector");
}

@Override
public void visit(Negation node) {
code.append("(-");
node.getOperand().accept(this);
code.append(")");
}

@Override
public void visit(Reverse node) {
not_implemented("Reverse");
}

@Override
public void visit(LogicalOr node) {
not_implemented("LogicalOr");
}

@Override
public void visit(LogicalAnd node) {
not_implemented("LogicalAnd");
}

@Override
public void visit(LogicalNegation node) {
not_implemented("LogicalNegation");
}

@Override
public void visit(Equality node) {
not_implemented("Equality");
}

@Override
public void visit(Inequality node) {
not_implemented("Inequality");
}

@Override
public void visit(Relation relation) {
not_implemented("Relation");
}

@Override
public void visit(FunctionArgument node) {
macro_error();
}

@Override
public void visit(MacroCall node) {
macro_error();
}

public String getCode() {
return code.toString();
}
}
Loading

0 comments on commit 6345699

Please sign in to comment.