Skip to content

Commit b311f18

Browse files
committed
Support pointer data types for sizeof operator
- Refactor test driver to make it capable of running different stage based on supplied stage number. - Refactor make rule "check" for checking stage 0 and stage 2 - Replace constant value 4 with PTR_SIZE to give appropriate corresponding target arch's pointer size - Add sizeof test - Introduce __SIZE_OF_PTR__ macro in lib/c.c - Fix arm32 div/mod, this was caused by inproper stack alignment
1 parent b310322 commit b311f18

File tree

6 files changed

+81
-9
lines changed

6 files changed

+81
-9
lines changed

Makefile

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,18 @@ $(OUT)/tests/%.elf: tests/%.c $(OUT)/$(STAGE0)
5252
chmod +x $@ ; $(PRINTF) "Running $@ ...\n"
5353
$(Q)$(TARGET_EXEC) $@ && $(call pass)
5454

55-
check: $(TESTBINS) tests/driver.sh
56-
tests/driver.sh
55+
check: check-stage0 check-stage2
56+
57+
check-stage0: $(OUT)/$(STAGE0) $(TESTBINS) tests/driver.sh
58+
$(VECHO) " TEST STAGE 0\n"
59+
tests/driver.sh 0
60+
61+
check-stage2: $(OUT)/$(STAGE2) $(TESTBINS) tests/driver.sh
62+
$(VECHO) " TEST STAGE 2\n"
63+
tests/driver.sh 2
5764

5865
check-snapshots: $(OUT)/$(STAGE0) $(SNAPSHOTS) tests/check-snapshots.sh
66+
$(VECHO) " TEST SNAPSHOTS\n"
5967
tests/check-snapshots.sh
6068

6169
$(OUT)/%.o: %.c

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,27 @@ Verify that the emitted IRs are identical to the snapshots by specifying `check-
112112
$ make check-snapshots
113113
```
114114

115-
`shecc` comes with unit tests. To run the tests, give `check` as an argument:
115+
`shecc` comes with unit tests consist of stage 0, stage 2. To run these tests, give `check` as an argument:
116116
```shell
117117
$ make check
118118
```
119119

120120
Reference output:
121121
```
122+
TEST STAGE 0
122123
...
123124
int main(int argc, int argv) { exit(sizeof(char)); } => 1
124125
int main(int argc, int argv) { int a; a = 0; switch (3) { case 0: return 2; case 3: a = 10; break; case 1: return 0; } exit(a); } => 10
125126
int main(int argc, int argv) { int a; a = 0; switch (3) { case 0: return 2; default: a = 10; break; } exit(a); } => 10
127+
OK
128+
TEST STAGE 2
129+
...
130+
int main(int argc, int argv) { exit(sizeof(char*)); }
131+
exit code => 4
132+
output =>
133+
int main(int argc, int argv) { exit(sizeof(int*)); }
134+
exit code => 4
135+
output =>
126136
OK
127137
```
128138

lib/c.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define false 0
1515

1616
#if defined(__arm__)
17+
#define __SIZEOF_POINTER__ 4
1718
#define __syscall_exit 1
1819
#define __syscall_read 3
1920
#define __syscall_write 4
@@ -23,6 +24,7 @@
2324
#define __syscall_munmap 91
2425

2526
#elif defined(__riscv)
27+
#define __SIZEOF_POINTER__ 4
2628
#define __syscall_exit 93
2729
#define __syscall_read 63
2830
#define __syscall_write 64

src/arm-codegen.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,10 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
336336
}
337337
interm = __r8;
338338
/* div/mod emulation */
339-
/* Preserve the values of the dividend and divisor */
340-
emit(__stmdb(__AL, 1, __sp, (1 << rn) | (1 << rm)));
339+
/* Preserve the values of the dividend and divisor. This also keeps stack pointer
340+
* to be aligned.
341+
*/
342+
emit(__stmdb(__AL, 1, __sp, (1 << __r11) | (1 << __r12) | (1 << rn) | (1 << rm)));
341343
/* Obtain absolute values of the dividend and divisor */
342344
emit(__srl_amt(__AL, 0, arith_rs, __r8, rn, 31));
343345
emit(__add_r(__AL, rn, rn, __r8));
@@ -382,7 +384,7 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
382384
* in rd.
383385
*/
384386
emit(__mov_r(__AL, __r9, rn));
385-
emit(__ldm(__AL, 1, __sp, (1 << rn) | (1 << rm)));
387+
emit(__ldm(__AL, 1, __sp, (1 << __r11) | (1 << __r12) | (1 << rn) | (1 << rm)));
386388
emit(__mov_r(__AL, rd, interm));
387389
/* Handle the correct sign for the quotient or remainder */
388390
emit(__cmp_i(__AL, __r10, 0));

