Skip to content

Commit

Permalink
Add unittest
Browse files Browse the repository at this point in the history
Suppress assignment expression if the LHS is `unused`,
because unused static variable is not emitted.
  • Loading branch information
tyfkda committed Dec 1, 2024
1 parent 6e5a90c commit ad6ac97
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 7 deletions.
8 changes: 7 additions & 1 deletion src/cc/backend/codegen_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -563,14 +563,20 @@ static VReg *gen_comma(Expr *expr) {
static VReg *gen_assign_sub(Expr *lhs, Expr *rhs) {
VReg *src = gen_expr(rhs);
if (lhs->kind == EX_VAR) {
const VarInfo *varinfo = scope_find(lhs->var.scope, lhs->var.name, NULL);
assert(varinfo != NULL);
if (is_prim_type(lhs->type) && !is_global_scope(lhs->var.scope)) {
const VarInfo *varinfo = scope_find(lhs->var.scope, lhs->var.name, NULL);
if (is_local_storage(varinfo)) {
assert(varinfo->local.vreg != NULL);
new_ir_mov(varinfo->local.vreg, src, is_unsigned(rhs->type) ? IRF_UNSIGNED : 0);
return src;
}
}

if ((varinfo->storage & (VS_STATIC | VS_USED)) == VS_STATIC) {
// Can be omitted.
return src;
}
}

VReg *dst = gen_lval(lhs);
Expand Down
2 changes: 2 additions & 0 deletions src/wcc/emit_wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ static void emit_global_number(void *ud, const Type *type, Expr *var, Fixnum off
v += get_indirect_function_index(var->var.name);
} else {
GVarInfo *info = get_gvar_info(var);
assert(info != NULL);
assert(!is_prim_type(info->varinfo->type) || (info->varinfo->storage & VS_REF_TAKEN));
v += info->non_prim.address;
}
Expand Down Expand Up @@ -116,6 +117,7 @@ static void emit_number(void *ud, const Type *type, Expr *var, Fixnum offset) {
} else {
assert(var->kind == EX_VAR);
const GVarInfo *info = get_gvar_info(var);
assert(info != NULL);
assert(!is_prim_type(info->varinfo->type) || (info->varinfo->storage & VS_REF_TAKEN));
v += info->non_prim.address;

Expand Down
10 changes: 10 additions & 0 deletions src/wcc/gen_wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ static void gen_ref_sub(Expr *expr) {
ADD_VARUINT32(info->indirect_index);
} else {
GVarInfo *info = get_gvar_info(expr);
assert(info != NULL);
ADD_CODE(OP_I32_CONST);
FuncExtra *extra = curfunc->extra;
DataStorage *code = extra->code;
Expand Down Expand Up @@ -554,6 +555,7 @@ static void gen_var(Expr *expr, bool needval) {
ADD_ULEB128(vreg->prim.local_index);
} else {
GVarInfo *info = get_gvar_info(expr);
assert(info != NULL);
ADD_CODE(OP_GLOBAL_GET);
FuncExtra *extra = curfunc->extra;
DataStorage *code = extra->code;
Expand Down Expand Up @@ -616,6 +618,7 @@ static void gen_set_to_var(Expr *var) {
} else {
assert(!is_global_datsec_var(varinfo, var->var.scope));
GVarInfo *info = get_gvar_info(var);
assert(info != NULL);
ADD_CODE(OP_GLOBAL_SET);
FuncExtra *extra = curfunc->extra;
DataStorage *code = extra->code;
Expand Down Expand Up @@ -799,6 +802,7 @@ static void gen_incdec(Expr *expr, bool needval) {
} else {
assert(!is_global_datsec_var(varinfo, scope));
GVarInfo *info = get_gvar_info(target);
assert(info != NULL);
ADD_CODE(OP_GLOBAL_SET);
ADD_ULEB128(info->prim.index);
if (needval) {
Expand All @@ -823,6 +827,12 @@ static void gen_assign_sub(Expr *lhs, Expr *rhs) {
gen_set_to_var(lhs);
break;
}

if ((varinfo->storage & (VS_STATIC | VS_USED)) == VS_STATIC) {
// Assignment can be omitted.
gen_expr(rhs, false);
return;
}
}
gen_lval(lhs);
gen_expr(rhs, true);
Expand Down
16 changes: 10 additions & 6 deletions src/wcc/traverse.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,15 @@ GVarInfo *get_gvar_info(Expr *expr) {
}
assert(varinfo != NULL);
GVarInfo *info = get_gvar_info_from_name(name);
if (info == NULL) {
if (info == NULL && (!(varinfo->storage & VS_STATIC) || (varinfo->storage & VS_USED))) {
// Returns dummy.
info = register_gvar_info(name, varinfo);
info->flag |= GVF_UNRESOLVED;
}
return info;
}

#define add_global_var(type, name) scope_add(global_scope, name, type, 0)
#define add_global_var(type, name) scope_add(global_scope, name, type, VS_USED)

void add_builtin_function(const char *str, Type *type, BuiltinFunctionProc *proc,
bool add_to_scope) {
Expand Down Expand Up @@ -629,7 +629,8 @@ static void traverse_varinfo(VarInfo *varinfo) {
if (scope_find(global_scope, varinfo->name, NULL) == NULL) {
// Register into global to output linking information.
GVarInfo *info = register_gvar_info(varinfo->name, varinfo);
info->flag |= GVF_UNRESOLVED;
if (info != NULL)
info->flag |= GVF_UNRESOLVED;
}
}
if (!(varinfo->storage & (VS_EXTERN | VS_STATIC | VS_ENUM_MEMBER)))
Expand Down Expand Up @@ -832,6 +833,7 @@ static void add_builtins(int flag) {
GVarInfo *info = get_gvar_info_from_name(name);
if (info == NULL)
info = register_gvar_info(name, varinfo);
assert(info != NULL);
info->flag |= GVF_UNRESOLVED;
}
}
Expand Down Expand Up @@ -889,7 +891,9 @@ static bool detect_compile_unit_sp(Function *func) {
static int detect_compile_unit_memory(void) {
for (int i = 0, len = global_scope->vars->len; i < len; ++i) {
VarInfo *varinfo = global_scope->vars->data[i];
if (varinfo->storage & (VS_EXTERN | VS_ENUM_MEMBER) || varinfo->type->kind == TY_FUNC)
if (varinfo->type->kind == TY_FUNC ||
(varinfo->storage & (VS_EXTERN | VS_ENUM_MEMBER)) ||
(varinfo->storage & (VS_STATIC | VS_USED)) == VS_STATIC) // Static variable but not used.
continue;
if (is_global_datsec_var(varinfo, global_scope))
return CUF_LINEAR_MEMORY;
Expand Down Expand Up @@ -992,8 +996,8 @@ void traverse_ast(Vector *decls) {
GVarInfo *info;
for (int it = 0; (it = table_iterate(&gvar_info_table, it, &name, (void**)&info)) != -1; ) {
const VarInfo *varinfo = info->varinfo;
if (varinfo->storage & VS_ENUM_MEMBER || varinfo->type->kind == TY_FUNC)
continue;
assert(!(varinfo->storage & VS_ENUM_MEMBER || varinfo->type->kind == TY_FUNC));
assert(!((varinfo->storage & (VS_STATIC | VS_USED)) == VS_STATIC));
if ((k == 0 && !(info->flag & GVF_UNRESOLVED)) ||
(k != 0 && ((info->flag & GVF_UNRESOLVED) || (varinfo->global.init == NULL) == (k == 1))))
continue;
Expand Down
6 changes: 6 additions & 0 deletions tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,12 @@ test_error() {
compile_error 'noreturn should not return' 'void sub(void) __attribute__((noreturn));\nvoid sub(void){}\nint main(){ sub(); }'
compile_error 'noreturn should be void' '#include <stdlib.h>\nint sub(void) __attribute__((noreturn));\nint sub(void){exit(0);}\nint main(){ sub(); }'

# Unused check.
compile_error 'unused local variable' 'int main(){ int x = 0; x = 1; return 0; }'
compile_error 'unused static variable' 'int main(){ static int x = 0; x = 1; return 0; }'
compile_error 'unused static global variable' 'static int s = 0; int g; int sub(){g=1; return 2;} int main(){ s = sub(); return g; }'
try_direct 'unused static can run w/o -Werror' 1 'static int s = 0; int g; int sub(){g=1; return 2;} int main(){ s = sub(); return g; } //-WNOERR'

compile_error 'enum and global' 'enum Foo { BAR }; int BAR; int main(){}'
compile_error 'global and enum' 'int BAR; enum Foo { BAR }; int main(){}'
compile_error 'dup enum elem' 'enum Foo { BAR, BAR }; int main(){}'
Expand Down

0 comments on commit ad6ac97

Please sign in to comment.