do the tree inlining during expansion phase
diff mbox series

Message ID 20200208235718.96389-1-luc.vanoostenryck@gmail.com
State Mainlined, archived
Headers show
Series
  • do the tree inlining during expansion phase
Related show

Commit Message

Luc Van Oostenryck Feb. 8, 2020, 11:57 p.m. UTC
Currently, the tree inlining is done very early, during the
evaluation phase. This means that the inlining is done even
if the corresponding call belong to a sub-expression that
will be discarded during the expansion phase.
Usually this is not a problem but in some pathological
cases it can lead to a huge waste of memory and CPU time.

So, move this inline expansion to ... the expansion phase.
Also, re-expand the resulting expression since constant
arguments may create new opportunities for simplification.

Note: the motivation for thsi is a pathological case in the
      kernel where a combination of max_t() + const_ilog2() +
      roundup_pow_of_two() + cpumask_weight() + __const_hweight*()
      caused Sparse to use 2.3Gb of memory. With this patch
      the memory consumption is down to 247Mb.

Link: https://marc.info/?l=linux-sparse&m=158098958501220
Link: https://lore.kernel.org/netdev/CAHk-=whvS9x5NKtOqcUgJeTY7dfdAHc
Reported-by: Randy Dunlap <rdunlap@infradead.org>
Originally-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 evaluate.c | 16 ----------------
 expand.c   | 19 +++++++++++++++++++
 inline.c   |  5 -----
 3 files changed, 19 insertions(+), 21 deletions(-)

Patch
diff mbox series

diff --git a/evaluate.c b/evaluate.c
index f1a266beccfd..b7bb1f52aa91 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -3107,22 +3107,6 @@  static int evaluate_symbol_call(struct expression *expr)
 	if (ctype->op && ctype->op->evaluate)
 		return ctype->op->evaluate(expr);
 
-	if (ctype->ctype.modifiers & MOD_INLINE) {
-		int ret;
-		struct symbol *curr = current_fn;
-
-		if (ctype->definition)
-			ctype = ctype->definition;
-
-		current_fn = ctype->ctype.base_type;
-
-		ret = inline_function(expr, ctype);
-
-		/* restore the old function */
-		current_fn = curr;
-		return ret;
-	}
-
 	return 0;
 }
 
diff --git a/expand.c b/expand.c
index 36612c8672dd..e75598781b6c 100644
--- a/expand.c
+++ b/expand.c
@@ -910,6 +910,25 @@  static int expand_symbol_call(struct expression *expr, int cost)
 	if (fn->type != EXPR_PREOP)
 		return SIDE_EFFECTS;
 
+	if (ctype->ctype.modifiers & MOD_INLINE) {
+		struct symbol *def;
+
+		def = ctype->definition ? ctype->definition : ctype;
+		if (inline_function(expr, def)) {
+			struct symbol *fn = def->ctype.base_type;
+			struct symbol *curr = current_fn;
+
+			current_fn = fn;
+			evaluate_statement(expr->statement);
+			current_fn = curr;
+
+			fn->expanding = 1;
+			cost = expand_expression(expr);
+			fn->expanding = 0;
+			return cost;
+		}
+	}
+
 	if (ctype->op && ctype->op->expand)
 		return ctype->op->expand(expr, cost);
 
diff --git a/inline.c b/inline.c
index 6f73a30556bc..a959728013f1 100644
--- a/inline.c
+++ b/inline.c
@@ -519,8 +519,6 @@  int inline_function(struct expression *expr, struct symbol *sym)
 	if (fn->expanding)
 		return 0;
 
-	fn->expanding = 1;
-
 	name_list = fn->arguments;
 
 	expr->type = EXPR_STATEMENT;
@@ -558,9 +556,6 @@  int inline_function(struct expression *expr, struct symbol *sym)
 
 	unset_replace_list(fn_symbol_list);
 
-	evaluate_statement(stmt);
-
-	fn->expanding = 0;
 	return 1;
 }