/* * Copyright 2012 Phil Pratt-Szeliga and other contributors * http://chirrup.org/ * * See the file LICENSE for copying permission. */ package org.trifort.rootbeer.generate.opencl; import java.util.ArrayList; import java.util.List; import org.trifort.rootbeer.configuration.Configuration; import org.trifort.rootbeer.generate.bytecode.Constants; import org.trifort.rootbeer.generate.opencl.body.MethodJimpleValueSwitch; import org.trifort.rootbeer.generate.opencl.tweaks.Tweaks; import soot.*; import soot.jimple.ArrayRef; import soot.jimple.NewArrayExpr; import soot.jimple.NewMultiArrayExpr; import soot.rbclassload.RootbeerClassLoader; public class OpenCLArrayType { private ArrayType m_arrayType; public OpenCLArrayType(ArrayType type){ m_arrayType = (ArrayType) type; } public ArrayType getArrayType(){ return m_arrayType; } public String getArrayRefGetter(ArrayRef arg0){ Value index = arg0.getIndex(); Value base = arg0.getBase(); if(base instanceof Local == false) throw new UnsupportedOperationException("what do I do if base is not a local?"); Local local = (Local) base; return getDerefTypeString()+"_get("+local.getName()+", "+index.toString()+", exception)"; } public String getArrayRefSetter(ArrayRef arg0){ Value index = arg0.getIndex(); Value base = arg0.getBase(); if(base instanceof Local == false) throw new UnsupportedOperationException("what do I do if base is not a local?"); Local local = (Local) base; return getDerefTypeString()+"_set("+local.getName()+", "+index.toString()+", "; } public String getDerefTypeString(){ OpenCLType type = new OpenCLType(m_arrayType); String ret = type.getDerefString(); return ret; } private String getMultiDeref(int dimensions){ Type base_type = m_arrayType.baseType; ArrayType array_type = ArrayType.v(base_type, dimensions); OpenCLType type = new OpenCLType(array_type); String ret = type.getDerefString(); return ret; } private List<String> getDecls(){ List<String> ret = new ArrayList<String>(); String function_qual = Tweaks.v().getDeviceFunctionQualifier(); ret.add(function_qual+" "+getAssignType()+" "+getDerefTypeString()+"_get(int thisref, int parameter0, int * exception)"); ret.add(function_qual+" void "+getDerefTypeString()+"_set(int thisref, int parameter0, "+getAssignType()+" parameter1, int * exception)"); ret.add(function_qual+" int "+getDerefTypeString()+"_new(int size, int * exception)"); String multi_dim_decl = ""; multi_dim_decl += function_qual+" int "+getDerefTypeString()+"_new_multi_array"; multi_dim_decl += "("; for(int i = 0; i < m_arrayType.numDimensions; ++i){ multi_dim_decl += "int dim"+i+", "; } multi_dim_decl += "int * exception)"; ret.add(multi_dim_decl); return ret; } public String getPrototypes(){ StringBuilder ret = new StringBuilder(); List<String> decls = getDecls(); for(String decl : decls) ret.append(decl+";\n"); return ret.toString(); } public String invokeNewArrayExpr(NewArrayExpr arg0){ StringBuilder ret = new StringBuilder(); ret.append(getDerefTypeString()+"_new("); MethodJimpleValueSwitch quick_value_switch = new MethodJimpleValueSwitch(ret); arg0.getSize().apply(quick_value_switch); ret.append(", "); ret.append("exception)"); return ret.toString(); } public String invokeNewMultiArrayExpr(NewMultiArrayExpr arg0){ StringBuilder ret = new StringBuilder(); ret.append(getDerefTypeString()+"_new_multi_array("); MethodJimpleValueSwitch quick_value_switch = new MethodJimpleValueSwitch(ret); for(int i = 0; i < arg0.getSizeCount(); ++i){ arg0.getSize(i).apply(quick_value_switch); ret.append(", "); } ret.append("exception)"); return ret.toString(); } private String getAssignType(){ ArrayType array_type = m_arrayType; if(array_type.numDimensions != 1) return "int"; OpenCLType type = new OpenCLType(array_type.baseType); return type.getCudaTypeString(); } private String initValue(){ String ret = ""; if(isBaseRefType()) ret = "-1"; else ret = "0"; return ret; } public String getBodies(){ StringBuilder ret = new StringBuilder(); List<String> decls = getDecls(); int element_size = getElementSize(); int offset_size = Constants.ArrayOffsetSize; String address_qual = Tweaks.v().getGlobalAddressSpaceQualifier(); SootClass null_ptr = Scene.v().getSootClass("java.lang.NullPointerException"); //get ret.append(decls.get(0)+"{\n"); ret.append("int offset;\n"); ret.append("int length;\n"); ret.append(address_qual+" char * thisref_deref;\n"); ret.append("offset = "+offset_size+"+(parameter0*"+element_size+");\n"); if(Configuration.compilerInstance().getExceptions()){ ret.append("if(thisref == -1){\n"); ret.append(" *exception = "+RootbeerClassLoader.v().getClassNumber(null_ptr) +";\n"); ret.append(" return 0;\n"); ret.append("}\n"); } ret.append("thisref_deref = org_trifort_gc_deref(thisref);\n"); if(Configuration.compilerInstance().getArrayChecks() && Configuration.compilerInstance().getExceptions()){ ret.append("length = org_trifort_getint(thisref_deref, 12);\n"); ret.append("if(parameter0 < 0 || parameter0 >= length){\n"); ret.append(" *exception = org_trifort_rootbeer_runtimegpu_GpuException_arrayOutOfBounds(parameter0, thisref, length, exception);"); ret.append(" return 0;\n"); ret.append("}\n"); } ret.append("return *(("+address_qual+" "+getAssignType()+" *) &thisref_deref[offset]);\n"); ret.append("}\n"); //set ret.append(decls.get(1)+"{\n"); ret.append("int length;\n"); ret.append(address_qual+" char * thisref_deref;\n"); if(Configuration.compilerInstance().getExceptions()){ ret.append(" if(thisref == -1){\n"); ret.append(" *exception = "+RootbeerClassLoader.v().getClassNumber(null_ptr) +";\n"); ret.append(" return;\n"); ret.append(" }\n"); } ret.append("thisref_deref = org_trifort_gc_deref(thisref);\n"); if(Configuration.compilerInstance().getArrayChecks() && Configuration.compilerInstance().getExceptions()){ ret.append("length = org_trifort_getint(thisref_deref, 12);\n"); ret.append("if(parameter0 < 0 || parameter0 >= length){\n"); ret.append(" *exception = org_trifort_rootbeer_runtimegpu_GpuException_arrayOutOfBounds(parameter0, thisref, length, exception);"); ret.append(" return;\n"); ret.append("}\n"); } if(isCharArray()){ ret.append("*(("+address_qual+" int *) &thisref_deref["+offset_size+"+(parameter0*"+element_size+")]) = 0;\n"); } ret.append("*(("+address_qual+" "+getAssignType()+" *) &thisref_deref["+offset_size+"+(parameter0*"+element_size+")]) = parameter1;\n"); ret.append("}\n"); //new int derived_type = RootbeerClassLoader.v().getClassNumber(m_arrayType.toString()); ret.append(decls.get(2)+"{\n"); ret.append("int i;\n"); ret.append("int total_size;\n"); ret.append("int mod;\n"); ret.append("int thisref;\n"); ret.append(address_qual+" char * thisref_deref;\n"); ret.append("total_size = (size * "+element_size+")+ "+offset_size+";\n"); ret.append("mod = total_size % "+Constants.MallocAlignBytes+";\n"); ret.append("if(mod != 0)\n"); ret.append(" total_size += ("+Constants.MallocAlignBytes+" - mod);\n"); ret.append("thisref = org_trifort_gc_malloc(total_size);\n"); if(Configuration.compilerInstance().getExceptions()){ ret.append("if(thisref == -1){\n"); ret.append(" *exception = "+RootbeerClassLoader.v().getClassNumber(null_ptr) +";\n"); ret.append(" return -1;\n"); ret.append("}\n"); } ret.append("thisref_deref = org_trifort_gc_deref(thisref);\n"); ret.append("\n//class info\n"); ret.append("org_trifort_gc_set_count(thisref_deref, 0);\n"); ret.append("org_trifort_gc_set_color(thisref_deref, COLOR_GREY);\n"); ret.append("org_trifort_gc_set_type(thisref_deref, "+Integer.toString(derived_type)+");\n"); ret.append("org_trifort_gc_set_ctor_used(thisref_deref, 1);\n"); ret.append("org_trifort_gc_set_size(thisref_deref, total_size);\n"); ret.append("org_trifort_setint(thisref_deref, 12, size);\n"); ret.append("for(i = 0; i < size; ++i){\n"); ret.append(" "+getDerefTypeString()+"_set(thisref, i, "+initValue()+", exception);\n"); ret.append("}\n"); ret.append("return thisref;\n"); ret.append("}\n"); String multi_decl = decls.get(3); int dim = m_arrayType.numDimensions; //new multi-dimensional ret.append(multi_decl+"{\n"); ret.append("int total_size = (dim0 * 8) + "+offset_size+";\n"); for(int i = 0; i < dim; ++i){ ret.append("int index"+i+";\n"); ret.append("int aref"+i+";\n"); } ret.append("int mod;\n"); ret.append("int thisref;\n"); ret.append(address_qual+" char * thisref_deref;\n"); ret.append("mod = total_size % "+Constants.MallocAlignBytes+";\n"); ret.append("if(mod != 0)\n"); ret.append(" total_size += ("+Constants.MallocAlignBytes+" - mod);\n"); ret.append("thisref = org_trifort_gc_malloc(total_size);\n"); if(Configuration.compilerInstance().getExceptions()){ ret.append("if(thisref == -1){\n"); ret.append(" *exception = "+RootbeerClassLoader.v().getClassNumber(null_ptr) +";\n"); ret.append(" return -1;\n"); ret.append("}\n"); } ret.append("thisref_deref = org_trifort_gc_deref(thisref);\n"); ret.append("\n//class info\n"); ret.append("org_trifort_gc_set_count(thisref_deref, 0);\n"); ret.append("org_trifort_gc_set_color(thisref_deref, COLOR_GREY);\n"); ret.append("org_trifort_gc_set_type(thisref_deref, "+Integer.toString(derived_type)+");\n"); ret.append("org_trifort_gc_set_ctor_used(thisref_deref, 1);\n"); ret.append("org_trifort_gc_set_size(thisref_deref, total_size);\n"); ret.append("org_trifort_setint(thisref_deref, 12, dim0);\n"); ret.append(multiInitString(dim)); ret.append("return thisref;\n"); ret.append("}\n"); return ret.toString(); } private String multiInitString(int dim){ String ret = ""; for(int i = 0; i < dim; ++i){ ret += "for(index"+i+" = 0; index"+i+" < dim"+i+"; ++index"+i+"){\n"; String thisref = "thisref"; if(i > 0){ thisref = "aref"+(i-1); } String set_str = getMultiDeref(dim-i)+"_set("+thisref; if(i < dim - 1){ String new_str = getMultiDeref(dim-1-i)+"_new(dim"+(i+1)+", exception)"; ret += " aref"+i+" = "+new_str+";\n"; ret += " "+set_str+", index"+i+", aref"+i+", exception);\n"; } else { ret += " "+set_str+", index"+i+", "+initValue()+", exception);\n"; } } for(int i = 0; i < dim; ++i){ ret += "}\n"; } return ret; } private boolean isBaseRefType(){ Type base_type = getBaseType(); if(base_type instanceof RefType) return true; else return false; } private Type getBaseType(){ Type base_type = null; ArrayType array_type = (ArrayType) m_arrayType; base_type = array_type.baseType; return base_type; } @Override public boolean equals(Object o){ if(o instanceof OpenCLArrayType == false) return false; OpenCLArrayType other = (OpenCLArrayType) o; if(this.m_arrayType.equals(other.m_arrayType)) return true; return false; } @Override public int hashCode() { int hash = 5; hash = 79 * hash + (this.m_arrayType != null ? this.m_arrayType.hashCode() : 0); return hash; } public int getElementSize() { if(m_arrayType.numDimensions != 1) return 4; Type base_type = m_arrayType.baseType; OpenCLType ocl_type = new OpenCLType(base_type); return ocl_type.getSize(); } int getTypeInteger() { return RootbeerClassLoader.v().getClassNumber(m_arrayType.toString()); } private boolean isCharArray() { Type base_type = getBaseType(); String str = base_type.toString(); if(str.equals("char")) return true; return false; } }