/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* (C) Copyright IBM Corporation 2010.
*/
package x10.optimizations.inlining;
import polyglot.ast.Allocation_c;
import polyglot.ast.Assign_c;
import polyglot.ast.Call_c;
import polyglot.ast.ConstructorCall;
import polyglot.ast.ConstructorCall_c;
import polyglot.ast.Expr;
import polyglot.ast.Expr_c;
import polyglot.ast.Instanceof_c;
import polyglot.ast.Lit_c;
import polyglot.ast.Local_c;
import polyglot.ast.Loop_c;
import polyglot.ast.NewArray_c;
import polyglot.ast.New_c;
import polyglot.ast.Node;
import polyglot.ast.Node_c;
import polyglot.ast.ProcedureDecl;
import polyglot.ast.Return_c;
import polyglot.ast.Special;
import polyglot.ast.Stmt_c;
import polyglot.ast.Throw_c;
import polyglot.frontend.Job;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.types.Types;
import polyglot.visit.NodeVisitor;
import x10.ast.AssignPropertyCall_c;
import x10.ast.Async_c;
import x10.ast.AtEach_c;
import x10.ast.AtExpr_c;
import x10.ast.AtStmt_c;
import x10.ast.Atomic_c;
import x10.ast.Closure;
import x10.ast.ClosureCall_c;
import x10.ast.Finish_c;
import x10.ast.Next_c;
import x10.ast.StmtExpr_c;
import x10.ast.Tuple_c;
import x10.ast.When_c;
import x10.ast.X10Loop_c;
import x10.visit.ExpressionFlattener;
import x10.visit.X10DelegatingVisitor;
/**
* @author Bowen Alpern
*
*/
class DeclPackage extends NodeVisitor {
static final boolean XTENLANG_2818_METHOD = false; // FIXME: Java back-end does not support non-virtual instance calls
static final boolean XTENLANG_2818_CTOR = false; // FIXME: Java back-end does not support non-virtual constructor calls
static final boolean XTENLANG_2819 = true; // FIXME: C++ back-end generates incorrect code for embedded fields
boolean inlinable;
String reason;
final private Job job;
final private ProcedureDecl decl;
final private InlineUtils utils;
final private CostDelegate delegate;
final protected int cost[] = new int[1];
DeclPackage(String r) {
inlinable = false;
reason = r;
job = null;
decl = null;
utils = null;
delegate = null;
}
DeclPackage(String r, Job j, ProcedureDecl pd) {
inlinable = false;
reason = r;
job = j;
decl = pd;
utils = new InlineUtils(job);
delegate = new CostDelegate(this);
}
DeclPackage(Job j, ProcedureDecl pd) {
inlinable = true;
job = j;
decl = pd;
utils = new InlineUtils(job);
delegate = new CostDelegate(this);
}
public ProcedureDecl getDecl(int budget, boolean inlinableOnly) {
if ((!inlinableOnly || inlinable) && cost[0] <= budget) {
return decl;
}
return null;
}
/**
* @param r
*/
private void cannotInline(String r) {
inlinable = false;
reason = r;
}
/* (non-Javadoc)
* @see polyglot.visit.NodeVisitor#override(polyglot.ast.Node)
*/
@Override
public Node override(Node n) {
if (!inlinable)
return n; // don't visit
return null; // visit
}
/* (non-Javadoc)
* @see polyglot.visit.NodeVisitor#leave(polyglot.ast.Node, polyglot.ast.Node, polyglot.visit.NodeVisitor)
*/
@Override
public Node leave(Node old, Node n, NodeVisitor v) {
if (XTENLANG_2818_METHOD && n instanceof Special && ((Special) n).kind() == Special.SUPER && ExpressionFlattener.javaBackend(job)) {
cannotInline("Java back-end cannot handle inlined super targets");
} else if (XTENLANG_2818_CTOR && n instanceof ConstructorCall && ((ConstructorCall) n).kind() == ConstructorCall.SUPER && ExpressionFlattener.javaBackend(job)) {
cannotInline("Java back-end cannot handle inlined super calls either");
} else if (XTENLANG_2819 && utils.hasEmbedAnnotation(n) && !ExpressionFlattener.javaBackend(job)) {
cannotInline("C++ back-end cannot handle embedded fields");
} else if (utils.isNativeCode(n)) {
cannotInline("Procedure body contains native code");
} else {
delegate.visitAppropriate(n);
}
return n;
}
}
final class CostDelegate extends X10DelegatingVisitor{
static final int CALL_COST = 8;
static final int NEW_COST = CALL_COST/2;
static final int CONSTRUCTOR_COST = CALL_COST/2;
static final int OPERATION_COST = 2;
static final int SMALL_COST = 1;
static final int NO_COST = 0;
final DeclPackage pkg;
CostDelegate(DeclPackage dp) {
pkg = dp;
}
/**
* Property calls are not charged.
*
* @see x10.visit.X10DelegatingVisitor#visit(x10.ast.AssignPropertyCall_c)
*/
public final void visit(AssignPropertyCall_c c) {
pkg.cost[0] += NO_COST;
}
/**
* Closure calls are free, if the target is a closure literal.
*
* @see x10.visit.X10DelegatingVisitor#visit(x10.ast.ClosureCall_c)
*/
@Override
public void visit(ClosureCall_c n) {
if (!(n.target() instanceof Closure))
pkg.cost[0] += CALL_COST;
}
/**
* Constructor calls are charged 8.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.ConstructorCall_c)
*/
public final void visit(ConstructorCall_c c) {
pkg.cost[0] += CONSTRUCTOR_COST;
}
/**
* Method calls are charged CALL_COST
* Intrinsic calls are charged OPERATION_COST
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Call_c)
*/
public final void visit(Call_c c) {
if (c.target() instanceof Expr) { // TODO @intrinsic
Type type = Types.baseType(((Expr) c.target()).type());
TypeSystem ts = type.typeSystem();
if (ts.isLongOrLess(type) || ts.isChar(type) || ts.isBoolean(type)) {
pkg.cost[0] += OPERATION_COST;
return;
}
}
pkg.cost[0] += CALL_COST;
}
/**
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Allocation_c)
*/
public final void visit(Allocation_c e) {
pkg.cost[0] += NEW_COST;
}
/**
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.NewArray_c)
*/
public final void visit(NewArray_c e) {
pkg.cost[0] += NEW_COST;
}
/**
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Tuple_c)
*/
public final void visit(Tuple_c e) {
pkg.cost[0] += NEW_COST;
}
/**
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.New_c)
*/
public final void visit(New_c e) {
pkg.cost[0] += NEW_COST + CONSTRUCTOR_COST;
}
/**
* Literals are not charged.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Lit_c)
*/
public final void visit(Lit_c l) {
pkg.cost[0] += NO_COST;
}
/**
* Locals are not charged.
*/
public final void visit(Local_c l) {
pkg.cost[0] += NO_COST;
}
/**
* Assignments are not charged.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Assign_c)
*/
@Override
public void visit(Assign_c n) {
pkg.cost[0] += NO_COST;
}
/**
* when inlined, a return is just like an assignment; therefore not charged.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Return_c)
*/
@Override
public void visit(Return_c n) {
pkg.cost[0] += NO_COST;
}
/**
* Statement Expressions are not charged.
*
* @see x10.visit.X10DelegatingVisitor#visit(x10.ast.StmtExpr_c)
*/
@Override
public void visit(StmtExpr_c n) {
pkg.cost[0] += NO_COST;
}
/**
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Instanceof_c)
*/
public final void visit(Instanceof_c e) {
pkg.cost[0] += CALL_COST;
}
/**
* Multiple calls.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.AtExpr_c)
*/
public final void visit(AtExpr_c e) {
pkg.cost[0] += 3 * CALL_COST;
}
/**
* Other expressions are charged 2.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Expr_c)
*/
public final void visit(Expr_c e) {
pkg.cost[0] += OPERATION_COST;
}
/**
* Charged as if it was a call.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.AtStmt_c)
*/
public final void visit(AtStmt_c s) {
pkg.cost[0] += CALL_COST;
}
/**
* Charged as if it was a call.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Async_c)
*/
public final void visit(Async_c s) {
pkg.cost[0] += CALL_COST;
}
/**
* Multiple calls.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Atomic_c)
*/
public final void visit(Atomic_c s) {
pkg.cost[0] += 3 * CALL_COST;
}
/**
* Multiple calls.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Finish_c)
*/
public final void visit(Finish_c s) {
pkg.cost[0] += 3 * CALL_COST;
}
/**
* Complex loops will get also charged in their sub-exprs.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Loop_c)
*/
public final void visit(Loop_c s) {
pkg.cost[0] += 2 * OPERATION_COST;
}
/**
* Complex loops will get also charged in their sub-exprs.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.X10Loop_c)
*/
public final void visit(X10Loop_c s) {
pkg.cost[0] += 2 * OPERATION_COST;
}
/**
* Multiple calls.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.AtEach_c)
*/
public final void visit(AtEach_c s) {
pkg.cost[0] += 5 * CALL_COST;
}
/**
* A call.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Next_c)
*/
public final void visit(Next_c s) {
pkg.cost[0] += CALL_COST;
}
/**
* A call.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Throw_c)
*/
public final void visit(Throw_c s) {
pkg.cost[0] += CALL_COST;
}
/**
* Multiple calls.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.When_c)
*/
public final void visit(When_c s) {
pkg.cost[0] += 4 * CALL_COST;
}
/**
* Other nodes are not charged.
*
* @see x10.visit.X10DelegatingVisitor#visit(polyglot.ast.Node_c)
*/
public final void visit(Node_c n) {
pkg.cost[0] += NO_COST;
}
}