int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) { InlineCostState ics; int cost; #define CANINLINE_LOG 0 #if CANINLINE_LOG printf("FuncDeclaration::canInline(hasthis = %d, statementsToo = %d, '%s')\n", hasthis, statementsToo, toPrettyChars()); #endif if (needThis() && !hasthis) return 0; if (inlineNest || (semanticRun < PASSsemantic3 && !hdrscan)) { #if CANINLINE_LOG printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); #endif return 0; } #if 1 switch (statementsToo ? inlineStatusStmt : inlineStatusExp) { case ILSyes: #if CANINLINE_LOG printf("\t1: yes %s\n", toChars()); #endif return 1; case ILSno: #if CANINLINE_LOG printf("\t1: no %s\n", toChars()); #endif return 0; case ILSuninitialized: break; default: assert(0); } #endif if (type) { assert(type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)type; if (tf->varargs == 1) // no variadic parameter lists goto Lno; /* Don't inline a function that returns non-void, but has * no return expression. * No statement inlining for non-voids. */ if (tf->next && tf->next->ty != Tvoid && (!(hasReturnExp & 1) || statementsToo) && !hdrscan) goto Lno; } // cannot inline constructor calls because we need to convert: // return; // to: // return this; if ( !fbody || ident == Id::ensure || // ensure() has magic properties the inliner loses (ident == Id::require && // require() has magic properties too toParent()->isFuncDeclaration() && // see bug 7699 toParent()->isFuncDeclaration()->needThis()) || !hdrscan && ( isSynchronized() || isImportedSymbol() || hasNestedFrameRefs() || // no nested references to this frame (isVirtual() && !isFinalFunc()) )) { goto Lno; } #if 0 /* If any parameters are Tsarray's (which are passed by reference) * or out parameters (also passed by reference), don't do inlining. */ if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { VarDeclaration *v = (*parameters)[i]; if (v->type->toBasetype()->ty == Tsarray) goto Lno; } } #endif memset(&ics, 0, sizeof(ics)); ics.hasthis = hasthis; ics.fd = this; ics.hdrscan = hdrscan; cost = fbody->inlineCost(&ics); #if CANINLINE_LOG printf("cost = %d for %s\n", cost, toChars()); #endif if (tooCostly(cost)) goto Lno; if (!statementsToo && cost > COST_MAX) goto Lno; if (!hdrscan) { // Don't modify inlineStatus for header content scan if (statementsToo) inlineStatusStmt = ILSyes; else inlineStatusExp = ILSyes; inlineScan(); // Don't scan recursively for header content scan if (inlineStatusExp == ILSuninitialized) { // Need to redo cost computation, as some statements or expressions have been inlined memset(&ics, 0, sizeof(ics)); ics.hasthis = hasthis; ics.fd = this; ics.hdrscan = hdrscan; cost = fbody->inlineCost(&ics); #if CANINLINE_LOG printf("recomputed cost = %d for %s\n", cost, toChars()); #endif if (tooCostly(cost)) goto Lno; if (!statementsToo && cost > COST_MAX) goto Lno; if (statementsToo) inlineStatusStmt = ILSyes; else inlineStatusExp = ILSyes; } } #if CANINLINE_LOG printf("\t2: yes %s\n", toChars()); #endif return 1; Lno: if (!hdrscan) // Don't modify inlineStatus for header content scan { if (statementsToo) inlineStatusStmt = ILSno; else inlineStatusExp = ILSno; } #if CANINLINE_LOG printf("\t2: no %s\n", toChars()); #endif return 0; }
int FuncDeclaration::canInline(int hasthis, int hdrscan) { InlineCostState ics; int cost; #define CANINLINE_LOG 0 #if CANINLINE_LOG printf("FuncDeclaration::canInline(hasthis = %d, '%s')\n", hasthis, toChars()); #endif if (needThis() && !hasthis) return 0; if (inlineNest || (semanticRun < PASSsemantic3 && !hdrscan)) { #if CANINLINE_LOG printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); #endif return 0; } switch (inlineStatus) { case ILSyes: #if CANINLINE_LOG printf("\t1: yes %s\n", toChars()); #endif return 1; case ILSno: #if CANINLINE_LOG printf("\t1: no %s\n", toChars()); #endif return 0; case ILSuninitialized: break; default: assert(0); } if (type) { assert(type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)(type); #if IN_LLVM // LDC: Only extern(C) varargs count. if (tf->linkage != LINKd) #endif if (tf->varargs == 1) // no variadic parameter lists goto Lno; /* Don't inline a function that returns non-void, but has * no return expression. */ if (tf->next && tf->next->ty != Tvoid && !(hasReturnExp & 1) && !hdrscan) goto Lno; } #if !IN_LLVM // LDC: Only extern(C) varargs count, and ctors use extern(D). else { CtorDeclaration *ctor = isCtorDeclaration(); if (ctor && ctor->varargs == 1) goto Lno; } #endif if ( !fbody || !hdrscan && ( #if 0 isCtorDeclaration() || // cannot because need to convert: // return; // to: // return this; #endif isSynchronized() || isImportedSymbol() || #if !IN_LLVM #if DMDV2 closureVars.dim || // no nested references to this frame #else nestedFrameRef || // no nested references to this frame #endif #endif // !IN_LLVM (isVirtual() && !isFinal()) )) { goto Lno; } #if !IN_LLVM #if !SARRAYVALUE /* If any parameters are Tsarray's (which are passed by reference) * or out parameters (also passed by reference), don't do inlining. */ if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { VarDeclaration *v = (VarDeclaration *)parameters->data[i]; if (/*v->isOut() || v->isRef() ||*/ v->type->toBasetype()->ty == Tsarray) goto Lno; } } #endif #endif memset(&ics, 0, sizeof(ics)); ics.hasthis = hasthis; ics.fd = this; ics.hdrscan = hdrscan; cost = fbody->inlineCost(&ics); #if CANINLINE_LOG printf("cost = %d\n", cost); #endif if (cost >= COST_MAX) goto Lno; #if !IN_LLVM if (!hdrscan) // Don't scan recursively for header content scan inlineScan(); #endif if (!hdrscan) // Don't modify inlineStatus for header content scan inlineStatus = ILSyes; #if CANINLINE_LOG printf("\t2: yes %s\n", toChars()); #endif return 1; Lno: if (!hdrscan) // Don't modify inlineStatus for header content scan inlineStatus = ILSno; #if CANINLINE_LOG printf("\t2: no %s\n", toChars()); #endif return 0; }