src/parser.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,11 @@ void read_expr_operand(block_t *parent, basic_block_t **bb)
844844
read_ternary_operation(parent, bb);
845845
lex_expect(T_close_bracket);
846846
} else if (lex_accept(T_sizeof)) {
847+
/* TODO: Use more generalized type grammar parsing function to handle
848+
* type reading
849+
*/
847850
char token[MAX_TYPE_LEN];
851+
int ptr_cnt = 0;
848852

849853
lex_expect(T_open_bracket);
850854
int find_type_flag = lex_accept(T_struct) ? 2 : 1;
@@ -853,9 +857,12 @@ void read_expr_operand(block_t *parent, basic_block_t **bb)
853857
if (!type)
854858
error("Unable to find type");
855859

860+
while (lex_accept(T_asterisk))
861+
ptr_cnt++;
862+
856863
ph1_ir = add_ph1_ir(OP_load_constant);
857864
vd = require_var(parent);
858-
vd->init_val = type->size;
865+
vd->init_val = ptr_cnt ? PTR_SIZE : type->size;
859866
strcpy(vd->var_name, gen_name());
860867
ph1_ir->dest = vd;
861868
opstack_push(vd);

tests/driver.sh

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,22 @@
22

33
set -u
44

5-
readonly SHECC="$PWD/out/shecc"
5+
if [ "$#" != 1 ]; then
6+
echo "Usage: $0 <stage>"
7+
exit 1
8+
fi
9+
10+
case "$1" in
11+
"0")
12+
readonly SHECC="$PWD/out/shecc" ;;
13+
"1")
14+
readonly SHECC="$PWD/out/shecc-stage1.elf" ;;
15+
"2")
16+
readonly SHECC="$PWD/out/shecc-stage2.elf" ;;
17+
*)
18+
echo "$1 is not a valid stage"
19+
exit 1 ;;
20+
esac
621

722
# try - test shecc with given code
823
# Usage:
@@ -405,8 +420,36 @@ items 5 "int a; a = 10; a -= 5; return a;"
405420
items 20 "int *p; int a[3]; a[0] = 10; a[1] = 20; a[2] = 30; p = a; p+=1; return p[0];"
406421

407422
# sizeof
408-
expr 4 "sizeof(int)";
423+
expr 0 "sizeof(void)";
424+
expr 1 "sizeof(_Bool)";
409425
expr 1 "sizeof(char)";
426+
expr 4 "sizeof(int)";
427+
# sizeof pointers
428+
expr 4 "sizeof(void*)";
429+
expr 4 "sizeof(_Bool*)";
430+
expr 4 "sizeof(char*)";
431+
expr 4 "sizeof(int*)";
432+
# sizeof multi-level pointer
433+
expr 4 "sizeof(void**)";
434+
expr 4 "sizeof(_Bool**)";
435+
expr 4 "sizeof(char**)";
436+
expr 4 "sizeof(int**)";
437+
# sizeof struct
438+
try_ 4 << EOF
439+
typedef struct {
440+
int a;
441+
int b;
442+
} struct_t;
443+
int main() { return sizeof(struct_t*); }
444+
EOF
445+
# sizeof enum
446+
try_ 4 << EOF
447+
typedef enum {
448+
A,
449+
B
450+
} enum_t;
451+
int main() { return sizeof(enum_t*); }
452+
EOF
410453

411454
# switch-case
412455
items 10 "int a; a = 0; switch (3) { case 0: return 2; case 3: a = 10; break; case 1: return 0; } return a;"

0 commit comments

Comments
 (0)