aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.c7
-rw-r--r--src/ast.h2
-rw-r--r--src/codegen.c42
-rw-r--r--src/parse.c3
4 files changed, 52 insertions, 2 deletions
diff --git a/src/ast.c b/src/ast.c
index 84fe38e..d698543 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -282,6 +282,13 @@ AstNode* ast_new_member_access_expr(AstNode* obj, const char* name) {
return e;
}
+AstNode* ast_new_cast_expr(AstNode* operand, Type* result_ty) {
+ AstNode* e = ast_new(AstNodeKind_cast_expr);
+ e->node_operand = operand;
+ e->ty = result_ty;
+ return e;
+}
+
int type_sizeof_struct(Type* ty) {
int next_offset = 0;
int struct_align = 0;
diff --git a/src/ast.h b/src/ast.h
index e0d8410..ce84739 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -89,6 +89,7 @@ typedef enum {
AstNodeKind_assign_expr,
AstNodeKind_binary_expr,
AstNodeKind_break_stmt,
+ AstNodeKind_cast_expr,
AstNodeKind_cond_expr,
AstNodeKind_continue_stmt,
AstNodeKind_deref_expr,
@@ -178,5 +179,6 @@ AstNode* ast_new_assign_sub_expr(AstNode* lhs, AstNode* rhs);
AstNode* ast_new_ref_expr(AstNode* operand);
AstNode* ast_new_deref_expr(AstNode* operand);
AstNode* ast_new_member_access_expr(AstNode* obj, const char* name);
+AstNode* ast_new_cast_expr(AstNode* operand, Type* result_ty);
#endif
diff --git a/src/codegen.c b/src/codegen.c
index 000126b..dccabe4 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -134,6 +134,46 @@ static void codegen_deref_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) {
}
}
+static void codegen_cast_expr(CodeGen* g, AstNode* ast) {
+ codegen_expr(g, ast->node_operand, GenMode_rval);
+
+ int src_size = type_sizeof(ast->node_operand->ty);
+ int dst_size = type_sizeof(ast->ty);
+
+ if (src_size == dst_size)
+ return;
+
+ fprintf(g->out, " pop rax\n");
+
+ if (dst_size == 1) {
+ fprintf(g->out, " movsx rax, al\n");
+ } else if (dst_size == 2) {
+ if (src_size == 1) {
+ fprintf(g->out, " movsx rax, al\n");
+ } else {
+ fprintf(g->out, " movsx rax, ax\n");
+ }
+ } else if (dst_size == 4) {
+ if (src_size == 1) {
+ fprintf(g->out, " movsx rax, al\n");
+ } else if (src_size == 2) {
+ fprintf(g->out, " movsx rax, ax\n");
+ } else {
+ fprintf(g->out, " movsxd rax, eax\n");
+ }
+ } else if (dst_size == 8) {
+ if (src_size == 1) {
+ fprintf(g->out, " movsx rax, al\n");
+ } else if (src_size == 2) {
+ fprintf(g->out, " movsx rax, ax\n");
+ } else if (src_size == 4) {
+ fprintf(g->out, " movsxd rax, eax\n");
+ }
+ }
+
+ fprintf(g->out, " push rax\n");
+}
+
static void codegen_logical_expr(CodeGen* g, AstNode* ast) {
int label = codegen_new_label(g);
@@ -406,6 +446,8 @@ static void codegen_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) {
codegen_ref_expr(g, ast, gen_mode);
} else if (ast->kind == AstNodeKind_deref_expr) {
codegen_deref_expr(g, ast, gen_mode);
+ } else if (ast->kind == AstNodeKind_cast_expr) {
+ codegen_cast_expr(g, ast);
} else if (ast->kind == AstNodeKind_binary_expr) {
codegen_binary_expr(g, ast, gen_mode);
} else if (ast->kind == AstNodeKind_cond_expr) {
diff --git a/src/parse.c b/src/parse.c
index b6fa043..b65a6b3 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -577,8 +577,7 @@ static AstNode* parse_cast_expr(Parser* p) {
// TODO: check whether the original type can be casted to the result type.
AstNode* e = parse_cast_expr(p);
- e->ty = ty;
- return e;
+ return ast_new_cast_expr(e, ty);
}
return parse_prefix_expr(p);
}