Skip to content

Commit 2710128

Browse files
committed
Only use the stack for variables whose address is actually taken
1 parent 9e0f406 commit 2710128

File tree

11 files changed

+97
-60
lines changed

11 files changed

+97
-60
lines changed

Changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Version 7.0.0
44
- Added some of the v44 Spin2 builtin methods like byteswap
55
- Cleaned up the Spin parser to enable direct access to struct/obj members
66
- Fixed long relative branches (tjz, djnz, etc.)
7+
- Only use the stack for variables whose address is actually taken (thanks to Ada for this!)
78

89
Version 6.9.10
910
- Fix compilation error when GETWORD is replaced by MOV or MUL

Test/Expect/stest163.pasm

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,9 @@ _main
99
add sp, #4
1010
mov fp, sp
1111
add sp, #104
12-
mov _var01, fp
13-
add fp, #100
14-
wrlong _var01, fp
15-
mov _var02, #65
16-
wrbyte _var02, _var01
17-
rdlong outa, fp
18-
sub fp, #100
12+
mov _var01, #65
13+
wrbyte _var01, fp
14+
mov outa, fp
1915
mov sp, fp
2016
sub sp, #4
2117
rdlong fp, sp
@@ -33,6 +29,4 @@ stackspace
3329
org COG_BSS_START
3430
_var01
3531
res 1
36-
_var02
37-
res 1
3832
fit 496

Test/Expect/stest280.pasm

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,20 @@ _blah1
99
add sp, #4
1010
mov fp, sp
1111
add sp, #48
12-
add fp, #4
13-
wrlong arg01, fp
14-
add fp, #4
12+
mov _var01, arg01
1513
mov arg01, fp
16-
sub fp, #8
14+
add arg01, #8
1715
mov arg02, #0
1816
mov arg03, #40
1917
LR__0001
2018
wrbyte arg02, arg01
2119
add arg01, #1
2220
djnz arg03, #LR__0001
23-
add fp, #4
24-
rdlong result1, fp
25-
shl result1, #2
26-
add fp, #4
27-
add result1, fp
28-
rdlong result1, result1
29-
sub fp, #8
21+
shl _var01, #2
22+
mov result1, fp
23+
add result1, #8
24+
add _var01, result1
25+
rdlong result1, _var01
3026
mov sp, fp
3127
sub sp, #4
3228
rdlong fp, sp
@@ -38,42 +34,38 @@ _blah2
3834
add sp, #4
3935
mov fp, sp
4036
add sp, #20
41-
add fp, #4
42-
wrlong arg01, fp
43-
add fp, #4
37+
mov _var01, arg01
4438
mov arg01, fp
45-
sub fp, #8
39+
add arg01, #8
4640
mov arg02, ptr__dat__
4741
mov arg03, #8
4842
cmps arg01, arg02 wc
4943
if_ae jmp #LR__0011
50-
mov _var01, #8
44+
mov _var02, #8
5145
LR__0010
5246
rdbyte result1, arg02
5347
wrbyte result1, arg01
5448
add arg01, #1
5549
add arg02, #1
56-
djnz _var01, #LR__0010
50+
djnz _var02, #LR__0010
5751
jmp #LR__0014
5852
LR__0011
5953
add arg01, arg03
6054
add arg02, arg03
61-
mov _var02, arg03 wz
55+
mov _var03, arg03 wz
6256
if_e jmp #LR__0013
6357
LR__0012
6458
sub arg01, #1
6559
sub arg02, #1
66-
rdbyte _var01, arg02
67-
wrbyte _var01, arg01
68-
djnz _var02, #LR__0012
60+
rdbyte _var02, arg02
61+
wrbyte _var02, arg01
62+
djnz _var03, #LR__0012
6963
LR__0013
7064
LR__0014
71-
add fp, #4
72-
rdlong result1, fp
73-
add fp, #4
74-
add result1, fp
75-
rdbyte result1, result1
76-
sub fp, #8
65+
mov result1, fp
66+
add result1, #8
67+
add _var01, result1
68+
rdbyte result1, _var01
7769
mov sp, fp
7870
sub sp, #4
7971
rdlong fp, sp
@@ -100,6 +92,8 @@ _var01
10092
res 1
10193
_var02
10294
res 1
95+
_var03
96+
res 1
10397
arg01
10498
res 1
10599
arg02

backends/asm/outasm.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
#define IS_FAST_CALL(f) ( (f == 0) || !FuncData(f) || FuncData(f)->convention == FAST_CALL)
3232
#define IS_STACK_CALL(f) ( (f != 0) && FuncData(f)->convention == STACK_CALL)
3333

34-
#define ALL_VARS_ON_STACK(f) ( IS_STACK_CALL(f) || f->local_address_taken || f->closure)
35-
#define ANY_VARS_ON_STACK(f) ( ALL_VARS_ON_STACK(f) || f->stack_local )
34+
#define ALL_VARS_ON_STACK(f) ( IS_STACK_CALL(f) || f->force_locals_to_stack || (f->local_address_taken && IsSpinLang(f->language) && !(f->optimize_flags & OPT_SPIN_STRICTMEM)) || f->closure)
35+
#define ANY_VARS_ON_STACK(f) ( ALL_VARS_ON_STACK(f) || f->stack_local || f->local_address_taken )
3636

3737
#define IS_LEAF(func) ((gl_compress == 0) && ((func)->is_leaf || (FuncData(func) && FuncData(func)->effectivelyLeaf)))
3838

@@ -299,6 +299,9 @@ PutVarOnStack(Function *func, Symbol *sym, int size)
299299
if (sym->kind == SYM_LOCALVAR && TypeGoesOnStack((AST *)sym->v.ptr)) {
300300
return true;
301301
}
302+
if (sym->flags & SYMF_ADDRESSABLE) {
303+
return true;
304+
}
302305
return false;
303306
}
304307

cmdline.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ static FlagTable optflag[] = {
538538
{ "local-reuse", OPT_LOCAL_REUSE},
539539
{ "aggressive-mem", OPT_AGGRESSIVE_MEM},
540540
{ "cold-code", OPT_COLD_CODE},
541-
541+
{ "spin-strict-memory", OPT_SPIN_STRICTMEM},
542542
{ "experimental", OPT_EXPERIMENTAL },
543543
{ "all", OPT_FLAGS_ALL },
544544
};

