add types to IR
This commit is contained in:
parent
a19ea7fbe5
commit
a8d5e0ebf4
@ -9,11 +9,16 @@
|
|||||||
// Operation code definations in the ACC IR(ACIR).
|
// Operation code definations in the ACC IR(ACIR).
|
||||||
enum {
|
enum {
|
||||||
// Loads
|
// Loads
|
||||||
IR_IMM_I32, // immediate integer (32bits)
|
IR_IMM, // load immediate
|
||||||
|
|
||||||
// SSA
|
// SSA
|
||||||
IR_PHI, // phi node in SSA
|
IR_PHI, // phi node in SSA
|
||||||
|
|
||||||
|
// Type casts
|
||||||
|
IR_ZEXT, // zero extend an integer
|
||||||
|
IR_SEXT, // signed extend an integer
|
||||||
|
IR_TRUNC, // truncate an integer
|
||||||
|
|
||||||
// Arithmetic operations
|
// Arithmetic operations
|
||||||
IR_NEG, // negation
|
IR_NEG, // negation
|
||||||
IR_NOT, // bitwise not
|
IR_NOT, // bitwise not
|
||||||
@ -28,6 +33,18 @@ enum {
|
|||||||
IR_NULL,
|
IR_NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Defination of IR type code, which simplier than VType.
|
||||||
|
enum {
|
||||||
|
IRT_VOID, // void
|
||||||
|
IRT_I1, // bool
|
||||||
|
IRT_I32, // 32bits integer
|
||||||
|
IRT_I64, // 64bits integer
|
||||||
|
IRT_PTR, // pointer
|
||||||
|
|
||||||
|
// Guard
|
||||||
|
IRT_EXCEED
|
||||||
|
};
|
||||||
|
|
||||||
// Argument of phi function.
|
// Argument of phi function.
|
||||||
struct IRphi_arg {
|
struct IRphi_arg {
|
||||||
struct llist_node n; // linklist header
|
struct llist_node n; // linklist header
|
||||||
@ -41,13 +58,16 @@ struct IRinstruction {
|
|||||||
struct llist_node n; // linklist header
|
struct llist_node n; // linklist header
|
||||||
int op; // operation code
|
int op; // operation code
|
||||||
int id; // value identifier
|
int id; // value identifier
|
||||||
|
int type; // value type in IR type code
|
||||||
struct IRblock *owner; // the basic block containing this instruction
|
struct IRblock *owner; // the basic block containing this instruction
|
||||||
union {
|
union {
|
||||||
struct { struct IRinstruction *left, *right; }; // left/right operands for calculations
|
struct { struct IRinstruction *left, *right; }; // left/right operands for calculations
|
||||||
struct { struct IRinstruction *cond; // jump condition
|
struct { struct IRinstruction *cond; // jump condition
|
||||||
struct IRblock *bt, *bf; }; // true branch & false branch for conditional jump
|
struct IRblock *bt, *bf; }; // true branch & false branch for conditional jump
|
||||||
struct linklist phi; // Phi instruction argument list
|
struct linklist phi; // Phi instruction argument list
|
||||||
int32_t val_i32; // immediate: integer (32bits)
|
int32_t val_i32; // immediate: 32bits integer
|
||||||
|
int64_t val_i64; // immediate: 64bits integer
|
||||||
|
bool val_i1; // immediate: bool
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -68,16 +88,22 @@ struct IRfunction {
|
|||||||
char *name; // function name
|
char *name; // function name
|
||||||
struct linklist bs; // basic blocks
|
struct linklist bs; // basic blocks
|
||||||
int ins_count; // number of instructions, used for allocating instruction identifier.
|
int ins_count; // number of instructions, used for allocating instruction identifier.
|
||||||
|
struct IRinstruction *null; // an instruction with a value void, considered to have instruction id 0.
|
||||||
|
// This is used for the null object patern.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructs an IRinstruction with an operator, and two operands.
|
// Constructs an IRinstruction with an operator, and two operands.
|
||||||
struct IRinstruction* IRinstruction_new(struct IRblock *owner, int op,
|
struct IRinstruction* IRinstruction_new(struct IRblock *owner, int op, int type,
|
||||||
struct IRinstruction *left, struct IRinstruction *right);
|
struct IRinstruction *left, struct IRinstruction *right);
|
||||||
|
|
||||||
// Constructs a IRinstruction with an integer immediate (32bits).
|
// Constructs an IRinstruction with an integer immediate (32bits).
|
||||||
struct IRinstruction* IRinstruction_new_i32(struct IRblock *owner, int32_t v);
|
struct IRinstruction* IRinstruction_new_i32(struct IRblock *owner, int32_t v);
|
||||||
|
|
||||||
// Constructs a IRinstuction with instruction Q_JMP or Q_BR (which is conditional jump).
|
// Contructs an IRinstruction with an void immediate only.
|
||||||
|
// Use IRfunction.null instead of contructing a new void immediate.
|
||||||
|
struct IRinstruction* IRinstruction_new_void(struct IRblock *owner);
|
||||||
|
|
||||||
|
// Constructs a IRinstuction with instruction IR_JMP or IR_BR (which is conditional jump).
|
||||||
struct IRinstruction* IRinstruction_new_jmp(struct IRblock *owner, int op, struct IRinstruction *cond,
|
struct IRinstruction* IRinstruction_new_jmp(struct IRblock *owner, int op, struct IRinstruction *cond,
|
||||||
struct IRblock *bt, struct IRblock *bf);
|
struct IRblock *bt, struct IRblock *bf);
|
||||||
|
|
||||||
@ -94,7 +120,16 @@ struct IRblock* IRblock_new(struct IRfunction *owner);
|
|||||||
// Allocating instruction identifiers in IRfunction
|
// Allocating instruction identifiers in IRfunction
|
||||||
int IRfunction_alloc_ins(struct IRfunction *self);
|
int IRfunction_alloc_ins(struct IRfunction *self);
|
||||||
|
|
||||||
// Generates Quad Repersentation from an AST
|
// Translates a VType into an IR type code.
|
||||||
|
int IRTypecode_from_VType(const struct VType *v);
|
||||||
|
|
||||||
|
// Returns a string identifier for the given type.
|
||||||
|
const char *IRTypecode_stringify(int self);
|
||||||
|
|
||||||
|
// Returns a string identifier for the given operation code.
|
||||||
|
const char* IRopcode_stringify(int op);
|
||||||
|
|
||||||
|
// Generates IR Repersentation from an AST
|
||||||
struct IRfunction* IRfunction_from_ast(struct Afunction *afunc);
|
struct IRfunction* IRfunction_from_ast(struct Afunction *afunc);
|
||||||
|
|
||||||
// Frees a IRinstruction and all its components.
|
// Frees a IRinstruction and all its components.
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdnoreturn.h>
|
#include <stdnoreturn.h>
|
||||||
|
|
||||||
|
noreturn void fail_unreachable(const char *func_name);
|
||||||
noreturn void fail_type(int line);
|
noreturn void fail_type(int line);
|
||||||
noreturn void fail_todo(const char *func_name);
|
noreturn void fail_todo(const char *func_name);
|
||||||
noreturn void fail_target(const char *target_name);
|
noreturn void fail_target(const char *target_name);
|
||||||
|
@ -1,13 +1,30 @@
|
|||||||
#ifndef ACC_TARGET_H
|
#ifndef ACC_TARGET_H
|
||||||
#define ACC_TARGET_H
|
#define ACC_TARGET_H
|
||||||
|
|
||||||
// Target types
|
#include "vtype.h"
|
||||||
|
|
||||||
|
// Defination of targets.
|
||||||
enum {
|
enum {
|
||||||
TARGET_AST,
|
TARGET_X86_64, // Intel/AMD x86-64
|
||||||
TARGET_ACIR,
|
TARGET_X86_32, // Intel/AMD x86-32
|
||||||
|
TARGET_UNKNOWN_16, // unspecified 16bit instruction set
|
||||||
|
TARGET_UNKNOWN_32, // unspecified 32bit instruction set
|
||||||
|
TARGET_RISCV_32, // RISC-V 32 bits (32 registers)
|
||||||
|
TARGET_RISCV_64, // RISC-V 64 bits (32 registers)
|
||||||
|
|
||||||
|
// Guard
|
||||||
TARGET_NULL,
|
TARGET_NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Target archtechture infomation.
|
||||||
|
struct target_info {
|
||||||
|
int int_size; // size of int(in bytes).
|
||||||
|
int long_size; // size of long(in bytes).
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct target_info Tinfo;
|
||||||
|
|
||||||
int target_parse(const char *target_string);
|
int target_parse(const char *target_string);
|
||||||
|
void Tinfo_load(int target);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,7 +10,6 @@ struct token {
|
|||||||
int line; // token location line number
|
int line; // token location line number
|
||||||
int type; // token type
|
int type; // token type
|
||||||
union { // hold the value of the literal that we scanned in
|
union { // hold the value of the literal that we scanned in
|
||||||
int16_t val_i16;
|
|
||||||
int32_t val_i32;
|
int32_t val_i32;
|
||||||
int64_t val_i64;
|
int64_t val_i64;
|
||||||
char *val_s;
|
char *val_s;
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
enum {
|
enum {
|
||||||
VT_VOID, // void
|
VT_VOID, // void
|
||||||
VT_BOOL, // bool
|
VT_BOOL, // bool
|
||||||
VT_I32, // int32_t
|
VT_I32, // signed 32 bits integer
|
||||||
VT_I64, // int64_t
|
VT_I64, // signed 64 bits integer
|
||||||
|
|
||||||
// Guard
|
// Guard
|
||||||
VT_EXCEED
|
VT_EXCEED
|
||||||
@ -16,7 +16,7 @@ enum {
|
|||||||
|
|
||||||
// Value type in C.
|
// Value type in C.
|
||||||
struct VType {
|
struct VType {
|
||||||
int bt; // base type(first class)
|
int bt; // base type.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find out the type after appling the give ast operator(unary arithmetic variant).
|
// Find out the type after appling the give ast operator(unary arithmetic variant).
|
||||||
|
16
main.c
16
main.c
@ -5,11 +5,12 @@
|
|||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "acir.h"
|
#include "acir.h"
|
||||||
|
#include "util/misc.h"
|
||||||
|
|
||||||
// Print out a usage if started incorrectly
|
// Print out a usage if started incorrectly
|
||||||
static void usage(char *prog) {
|
static void usage(char *prog) {
|
||||||
fprintf(stderr, "ACC the C compiler. built on: %s.\n", __DATE__);
|
fprintf(stderr, "ACC the C compiler. built on: %s.\n", __DATE__);
|
||||||
fprintf(stderr, "Usage: %s target infile (outfile)\n", prog);
|
fprintf(stderr, "Usage: %s target format infile (outfile)\n", prog);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,21 +25,22 @@ void unload(void) {
|
|||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
atexit(unload);
|
atexit(unload);
|
||||||
if (argc < 3) {
|
if (argc < 4) {
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc >= 4) {
|
if (argc >= 5) {
|
||||||
Outfile = fopen(argv[3], "w");
|
Outfile = fopen(argv[4], "w");
|
||||||
} else {
|
} else {
|
||||||
Outfile = stdout;
|
Outfile = stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
int target = target_parse(argv[1]);
|
int target = target_parse(argv[1]);
|
||||||
struct Afunction *afunc = Afunction_from_source(argv[2]);
|
Tinfo_load(target);
|
||||||
if (target == TARGET_AST) {
|
struct Afunction *afunc = Afunction_from_source(argv[3]);
|
||||||
|
if (strequal(argv[2], "_ast")) {
|
||||||
Afunction_print(Outfile, afunc);
|
Afunction_print(Outfile, afunc);
|
||||||
} else if (target == TARGET_ACIR) {
|
} else if (strequal(argv[2], "_ir")) {
|
||||||
struct IRfunction *ir = IRfunction_from_ast(afunc);
|
struct IRfunction *ir = IRfunction_from_ast(afunc);
|
||||||
IRfunction_print(ir, Outfile);
|
IRfunction_print(ir, Outfile);
|
||||||
IRfunction_free(ir);
|
IRfunction_free(ir);
|
||||||
|
156
src/acir.c
156
src/acir.c
@ -19,11 +19,12 @@ static void IRblock_add_ins(struct IRblock *self, struct IRinstruction *x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constructs an IRinstruction with an operator, and two operands.
|
// Constructs an IRinstruction with an operator, and two operands.
|
||||||
struct IRinstruction* IRinstruction_new(struct IRblock *owner, int op,
|
struct IRinstruction* IRinstruction_new(struct IRblock *owner, int op, int type,
|
||||||
struct IRinstruction *left, struct IRinstruction *right) {
|
struct IRinstruction *left, struct IRinstruction *right) {
|
||||||
IRinstruction_constructor_shared_code
|
IRinstruction_constructor_shared_code
|
||||||
|
|
||||||
self->op = op;
|
self->op = op;
|
||||||
|
self->type = type;
|
||||||
self->left = left;
|
self->left = left;
|
||||||
self->right = right;
|
self->right = right;
|
||||||
|
|
||||||
@ -33,21 +34,33 @@ struct IRinstruction* IRinstruction_new(struct IRblock *owner, int op,
|
|||||||
return (self);
|
return (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructs a IRinstruction with an integer immediate (32bits).
|
// Constructs an IRinstruction with an integer immediate (32bits).
|
||||||
struct IRinstruction* IRinstruction_new_i32(struct IRblock *owner, int32_t v) {
|
struct IRinstruction* IRinstruction_new_i32(struct IRblock *owner, int32_t v) {
|
||||||
IRinstruction_constructor_shared_code
|
IRinstruction_constructor_shared_code
|
||||||
|
|
||||||
self->op = IR_IMM_I32;
|
self->op = IR_IMM;
|
||||||
|
self->type = IRT_I32;
|
||||||
self->val_i32 = v;
|
self->val_i32 = v;
|
||||||
return (self);
|
return (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructs a IRinstuction with instruction Q_JMP or Q_BR (which is conditional jump).
|
// Contructs an IRinstruction with an void immediate only.
|
||||||
|
// Use IRfunction.null instead of contructing a new void immediate.
|
||||||
|
struct IRinstruction* IRinstruction_new_void(struct IRblock *owner) {
|
||||||
|
IRinstruction_constructor_shared_code
|
||||||
|
|
||||||
|
self->op = IR_IMM;
|
||||||
|
self->type = IRT_VOID;
|
||||||
|
return (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a IRinstuction with instruction IR_JMP or IR_BR (which is conditional jump).
|
||||||
struct IRinstruction* IRinstruction_new_jmp(struct IRblock *owner, int op, struct IRinstruction *cond,
|
struct IRinstruction* IRinstruction_new_jmp(struct IRblock *owner, int op, struct IRinstruction *cond,
|
||||||
struct IRblock *bt, struct IRblock *bf) {
|
struct IRblock *bt, struct IRblock *bf) {
|
||||||
IRinstruction_constructor_shared_code
|
IRinstruction_constructor_shared_code
|
||||||
|
|
||||||
self->op = op;
|
self->op = op;
|
||||||
|
self->type = IRT_VOID;
|
||||||
self->cond = cond;
|
self->cond = cond;
|
||||||
self->bt = bt;
|
self->bt = bt;
|
||||||
self->bf = bf;
|
self->bf = bf;
|
||||||
@ -103,8 +116,52 @@ int IRfunction_alloc_ins(struct IRfunction *self) {
|
|||||||
return self->ins_count++;
|
return self->ins_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translates a VType into an IR type code.
|
||||||
|
int IRTypecode_from_VType(const struct VType *v) {
|
||||||
|
int map[][2] = {
|
||||||
|
{VT_VOID, IRT_VOID},
|
||||||
|
{VT_BOOL, IRT_I1},
|
||||||
|
{VT_I32, IRT_I32},
|
||||||
|
{VT_I64, IRT_I64},
|
||||||
|
{VT_EXCEED}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; map[i][0] != VT_EXCEED; ++i) {
|
||||||
|
if (map[i][0] == v->bt) {
|
||||||
|
return (map[i][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_unreachable(__FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IRTypecode_integer_promote(int self) {
|
||||||
|
switch(self) {
|
||||||
|
case IRT_I1: case IRT_I32:
|
||||||
|
return (IRT_I32);
|
||||||
|
case IRT_I64:
|
||||||
|
return (IRT_I64);
|
||||||
|
default:
|
||||||
|
fail_unreachable(__FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a string identifier for the given type.
|
||||||
|
const char *IRTypecode_stringify(int self) {
|
||||||
|
static const char *map[] = {
|
||||||
|
"void",
|
||||||
|
"i1",
|
||||||
|
"i32",
|
||||||
|
"i64",
|
||||||
|
"ptr",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
return map[self];
|
||||||
|
}
|
||||||
|
|
||||||
// Translate an AST unary arithmetic opcode to a IR opcode.
|
// Translate an AST unary arithmetic opcode to a IR opcode.
|
||||||
static int translate_ast_unary_op(int op) {
|
static int IRopcode_from_ast_unary(int op) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case A_NEG: return (IR_NEG);
|
case A_NEG: return (IR_NEG);
|
||||||
case A_BNOT: return (IR_NOT);
|
case A_BNOT: return (IR_NOT);
|
||||||
@ -112,18 +169,40 @@ static int translate_ast_unary_op(int op) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a string identifier for the given operation code.
|
||||||
|
const char* IRopcode_stringify(int self) {
|
||||||
|
static const char *map[] = {
|
||||||
|
"imm",
|
||||||
|
"phi",
|
||||||
|
"zext",
|
||||||
|
"sext",
|
||||||
|
"trunc",
|
||||||
|
"neg",
|
||||||
|
"not",
|
||||||
|
"eq",
|
||||||
|
"ret",
|
||||||
|
"jmp",
|
||||||
|
"br",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
return map[self];
|
||||||
|
}
|
||||||
|
|
||||||
|
// DFS on an AST and build IR.
|
||||||
static struct IRinstruction* IRcg_dfs(struct ASTnode *x, struct IRfunction *f, struct IRblock *b) {
|
static struct IRinstruction* IRcg_dfs(struct ASTnode *x, struct IRfunction *f, struct IRblock *b) {
|
||||||
|
// nothing to do, return the null object.
|
||||||
if (x == NULL) {
|
if (x == NULL) {
|
||||||
return (NULL);
|
return (f->null);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (x->op) {
|
switch (x->op) {
|
||||||
case A_RETURN: {
|
case A_RETURN: {
|
||||||
struct ASTunnode *t = (void*)x;
|
struct ASTunnode *t = (void*)x;
|
||||||
struct IRinstruction *value = IRcg_dfs(t->left, f, b);
|
struct IRinstruction *value = IRcg_dfs(t->left, f, b);
|
||||||
IRinstruction_new(b, IR_RET, value, NULL);
|
IRinstruction_new(b, IR_RET, IRT_VOID, value, NULL);
|
||||||
b->is_complete = true;
|
b->is_complete = true;
|
||||||
return (NULL);
|
return (f->null);
|
||||||
}
|
}
|
||||||
|
|
||||||
case A_BLOCK: {
|
case A_BLOCK: {
|
||||||
@ -133,7 +212,7 @@ static struct IRinstruction* IRcg_dfs(struct ASTnode *x, struct IRfunction *f, s
|
|||||||
IRcg_dfs((struct ASTnode*)p, f, b);
|
IRcg_dfs((struct ASTnode*)p, f, b);
|
||||||
p = p->nxt;
|
p = p->nxt;
|
||||||
}
|
}
|
||||||
return (NULL);
|
return (f->null);
|
||||||
}
|
}
|
||||||
|
|
||||||
case A_LIT_I32: {
|
case A_LIT_I32: {
|
||||||
@ -144,14 +223,21 @@ static struct IRinstruction* IRcg_dfs(struct ASTnode *x, struct IRfunction *f, s
|
|||||||
case A_NEG: case A_BNOT: {
|
case A_NEG: case A_BNOT: {
|
||||||
struct ASTunnode *t = (void*)x;
|
struct ASTunnode *t = (void*)x;
|
||||||
struct IRinstruction *value = IRcg_dfs(t->left, f, b);
|
struct IRinstruction *value = IRcg_dfs(t->left, f, b);
|
||||||
return (IRinstruction_new(b, translate_ast_unary_op(x->op), value, NULL));
|
|
||||||
|
int type = IRTypecode_integer_promote(value->type);
|
||||||
|
if (type != value->type) {
|
||||||
|
value = IRinstruction_new(b, IR_SEXT, type, value, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (IRinstruction_new(b, IRopcode_from_ast_unary(x->op), type, value, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
case A_LNOT: {
|
case A_LNOT: {
|
||||||
struct ASTunnode *t = (void*)x;
|
struct ASTunnode *t = (void*)x;
|
||||||
|
// A logical not operation is basicly equivlant to comparing the value to 0.
|
||||||
struct IRinstruction *value = IRcg_dfs(t->left, f, b),
|
struct IRinstruction *value = IRcg_dfs(t->left, f, b),
|
||||||
*zero = IRinstruction_new_i32(b, 0);
|
*zero = IRinstruction_new_i32(b, 0);
|
||||||
return (IRinstruction_new(b, IR_CMP_EQ, value, zero));
|
return (IRinstruction_new(b, IR_CMP_EQ, IRT_I1, value, zero));
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
@ -160,7 +246,7 @@ static struct IRinstruction* IRcg_dfs(struct ASTnode *x, struct IRfunction *f, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates Quad Repersentation from an AST
|
// Generates IR Repersentation from an AST
|
||||||
struct IRfunction* IRfunction_from_ast(struct Afunction *afunc) {
|
struct IRfunction* IRfunction_from_ast(struct Afunction *afunc) {
|
||||||
struct IRfunction *self = try_malloc(sizeof(struct IRfunction), __FUNCTION__);
|
struct IRfunction *self = try_malloc(sizeof(struct IRfunction), __FUNCTION__);
|
||||||
|
|
||||||
@ -170,8 +256,9 @@ struct IRfunction* IRfunction_from_ast(struct Afunction *afunc) {
|
|||||||
self->ins_count = 0;
|
self->ins_count = 0;
|
||||||
llist_init(&self->bs);
|
llist_init(&self->bs);
|
||||||
|
|
||||||
struct IRblock *entry = IRblock_new(self);
|
struct IRblock *entry = IRblock_new(self); // construct the function entry block.
|
||||||
IRcg_dfs(afunc->rt, self, entry);
|
self->null = IRinstruction_new_void(entry); // initialize the null object.
|
||||||
|
IRcg_dfs(afunc->rt, self, entry); // generate code by doing a DFS in our AST.
|
||||||
return (self);
|
return (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,28 +300,41 @@ void IRfunction_free(struct IRfunction *self) {
|
|||||||
// Outputs the instruction.
|
// Outputs the instruction.
|
||||||
void IRinstruction_print(struct IRinstruction *self, FILE *Outfile) {
|
void IRinstruction_print(struct IRinstruction *self, FILE *Outfile) {
|
||||||
switch(self->op) {
|
switch(self->op) {
|
||||||
case IR_IMM_I32: {
|
case IR_IMM: {
|
||||||
fprintf(Outfile, "\t$%d = i32 %d;\n", self->id, self->val_i32);
|
fprintf(Outfile, "\t$%d = %s", self->id, IRTypecode_stringify(self->type));
|
||||||
|
switch (self->type) {
|
||||||
|
case IRT_VOID: {
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case IRT_I1: {
|
||||||
|
fprintf(Outfile, " %s", self->val_i1 ? "true" : "false");
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case IRT_I32: {
|
||||||
|
fprintf(Outfile, " %d", self->val_i32);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case IRT_I64: {
|
||||||
|
fprintf(Outfile, " %lld", self->val_i64);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
fputs(";\n", Outfile);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case IR_RET: {
|
case IR_RET: {
|
||||||
if (self->left) {
|
|
||||||
fprintf(Outfile, "\tret $%d.\n", self->left->id);
|
fprintf(Outfile, "\tret $%d.\n", self->left->id);
|
||||||
} else {
|
|
||||||
fputs("\tret.", Outfile);
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case IR_NEG: {
|
case IR_SEXT: case IR_ZEXT: case IR_TRUNC:
|
||||||
fprintf(Outfile, "\t$%d = neg $%d;\n", self->id, self->left->id);
|
case IR_NEG: case IR_NOT: {
|
||||||
} break;
|
fprintf(Outfile, "\t$%d = %s %s $%d;\n", self->id,
|
||||||
|
IRTypecode_stringify(self->type), IRopcode_stringify(self->op), self->left->id);
|
||||||
case IR_NOT: {
|
|
||||||
fprintf(Outfile, "\t$%d = not $%d;\n", self->id, self->left->id);
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case IR_CMP_EQ: {
|
case IR_CMP_EQ: {
|
||||||
fprintf(Outfile, "\t$%d = eq $%d, $%d;\n", self->id, self->left->id, self->right->id);
|
fprintf(Outfile, "\t$%d = %s %s $%d $%d;\n", self->id
|
||||||
|
, IRTypecode_stringify(self->type), IRopcode_stringify(self->op), self->left->id
|
||||||
|
, self->right->id);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
@ -246,6 +346,7 @@ void IRinstruction_print(struct IRinstruction *self, FILE *Outfile) {
|
|||||||
// Outputs the containing instructions of the IRblock.
|
// Outputs the containing instructions of the IRblock.
|
||||||
void IRblock_print(struct IRblock *self, FILE *Outfile) {
|
void IRblock_print(struct IRblock *self, FILE *Outfile) {
|
||||||
fprintf(Outfile, "L%d:\n", self->id);
|
fprintf(Outfile, "L%d:\n", self->id);
|
||||||
|
|
||||||
struct llist_node *p = self->ins.head;
|
struct llist_node *p = self->ins.head;
|
||||||
while (p) {
|
while (p) {
|
||||||
IRinstruction_print((void*)p, Outfile);
|
IRinstruction_print((void*)p, Outfile);
|
||||||
@ -256,6 +357,7 @@ void IRblock_print(struct IRblock *self, FILE *Outfile) {
|
|||||||
// Outputs the containing instructions of the IRfunction.
|
// Outputs the containing instructions of the IRfunction.
|
||||||
void IRfunction_print(struct IRfunction *self, FILE *Outfile) {
|
void IRfunction_print(struct IRfunction *self, FILE *Outfile) {
|
||||||
fprintf(Outfile, "%s:\n", self->name);
|
fprintf(Outfile, "%s:\n", self->name);
|
||||||
|
|
||||||
struct llist_node *p = self->bs.head;
|
struct llist_node *p = self->bs.head;
|
||||||
while (p) {
|
while (p) {
|
||||||
IRblock_print((void*)p, Outfile);
|
IRblock_print((void*)p, Outfile);
|
||||||
|
@ -10,6 +10,11 @@ void fail_todo(const char *func_name) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fail_unreachable(const char *func_name) {
|
||||||
|
fprintf(stderr, "%s: Unreachable reached.", func_name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
void fail_type(int line) {
|
void fail_type(int line) {
|
||||||
fprintf(stderr, "sytax error on line %d: incorrect or incomplete type.\n", line);
|
fprintf(stderr, "sytax error on line %d: incorrect or incomplete type.\n", line);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
46
src/target.c
46
src/target.c
@ -6,14 +6,22 @@
|
|||||||
// Parse the target string
|
// Parse the target string
|
||||||
int target_parse(const char *target_string) {
|
int target_parse(const char *target_string) {
|
||||||
static const char *target_map_k[] = {
|
static const char *target_map_k[] = {
|
||||||
"_ast",
|
"x86_64",
|
||||||
"_acir",
|
"x86",
|
||||||
|
"unknown16",
|
||||||
|
"unknown32",
|
||||||
|
"riscv_32",
|
||||||
|
"riscv_64",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int target_map_v[] = {
|
static const int target_map_v[] = {
|
||||||
TARGET_AST,
|
TARGET_X86_64,
|
||||||
TARGET_ACIR,
|
TARGET_X86_32,
|
||||||
|
TARGET_UNKNOWN_16,
|
||||||
|
TARGET_UNKNOWN_32,
|
||||||
|
TARGET_RISCV_32,
|
||||||
|
TARGET_RISCV_64,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; target_map_k[i]; ++i) {
|
for (int i = 0; target_map_k[i]; ++i) {
|
||||||
@ -24,3 +32,33 @@ int target_parse(const char *target_string) {
|
|||||||
|
|
||||||
fail_target(target_string);
|
fail_target(target_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct target_info Tinfo;
|
||||||
|
|
||||||
|
void Tinfo_load(int target) {
|
||||||
|
static struct target_info map[] = {
|
||||||
|
{ // x86-64
|
||||||
|
.int_size = 4,
|
||||||
|
.long_size = 8,
|
||||||
|
}, { // x84
|
||||||
|
.int_size = 4,
|
||||||
|
.long_size = 4,
|
||||||
|
}, { // unknown16
|
||||||
|
.int_size = 2,
|
||||||
|
.long_size = 2,
|
||||||
|
}, { // unknown32
|
||||||
|
.int_size = 4,
|
||||||
|
.long_size = 4,
|
||||||
|
}, { // riscv_32
|
||||||
|
.int_size = 4,
|
||||||
|
.long_size = 4,
|
||||||
|
}, { // riscv_64
|
||||||
|
.int_size = 4,
|
||||||
|
.long_size = 8
|
||||||
|
}};
|
||||||
|
|
||||||
|
if (target < 0 || target >= TARGET_NULL) {
|
||||||
|
fail_unreachable(__FUNCTION__);
|
||||||
|
}
|
||||||
|
Tinfo = map[target];
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
#include "util/critbit.h"
|
#include "util/critbit.h"
|
||||||
#include "util/misc.h"
|
#include "util/misc.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
// critbit tree internal node
|
// critbit tree internal node
|
||||||
struct critbit_intern {
|
struct critbit_intern {
|
||||||
@ -179,7 +180,7 @@ struct critbit_node *critbit_erase(struct critbit_tree *self, const char *key) {
|
|||||||
void **wherep = &self->rt;
|
void **wherep = &self->rt;
|
||||||
void **whereq = NULL;
|
void **whereq = NULL;
|
||||||
struct critbit_intern *p = self->rt, *q;
|
struct critbit_intern *p = self->rt, *q;
|
||||||
const size_t len = strlen(str);
|
const size_t len = strlen(key);
|
||||||
|
|
||||||
while (p->type == 0) {
|
while (p->type == 0) {
|
||||||
whereq = wherep;
|
whereq = wherep;
|
||||||
@ -197,10 +198,10 @@ struct critbit_node *critbit_erase(struct critbit_tree *self, const char *key) {
|
|||||||
|
|
||||||
if (!whereq) {
|
if (!whereq) {
|
||||||
self->rt = NULL;
|
self->rt = NULL;
|
||||||
return (p);
|
return ((void*)p);
|
||||||
}
|
}
|
||||||
|
|
||||||
*whereq = q->child[1 - dir];
|
*whereq = q->child[1 - dir];
|
||||||
free(q);
|
free(q);
|
||||||
return (p);
|
return ((void*)p);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user