Skip to content

Commit 5b47efd

Browse files
authored
Merge pull request #171 from ChAoSUnItY/feat/sizeof
Support pointer data types for sizeof operator
2 parents 18e005d + 10ef491 commit 5b47efd

File tree

7 files changed

+99
-15
lines changed

7 files changed

+99
-15
lines changed

Makefile

+10-2
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

+11-1
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

+2
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/parser.c

+8-1
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);

src/reg-alloc.c

+18-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@
1212
* dead variable and does NOT wrtie it back to the stack.
1313
*/
1414

15+
/* Aligns size to nearest multiple of 4, this meets
16+
* ARMv7's alignment requirement.
17+
*
18+
* This function should
19+
* be called whenever handling with user-defined type's
20+
* size.
21+
*/
22+
int align_size(int i)
23+
{
24+
return i <= 4 ? 4 : (i + 3) & ~3;
25+
}
26+
1527
bool check_live_out(basic_block_t *bb, var_t *var)
1628
{
1729
for (int i = 0; i < bb->live_out_idx; i++) {
@@ -239,11 +251,11 @@ void reg_alloc()
239251
src0 = GLOBAL_FUNC.stack_size;
240252
if (global_insn->rd->is_ptr)
241253
GLOBAL_FUNC.stack_size +=
242-
(PTR_SIZE * global_insn->rd->array_size);
254+
align_size(PTR_SIZE * global_insn->rd->array_size);
243255
else {
244256
type_t *type = find_type(global_insn->rd->type_name, 0);
245257
GLOBAL_FUNC.stack_size +=
246-
(global_insn->rd->array_size * type->size);
258+
align_size(global_insn->rd->array_size * type->size);
247259
}
248260

249261
dest =
@@ -260,7 +272,7 @@ void reg_alloc()
260272
strcmp(global_insn->rd->type_name, "char") &&
261273
strcmp(global_insn->rd->type_name, "_Bool")) {
262274
type_t *type = find_type(global_insn->rd->type_name, 0);
263-
GLOBAL_FUNC.stack_size += type->size;
275+
GLOBAL_FUNC.stack_size += align_size(type->size);
264276
} else
265277
/* 'char' is aligned to one byte for the convenience */
266278
GLOBAL_FUNC.stack_size += 4;
@@ -365,9 +377,10 @@ void reg_alloc()
365377
}
366378

367379
if (insn->rd->array_size)
368-
fn->func->stack_size += (insn->rd->array_size * sz);
380+
fn->func->stack_size +=
381+
align_size(insn->rd->array_size * sz);
369382
else
370-
fn->func->stack_size += sz;
383+
fn->func->stack_size += align_size(sz);
371384

372385
dest = prepare_dest(bb, insn->rd, -1, -1);
373386
ir = bb_add_ph2_ir(bb, OP_address_of);

src/riscv-codegen.c

+5-4
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ void update_elf_offset(ph2_ir_t *ph2_ir)
7272
if (hard_mul_div)
7373
elf_offset += 4;
7474
else
75-
elf_offset += 104;
75+
elf_offset += 108;
7676
return;
7777
case OP_load_data_address:
7878
case OP_neq:
@@ -331,12 +331,13 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
331331
/* Unsigned integer division */
332332
emit(__addi(__t0, __zero, 0));
333333
emit(__addi(__t1, __zero, 1));
334-
emit(__beq(__t3, __zero, 48));
335-
emit(__beq(__t2, __zero, 44));
334+
emit(__beq(__t3, __zero, 52));
335+
emit(__beq(__t2, __zero, 48));
336+
emit(__beq(__t2, __t3, 20));
336337
emit(__bltu(__t2, __t3, 16));
337338
emit(__slli(__t3, __t3, 1));
338339
emit(__slli(__t1, __t1, 1));
339-
emit(__jal(__zero, -12));
340+
emit(__jal(__zero, -16));
340341
emit(__bltu(__t2, __t3, 12));
341342
emit(__sub(__t2, __t2, __t3));
342343
emit(__add(__t0, __t0, __t1));

tests/driver.sh

+45-2
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)