/*
* Copyright 2012 Phil Pratt-Szeliga and other contributors
* http://chirrup.org/
*
* See the file LICENSE for copying permission.
*/
package org.trifort.rootbeer.generate.opencl.body;
import org.trifort.rootbeer.generate.opencl.*;
import org.trifort.rootbeer.generate.opencl.fields.OpenCLField;
import soot.rbclassload.ClassConstantReader;
import soot.*;
import soot.jimple.AddExpr;
import soot.jimple.AndExpr;
import soot.jimple.ArrayRef;
import soot.jimple.BinopExpr;
import soot.jimple.CastExpr;
import soot.jimple.CaughtExceptionRef;
import soot.jimple.ClassConstant;
import soot.jimple.CmpExpr;
import soot.jimple.CmpgExpr;
import soot.jimple.CmplExpr;
import soot.jimple.DivExpr;
import soot.jimple.DoubleConstant;
import soot.jimple.DynamicInvokeExpr;
import soot.jimple.EqExpr;
import soot.jimple.FloatConstant;
import soot.jimple.GeExpr;
import soot.jimple.GtExpr;
import soot.jimple.InstanceFieldRef;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InstanceOfExpr;
import soot.jimple.IntConstant;
import soot.jimple.InterfaceInvokeExpr;
import soot.jimple.JimpleValueSwitch;
import soot.jimple.LeExpr;
import soot.jimple.LengthExpr;
import soot.jimple.LongConstant;
import soot.jimple.LtExpr;
import soot.jimple.MulExpr;
import soot.jimple.NeExpr;
import soot.jimple.NegExpr;
import soot.jimple.NewArrayExpr;
import soot.jimple.NewExpr;
import soot.jimple.NewMultiArrayExpr;
import soot.jimple.NullConstant;
import soot.jimple.OrExpr;
import soot.jimple.ParameterRef;
import soot.jimple.RemExpr;
import soot.jimple.ShlExpr;
import soot.jimple.ShrExpr;
import soot.jimple.SpecialInvokeExpr;
import soot.jimple.StaticFieldRef;
import soot.jimple.StaticInvokeExpr;
import soot.jimple.StringConstant;
import soot.jimple.SubExpr;
import soot.jimple.ThisRef;
import soot.jimple.UshrExpr;
import soot.jimple.VirtualInvokeExpr;
import soot.jimple.XorExpr;
import soot.rbclassload.RootbeerClassLoader;
public class MethodJimpleValueSwitch implements JimpleValueSwitch {
protected final StringBuilder m_output;
private boolean m_lhs;
private boolean m_rhs;
private boolean m_newCalled;
private boolean m_caughtExceptionRef;
private String m_thisRef;
private String m_previousLocal;
private boolean m_checkException;
private ClassConstantReader m_classConstantReader;
public MethodJimpleValueSwitch(StringBuilder output) {
m_output = output;
m_newCalled = false;
m_classConstantReader = new ClassConstantReader();
clearLhsRhs();
}
public boolean newHasBeenCalled(){
return m_newCalled;
}
public void resetNewCalled(){
m_newCalled = false;
}
void setLhs(){
m_lhs = true;
m_rhs = false;
}
void setRhs(){
m_rhs = true;
m_lhs = false;
}
void clearLhsRhs(){
m_lhs = false;
m_rhs = false;
}
boolean isLhs(){
if(m_lhs == false && m_rhs == false)
throw new IllegalStateException("Lhs/Rhs in invalid state");
return m_lhs;
}
private void writeBinOpExpr(BinopExpr arg0){
String symbol = arg0.getSymbol().trim();
if(needDoubleMod(arg0, symbol)){
m_output.append("org_trifort_modulus(");
arg0.getOp1().apply(this);
m_output.append(", ");
arg0.getOp2().apply(this);
m_output.append(")");
} else if(symbol.equals("cmp")){
m_output.append("org_trifort_cmp(");
arg0.getOp1().apply(this);
m_output.append(", ");
arg0.getOp2().apply(this);
m_output.append(")");
} else if(symbol.equals("cmpl")){
m_output.append("org_trifort_cmpl((double)");
arg0.getOp1().apply(this);
m_output.append(", (double)");
arg0.getOp2().apply(this);
m_output.append(")");
} else if(symbol.equals("cmpg")){
m_output.append("org_trifort_cmpg((double)");
arg0.getOp1().apply(this);
m_output.append(", (double)");
arg0.getOp2().apply(this);
m_output.append(")");
} else {
arg0.getOp1().apply(this);
m_output.append(" "+symbol+" ");
arg0.getOp2().apply(this);
m_output.append(" ");
}
}
private boolean needDoubleMod(BinopExpr arg0, String symbol) {
if(symbol.equals("%") == false)
return false;
if(!arg0.getOp1().getType().equals(DoubleType.v()) && !arg0.getOp1().getType().equals(FloatType.v()))
return false;
if(!arg0.getOp2().getType().equals(DoubleType.v()) && !arg0.getOp2().getType().equals(FloatType.v()))
return false;
return true;
}
public void caseAddExpr(AddExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseAndExpr(AndExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseCmpExpr(CmpExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseCmpgExpr(CmpgExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseCmplExpr(CmplExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseDivExpr(DivExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseEqExpr(EqExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseNeExpr(NeExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseGeExpr(GeExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseGtExpr(GtExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseLeExpr(LeExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseLtExpr(LtExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseMulExpr(MulExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseOrExpr(OrExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseRemExpr(RemExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseShlExpr(ShlExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseShrExpr(ShrExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseUshrExpr(UshrExpr arg0) {
m_output.append("(");
arg0.getOp1().apply(this);
m_output.append(" >> ");
arg0.getOp2().apply(this);
m_output.append(" ) & ");
OpenCLType lhs_ocl_type = new OpenCLType(arg0.getOp1().getType());
OpenCLType rhs_ocl_type = new OpenCLType(arg0.getOp2().getType());
int max_size = lhs_ocl_type.getSize();
if(rhs_ocl_type.getSize() > max_size){
max_size = rhs_ocl_type.getSize();
}
String mask = "";
switch(max_size){
case 1:
mask = "0x7f";
break;
case 2:
mask = "0x7fff";
break;
case 4:
mask = "0x7fffffff";
break;
case 8:
mask = "0x7fffffffffffffffL";
break;
}
m_output.append(mask);
}
public void caseSubExpr(SubExpr arg0) {
writeBinOpExpr(arg0);
}
public void caseXorExpr(XorExpr arg0) {
writeBinOpExpr(arg0);
}
private void caseInstanceInvokeExpr(InstanceInvokeExpr arg0){
SootMethod soot_method = arg0.getMethod();
SootClass soot_class = soot_method.getDeclaringClass();
OpenCLMethod ocl_method = new OpenCLMethod(soot_method, soot_class);
m_output.append(ocl_method.getInstanceInvokeString(arg0));
setCheckException();
}
public void caseInterfaceInvokeExpr(InterfaceInvokeExpr arg0) {
caseInstanceInvokeExpr(arg0);
setCheckException();
}
public void caseSpecialInvokeExpr(SpecialInvokeExpr arg0) {
SootMethod soot_method = arg0.getMethod();
SootClass soot_class = soot_method.getDeclaringClass();
OpenCLMethod ocl_method = new OpenCLMethod(soot_method, soot_class);
m_output.append(ocl_method.getInstanceInvokeString(arg0));
setCheckException();
}
public void caseStaticInvokeExpr(StaticInvokeExpr arg0) {
SootMethod soot_method = arg0.getMethod();
SootClass soot_class = soot_method.getDeclaringClass();
OpenCLMethod ocl_method = new OpenCLMethod(soot_method, soot_class);
m_output.append(ocl_method.getStaticInvokeString(arg0));
setCheckException();
}
public void caseVirtualInvokeExpr(VirtualInvokeExpr arg0) {
caseInstanceInvokeExpr(arg0);
}
public void caseCastExpr(CastExpr arg0) {
Type cast_type = arg0.getCastType();
OpenCLType ocl_type = new OpenCLType(cast_type);
m_output.append("("+ocl_type.getCudaTypeString()+") ");
Value rhs = arg0.getOp();
rhs.apply(this);
}
public void caseInstanceOfExpr(InstanceOfExpr arg0) {
OpenCLScene.v().addInstanceof(arg0.getCheckType());
OpenCLInstanceof instance_of = new OpenCLInstanceof(arg0.getCheckType());
m_output.append(instance_of.invokeExpr(arg0));
}
public void caseNewArrayExpr(NewArrayExpr arg0) {
OpenCLScene.v().setUsingGarbageCollector();
OpenCLArrayType array_type = new OpenCLArrayType((ArrayType) arg0.getType());
m_output.append(array_type.invokeNewArrayExpr(arg0));
m_newCalled = true;
}
public void caseNewMultiArrayExpr(NewMultiArrayExpr arg0) {
OpenCLScene.v().setUsingGarbageCollector();
OpenCLArrayType array_type = new OpenCLArrayType((ArrayType) arg0.getType());
m_output.append(array_type.invokeNewMultiArrayExpr(arg0));
m_newCalled = true;
}
public void caseNewExpr(NewExpr arg0) {
OpenCLScene.v().setUsingGarbageCollector();
m_output.append(" -1 ");
}
public void caseLengthExpr(LengthExpr arg0) {
Value op = arg0.getOp();
m_output.append("org_trifort_array_length(");
op.apply(this);
m_output.append(", exception)");
setCheckException();
}
public void caseNegExpr(NegExpr arg0) {
Value op = arg0.getOp();
m_output.append("-");
op.apply(this);
}
public void defaultCase(Object arg0) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void caseLocal(Local arg0) {
m_output.append(" "+arg0.getName()+" ");
m_previousLocal = arg0.getName();
}
public void caseDoubleConstant(DoubleConstant arg0) {
m_output.append(" "+replaceNumber(arg0.toString())+" ");
}
public void caseFloatConstant(FloatConstant arg0) {
m_output.append(" "+replaceNumber(arg0.toString())+" ");
}
public void caseIntConstant(IntConstant arg0) {
m_output.append(" "+replaceNumber(arg0.toString())+" ");
}
public void caseLongConstant(LongConstant arg0) {
m_output.append(" "+replaceNumber(arg0.toString())+" ");
}
public void caseNullConstant(NullConstant arg0) {
m_output.append(" -1 ");
}
private String replaceNumber(String number){
if(number.equals("#Infinity"))
return "INFINITY";
if(number.equals("#-Infinity"))
return "-INFINITY";
if(number.equals("#NaN"))
return "NAN";
return number;
}
public void caseStringConstant(StringConstant arg0) {
m_output.append(" org_trifort_string_constant((char *) "+arg0.toString()+", exception) ");
}
public void caseClassConstant(ClassConstant arg0) {
String value = arg0.getValue();
Type type = m_classConstantReader.stringToType(value);
int num = OpenCLScene.v().getClassConstantNumbers().get(type);
m_output.append("org_trifort_classConstant("+num+")");
}
public void caseArrayRef(ArrayRef arg0) {
OpenCLArrayType array = new OpenCLArrayType((ArrayType) arg0.getBase().getType());
if(isLhs()){
m_output.append(array.getArrayRefSetter(arg0));
setCheckException();
} else {
m_output.append(array.getArrayRefGetter(arg0));
setCheckException();
}
}
public void caseStaticFieldRef(StaticFieldRef arg0) {
SootField field = arg0.getField();
OpenCLField ocl_field = new OpenCLField(arg0.getField(), field.getDeclaringClass());
if(isLhs()){
m_output.append(ocl_field.getStaticSetterInvoke());
} else {
m_output.append(ocl_field.getStaticGetterInvoke());
}
}
public void caseInstanceFieldRef(InstanceFieldRef arg0) {
Value base = arg0.getBase();
if(base instanceof Local == false)
throw new UnsupportedOperationException("How do I handle base is not a local?");
Local local = (Local) base;
Type type = local.getType();
if(type instanceof RefType == false)
throw new UnsupportedOperationException("How do I handle type is not a ref type?");
RefType ref = (RefType) type;
OpenCLField ocl_field = new OpenCLField(arg0.getField(), ref.getSootClass());
if(isLhs()){
m_output.append(ocl_field.getInstanceSetterInvoke(arg0.getBase()));
} else {
m_output.append(ocl_field.getInstanceGetterInvoke(arg0.getBase()));
}
setCheckException();
}
public void caseParameterRef(ParameterRef arg0) {
m_output.append(" parameter"+Integer.toString(arg0.getIndex())+" ");
}
public void caseCaughtExceptionRef(CaughtExceptionRef arg0) {
m_output.append(" *exception ");
m_caughtExceptionRef = true;
}
public void caseThisRef(ThisRef arg0) {
m_output.append(" thisref ");
m_thisRef = m_previousLocal;
}
public void caseDynamicInvokeExpr(DynamicInvokeExpr die) {
throw new UnsupportedOperationException("Not supported yet.");
}
void reset() {
m_caughtExceptionRef = false;
m_checkException = false;
}
boolean hasCaughtExceptionRef() {
return m_caughtExceptionRef;
}
public String getThisRef() {
return m_thisRef;
}
private void setCheckException() {
m_checkException = true;
}
public boolean getCheckException(){
return m_checkException;
}
}