Do not emit static inline functions if referenced by no one

This commit is contained in:
Rui Ueyama 2020-09-13 10:49:25 +09:00
parent 31087f8d4b
commit e5f4ca90fd
4 changed files with 83 additions and 0 deletions

View File

@ -146,6 +146,11 @@ struct Obj {
Obj *locals;
Obj *va_area;
int stack_size;
// Static inline function
bool is_live;
bool is_root;
StringArray refs;
};
// Global variable can be initialized either by a constant expression

View File

@ -1199,6 +1199,11 @@ static void emit_text(Obj *prog) {
if (!fn->is_function || !fn->is_definition)
continue;
// No code is emitted for "static inline" functions
// if no one is referencing them.
if (!fn->is_live)
continue;
if (fn->is_static)
println(" .local %s", fn->name);
else

37
parse.c
View File

@ -2766,6 +2766,14 @@ static Node *primary(Token **rest, Token *tok) {
VarScope *sc = find_var(tok);
*rest = tok->next;
// For "static inline" function
if (sc && sc->var && sc->var->is_function) {
if (current_fn)
strarray_push(&current_fn->refs, sc->var->name);
else
sc->var->is_root = true;
}
if (sc) {
if (sc->var)
return new_var_node(sc->var, tok);
@ -2847,6 +2855,29 @@ static void resolve_goto_labels(void) {
gotos = labels = NULL;
}
static Obj *find_func(char *name) {
Scope *sc = scope;
while (sc->next)
sc = sc->next;
for (VarScope *sc2 = sc->vars; sc2; sc2 = sc2->next)
if (!strcmp(sc2->name, name) && sc2->var && sc2->var->is_function)
return sc2->var;
return NULL;
}
static void mark_live(Obj *var) {
if (!var->is_function || var->is_live)
return;
var->is_live = true;
for (int i = 0; i < var->refs.len; i++) {
Obj *fn = find_func(var->refs.data[i]);
if (fn)
mark_live(fn);
}
}
static Token *function(Token *tok, Type *basety, VarAttr *attr) {
Type *ty = declarator(&tok, tok, basety);
if (!ty->name)
@ -2857,6 +2888,7 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) {
fn->is_definition = !consume(&tok, tok, ";");
fn->is_static = attr->is_static || (attr->is_inline && !attr->is_extern);
fn->is_inline = attr->is_inline;
fn->is_root = !(fn->is_static && fn->is_inline);
if (!fn->is_definition)
return tok;
@ -2953,5 +2985,10 @@ Obj *parse(Token *tok) {
// Global variable
tok = global_variable(tok, basety, &attr);
}
for (Obj *var = globals; var; var = var->next)
if (var->is_root)
mark_live(var);
return globals;
}

View File

@ -125,4 +125,40 @@ echo 'int foo(); int main() { foo(); }' > $tmp/inline2.c
$chibicc -o /dev/null $tmp/inline1.c $tmp/inline2.c
check inline
echo 'static inline void f1() {}' | $chibicc -o- -S - | grep -v -q f1:
check inline
echo 'static inline void f1() {} void foo() { f1(); }' | $chibicc -o- -S - | grep -q f1:
check inline
echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S - | grep -q f1:
check inline
echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S - | grep -v -q f2:
check inline
echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S - | grep -q f1:
check inline
echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S - | grep -q f2:
check inline
echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S - | grep -v -q f1:
check inline
echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S - | grep -v -q f2:
check inline
echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S - | grep -q f1:
check inline
echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S - | grep -q f2:
check inline
echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S - | grep -q f1:
check inline
echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S - | grep -q f2:
check inline
echo OK