/*
* Copyright 2012 Phil Pratt-Szeliga and other contributors
* http://chirrup.org/
*
* See the file LICENSE for copying permission.
*/
package org.trifort.rootbeer.generate.opencl.fields;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.trifort.rootbeer.generate.bytecode.Constants;
import org.trifort.rootbeer.generate.opencl.OpenCLClass;
import org.trifort.rootbeer.generate.opencl.OpenCLScene;
import soot.SootClass;
public class OffsetCalculator {
private Map<SootClass, Map<OpenCLField, Integer>> m_OffsetMap;
private Map<OpenCLField, Integer> m_CurrOffsetSubMap;
private int m_CurrOffset;
public OffsetCalculator(CompositeField composite) {
m_OffsetMap = new HashMap<SootClass, Map<OpenCLField, Integer>>();
//classes are sorted with base at index 0, most derived at index size-1
List<SootClass> classes = composite.getClasses();
for(int i = classes.size()-1; i >= 0; --i){
SootClass curr_key_class = classes.get(i);
m_CurrOffsetSubMap = new HashMap<OpenCLField, Integer>();
m_CurrOffset = Constants.SizeGcInfo;
for(int j = i; j >= 0; --j){
SootClass curr_field_class = classes.get(j);
List<OpenCLField> fields = composite.getRefFieldsByClass(curr_field_class);
fields = trimFields(fields, curr_field_class, true);
calculateForSet(fields);
alignCurrOffset();
}
for(int j = i; j >= 0; --j){
SootClass curr_field_class = classes.get(j);
List<OpenCLField> fields = composite.getNonRefFieldsByClass(curr_field_class);
fields = trimFields(fields, curr_field_class, false);
calculateForSet(fields);
alignCurrOffset();
}
m_OffsetMap.put(curr_key_class, m_CurrOffsetSubMap);
}
}
private void alignCurrOffset(){
//non_ref starts on alignment of 8
int mod = m_CurrOffset % 8;
if(mod != 0)
m_CurrOffset += (8 - mod);
}
private void calculateForSet(List<OpenCLField> sorted){
if(sorted.isEmpty())
return;
OpenCLField first = sorted.get(0);
int prev_size = first.getSize();
for(OpenCLField field : sorted){
if(field.isCloned())
continue;
if(prev_size != field.getSize()){
int mod = m_CurrOffset % prev_size;
if(mod != 0)
m_CurrOffset += (prev_size - mod);
prev_size = field.getSize();
}
m_CurrOffsetSubMap.put(field, m_CurrOffset);
m_CurrOffset += field.getSize();
}
}
public int getOffset(OpenCLField field, SootClass soot_class) {
Map<OpenCLField, Integer> offset_map = m_OffsetMap.get(soot_class);
if(field.isCloned()){
if(offset_map.containsKey(field.getCloneSource())){
return offset_map.get(field.getCloneSource());
} else {
return -1;
}
} else {
if(offset_map.containsKey(field)){
return offset_map.get(field);
} else {
return -1;
}
}
}
public int getSize(SootClass soot_class) {
int ret = Constants.SizeGcInfo;
Map<OpenCLField, Integer> offset_map = m_OffsetMap.get(soot_class);
OpenCLField max_field = null;
int max_offset = Integer.MIN_VALUE;
Iterator<OpenCLField> iter = offset_map.keySet().iterator();
while(iter.hasNext()){
OpenCLField field = iter.next();
int offset = offset_map.get(field);
if(offset > max_offset){
max_offset = offset;
max_field = field;
}
}
if(max_field == null)
return ret;
ret = max_offset;
ret += max_field.getSize();
int mod = ret % 16;
if(mod != 0){
ret += (16 - mod);
}
return ret;
}
private List<OpenCLField> trimFields(List<OpenCLField> org_fields, SootClass curr_field_class, boolean ref_fields) {
OpenCLClass ocl_class = OpenCLScene.v().getOpenCLClass(curr_field_class);
List<OpenCLField> used_fields;
if(ref_fields){
used_fields = ocl_class.getInstanceRefFields();
} else {
used_fields = ocl_class.getInstanceNonRefFields();
}
List<OpenCLField> ret = new ArrayList<OpenCLField>();
for(OpenCLField field : org_fields){
if(listContains(used_fields, field.getName()))
ret.add(field);
}
return ret;
}
private boolean listContains(List<OpenCLField> lst, String name){
for(OpenCLField field : lst){
if(field.getName().equals(name))
return true;
}
return false;
}
}