/*
* Copyright (c) 2010-2011, IRISA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IRISA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.backends.c.hmpp.transformations;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.sf.orcc.df.Actor;
import net.sf.orcc.df.util.DfVisitor;
import net.sf.orcc.ir.Def;
import net.sf.orcc.ir.InstCall;
import net.sf.orcc.ir.Param;
import net.sf.orcc.ir.Procedure;
import net.sf.orcc.ir.Use;
import net.sf.orcc.ir.Var;
import net.sf.orcc.ir.util.AbstractIrVisitor;
import net.sf.orcc.util.Attribute;
import net.sf.orcc.util.util.EcoreHelper;
/**
* This class adds annotations to some IR elements. These annotations are used
* later to produce valid HMPP pragmas.
*
* @author Jérôme Gorin
* @author Antoine Lorence
*
*/
public class SetHMPPAnnotations extends DfVisitor<Void> {
Map<Procedure, String> codelets;
private class InnerSetHMPPAnnotations extends AbstractIrVisitor<Void> {
/**
* This the entry point for this transformation. It visits InstCall
* instances and check for ones having a "codelet" attribute. For these
* ones, it run methods to add HMPP attributes to all IR elements which
* needs.
*/
@Override
public Void caseInstCall(InstCall call) {
Procedure proc = call.getProcedure();
// Procedure referenced by this call instruction must be run on the
// graphic card using HMPP compiler
if (proc.hasAttribute("codelet")) {
// This will set attributes for pragmas codelet, group (only
// once per procedure)
if (!codelets.containsKey(proc)) {
setCodeletAttribute(proc);
}
// This will set attributes for pragmas callsite, resident,
// advancedload, delegatedstore
setCallsiteAttribute(call, getGroupLabel(),
getCodeletLabel(proc));
}
return null;
}
/**
* Set <b>codelet</b> attribute to given <i>proc</i> and updates its
* sub-attributes.
*
* @param proc
*/
private void setCodeletAttribute(Procedure proc) {
Attribute codeletAttr = proc.getAttribute("codelet");
setGroupAttribute(getGroupLabel(), codeletAttr.getAttributes());
Attribute grp = addGroupLabel(codeletAttr, getGroupLabel());
Attribute cdlt = addCodeletLabel(grp, getCodeletLabel(proc));
Map<String, String> cdltParams = new HashMap<String, String>();
// Check if procedure parameter is not a scalar
for (Param param : proc.getParameters()) {
Var var = param.getVariable();
if (var.getType().isList()) {
String direction = isVarUsed(var, proc) ? "in" : "";
direction += isVarDefined(var, proc) ? "out" : "";
cdltParams.put(var.getName(), direction);
}
}
cdlt.setObjectValue(cdltParams);
}
/**
* Add to given <i>call</i> a <b>callsite</b> attribute and add it a
* group label as child, a codelet label as sub-child. Call necessary
* methods to add other attributes to the call and the variables used
* inside the procedure called.
*
* @param call
* @param grpLabel
* @param cdltLabel
*/
private void setCallsiteAttribute(InstCall call, String grpLabel,
String cdltLabel) {
Attribute callsite = call.getAttribute("callsite");
if (callsite == null) {
call.addAttribute("callsite");
callsite = call.getAttribute("callsite");
}
Attribute grp = addGroupLabel(callsite, grpLabel);
addCodeletLabel(grp, cdltLabel);
// Check for state variables used or defined inside the procedure
Procedure proc = call.getProcedure();
Set<String> inVars = new HashSet<String>();
Set<String> outVars = new HashSet<String>();
for (Var var : actor.getStateVars()) {
if (var.isAssignable()) {
String direction = "";
if (isVarUsed(var, proc)) {
inVars.add(var.getName());
direction += "in";
}
if (isVarDefined(var, proc)) {
outVars.add(var.getName());
direction += "out";
}
if (!direction.isEmpty()) {
setResidentAttribute(var, grpLabel, direction);
}
}
}
setAdvanceloadAttribute(call, cdltLabel, grpLabel, inVars);
setDelegatedstoreAttribute(call, cdltLabel, grpLabel, outVars);
}
/**
* Add to given <i>call</i> a <b>advancedload</b> attribute and add it a
* group label as child, a codelet label as sub-child. Given <i>vars</i>
* are added to codelet label's objectValue to determine variables to
* load after the call.
*
* @param call
* @param cdltLabel
* @param grpLabel
* @param vars
*/
private void setAdvanceloadAttribute(InstCall call, String cdltLabel,
String grpLabel, Set<String> vars) {
Procedure parentProc = EcoreHelper.getContainerOfType(call,
Procedure.class);
Attribute delStore = parentProc.getAttribute("advancedload");
if (delStore == null) {
parentProc.addAttribute("advancedload");
delStore = parentProc.getAttribute("advancedload");
}
Attribute grp = addGroupLabel(delStore, getGroupLabel());
Attribute cdlt = addCodeletLabel(grp,
getCodeletLabel(call.getProcedure()));
cdlt.setObjectValue(vars);
}
/**
* Add to given <i>call</i> a <b>delegatedstore</b> attribute and add it
* a group label as child, a codelet label as sub-child. Given
* <i>vars</i> are added to codelet label's objectValue to determine
* variables to store before the call.
*
* @param call
* @param cdltLabel
* @param grpLabel
* @param vars
*/
private void setDelegatedstoreAttribute(InstCall call,
String cdltLabel, String grpLabel, Set<String> vars) {
Procedure parentProc = EcoreHelper.getContainerOfType(call,
Procedure.class);
Attribute delStore = parentProc.getAttribute("delegatedstore");
if (delStore == null) {
parentProc.addAttribute("delegatedstore");
delStore = parentProc.getAttribute("delegatedstore");
}
Attribute grp = addGroupLabel(delStore, getGroupLabel());
Attribute cdlt = addCodeletLabel(grp,
getCodeletLabel(call.getProcedure()));
cdlt.setObjectValue(vars);
}
/**
* Add to current <i>actor</i> a <b>group</b> attribute and add it a
* group label as child. Given <i>parameters</i> are added to group
* label attribute's children.
*
* @param grpLabel
* @param params
*/
private void setGroupAttribute(String grpLabel,
Collection<Attribute> params) {
Attribute grpPragma = actor.getAttribute("group");
if (grpPragma == null) {
actor.addAttribute("group");
grpPragma = actor.getAttribute("group");
}
Attribute grp = addGroupLabel(grpPragma, grpLabel);
grp.getAttributes().addAll(params);
}
/**
* Add to given <i>variable</i> a <b>resident</b> attribute and add it a
* group label as child. Parameters are added to group label attribute's
* children. The direction (in/out/inout) is currently the only
* parameter supported. Value is given by <i>direction</i> parameter.
*
* @param var
* @param grpLabel
* @param direction
*/
private void setResidentAttribute(Var var, String grpLabel,
String direction) {
Attribute resident = var.getAttribute("resident");
if (resident == null) {
var.addAttribute("resident");
resident = var.getAttribute("resident");
}
Attribute grp = addGroupLabel(resident, grpLabel);
grp.setAttribute("direction", direction);
}
/**
* Add a group label to a given attribute
*
* @param attribute
* @param grpLabel
* The group label
* @return The Attribute just created
*/
private Attribute addGroupLabel(Attribute attribute, String grpLabel) {
attribute.addAttribute(grpLabel);
return attribute.getAttribute(grpLabel);
}
/**
* Add a codelet label to a given attribute
*
* @param attribute
* @param cdltLabel
* The codelet label
* @return The Attribute just created
*/
private Attribute addCodeletLabel(Attribute attribute, String cdltLabel) {
attribute.addAttribute(cdltLabel);
return attribute.getAttribute(cdltLabel);
}
/**
* Generate and returns a group label. This method is now used to ensure
* the same name will be used everywhere. It should be modified when
* HMPP backend will support having multiple groups defined in a file.
*
* @return A default group label
*/
private String getGroupLabel() {
return "<grp_default>";
}
/**
* Return the codelet label for this procedure. This method will NOT
* update procedure to add missing attributes.
*
* @param proc
* @return
*/
private String getCodeletLabel(Procedure proc) {
if (codelets.containsKey(proc)) {
return codelets.get(proc);
} else if (proc.hasAttribute("codelet")
&& proc.getAttribute("codelet").hasAttribute(
"codelet_label")) {
String name = proc.getAttribute("codelet").getValueAsString(
"codelet_label");
codelets.put(proc, name);
return name;
} else {
String name = "cdlt_" + proc.getName();
codelets.put(proc, name);
return name;
}
}
/**
* Return true if the given variable is used in the given procedure.
* (i.e. the given procedure contains uses on the variable)
*
* @param var
* @param proc
* @return
*/
private boolean isVarUsed(Var var, Procedure proc) {
for (Use use : var.getUses()) {
if (EcoreHelper.getContainerOfType(use, Procedure.class)
.equals(proc)) {
return true;
}
}
return false;
}
/**
* Return true if the given variable is defined in the given procedure.
* (i.e. the given procedure contains defs on the variable)
*
* @param var
* @param proc
* @return
*/
private boolean isVarDefined(Var var, Procedure proc) {
for (Def def : var.getDefs()) {
if (EcoreHelper.getContainerOfType(def, Procedure.class)
.equals(proc)) {
return true;
}
}
return false;
}
}
public SetHMPPAnnotations() {
super();
codelets = new HashMap<Procedure, String>();
irVisitor = new InnerSetHMPPAnnotations();
}
@Override
public Void caseActor(Actor actor) {
codelets.clear();
this.actor = actor;
super.caseActor(actor);
return null;
}
}