diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ast.c | 7 | ||||
| -rw-r--r-- | src/ast.h | 2 | ||||
| -rw-r--r-- | src/codegen.c | 42 | ||||
| -rw-r--r-- | src/parse.c | 3 |
4 files changed, 52 insertions, 2 deletions
@@ -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; @@ -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); } |
