2024-01-15 14:17:14 +00:00
|
|
|
#include "macro.h"
|
2024-01-12 17:07:20 +00:00
|
|
|
#include "sys/types.h"
|
2024-01-15 09:03:16 +00:00
|
|
|
#include <unistd.h>
|
2024-01-12 17:07:20 +00:00
|
|
|
#include <assert.h>
|
2024-01-13 02:08:10 +00:00
|
|
|
#include <check.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2024-01-12 17:07:20 +00:00
|
|
|
#include <time.h>
|
2024-01-13 02:10:36 +00:00
|
|
|
#include <addrexp.h>
|
|
|
|
#include <addrexp_lex.h>
|
2024-01-15 14:26:51 +00:00
|
|
|
#include <isa.h>
|
2024-01-15 14:17:14 +00:00
|
|
|
#include <reg.h>
|
2024-01-12 15:23:43 +00:00
|
|
|
|
2024-01-13 01:25:24 +00:00
|
|
|
char buf[65536] = {}, ref_buf[65536] = {};
|
2024-01-12 18:55:41 +00:00
|
|
|
static char code_buf[65536 + 128] = {}; // a little larger than `buf`
|
|
|
|
const int buf_start_pos = 0;
|
2024-01-13 01:25:24 +00:00
|
|
|
char *buf_ptr = buf + buf_start_pos, *ref_buf_ptr = ref_buf;
|
2024-01-13 02:08:10 +00:00
|
|
|
static char *code_format = "#include <stdio.h>\n"
|
|
|
|
"#include <stdint.h>\n"
|
|
|
|
"int main() { "
|
|
|
|
" uint32_t result = %s; "
|
|
|
|
" printf(\"%%u\", result); "
|
|
|
|
" return 0; "
|
|
|
|
"}";
|
2024-01-12 17:07:20 +00:00
|
|
|
|
|
|
|
void gen(char c) {
|
|
|
|
*(buf_ptr++) = c;
|
2024-01-13 01:26:58 +00:00
|
|
|
*(ref_buf_ptr++) = c;
|
2024-01-12 17:07:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void gen_num(void) {
|
2024-01-13 01:50:01 +00:00
|
|
|
uint32_t num = rand();
|
2024-01-13 01:25:24 +00:00
|
|
|
int len = 0, ref_len = 0;
|
2024-01-13 02:08:10 +00:00
|
|
|
switch (rand() % 3) {
|
|
|
|
case 0:
|
|
|
|
len = snprintf(buf_ptr, 100, "%u", num);
|
|
|
|
ref_len = snprintf(ref_buf_ptr, 100, "%uU", num);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
len = snprintf(buf_ptr, 100, "0x%x", num);
|
|
|
|
ref_len = snprintf(ref_buf_ptr, 100, "%uU", num);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
len = snprintf(buf_ptr, 100, "%d", num);
|
|
|
|
ref_len = snprintf(ref_buf_ptr, 100, "%d", num);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
2024-01-12 17:07:20 +00:00
|
|
|
}
|
2024-01-12 18:55:41 +00:00
|
|
|
buf_ptr += len;
|
2024-01-13 01:25:24 +00:00
|
|
|
ref_buf_ptr += ref_len;
|
2024-01-12 17:07:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void gen_rand_op(void) {
|
2024-01-13 02:08:10 +00:00
|
|
|
switch (rand() % 4) {
|
|
|
|
case 0:
|
|
|
|
gen('+');
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
gen('-');
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
gen('*');
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
gen('/');
|
|
|
|
break;
|
2024-01-12 17:07:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gen_rand_expr(void) {
|
|
|
|
int choice = rand() % 3;
|
2024-01-12 18:58:02 +00:00
|
|
|
if (buf_ptr - buf > 2000) {
|
2024-01-12 18:58:42 +00:00
|
|
|
choice = 0;
|
2024-01-13 02:08:10 +00:00
|
|
|
}
|
2024-01-12 17:07:20 +00:00
|
|
|
switch (choice) {
|
2024-01-13 02:08:10 +00:00
|
|
|
case 0:
|
|
|
|
gen_num();
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
gen('(');
|
|
|
|
gen_rand_expr();
|
|
|
|
gen(')');
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gen_rand_expr();
|
|
|
|
gen(' ');
|
|
|
|
gen_rand_op();
|
|
|
|
gen(' ');
|
|
|
|
gen_rand_expr();
|
|
|
|
break;
|
2024-01-12 17:07:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-12 18:55:41 +00:00
|
|
|
START_TEST(test_expr_random_100) {
|
|
|
|
srand(time(0) + _i * 100);
|
|
|
|
gen_rand_expr();
|
|
|
|
|
2024-01-13 01:25:24 +00:00
|
|
|
sprintf(code_buf, code_format, ref_buf);
|
2024-01-12 18:55:41 +00:00
|
|
|
|
|
|
|
FILE *fp = fopen("/tmp/.code.c", "w");
|
|
|
|
ck_assert(fp != NULL);
|
|
|
|
fputs(code_buf, fp);
|
|
|
|
fclose(fp);
|
|
|
|
|
2024-01-13 02:08:10 +00:00
|
|
|
int ret =
|
|
|
|
system("gcc /tmp/.code.c -Werror=div-by-zero -o /tmp/.expr 2>/dev/null");
|
|
|
|
if (ret == 256) {
|
2024-01-13 01:45:22 +00:00
|
|
|
// Probably devide by zero. Skip
|
|
|
|
goto clean_up;
|
|
|
|
}
|
2024-01-12 18:55:41 +00:00
|
|
|
ck_assert_msg(!ret, "system ret: %d, error: %s", ret, strerror(ret));
|
|
|
|
|
2024-01-13 01:39:21 +00:00
|
|
|
fp = popen("/tmp/.expr", "r");
|
|
|
|
ck_assert(fp != NULL);
|
2024-01-12 18:55:41 +00:00
|
|
|
|
2024-01-13 01:39:21 +00:00
|
|
|
uint32_t reference;
|
|
|
|
ret = fscanf(fp, "%u", &reference);
|
|
|
|
ck_assert(ret == 1);
|
|
|
|
pclose(fp);
|
2024-01-13 02:08:10 +00:00
|
|
|
// fprintf(stderr, "\n\tbuf = %s\n\taddr = %u, reference = %u", buf, addr,
|
|
|
|
// reference);
|
2024-01-12 18:55:41 +00:00
|
|
|
|
2024-01-13 01:42:29 +00:00
|
|
|
yy_scan_string(buf + buf_start_pos);
|
|
|
|
uint32_t addr;
|
|
|
|
ck_assert(!yyparse(&addr));
|
|
|
|
yylex_destroy();
|
|
|
|
|
2024-01-13 02:08:10 +00:00
|
|
|
ck_assert_msg(addr == reference,
|
|
|
|
"\n\tbuf = %s\n\t(addr = %u) != (reference = %u)\n", buf, addr,
|
|
|
|
reference);
|
2024-01-12 18:55:41 +00:00
|
|
|
|
2024-01-13 01:45:22 +00:00
|
|
|
clean_up:
|
2024-01-13 02:08:10 +00:00
|
|
|
while (buf_ptr != buf + buf_start_pos) {
|
2024-01-13 01:25:24 +00:00
|
|
|
*(--buf_ptr) = '\0';
|
|
|
|
}
|
2024-01-13 02:08:10 +00:00
|
|
|
while (ref_buf_ptr != ref_buf) {
|
2024-01-13 01:25:24 +00:00
|
|
|
*(--ref_buf_ptr) = '\0';
|
2024-01-12 17:07:20 +00:00
|
|
|
}
|
2024-01-13 02:08:10 +00:00
|
|
|
}
|
|
|
|
END_TEST
|
|
|
|
|
|
|
|
struct {
|
|
|
|
const char *expr;
|
|
|
|
uint32_t reference;
|
|
|
|
} exprs[] = {
|
|
|
|
{"-1", 0xFFFFFFFFU},
|
2024-01-13 02:13:56 +00:00
|
|
|
{"-0x1", 0xFFFFFFFFU},
|
2024-01-13 02:13:19 +00:00
|
|
|
{"0--1", 0x1},
|
2024-01-13 02:13:56 +00:00
|
|
|
{"0--0x1", 0x1},
|
2024-01-15 09:09:34 +00:00
|
|
|
}, reg_exprs[] = {
|
|
|
|
{"$$0", 0x0},
|
2024-01-13 02:08:10 +00:00
|
|
|
};
|
|
|
|
START_TEST(test_expr_negative_operand) {
|
|
|
|
yy_scan_string(exprs[_i].expr);
|
|
|
|
uint32_t addr;
|
|
|
|
ck_assert(!yyparse(&addr));
|
|
|
|
yylex_destroy();
|
2024-01-12 17:07:20 +00:00
|
|
|
|
2024-01-13 02:08:10 +00:00
|
|
|
ck_assert_msg(addr == exprs[_i].reference,
|
|
|
|
"\n\texpr = %s\n\t(addr = %u) != (reference = %u)\n", exprs[_i].expr,
|
|
|
|
addr, exprs[_i].reference);
|
|
|
|
}
|
|
|
|
END_TEST
|
2024-01-12 17:07:20 +00:00
|
|
|
|
2024-01-15 14:17:14 +00:00
|
|
|
extern const char *regs[];
|
|
|
|
START_TEST(test_expr_plain_register) {
|
|
|
|
int i;
|
|
|
|
char buf[5] = {};
|
|
|
|
// NOTE: need to fix this if want to support more arch
|
|
|
|
buf[0] = '$';
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
strcpy(buf + 1, regs[i]);
|
|
|
|
gpr(i) = i;
|
|
|
|
}
|
|
|
|
for (i = 1; i < 5; i++) {
|
|
|
|
buf[i] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
END_TEST
|
|
|
|
|
2024-01-15 09:09:34 +00:00
|
|
|
START_TEST(test_expr_register) {
|
|
|
|
yy_scan_string(reg_exprs[_i].expr);
|
|
|
|
uint32_t value;
|
|
|
|
ck_assert(!yyparse(&value));
|
|
|
|
yylex_destroy();
|
|
|
|
|
|
|
|
ck_assert_msg(value == reg_exprs[_i].reference,
|
|
|
|
"\n\texpr = %s\n\t(addr = %u) != (reference = %u)\n", reg_exprs[_i].expr,
|
|
|
|
value, reg_exprs[_i].reference);
|
|
|
|
}
|
|
|
|
END_TEST
|
|
|
|
|
2024-01-12 17:07:20 +00:00
|
|
|
Suite *expr_suite(void) {
|
2024-01-13 02:08:10 +00:00
|
|
|
Suite *s;
|
|
|
|
TCase *tc_core;
|
2024-01-12 17:07:20 +00:00
|
|
|
|
2024-01-13 02:08:10 +00:00
|
|
|
s = suite_create("Expr test");
|
|
|
|
tc_core = tcase_create("Core");
|
2024-01-12 17:07:20 +00:00
|
|
|
|
2024-01-13 02:13:34 +00:00
|
|
|
tcase_add_loop_test(tc_core, test_expr_random_100, 0, 20);
|
2024-01-13 02:08:10 +00:00
|
|
|
tcase_add_loop_test(tc_core, test_expr_negative_operand, 0,
|
|
|
|
sizeof(exprs) / sizeof(exprs[0]));
|
2024-01-15 14:17:14 +00:00
|
|
|
tcase_add_loop_test(tc_core, test_expr_plain_register, 0,
|
|
|
|
sizeof(reg_exprs) / sizeof(reg_exprs[0]));
|
2024-01-15 09:09:34 +00:00
|
|
|
tcase_add_loop_test(tc_core, test_expr_register, 0,
|
|
|
|
sizeof(reg_exprs) / sizeof(reg_exprs[0]));
|
2024-01-13 02:08:10 +00:00
|
|
|
suite_add_tcase(s, tc_core);
|
2024-01-12 17:07:20 +00:00
|
|
|
|
2024-01-13 02:08:10 +00:00
|
|
|
return s;
|
2024-01-12 17:07:20 +00:00
|
|
|
}
|
|
|
|
|
2024-01-12 18:55:41 +00:00
|
|
|
int main(void) {
|
2024-01-13 02:08:10 +00:00
|
|
|
int number_failed;
|
|
|
|
Suite *s;
|
|
|
|
SRunner *sr;
|
2024-01-12 17:07:20 +00:00
|
|
|
|
2024-01-13 02:08:10 +00:00
|
|
|
s = expr_suite();
|
|
|
|
sr = srunner_create(s);
|
2024-01-12 17:07:20 +00:00
|
|
|
|
2024-01-13 02:08:10 +00:00
|
|
|
srunner_run_all(sr, CK_NORMAL);
|
|
|
|
number_failed = srunner_ntests_failed(sr);
|
|
|
|
srunner_free(sr);
|
2024-01-12 17:07:20 +00:00
|
|
|
|
2024-01-13 02:08:10 +00:00
|
|
|
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
2024-01-12 17:07:20 +00:00
|
|
|
}
|