blob: 7aeed1a9c7207f5e668517e321485fa88bf930e6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.photran.internal.core.analysis.dependence;
import java.util.ArrayList;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.photran.internal.core.analysis.loops.GenericASTVisitorWithLoops;
import org.eclipse.photran.internal.core.parser.ASTAssignmentStmtNode;
import org.eclipse.photran.internal.core.parser.ASTVarOrFnRefNode;
import org.eclipse.photran.internal.core.parser.IASTListNode;
import org.eclipse.photran.internal.core.parser.IASTNode;
import org.eclipse.photran.internal.core.parser.IExpr;
import org.eclipse.photran.internal.core.vpg.PhotranVPG;
import org.eclipse.rephraserengine.core.analysis.dependence.DependenceTestFailure;
import org.eclipse.rephraserengine.core.analysis.dependence.IVariableReference;
/**
* Describes a reference to a scalar variable or a reference into an array variable where
* each subscript is a linear function.
* <p>
* This class is intended to describe scalar variable references as well as array references
* such as A(3), A(I), A(3+I), A(2*I+1), A(3, 4), and A(I, J, K) where each subscript is
* a function of the form <i>m*x+b</i> where <i>m</i> and <i>b</i> are integer constants
* and <i>x</i> is a scalar variable.
* <p>
* THIS IS PRELIMINARY AND EXPERIMENTAL. IT IS NOT APPROPRIATE FOR PRODUCTION USE.
*
* @author Jeff Overbey
*/
public /*was package-private*/ class VariableReference implements IVariableReference
{
/**
* Represents a linear function <i>m*x+b</i>, where <i>m</i> and <i>b</i> are integer
* constants and <i>x</i> is a scalar variable.
*
* @author Jeff Overbey
*/
public static class LinearFunction
{
/** The value of <i>m</i>, where this object represents the linear function <i>m*x+b</i> */
public final int slope;
/**
* The (canonicalized) name of the variable <i>x</i>,
* where this object represents the linear function <i>m*x+b</i>
*/
public final String variable;
/** The value of <i>b</i>, where this object represents the linear function <i>m*x+b</i> */
public final int y_intercept;
private LinearFunction(int slope, String variable, int y_intercept)
{
super();
this.slope = slope;
this.variable = variable;
this.y_intercept = y_intercept;
}
/** Factory method */
public static LinearFunction from(String slope, String variable, String y_intercept)
{
try
{
int m = slope == null || slope.equals("") ? 1 : Integer.parseInt(slope); //$NON-NLS-1$
String x = variable == null ? null : PhotranVPG.canonicalizeIdentifier(variable);
int b = y_intercept == null || y_intercept.equals("") ? 0 : Integer.parseInt(y_intercept); //$NON-NLS-1$
return new LinearFunction(
m,
x,
b);
}
catch (NumberFormatException e)
{
return null;
}
}
/** Array factory method */
public static LinearFunction[] fromList(IASTListNode<? extends IASTNode> list)
{
if (list == null) return null;
LinearFunction[] result = new LinearFunction[list.size()];
for (int i = 0; i < list.size(); i++)
{
LinearFunction thisIndex = fromNode(list.get(i));
if (thisIndex == null) return null;
result[i] = thisIndex;
}
return result;
}
/*
* Regex notes:
* \S matches any non-whitespace character
* \d matches [0-9]
* \w matches [A-Za-z_0-9]
* Parentheses define a capturing group (capturing groups are numbered below)
*/
// 12 3 4 5 6
// ===m=== * ==x== + ==b==
private static Pattern mxb = Pattern.compile("((-?(\\d+)[ \t]*\\*[ \t]*)?(\\w+)[ \t]*(\\+|-)[ \t]*)?(\\d+)"); //$NON-NLS-1$
// 12 3
// ===m=== * ==x==
private static Pattern mx = Pattern.compile( "((-?\\d+)[ \t]*\\*[ \t]*)?(\\w+)"); //$NON-NLS-1$
// 1 23 4
// ===b=== + ===m=== * ==x==
private static Pattern bmx = Pattern.compile("(-?\\d+)[ \t]*\\+[ \t]*((-?\\d+)[ \t]*\\*[ \t]*)?(\\w+)"); //$NON-NLS-1$
// 1 2 3 4
// - ==x== + ==b==
private static Pattern nxb = Pattern.compile("-[ \\t]*(\\w+)([ \t]*(\\+|-)[ \t]*(\\d+))?"); //$NON-NLS-1$
// 1 2
// ===b=== + - ==x==
private static Pattern bnx = Pattern.compile("(-?\\d+)[ \t]*\\+[ \t]*-[ \t]*(\\w+)"); //$NON-NLS-1$
/** Factory method */
public static LinearFunction fromNode(IASTNode node)
{
String str = node.toString().trim();
if (str.startsWith(",")) str = str.substring(1); //$NON-NLS-1$
str = str.trim();
Matcher m;
m = mxb.matcher(str);
if (m.matches()) return LinearFunction.from(m.group(3), m.group(4), intString(m.group(5), m.group(6)));
m = mx.matcher(str);
if (m.matches()) return LinearFunction.from(m.group(2), m.group(3), null);
m = bmx.matcher(str);
if (m.matches()) return LinearFunction.from(m.group(3), m.group(4), m.group(1));
m = nxb.matcher(str);
if (m.matches()) return LinearFunction.from("-1", m.group(1), intString(m.group(3), m.group(4))); //$NON-NLS-1$
m = bnx.matcher(str);
if (m.matches()) return LinearFunction.from("-1", m.group(2), m.group(1)); //$NON-NLS-1$
return null;
}
private static String intString(String sign, String value)
{
if (sign == null)
return value;
else if (value == null)
return null;
else
return sign.replace("+", "") + value; //$NON-NLS-1$ //$NON-NLS-2$
}
@Override public String toString()
{
if (variable == null)
return Integer.toString(y_intercept);
else
return slope
+ "*" //$NON-NLS-1$
+ variable
+ (y_intercept >= 0 ? "+" : "-") //$NON-NLS-1$ //$NON-NLS-2$
+ Math.abs(y_intercept);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/** The AST node representing the variable access */
public final IASTNode node;
/** The (canonicalized) name of the variable being referenced */
public final String variable;
/** The indices into that variable, or <code>null</code> if the variable is scalar or the indices are
* not linear functions of the expected form */
public final LinearFunction[] indices;
/** True iff this reference is a write; false if it is a read */
protected final boolean isWrite;
private VariableReference(IASTNode node, String array, LinearFunction[] indices, boolean isWrite)
{
this.node = node;
this.variable = array;
this.indices = indices;
this.isWrite = isWrite;
}
/** Factory method */
public static VariableReference fromLHS(ASTAssignmentStmtNode node)
{
String lhsVar = PhotranVPG.canonicalizeIdentifier(node.getLhsVariable().getName().getText());
LinearFunction[] lhsIndices = null;
if (node.getLhsExprList() != null)
lhsIndices = LinearFunction.fromList(node.getLhsExprList());
else if (node.getLhsNameList() != null)
lhsIndices = LinearFunction.fromList(node.getLhsNameList());
return new VariableReference(node, lhsVar, lhsIndices, true);
}
/** Factory method */
public static Collection<VariableReference> fromRHS(ASTAssignmentStmtNode node)
{
if (node.getRhs() == null)
throw new DependenceTestFailure(
Messages.bind(
Messages.VariableReference_AssignmentStmtCannotBeProcessed,
node.toString().trim()));
return VariableReference.fromExpr(node.getRhs(), false);
}
/** Factory method */
public static Collection<VariableReference> fromExpr(IExpr expr, final boolean isWrite)
{
final ArrayList<VariableReference> result = new ArrayList<VariableReference>();
expr.accept(new GenericASTVisitorWithLoops()
{
@Override
public void visitASTVarOrFnRefNode(ASTVarOrFnRefNode node)
{
if (node.getName() == null
|| node.getFunctionArgList() != null
|| node.getDerivedTypeComponentRef() != null
|| node.getComponentSectionSubscriptList() != null
|| node.getSubstringRange() != null)
{
return;
}
String name = PhotranVPG.canonicalizeIdentifier(node.getName().getName().getText());
LinearFunction[] indices = LinearFunction.fromList(node.getPrimarySectionSubscriptList());
result.add(new VariableReference(node, name, indices, isWrite));
}
});
return result;
}
@Override public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(variable);
if (indices != null)
{
sb.append("("); //$NON-NLS-1$
for (int i = 0; i < indices.length; i++)
sb.append((i > 0 ? ", " : "") + indices[i]); //$NON-NLS-1$ //$NON-NLS-2$
sb.append(")"); //$NON-NLS-1$
}
return sb.toString();
}
@Override public boolean equals(Object o)
{
if (!this.getClass().equals(o.getClass())) return false;
return this.toString().equals(o.toString()); // Cheat -- for testing only
}
@Override public int hashCode()
{
return toString().hashCode();
}
/** @return true iff this variable reference represents a read, rather than a write, of the variable */
public boolean isRead()
{
return !isWrite;
}
/** @return true iff this variable reference represents a write, rather than a read, of the variable */
public boolean isWrite()
{
return isWrite;
}
/** @return true if this variable is a scalar or an array access with the subscripts not of the expected form */
public boolean isScalar()
{
return indices == null;
}
}