frontends/basic/basiclang.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -927,12 +927,17 @@ doBasicTransform(AST **astptr, bool transformFuncall)
927927
{
928928
doBasicTransform(&ast->left, transformFuncall);
929929
doBasicTransform(&ast->right, transformFuncall);
930-
if (IsLocalVariable(ast->left)) {
930+
Symbol *sym;
931+
if (IsLocalVariableEx(ast->left, &sym)) {
931932
curfunc->local_address_taken = 1;
933+
if (sym) {
934+
sym->flags |= SYMF_ADDRESSABLE;
935+
} else {
936+
curfunc->force_locals_to_stack = 1; // fallback if we couldn't get a symbol
937+
}
932938
}
933939
// taking the address of a function may restrict how
934940
// we can call it (stack vs. register calling)
935-
Symbol *sym;
936941
Function *f = NULL;
937942
sym = FindCalledFuncSymbol(ast, NULL, 0);
938943
if (sym && sym->kind == SYM_FUNCTION) {
@@ -997,7 +1002,7 @@ doBasicTransform(AST **astptr, bool transformFuncall)
9971002
doBasicTransform(&ast->right, transformFuncall);
9981003
// keep local variables on stack, so they will be preserved
9991004
// if an exception throws us back here without cleanup
1000-
curfunc->local_address_taken = 1;
1005+
curfunc->force_locals_to_stack = 1;
10011006
break;
10021007
case AST_READ:
10031008
doBasicTransform(&ast->left, transformFuncall);

frontends/c/clang.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Spin to C/C++ converter
3-
* Copyright 2011-2023 Total Spectrum Software Inc.
3+
* Copyright 2011-2024 Total Spectrum Software Inc.
44
* See the file COPYING for terms of use
55
*
66
* code for C specific features
@@ -66,12 +66,17 @@ doCTransform(AST **astptr, unsigned cflags)
6666
{
6767
doCTransform(&ast->left, cflags);
6868
doCTransform(&ast->right, cflags);
69-
if (curfunc && IsLocalVariable(ast->left)) {
69+
Symbol *sym;
70+
if (curfunc && IsLocalVariableEx(ast->left, &sym)) {
7071
curfunc->local_address_taken = 1;
72+
if (sym) {
73+
sym->flags |= SYMF_ADDRESSABLE;
74+
} else {
75+
curfunc->force_locals_to_stack = 1; // fallback if we couldn't get a symbol
76+
}
7177
}
7278
// taking the address of a function may restrict how
7379
// we can call it (stack vs. register calling)
74-
Symbol *sym;
7580
Function *f = NULL;
7681
sym = FindCalledFuncSymbol(ast, NULL, 0);
7782
if (sym && sym->kind == SYM_FUNCTION) {
@@ -107,7 +112,7 @@ doCTransform(AST **astptr, unsigned cflags)
107112
// keep local variables on stack, so they will be preserved
108113
// if an exception throws us back here without cleanup
109114
if (curfunc) {
110-
curfunc->local_address_taken = 1;
115+
curfunc->force_locals_to_stack = 1;
111116
} else {
112117
ERROR(ast, "setjmp/longjmp outside of a function");
113118
}

frontends/common.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,10 @@ extern int gl_optimize_flags; /* flags for optimization */
193193
#define OPT_AGGRESSIVE_MEM 0x00200000 /* aggressive load/store optimization */
194194
#define OPT_COLD_CODE 0x00400000 /* move cold code to end of function */
195195
#define OPT_MERGE_DUPLICATES 0x00800000 /* merge duplicate functions */
196+
#define OPT_SPIN_STRICTMEM 0x01000000 /* strict memory semantics for Spin */
196197

197198
#define OPT_EXPERIMENTAL 0x80000000 /* gate new or experimental optimizations */
198-
#define OPT_FLAGS_ALL 0xffffffff
199+
#define OPT_FLAGS_ALL (0xffffffff & ~OPT_SPIN_STRICTMEM)
199200

200201
#define OPT_ASM_BASIC (OPT_BASIC_REGS|OPT_BRANCHES|OPT_PEEPHOLE|OPT_CONST_PROPAGATE|OPT_REMOVE_FEATURES|OPT_MAKE_MACROS)
201202

@@ -450,6 +451,7 @@ typedef struct funcdef {
450451
unsigned cog_task:1; // 1 if function is started in another cog
451452
unsigned used_as_ptr:1; // 1 if function's address is taken as a pointer
452453
unsigned local_address_taken: 1; // 1 if a local variable or parameter has its address taken
454+
unsigned force_locals_to_stack: 1; // 1 if function must store all locals on the stack
453455
unsigned no_inline:1; // 1 if function cannot be inlined
454456
unsigned prefer_inline:1; // 1 if function should be inlined more often
455457
unsigned is_leaf:1; // 1 if function is a leaf function
@@ -980,6 +982,9 @@ AST *GetComments(void);
980982
/* is an AST identifier a local variable? */
981983
bool IsLocalVariable(AST *ast);
982984

985+
/* like IsLocalVariable but looks up symbol too */
986+
bool IsLocalVariableEx(AST *ast, Symbol **symout);
987+
983988
/* push the current types identifier */
984989
void PushCurrentTypes(void);
985990

frontends/spin/spinlang.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
extern AST *ParsePrintStatement(AST *ast); /* in basiclang.c */
1414

1515
bool
16-
IsLocalVariable(AST *ast) {
16+
IsLocalVariableEx(AST *ast, Symbol **symout) {
1717
Symbol *sym;
1818

19+
if (symout) *symout = NULL;
1920
if (!ast) return false;
2021
if (ast->kind == AST_STMTLIST || ast->kind == AST_SEQUENCE) {
2122
while (ast && ast->right) {
@@ -29,14 +30,15 @@ IsLocalVariable(AST *ast) {
2930
}
3031
switch (ast->kind) {
3132
case AST_CAST:
32-
return IsLocalVariable(ast->right);
33+
return IsLocalVariableEx(ast->right, symout);
3334
case AST_IDENTIFIER:
3435
sym = LookupSymbol(ast->d.string);
3536
if (!sym) return false;
3637
switch (sym->kind) {
3738
case SYM_RESULT:
3839
case SYM_LOCALVAR:
3940
case SYM_PARAMETER:
41+
if (symout) *symout = sym;
4042
return true;
4143
default:
4244
return false;
@@ -45,7 +47,7 @@ IsLocalVariable(AST *ast) {
4547
case AST_RANGEREF:
4648
case AST_METHODREF:
4749
case AST_ARRAYREF:
48-
if (IsLocalVariable(ast->left)) {
50+
if (IsLocalVariableEx(ast->left, symout)) {
4951
// check for pointer dereference, which is not
5052
// actually going to cause us grief
5153
if (IsPointerType(ExprType(ast->left))) {
@@ -61,6 +63,11 @@ IsLocalVariable(AST *ast) {
6163
}
6264
}
6365

66+
bool
67+
IsLocalVariable(AST *ast) {
68+
return IsLocalVariableEx(ast, NULL);
69+
}
70+
6471
/*
6572
* check for a variable having its address taken
6673
*/
@@ -551,7 +558,7 @@ doSpinTransform(AST **astptr, int level, AST *parent)
551558
// in that you can only set up a catch on a call
552559
// and can't differentiate a normal return from an abort.
553560
if (gl_output != OUTPUT_BYTECODE /*|| gl_interp_kind == INTERP_KIND_NUCODE */ ) {
554-
curfunc->local_address_taken = 1; // if we do a catch we will want data on stack
561+
curfunc->force_locals_to_stack = 1; // if we do a catch we will want data on stack
555562
AstReportAs(ast, &saveinfo); // any newly created AST nodes should reflect debug info from this one
556563
*astptr = ast = NewAST(AST_TRYENV,
557564
NewAST(AST_CONDRESULT,
@@ -792,15 +799,25 @@ doSpinTransform(AST **astptr, int level, AST *parent)
792799
if (ast->left && ast->left->kind != AST_RANGEREF) {
793800
doSpinTransform(&ast->left, 0, ast);
794801
}
795-
if (IsLocalVariable(ast->left)) {
802+
if (IsLocalVariableEx(ast->left, &sym)) {
796803
curfunc->local_address_taken = 1;
804+
if (sym) {
805+
sym->flags |= SYMF_ADDRESSABLE;
806+
} else {
807+
curfunc->force_locals_to_stack = 1;
808+
}
797809
}
798810
break;
799811
case AST_ADDROF:
800812
case AST_ABSADDROF:
801813
doSpinTransform(&ast->left, 0, ast);
802-
if (IsLocalVariable(ast->left)) {
814+
if (IsLocalVariableEx(ast->left, &sym)) {
803815
curfunc->local_address_taken = 1;
816+
if (sym) {
817+
sym->flags |= SYMF_ADDRESSABLE;
818+
} else {
819+
curfunc->force_locals_to_stack = 1;
820+
}
804821
}
805822
break;
806823
case AST_MEMREF:
@@ -853,6 +870,7 @@ doSpinTransform(AST **astptr, int level, AST *parent)
853870
*ast = *NewAST(AST_ARRAYREF, memref, ast->right);
854871
if (isLocal) {
855872
SetLocalArray(curfunc, sym, NULL);
873+
sym->flags |= SYMF_ADDRESSABLE;
856874
curfunc->local_address_taken = 1;
857875
}
858876
AstReportDone(&saveinfo);

frontends/types.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -909,8 +909,14 @@ static AST *ScalePointer(AST *type, AST *val)
909909
// return the address of an array
910910
AST *ArrayAddress(AST *expr)
911911
{
912-
if (curfunc && IsLocalVariable(expr)) {
912+
Symbol *sym;
913+
if (curfunc && IsLocalVariableEx(expr, &sym)) {
913914
curfunc->local_address_taken = 1;
915+
if (sym) {
916+
sym->flags |= SYMF_ADDRESSABLE;
917+
} else {
918+
curfunc->force_locals_to_stack = 1; // fallback if we couldn't get a symbol
919+
}
914920
}
915921
return NewAST(AST_ABSADDROF,
916922
NewAST(AST_ARRAYREF, expr, AstInteger(0)),
@@ -1332,9 +1338,15 @@ AST *CoerceAssignTypes(AST *line, int kind, AST **astptr, AST *desttype, AST *sr
13321338
AST *copy = MakeOperatorCall(struct_copy, lptr, rptr, sizeExpr);
13331339
*astptr = copy;
13341340
} else {
1341+
Symbol *sym;
13351342
*astptr = NewAST(AST_ADDROF, expr, NULL);
1336-
if (curfunc && IsLocalVariable(expr)) {
1343+
if (curfunc && IsLocalVariableEx(expr, &sym)) {
13371344
curfunc->local_address_taken = 1;
1345+
if (sym) {
1346+
sym->flags |= SYMF_ADDRESSABLE;
1347+
} else {
1348+
curfunc->force_locals_to_stack = 1; // fallback if we couldn't get a symbol
1349+
}
13381350
}
13391351
}
13401352
srctype = NewAST(AST_REFTYPE, srctype, NULL);

0 commit comments

Comments
 (0)