VLA fix: save stack pointer right after modification
This patch disables the optimization of saving stack pointers lazily, which didn't fully take into account that control flow might not reach the stack-saving instructions. I've decided to leave in the extra calls to vla_sp_save() in case anyone wants to restore this optimization. Tests added and enabled. There are two remaining bugs: VLA variables can be modified, and jumping into the scope of a declared VLA will cause a segfault rather than a compiler error. Both of these do not affect correct C code, but should be fixed at some point. Once VLA variables have been made properly immutable, we can share them with the saved stack pointer and save stack and instructions.
This commit is contained in:
parent
d2dd6fdbfb
commit
44c330d647
4 changed files with 37 additions and 9 deletions
15
tccgen.c
15
tccgen.c
|
@ -3480,7 +3480,7 @@ static void post_type(CType *type, AttributeDef *ad)
|
||||||
|
|
||||||
vla_runtime_type_size(type, &align);
|
vla_runtime_type_size(type, &align);
|
||||||
gen_op('*');
|
gen_op('*');
|
||||||
vset(&int_type, VT_LOCAL|VT_LVAL, loc);
|
vset(&int_type, VT_LOCAL|VT_LVAL, n);
|
||||||
vswap();
|
vswap();
|
||||||
vstore();
|
vstore();
|
||||||
}
|
}
|
||||||
|
@ -4809,7 +4809,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||||
gsym_addr(b, d);
|
gsym_addr(b, d);
|
||||||
} else if (tok == '{') {
|
} else if (tok == '{') {
|
||||||
Sym *llabel;
|
Sym *llabel;
|
||||||
int block_vla_sp_loc, *saved_vla_sp_loc, saved_vla_flags;
|
int block_vla_sp_loc, *saved_vla_sp_loc, saved_vla_flags, *orig_vla_sp_loc;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
/* record local declaration stack position */
|
/* record local declaration stack position */
|
||||||
|
@ -4822,7 +4822,8 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||||
/* save VLA state */
|
/* save VLA state */
|
||||||
block_vla_sp_loc = *(saved_vla_sp_loc = vla_sp_loc);
|
block_vla_sp_loc = *(saved_vla_sp_loc = vla_sp_loc);
|
||||||
if (saved_vla_sp_loc != &vla_sp_root_loc)
|
if (saved_vla_sp_loc != &vla_sp_root_loc)
|
||||||
vla_sp_loc = &block_vla_sp_loc;
|
vla_sp_loc = &block_vla_sp_loc;
|
||||||
|
orig_vla_sp_loc = vla_sp_loc;
|
||||||
|
|
||||||
saved_vla_flags = vla_flags;
|
saved_vla_flags = vla_flags;
|
||||||
vla_flags |= VLA_NEED_NEW_FRAME;
|
vla_flags |= VLA_NEED_NEW_FRAME;
|
||||||
|
@ -4878,10 +4879,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||||
/* Pop VLA frames and restore stack pointer if required */
|
/* Pop VLA frames and restore stack pointer if required */
|
||||||
if (saved_vla_sp_loc != &vla_sp_root_loc)
|
if (saved_vla_sp_loc != &vla_sp_root_loc)
|
||||||
*saved_vla_sp_loc = block_vla_sp_loc;
|
*saved_vla_sp_loc = block_vla_sp_loc;
|
||||||
if (vla_sp_loc != (saved_vla_sp_loc == &vla_sp_root_loc ? &vla_sp_root_loc : &block_vla_sp_loc)) {
|
if (vla_sp_loc != orig_vla_sp_loc) {
|
||||||
vla_sp_loc = saved_vla_sp_loc;
|
gen_vla_sp_restore(*saved_vla_sp_loc);
|
||||||
gen_vla_sp_restore(*vla_sp_loc);
|
|
||||||
}
|
}
|
||||||
|
vla_sp_loc = saved_vla_sp_loc;
|
||||||
vla_flags = (vla_flags & ~VLA_SCOPE_FLAGS) | (saved_vla_flags & VLA_SCOPE_FLAGS);
|
vla_flags = (vla_flags & ~VLA_SCOPE_FLAGS) | (saved_vla_flags & VLA_SCOPE_FLAGS);
|
||||||
|
|
||||||
next();
|
next();
|
||||||
|
@ -5482,6 +5483,8 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
||||||
|
|
||||||
vla_runtime_type_size(type, &a);
|
vla_runtime_type_size(type, &a);
|
||||||
gen_vla_alloc(type, a);
|
gen_vla_alloc(type, a);
|
||||||
|
vla_flags = VLA_IN_SCOPE;
|
||||||
|
vla_sp_save();
|
||||||
vset(type, VT_LOCAL|VT_LVAL, c);
|
vset(type, VT_LOCAL|VT_LVAL, c);
|
||||||
vswap();
|
vswap();
|
||||||
vstore();
|
vstore();
|
||||||
|
|
|
@ -81,12 +81,36 @@ void test4()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test5()
|
||||||
|
{
|
||||||
|
int count = 10;
|
||||||
|
int a[f()];
|
||||||
|
int c[f()];
|
||||||
|
|
||||||
|
c[0] = 42;
|
||||||
|
|
||||||
|
for(;count--;) {
|
||||||
|
int b[f()];
|
||||||
|
int i;
|
||||||
|
for (i=0; i<f(); i++) {
|
||||||
|
b[i] = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c[0] == 42) {
|
||||||
|
printf("OK\n");
|
||||||
|
} else {
|
||||||
|
printf("NOT OK\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
test1();
|
test1();
|
||||||
test2();
|
test2();
|
||||||
test3();
|
test3();
|
||||||
test4();
|
test4();
|
||||||
|
test5();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,4 @@ OK
|
||||||
OK
|
OK
|
||||||
OK
|
OK
|
||||||
OK
|
OK
|
||||||
|
OK
|
||||||
|
|
|
@ -96,9 +96,9 @@ TESTS = \
|
||||||
74_nocode_wanted.test \
|
74_nocode_wanted.test \
|
||||||
75_array_in_struct_init.test \
|
75_array_in_struct_init.test \
|
||||||
76_dollars_in_identifiers.test \
|
76_dollars_in_identifiers.test \
|
||||||
77_push_pop_macro.test
|
77_push_pop_macro.test \
|
||||||
# 78_vla_label.test -- currently broken
|
78_vla_label.test \
|
||||||
# 79_vla_continue.test -- currently broken
|
79_vla_continue.test
|
||||||
|
|
||||||
# 34_array_assignment.test -- array assignment is not in C standard
|
# 34_array_assignment.test -- array assignment is not in C standard
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue