Created
April 19, 2019 03:37
-
-
Save karino2/b0aeb68883d6d40377e9d3ba769e160b to your computer and use it in GitHub Desktop.
Answer of jit assignment https://karino2.github.io/c-lesson/casm_link_load.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <sys/mman.h> | |
#include "parser.h" | |
#include "test_util.h" | |
extern int eval(int r0, int r1, char *str); | |
/* | |
JIT | |
*/ | |
int *binary_buf = NULL; | |
int* allocate_executable_buf(int size) { | |
return (int*)mmap(0, size, | |
PROT_READ | PROT_WRITE | PROT_EXEC, | |
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
} | |
void init_jit() { | |
if(binary_buf == NULL) { | |
binary_buf = allocate_executable_buf(1024); | |
} | |
} | |
int binary_pos = 0; | |
void emit_word(int word) { | |
binary_buf[binary_pos++] = word; | |
} | |
int asm_mov_reg(int reg_1st, int reg_2nd) { | |
int oneword = 0xE1A00000; | |
oneword += reg_1st << 12; | |
oneword += reg_2nd; | |
return oneword; | |
} | |
void emit_mov_reg(int reg1, int reg2) { | |
emit_word(asm_mov_reg(reg1, reg2)); | |
} | |
int asm_mov_imm(int reg, int imm_value) { | |
int oneword = 0xE3A00000; | |
oneword += reg << 12; | |
oneword += imm_value; | |
return oneword; | |
} | |
int asm_add_sub_common(int reg1, int dest_reg, int reg3, int baseword) { | |
int oneword = baseword; | |
oneword += reg1 << 16; | |
oneword += dest_reg << 12; | |
oneword += reg3; | |
return oneword; | |
} | |
int asm_add_reg(int reg1, int dest_reg, int reg3) { | |
// p29 | |
// 00I OPCODE = 000 0100 = 0000 100 | |
// OPCODE S = 100 0 = 8 | |
return asm_add_sub_common(reg1, dest_reg, reg3, 0xE0800000); | |
// return asm_add_sub_common(reg1, dest_reg, reg3, 0xE2800000); | |
} | |
int asm_sub_reg(int reg1, int dest_reg, int reg3) { | |
// return asm_add_sub_common(reg1, dest_reg, reg3, 0xE2400000); | |
return asm_add_sub_common(reg1, dest_reg, reg3, 0xE0400000); | |
} | |
// mul r3, r1, r2 | |
// r3 = r1*r2 | |
int asm_mul_reg(int reg_dest, int reg1, int reg2) { | |
// p40. | |
// 0000 | |
// 00AS = 0000 | |
// rd XXXX rs 1001 rm | |
// XXXX is ignored. | |
int oneword = 0xe0000090; | |
oneword += reg_dest<<16; | |
oneword += reg1<<8; | |
oneword += reg2; | |
return oneword; | |
} | |
// always write back. | |
int asm_stmdb(int basereg, int registerlist) { | |
int stmdb = 0xe9200000; | |
stmdb += basereg << 16; | |
stmdb += registerlist; | |
return stmdb; | |
} | |
int asm_ldmia(int basereg, int registerlist) { | |
int ldmia = 0xe8b00000; | |
ldmia += basereg << 16; | |
ldmia += registerlist; | |
return ldmia; | |
} | |
// strdb r0, [r1]! | |
int asm_strdb(int basereg, int destreg) { | |
// p42. | |
// int oneword = 0xE5000000; | |
// int stmdb = 0xe9200000; | |
// 01IP = 0101 = 5 | |
// UBWL = 0010 = 2 | |
int oneword = 0xE5200000; | |
oneword += basereg << 16; | |
oneword += destreg << 12; | |
return oneword; | |
} | |
// ldria r0, [r1]! | |
int asm_ldria(int basereg, int srcreg) { | |
// int ldmia = 0xe8b00000; | |
// 01IP = 0100 = 4 | |
// UBWL = 0011 = 3 | |
int oneword = 0xE4300000; | |
oneword += basereg << 16; | |
oneword += srcreg << 12; | |
return oneword; | |
} | |
void emit_push_reg(int reg) { | |
int word; | |
// word = asm_strdb(reg, 13); | |
word = asm_stmdb(13, 1<<reg); | |
emit_word(word); | |
} | |
// mov r2, val | |
// ldr r2, [r13]! | |
void emit_push_val(int val) { | |
int word; | |
word = asm_mov_imm(2, val); | |
emit_word(word); | |
emit_push_reg(2); | |
} | |
void emit_pop_reg(int reg) { | |
int word; | |
// word = asm_ldria(reg, 13); | |
word = asm_ldmia(13, 1 << reg); | |
emit_word(word); | |
} | |
/* | |
ldria r3 [r13]! | |
ldria r2 [r13]! | |
*/ | |
void emit_pop_r2_r3() { | |
emit_pop_reg(3); | |
emit_pop_reg(2); | |
} | |
// add r2, r2, r3 | |
void emit_add_r2_r3() { | |
int word = asm_add_reg(2, 2, 3); | |
emit_word(word); | |
} | |
void emit_sub_r2_r3() { | |
int word = asm_sub_reg(2, 2, 3); | |
emit_word(word); | |
} | |
void emit_mul_r2_r3() { | |
int word = asm_mul_reg(2, 2, 3); | |
emit_word(word); | |
} | |
int* jit_script(char *input) { | |
binary_pos = 0; | |
struct Substr remain={input, strlen(input)}; | |
int val; | |
while(!is_end(&remain)) { | |
skip_space(&remain); | |
if(is_number(remain.ptr)) { | |
val = parse_number(remain.ptr); | |
emit_push_val(val); | |
skip_token(&remain); | |
continue; | |
}else if(is_register(remain.ptr)) { | |
if(remain.ptr[1] == '1') { | |
emit_push_reg(1); | |
} else { | |
emit_push_reg(0); | |
} | |
skip_token(&remain); | |
continue; | |
} else { | |
// must be op. | |
val = parse_word(&remain); | |
skip_token(&remain); | |
emit_pop_r2_r3(); | |
switch(val) { | |
case OP_ADD: | |
emit_add_r2_r3(); | |
break; | |
case OP_SUB: | |
emit_sub_r2_r3(); | |
break; | |
case OP_MUL: | |
emit_mul_r2_r3(); | |
break; | |
case OP_DIV: | |
fprintf(stderr, "div not supported\n"); | |
exit(1); | |
break; | |
} | |
// result is in r2. | |
emit_push_reg(2); | |
continue; | |
} | |
} | |
// final result, pop to r0 | |
emit_pop_reg(0); | |
emit_mov_reg(15, 14); | |
return binary_buf; | |
} | |
static void run_unit_tests() { | |
printf("all test done\n"); | |
} | |
int main() { | |
int res; | |
int (*funcvar)(int, int); | |
run_unit_tests(); | |
res = eval(1, 5, "3 7 add r1 sub 4 mul"); | |
printf("res=%d\n", res); | |
/* | |
TODO: Make below test pass. | |
*/ | |
init_jit(); | |
funcvar = (int(*)(int,int))jit_script("3 7 add r1 sub 4 mul"); | |
// funcvar = (int(*)(int,int))jit_script("3 7 add 5 sub 4 mul"); | |
// funcvar = (int(*)(int,int))jit_script("3 7 add"); | |
/* | |
// mov r0, #5 | |
binary_buf[0] = 0xe3a00005; | |
// mov r15, r14 | |
binary_buf[1] = 0xe1a0f00e; | |
*/ | |
/* OK | |
binary_pos = 0; | |
int word = asm_mov_imm(2, 3); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_stmdb(13, 1<<2); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_mov_imm(2, 7); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_stmdb(13, 1<<2); | |
printf("%x\n", word); | |
emit_word(word); | |
// 1100 = c | |
word = asm_ldmia(13, 0x0c); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_add_reg(2, 2, 3); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_stmdb(13, 1<<2); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_ldmia(13, 0x01); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_mov_reg(15, 14); | |
printf("%x\n", word); | |
emit_word(word); | |
funcvar = (int(*)(int,int))binary_buf; | |
*/ | |
/* OK | |
binary_pos = 0; | |
int word = asm_mov_imm(2, 8); | |
printf("%x\n", word); | |
emit_word(word); | |
// word = asm_strdb(2, 13); | |
word = asm_stmdb(13, 0x04); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_ldmia(13, 0x01); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_mov_reg(15, 14); | |
printf("%x\n", word); | |
emit_word(word); | |
funcvar = (int(*)(int,int))binary_buf; | |
*/ | |
/* | |
asm_ldria(0, 13); | |
printf("%x\n", word); | |
emit_word(word); | |
*/ | |
/*OK | |
int word = asm_mov_imm(2, 3); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_mov_imm(3, 7); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_add_reg(2, 0, 3); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_mov_reg(15, 14); | |
printf("%x\n", word); | |
emit_word(word); | |
funcvar = (int(*)(int,int))binary_buf; | |
*/ | |
/* OK. | |
int word = asm_mov_imm(0, 5); | |
printf("%x\n", word); | |
emit_word(word); | |
word = asm_mov_reg(15, 14); | |
printf("%x\n", word); | |
emit_word(word); | |
funcvar = (int(*)(int,int))binary_buf; | |
*/ | |
res = funcvar(1, 5); | |
printf("res jit =%d\n", res); | |
assert_int_eq(20, res); | |
res = funcvar(1, 4); | |
assert_int_eq(24, res); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment