Skip to content

Commit

Permalink
Merge pull request #171 from ChAoSUnItY/feat/sizeof
Browse files Browse the repository at this point in the history
Support pointer data types for sizeof operator
  • Loading branch information
jserv authored Dec 15, 2024
2 parents 18e005d + 10ef491 commit 5b47efd
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 15 deletions.
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,18 @@ $(OUT)/tests/%.elf: tests/%.c $(OUT)/$(STAGE0)
chmod +x $@ ; $(PRINTF) "Running $@ ...\n"
$(Q)$(TARGET_EXEC) $@ && $(call pass)

check: $(TESTBINS) tests/driver.sh
tests/driver.sh
check: check-stage0 check-stage2

check-stage0: $(OUT)/$(STAGE0) $(TESTBINS) tests/driver.sh
$(VECHO) " TEST STAGE 0\n"
tests/driver.sh 0

check-stage2: $(OUT)/$(STAGE2) $(TESTBINS) tests/driver.sh
$(VECHO) " TEST STAGE 2\n"
tests/driver.sh 2

check-snapshots: $(OUT)/$(STAGE0) $(SNAPSHOTS) tests/check-snapshots.sh
$(VECHO) " TEST SNAPSHOTS\n"
tests/check-snapshots.sh

$(OUT)/%.o: %.c
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,27 @@ Verify that the emitted IRs are identical to the snapshots by specifying `check-
$ make check-snapshots
```

`shecc` comes with unit tests. To run the tests, give `check` as an argument:
`shecc` comes with unit tests consist of stage 0, stage 2. To run these tests, give `check` as an argument:
```shell
$ make check
```

Reference output:
```
TEST STAGE 0
...
int main(int argc, int argv) { exit(sizeof(char)); } => 1
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
int main(int argc, int argv) { int a; a = 0; switch (3) { case 0: return 2; default: a = 10; break; } exit(a); } => 10
OK
TEST STAGE 2
...
int main(int argc, int argv) { exit(sizeof(char*)); }
exit code => 4
output =>
int main(int argc, int argv) { exit(sizeof(int*)); }
exit code => 4
output =>
OK
```

Expand Down
2 changes: 2 additions & 0 deletions lib/c.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define false 0

#if defined(__arm__)
#define __SIZEOF_POINTER__ 4
#define __syscall_exit 1
#define __syscall_read 3
#define __syscall_write 4
Expand All @@ -23,6 +24,7 @@
#define __syscall_munmap 91

#elif defined(__riscv)
#define __SIZEOF_POINTER__ 4
#define __syscall_exit 93
#define __syscall_read 63
#define __syscall_write 64
Expand Down
9 changes: 8 additions & 1 deletion src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,11 @@ void read_expr_operand(block_t *parent, basic_block_t **bb)
read_ternary_operation(parent, bb);
lex_expect(T_close_bracket);
} else if (lex_accept(T_sizeof)) {
/* TODO: Use more generalized type grammar parsing function to handle
* type reading
*/
char token[MAX_TYPE_LEN];
int ptr_cnt = 0;

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

while (lex_accept(T_asterisk))
ptr_cnt++;

ph1_ir = add_ph1_ir(OP_load_constant);
vd = require_var(parent);
vd->init_val = type->size;
vd->init_val = ptr_cnt ? PTR_SIZE : type->size;
strcpy(vd->var_name, gen_name());
ph1_ir->dest = vd;
opstack_push(vd);
Expand Down
23 changes: 18 additions & 5 deletions src/reg-alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@
* dead variable and does NOT wrtie it back to the stack.
*/

/* Aligns size to nearest multiple of 4, this meets
* ARMv7's alignment requirement.
*
* This function should
* be called whenever handling with user-defined type's
* size.
*/
int align_size(int i)
{
return i <= 4 ? 4 : (i + 3) & ~3;
}

bool check_live_out(basic_block_t *bb, var_t *var)
{
for (int i = 0; i < bb->live_out_idx; i++) {
Expand Down Expand Up @@ -239,11 +251,11 @@ void reg_alloc()
src0 = GLOBAL_FUNC.stack_size;
if (global_insn->rd->is_ptr)
GLOBAL_FUNC.stack_size +=
(PTR_SIZE * global_insn->rd->array_size);
align_size(PTR_SIZE * global_insn->rd->array_size);
else {
type_t *type = find_type(global_insn->rd->type_name, 0);
GLOBAL_FUNC.stack_size +=
(global_insn->rd->array_size * type->size);
align_size(global_insn->rd->array_size * type->size);
}

dest =
Expand All @@ -260,7 +272,7 @@ void reg_alloc()
strcmp(global_insn->rd->type_name, "char") &&
strcmp(global_insn->rd->type_name, "_Bool")) {
type_t *type = find_type(global_insn->rd->type_name, 0);
GLOBAL_FUNC.stack_size += type->size;
GLOBAL_FUNC.stack_size += align_size(type->size);
} else
/* 'char' is aligned to one byte for the convenience */
GLOBAL_FUNC.stack_size += 4;
Expand Down Expand Up @@ -365,9 +377,10 @@ void reg_alloc()
}

if (insn->rd->array_size)
fn->func->stack_size += (insn->rd->array_size * sz);
fn->func->stack_size +=
align_size(insn->rd->array_size * sz);
else
fn->func->stack_size += sz;
fn->func->stack_size += align_size(sz);

dest = prepare_dest(bb, insn->rd, -1, -1);
ir = bb_add_ph2_ir(bb, OP_address_of);
Expand Down
9 changes: 5 additions & 4 deletions src/riscv-codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ void update_elf_offset(ph2_ir_t *ph2_ir)
if (hard_mul_div)
elf_offset += 4;
else
elf_offset += 104;
elf_offset += 108;
return;
case OP_load_data_address:
case OP_neq:
Expand Down Expand Up @@ -331,12 +331,13 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
/* Unsigned integer division */
emit(__addi(__t0, __zero, 0));
emit(__addi(__t1, __zero, 1));
emit(__beq(__t3, __zero, 48));
emit(__beq(__t2, __zero, 44));
emit(__beq(__t3, __zero, 52));
emit(__beq(__t2, __zero, 48));
emit(__beq(__t2, __t3, 20));
emit(__bltu(__t2, __t3, 16));
emit(__slli(__t3, __t3, 1));
emit(__slli(__t1, __t1, 1));
emit(__jal(__zero, -12));
emit(__jal(__zero, -16));
emit(__bltu(__t2, __t3, 12));
emit(__sub(__t2, __t2, __t3));
emit(__add(__t0, __t0, __t1));
Expand Down
47 changes: 45 additions & 2 deletions tests/driver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,22 @@

set -u

readonly SHECC="$PWD/out/shecc"
if [ "$#" != 1 ]; then
echo "Usage: $0 <stage>"
exit 1
fi

case "$1" in
"0")
readonly SHECC="$PWD/out/shecc" ;;
"1")
readonly SHECC="$PWD/out/shecc-stage1.elf" ;;
"2")
readonly SHECC="$PWD/out/shecc-stage2.elf" ;;
*)
echo "$1 is not a valid stage"
exit 1 ;;
esac

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

# sizeof
expr 4 "sizeof(int)";
expr 0 "sizeof(void)";
expr 1 "sizeof(_Bool)";
expr 1 "sizeof(char)";
expr 4 "sizeof(int)";
# sizeof pointers
expr 4 "sizeof(void*)";
expr 4 "sizeof(_Bool*)";
expr 4 "sizeof(char*)";
expr 4 "sizeof(int*)";
# sizeof multi-level pointer
expr 4 "sizeof(void**)";
expr 4 "sizeof(_Bool**)";
expr 4 "sizeof(char**)";
expr 4 "sizeof(int**)";
# sizeof struct
try_ 4 << EOF
typedef struct {
int a;
int b;
} struct_t;
int main() { return sizeof(struct_t*); }
EOF
# sizeof enum
try_ 4 << EOF
typedef enum {
A,
B
} enum_t;
int main() { return sizeof(enum_t*); }
EOF

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

0 comments on commit 5b47efd

Please sign in to comment.