/* * 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 2006-2010. */ package x10c.visit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import polyglot.ast.Assign; import polyglot.ast.Block; import polyglot.ast.Do; import polyglot.ast.Eval; import polyglot.ast.Expr; import polyglot.ast.Field; import polyglot.ast.For; import polyglot.ast.ForInit; import polyglot.ast.ForUpdate; import polyglot.ast.Id; import polyglot.ast.Local; import polyglot.ast.LocalAssign; import polyglot.ast.LocalDecl; import polyglot.ast.Loop; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.NullLit; import polyglot.ast.Receiver; import polyglot.ast.Stmt; import polyglot.ast.While; import polyglot.frontend.Job; import polyglot.types.Flags; import polyglot.types.LocalDef; import polyglot.types.Name; import polyglot.types.QName; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.util.InternalCompilerError; import polyglot.util.Pair; import polyglot.util.Position; import polyglot.util.CollectionUtil; import x10.util.CollectionFactory; import polyglot.visit.ContextVisitor; import polyglot.visit.NodeVisitor; import x10.ast.Closure; import x10.ast.ClosureCall; import x10.ast.SettableAssign; import x10.ast.SettableAssign_c; import x10.ast.X10Call; import x10.ast.X10CanonicalTypeNode; import x10.ast.X10Loop; import x10.ast.X10Special; import x10.types.ParameterType; import x10.types.X10ClassType; import x10.types.X10LocalDef; import x10.types.X10ParsedClassType_c; import polyglot.types.TypeSystem; import x10.visit.X10PrettyPrinterVisitor; import x10c.ast.BackingArray; import x10c.ast.BackingArrayAccess; import x10c.ast.X10CBackingArrayAccess_c; import x10c.ast.X10CNodeFactory_c; import x10c.types.X10CTypeSystem_c; public class RailInLoopOptimizer extends ContextVisitor { // TODO enable this private static final boolean ANALYZE_TEMP_VALS = false; private static final String IMC_FIELD_NAME = "raw"; private final X10CTypeSystem_c xts; private final X10CNodeFactory_c xnf; private final Map<Name,X10LocalDef> localdefs = CollectionFactory.newHashMap(); // map tmp values to Array type exprs. e.g.) temp000 -> array private final Map<Name, Expr> nameToArray = CollectionFactory.newHashMap(); // map tmp values to Rail/IMC type exprs. e.g.) temp001 -> array.raw private final Map<Name, Expr> nameToRailIMC = CollectionFactory.newHashMap(); public RailInLoopOptimizer(Job job, TypeSystem ts, NodeFactory nf) { super(job, ts, nf); xts = (X10CTypeSystem_c) ts; xnf = (X10CNodeFactory_c) nf; } private X10LocalDef getLocalDef(Type type, Name name) { if (localdefs.containsKey(name)) { return localdefs.get(name); } else { X10LocalDef ldef = xts.localDef(Position.COMPILER_GENERATED, xts.NoFlags(), Types.ref(type), name); localdefs.put(name, ldef); return ldef; } } @Override protected Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) throws SemanticException { if (n instanceof Loop) { Loop loop = (Loop) n; // list of not loop invariant var names final List<String> ignores = new ArrayList<String>(); if (n instanceof For) { checkInitCondUpdate(ignores, (For) loop); } // targets to privatize final List<Pair<BackingArray, Boolean>> backingArrayAndIsFinals = new ArrayList<Pair<BackingArray, Boolean>>(); final Map<BackingArray, Id> backingArrayToId = CollectionFactory.newHashMap(); Stmt visited1 = (Stmt) loop.body().visit(new NodeVisitor() { @Override public Node override(Node parent, Node n) { if (n instanceof Loop) { return n; } if (n instanceof Closure) { return n; } return null; } @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof LocalDecl) { LocalDecl ld = (LocalDecl) n; Expr init = ld.init(); // to merge privatization statement if (init instanceof BackingArray) { BackingArray ba = (BackingArray) init; Expr rail = ba.container(); if (!ignores.contains(rail.toString())) { if (rail instanceof Field && ignores.contains(((Field) rail).target().toString())) { ignores.add(ld.name().toString()); return ld; } if (rail instanceof X10CBackingArrayAccess_c && ignores.contains(((X10CBackingArrayAccess_c) rail).index().toString())) { ignores.add(ld.name().toString()); return ld; } Type type = ld.type().type(); for (Pair<BackingArray, Boolean> pair : backingArrayAndIsFinals) { // already privatized at another loop if (pair.fst().container().toString().equals(rail.toString())) { ignores.add(ld.name().toString()); X10CanonicalTypeNode tn = xnf.X10CanonicalTypeNode(ld.position(), type); Id id = backingArrayToId.get(pair.fst()); LocalDef ldef = getLocalDef(type, id.id()); ldef.setFlags(Flags.FINAL); return xnf.LocalDecl(n.position(), xnf.FlagsNode(ld.position(), Flags.FINAL), tn, ld.name(), xnf.Local(ld.position(), id).localInstance(ldef.asInstance()).type(type)).localDef(ldef).type(tn); } } Id id = xnf.Id(ld.position(), Name.make(ld.name().toString())); BackingArray nba = xnf.BackingArray(ld.position(), id, type, rail); backingArrayToId.put(nba, id); backingArrayAndIsFinals.add(new Pair<BackingArray, Boolean>(nba, true)); } } else { if (ANALYZE_TEMP_VALS) { analyzeTempVals(ignores, ld, nameToArray, nameToRailIMC); } ignores.add(ld.name().toString()); } } return n; } }); final List<Stmt> moves = new ArrayList<Stmt>(); Stmt visited2 = (Stmt) visited1.visit(new NodeVisitor() { @Override public Node override(Node parent, Node n) { if (n instanceof Loop) { return n; } if (n instanceof Closure) { return n; } return null; } @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof X10Call) { X10Call call = (X10Call) n; Position pos = call.position(); Receiver target = call.target(); if ( target != null && isOptimizationTarget(target.type()) && (call.methodInstance().name()==ClosureCall.APPLY || call.methodInstance().name()==SettableAssign.SET) ) { Expr elem; Expr index; // apply if (call.arguments().size() == 1) { elem = null; index = call.arguments().get(0); } // set else { elem = call.arguments().get(1); index = call.arguments().get(0); } if (target instanceof Local) { Local local = (Local) target; if (ANALYZE_TEMP_VALS && nameToRailIMC.containsKey(local.name().id())) { target = nameToRailIMC.get(local.name().id()); } } else if (target instanceof Field) { Field field = (Field) target; if (!field.flags().isFinal()) { return n; } else if (!(field.target() instanceof X10Special && ((X10Special) field.target()).kind().equals(X10Special.THIS))) { return n; } else if (ignores.contains(((Field) target).target().toString())) { return n; } } else { return n; } if (ignores.contains(target.toString())) { return n; } boolean contains = false; Id id = null; for (Pair<BackingArray, Boolean> pair : backingArrayAndIsFinals) { if (pair.fst().container().toString().equals(target.toString())) { contains = true; id = backingArrayToId.get(pair.fst()); break; } } X10ClassType ct = (X10ClassType) Types.baseType(target.type()); List<Type> typeArguments = ct.typeArguments(); if (typeArguments == null) typeArguments = new ArrayList<Type>(ct.x10Def().typeParameters()); Type type = Types.baseType(typeArguments.get(0)); if (!contains) { id = xnf.Id(pos, Name.makeFresh(target.toString().replace(".", "$").replaceAll("[\\[\\]]", "_").replaceAll(", ","_") + "$value")); BackingArray ba = xnf.BackingArray(pos, id, createArrayType(type), (Expr) target); backingArrayToId.put(ba, id); backingArrayAndIsFinals.add(new Pair<BackingArray, Boolean>(ba, true)); } if (elem == null) { Type arrayType = createArrayType(target.type()); LocalDef ldef = getLocalDef(arrayType, id.id()); return xnf.BackingArrayAccess(pos, xnf.Local(pos, id).localInstance(ldef.asInstance()).type(arrayType), index, type); } Type arrayType = createArrayType(type); LocalDef ldef = getLocalDef(arrayType, id.id()); return xnf.BackingArrayAccessAssign(pos, xnf.Local(pos, id).localInstance(ldef.asInstance()).type(arrayType), index, Assign.ASSIGN, elem).type(type); } } if (n instanceof SettableAssign_c) { Type type = Types.baseType(((SettableAssign_c) n).type()); Expr array = ((SettableAssign_c) n).array(); if (isOptimizationTarget(array.type())) { if (((SettableAssign_c) n).index().size() > 1) { return n; } if (ignores.contains(array.toString())) { return n; } if (array instanceof Local) { Local local = (Local) array; if (ANALYZE_TEMP_VALS && nameToRailIMC.containsKey(local.name().id())) { array = nameToRailIMC.get(local.name().id()); } } else if (array instanceof Field) { Field field = (Field) array; if (!field.flags().isFinal()) { return n; } else if (!(field.target() instanceof X10Special && ((X10Special) field.target()).kind().equals(X10Special.THIS))) { return n; } else if (ignores.contains(((Field) array).target().toString())) { return n; } } else { return n; } boolean contains = false; Id id = null; for (Pair<BackingArray, Boolean> pair : backingArrayAndIsFinals) { if (pair.fst().container().toString().equals(array.toString())) { contains = true; id = backingArrayToId.get(pair.fst()); break; } } BackingArray ba; if (!contains) { id = xnf.Id(n.position(), Name.makeFresh(array.toString().replace(".", "$").replaceAll("[\\[\\]]", "_") + "$value")); ba = xnf.BackingArray(n.position(), id, createArrayType(type), array); backingArrayToId.put(ba, id); backingArrayAndIsFinals.add(new Pair<BackingArray, Boolean>(ba, true)); } else { ba = xnf.BackingArray(n.position(), id, createArrayType(type), array); } Type arrayType = createArrayType(type); LocalDef ldef = getLocalDef(arrayType, id.id()); return xnf.BackingArrayAccessAssign(n.position(), xnf.Local(n.position(), id).localInstance(ldef.asInstance()).type(arrayType), ((SettableAssign_c) n).index().get(0), ((SettableAssign_c) n).operator(), ((SettableAssign_c) n).right()).type(type); } } // rail = Rail.make(10) -> rail = Rail.make(10); railvaluexxx = (int[]) rail.value; if (n instanceof LocalDecl) { LocalDecl ld = (LocalDecl) n; Expr init = ((LocalDecl) n).init(); if (init instanceof BackingArray) { BackingArray ba = (BackingArray) init; Expr rail = ba.container(); if (rail != null) { if (!ignores.contains(rail.toString())) { if (rail instanceof Field && ignores.contains(((Field) rail).target().toString())) { return n; } if (rail instanceof X10CBackingArrayAccess_c) { if (ignores.contains(((X10CBackingArrayAccess_c) rail).index().toString())) { return n; } } for (int i = 0; i < backingArrayAndIsFinals.size(); i++) { Pair<BackingArray, Boolean> pair = backingArrayAndIsFinals.get(i); // already exist if (backingArrayToId.get(pair.fst()).toString().equals(ld.name().toString())) { if (!ld.flags().flags().isFinal()) { backingArrayAndIsFinals.set(i, new Pair<BackingArray, Boolean>(pair.fst(), false)); } return null; } } moves.add(ld); return null; } } } } return n; } }); Stmt visited3 = (Stmt) visited2.visit(new NodeVisitor() { @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { // rail = Rail.make(10) -> rail = Rail.make(10); // railvaluexxx = (int[]) rail.value; // when : rail = null -> rail = null; // raiilvaluexxx = null; if (n instanceof Eval) { if (((Eval) n).expr() instanceof LocalAssign) { LocalAssign la = (LocalAssign) ((Eval) n).expr(); Type type = Types.baseType(la.type()); Local local = la.local(); if (isIMC(type)) { boolean contains = false; Id id = null; for (int i = 0; i < backingArrayAndIsFinals.size(); i++) { Pair<BackingArray, Boolean> pair = backingArrayAndIsFinals.get(i); if (pair.fst().container().toString().equals(local.toString())) { contains = true; id = backingArrayToId.get(pair.fst()); backingArrayAndIsFinals.set(i, new Pair<BackingArray, Boolean>(pair.fst(), false)); break; } } if (!contains) { return n; } if (parent instanceof Block) { for (Stmt stmt : ((Block) parent).statements()) { if (stmt instanceof LocalDecl && ((LocalDecl) stmt).init() instanceof BackingArray) { BackingArray ba = (BackingArray) ((LocalDecl) stmt).init(); if (backingArrayToId.get(ba).toString().equals(id.toString())) { return n; } } } } List<Stmt> stmts = new ArrayList<Stmt>(); stmts.add((Stmt) n); Type pt = Types.baseType(((X10ClassType) type).typeArguments().get(0)); Expr expr; Type arrayType = createArrayType(pt); LocalDef ldef = getLocalDef(arrayType, id.id()); if (la.right() instanceof NullLit) { expr = xnf.LocalAssign(n.position(), (Local) xnf.Local(n.position(), id).localInstance(ldef.asInstance()).type(arrayType), Assign.ASSIGN, la.right()).type(arrayType); } else { expr = xnf.LocalAssign(n.position(), (Local) xnf.Local(n.position(), id).localInstance(ldef.asInstance()).type(arrayType), Assign.ASSIGN, xnf.BackingArray(n.position(), id, arrayType, local)).type(arrayType); } stmts.add(xnf.Eval(n.position(), expr)); return xnf.StmtSeq(n.position(), stmts); } } } return n; }; }); if (loop instanceof For) { loop = ((For) loop).body(visited3); } else if (loop instanceof While) { loop = ((While) loop).body(visited3); } else if (loop instanceof Do) { loop = ((Do) loop).body(visited3); } else if (loop instanceof X10Loop) { loop = ((X10Loop) loop).body(visited3); } else { throw new InternalCompilerError("something wrong!!!"); } if (moves.isEmpty() && backingArrayAndIsFinals.isEmpty()) { return n; } List<Stmt> statements = new ArrayList<Stmt>(); statements.addAll(moves); for (Pair<BackingArray, Boolean> pair : backingArrayAndIsFinals) { Type type = Types.baseType(pair.fst().container().type()); if (type instanceof X10ClassType) { Type pt = ((X10ClassType) type).typeArguments().get(0); X10CanonicalTypeNode tn = xnf.X10CanonicalTypeNode(n.position(), pair.fst().type()); LocalDecl ld; LocalDef localDef = getLocalDef(pair.fst().type(), backingArrayToId.get(pair.fst()).id()); if (pair.snd()) { localDef.setFlags(xts.Final()); ld = xnf.LocalDecl(n.position(), xnf.FlagsNode(n.position(), xts.Final()), tn, backingArrayToId.get(pair.fst()), pair.fst()) .localDef(localDef) .type(tn); } else { ld = xnf.LocalDecl(n.position(), xnf.FlagsNode(n.position(), xts.NoFlags()), tn, backingArrayToId.get(pair.fst()), pair.fst()) .localDef(localDef) .type(tn); } statements.add(ld); } } statements.add(loop); return xnf.Block(n.position(), statements); } return n; } private void checkInitCondUpdate(final List<String> ignores, For forn) { for (ForInit forInit : forn.inits()) { if (forInit instanceof LocalDecl) { ignores.add(((LocalDecl) forInit).name().toString()); } if (forInit instanceof Eval) { if (((Eval) forInit).expr() instanceof LocalAssign) { LocalAssign la = (LocalAssign) ((Eval) forInit).expr(); ignores.add(la.local().name().toString()); } } } List<ForUpdate> iters = forn.iters(); for (ForUpdate forUpdate : iters) { if (forUpdate instanceof Eval) { if (((Eval) forUpdate).expr() instanceof LocalAssign) { LocalAssign la = (LocalAssign) ((Eval) forUpdate).expr(); ignores.add(la.local().name().toString()); } } } } // TODO limitation: cannot handle like the following code: val temp; temp = array and var temp = array; private void analyzeTempVals(final List<String> ignores, LocalDecl ld, Map<Name, Expr> nameToArray, Map<Name, Expr> nameToRailIMC) { Expr init2 = ld.init(); if (init2 != null && ld.flags().flags().isFinal()) { Type lt = ld.localDef().type().get(); if (Types.isX10Array(init2.type()) && Types.isX10Array(lt)) { if (init2 instanceof Local) { Local local = (Local) init2; if (nameToArray.containsKey(local.name().id())) { nameToArray.put(ld.name().id(), nameToArray.get(local.name().id())); } else if (!ignores.contains(local.name().toString())) { nameToArray.put(ld.name().id(), local); } } else if (init2 instanceof Field) { Field f = (Field) init2; if (f.flags().isFinal() && f.target() instanceof X10Special && ((X10Special) f.target()).kind().equals(X10Special.THIS)) { nameToArray.put(ld.name().id(), init2); } } } else if (isIMC(init2.type()) && isIMC(lt)) { if (init2 instanceof Local) { Local local = (Local) init2; if (nameToRailIMC.containsKey(local.name().id())) { nameToRailIMC.put(ld.name().id(), nameToRailIMC.get(local.name().id())); } else if (!ignores.contains(local.name().toString())) { nameToRailIMC.put(ld.name().id(), init2); } } else if (init2 instanceof Field) { Field f = (Field) init2; // special care for the raw field of array. // var/val imc:IndexedMemoryChunck[T] = array.raw; if (f.target() instanceof Local && Types.isX10Array(f.target().type()) && f.name().toString().equals(IMC_FIELD_NAME)) { Local target = (Local) f.target(); if (nameToArray.containsKey(target.name().id())) { Field f2 = (Field) xnf.Field(ld.position(), nameToArray.get(target.name().id()), f.name()).fieldInstance(f.fieldInstance()).type(f.type()); nameToRailIMC.put(ld.name().id(), f2); } } else if (f.flags().isFinal() && f.target() instanceof X10Special && ((X10Special) f.target()).kind().equals(X10Special.THIS)) { nameToRailIMC.put(ld.name().id(), init2); } } } } } Type createArrayType(Type t) { return xts.createBackingArray(t.position(), Types.ref(t)); } private boolean isIMC(Type type) { Type tbase = Types.baseType(type); return tbase instanceof X10ParsedClassType_c && ((X10ParsedClassType_c) tbase).def().asType().typeEquals(xts.IndexedMemoryChunk(), context); }; private boolean isOptimizationTarget(Type ttype) { ttype = Types.baseType(ttype); if (!isIMC(ttype)) return false; if (!X10PrettyPrinterVisitor.hasParams(ttype)) return true; List<Type> ta = ((X10ClassType) ttype).typeArguments(); if (ta != null && !ta.isEmpty() && !xts.isParameterType(ta.get(0))) { return true; } return false; } }