33import com .google .common .collect .Lists ;
44import com .google .common .collect .Maps ;
55import com .google .common .collect .Sets ;
6+ import de .peeeq .wurstscript .WLogger ;
67import de .peeeq .wurstscript .jassIm .*;
78import de .peeeq .wurstscript .translation .imtranslation .*;
89import de .peeeq .wurstscript .types .TypesHelper ;
@@ -20,6 +21,7 @@ public class ImInliner {
2021 private static final double THRESHOLD_MODIFIER_CONSTANT_ARG = 2 ;
2122
2223 private static final Set <String > dontInline = Sets .newLinkedHashSet ();
24+ private static final boolean LOG_INLINER = Boolean .getBoolean ("wurst.inliner.log" );
2325 private final ImTranslator translator ;
2426 private final ImProg prog ;
2527 private final Set <ImFunction > inlinableFunctions = Sets .newLinkedHashSet ();
@@ -71,7 +73,14 @@ private ImFunction inlineFunctions(ImFunction f, Element parent, int parentI, El
7173 if (e instanceof ImFunctionCall ) {
7274 ImFunctionCall call = (ImFunctionCall ) e ;
7375 ImFunction called = call .getFunc ();
74- if (f != called && shouldInline (call , called )) {
76+ boolean canInline = f != called && shouldInline (call , called );
77+ if (LOG_INLINER ) {
78+ String msg = "[INLINER] caller=" + f .getName () + " callee=" + called .getName () + " decision=" + (canInline ? "inline" : "keep" ) +
79+ (canInline ? "" : " reason=" + skipReason (call , called ));
80+ WLogger .info (msg );
81+ System .out .println (msg );
82+ }
83+ if (canInline ) {
7584 if (alreadyInlined .getOrDefault (called , 0 ) < 5 ) { // check maximum to ensure termination
7685 inlineCall (f , parent , parentI , call );
7786// translator.removeCallRelation(f, called); // XXX is it safe to remove this call relation?
@@ -100,6 +109,33 @@ private ImFunction inlineFunctions(ImFunction f, Element parent, int parentI, El
100109 return null ;
101110 }
102111
112+ private String skipReason (ImFunctionCall call , ImFunction f ) {
113+ if (f .isNative ()) {
114+ return "native" ;
115+ }
116+ if (call .getCallType () == CallType .EXECUTE ) {
117+ return "execute_call" ;
118+ }
119+ if (!inlinableFunctions .contains (f )) {
120+ return "not_in_inlinable_set" ;
121+ }
122+ if (isRecursive (f )) {
123+ return "recursive" ;
124+ }
125+ double threshold = inlineTreshold ;
126+ for (ImExpr arg : call .getArguments ()) {
127+ if (arg instanceof ImConst ) {
128+ threshold *= THRESHOLD_MODIFIER_CONSTANT_ARG ;
129+ break ;
130+ }
131+ }
132+ double rating = getRating (f );
133+ if (rating >= threshold ) {
134+ return "rating_too_high(" + rating + ">=" + threshold + ")" ;
135+ }
136+ return "unknown" ;
137+ }
138+
103139 private void inlineCall (ImFunction f , Element parent , int parentI , ImFunctionCall call ) {
104140 ImFunction called = call .getFunc ();
105141 if (called == f ) {
@@ -229,7 +265,8 @@ private ImStmt rewriteStmtForEarlyReturn(ImStmt s, ImVar doneVar, ImVar retVar)
229265 loopBody .addAll (rewriteForEarlyReturns (l .getBody ().copy (), doneVar , retVar ).removeAll ());
230266 return JassIm .ImVarargLoop (l .getTrace (), loopBody , l .getLoopVar ());
231267 }
232- return s ;
268+ // Keep tree ownership valid when rewrapping statements into new blocks.
269+ return s .copy ();
233270 }
234271
235272 private void rateInlinableFunctions () {
@@ -346,22 +383,34 @@ private int getCallCount(ImFunction f) {
346383
347384 private void collectInlinableFunctions () {
348385 for (ImFunction f : ImHelper .calculateFunctionsOfProg (prog )) {
349- if (f .hasFlag (FunctionFlagEnum .IS_COMPILETIME_NATIVE ) || f .hasFlag (FunctionFlagEnum .IS_NATIVE )) {
350- // do not inline natives
351- continue ;
352- }
353- if (f == translator .getGlobalInitFunc ()) {
354- continue ;
386+ if (isInlineCandidate (f )) {
387+ inlinableFunctions .add (f );
355388 }
356- if (f .hasFlag (IS_VARARG )) {
357- // do not inline vararg functions
358- // this is only relevant for lua, because in JASS they are eliminated before inlining
359- continue ;
389+ }
390+ // Some call targets can survive in the call graph but not in prog/classes lists.
391+ for (ImFunction f : translator .getCalledFunctions ().values ()) {
392+ if (isInlineCandidate (f )) {
393+ inlinableFunctions .add (f );
360394 }
361- inlinableFunctions .add (f );
362395 }
363396 }
364397
398+ private boolean isInlineCandidate (ImFunction f ) {
399+ if (f .hasFlag (FunctionFlagEnum .IS_COMPILETIME_NATIVE ) || f .hasFlag (FunctionFlagEnum .IS_NATIVE )) {
400+ // do not inline natives
401+ return false ;
402+ }
403+ if (f == translator .getGlobalInitFunc ()) {
404+ return false ;
405+ }
406+ if (f .hasFlag (IS_VARARG )) {
407+ // do not inline vararg functions
408+ // this is only relevant for lua, because in JASS they are eliminated before inlining
409+ return false ;
410+ }
411+ return true ;
412+ }
413+
365414 private boolean maxOneReturn (ImFunction f ) {
366415 return maxOneReturn (f .getBody ());
367416 }
0 commit comments