| ... | ... | @@ -63,6 +63,8 @@ void codegen_set_libc_path(CodeGen *g, Buf *libc_path) { |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); |
| 66 | static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry); |
| 67 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue); |
| 66 | 68 | |
| 67 | 69 | |
| 68 | 70 | static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) { |
| ... | ... | @@ -192,6 +194,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 192 | 194 | static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) { |
| 193 | 195 | assert(node->type == NodeTypeArrayAccessExpr); |
| 194 | 196 | |
| 197 | // TODO gen_lvalue |
| 195 | 198 | LLVMValueRef array_ref_value = gen_expr(g, node->data.array_access_expr.array_ref_expr); |
| 196 | 199 | LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript); |
| 197 | 200 | |
| ... | ... | @@ -209,15 +212,34 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) { |
| 209 | 212 | static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) { |
| 210 | 213 | assert(node->type == NodeTypeFieldAccessExpr); |
| 211 | 214 | |
| 212 | | //TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr); |
| 213 | | LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr); |
| 214 | | assert(struct_ptr); |
| 215 | AstNode *struct_expr_node = node->data.field_access_expr.struct_expr; |
| 215 | 216 | |
| 216 | | /* |
| 217 | | if (struct_type->id == TypeTableEntryIdPointer) { |
| 218 | | zig_panic("TODO pointer field struct access"); |
| 217 | LLVMValueRef struct_ptr; |
| 218 | if (struct_expr_node->type == NodeTypeSymbol) { |
| 219 | VariableTableEntry *var = find_variable(struct_expr_node->codegen_node->expr_node.block_context, |
| 220 | &struct_expr_node->data.symbol); |
| 221 | assert(var); |
| 222 | |
| 223 | if (var->is_ptr && var->type->id == TypeTableEntryIdPointer) { |
| 224 | add_debug_source_node(g, node); |
| 225 | struct_ptr = LLVMBuildLoad(g->builder, var->value_ref, ""); |
| 226 | } else { |
| 227 | struct_ptr = var->value_ref; |
| 228 | } |
| 229 | } else if (struct_expr_node->type == NodeTypeFieldAccessExpr) { |
| 230 | struct_ptr = gen_field_access_expr(g, struct_expr_node, true); |
| 231 | TypeTableEntry *field_type = get_expr_type(struct_expr_node); |
| 232 | if (field_type->id == TypeTableEntryIdPointer) { |
| 233 | // we have a double pointer so we must dereference it once |
| 234 | add_debug_source_node(g, node); |
| 235 | struct_ptr = LLVMBuildLoad(g->builder, struct_ptr, ""); |
| 236 | } |
| 237 | } else { |
| 238 | struct_ptr = gen_expr(g, struct_expr_node); |
| 219 | 239 | } |
| 220 | | */ |
| 240 | |
| 241 | assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind); |
| 242 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind); |
| 221 | 243 | |
| 222 | 244 | FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node; |
| 223 | 245 | |
| ... | ... | @@ -229,15 +251,20 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou |
| 229 | 251 | return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, ""); |
| 230 | 252 | } |
| 231 | 253 | |
| 232 | | static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) { |
| 254 | static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { |
| 233 | 255 | assert(node->type == NodeTypeArrayAccessExpr); |
| 234 | 256 | |
| 235 | 257 | LLVMValueRef ptr = gen_array_ptr(g, node); |
| 236 | | add_debug_source_node(g, node); |
| 237 | | return LLVMBuildLoad(g->builder, ptr, ""); |
| 258 | |
| 259 | if (is_lvalue) { |
| 260 | return ptr; |
| 261 | } else { |
| 262 | add_debug_source_node(g, node); |
| 263 | return LLVMBuildLoad(g->builder, ptr, ""); |
| 264 | } |
| 238 | 265 | } |
| 239 | 266 | |
| 240 | | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) { |
| 267 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { |
| 241 | 268 | assert(node->type == NodeTypeFieldAccessExpr); |
| 242 | 269 | |
| 243 | 270 | TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr); |
| ... | ... | @@ -255,21 +282,26 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) { |
| 255 | 282 | { |
| 256 | 283 | TypeTableEntry *type_entry; |
| 257 | 284 | LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry); |
| 258 | | return LLVMBuildLoad(g->builder, ptr, ""); |
| 285 | if (is_lvalue) { |
| 286 | return ptr; |
| 287 | } else { |
| 288 | add_debug_source_node(g, node); |
| 289 | return LLVMBuildLoad(g->builder, ptr, ""); |
| 290 | } |
| 259 | 291 | } else { |
| 260 | 292 | zig_panic("gen_field_access_expr bad struct type"); |
| 261 | 293 | } |
| 262 | 294 | } |
| 263 | 295 | |
| 264 | | static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *parent_node, AstNode *node, |
| 296 | static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, |
| 265 | 297 | TypeTableEntry **out_type_entry) |
| 266 | 298 | { |
| 267 | 299 | LLVMValueRef target_ref; |
| 268 | 300 | |
| 269 | 301 | if (node->type == NodeTypeSymbol) { |
| 270 | | VariableTableEntry *var = find_variable(parent_node->codegen_node->expr_node.block_context, |
| 302 | VariableTableEntry *var = find_variable(expr_node->codegen_node->expr_node.block_context, |
| 271 | 303 | &node->data.symbol); |
| 272 | | |
| 304 | assert(var); |
| 273 | 305 | // semantic checking ensures no variables are constant |
| 274 | 306 | assert(!var->is_const); |
| 275 | 307 | |
| ... | ... | @@ -631,6 +663,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { |
| 631 | 663 | AstNode *lhs_node = node->data.bin_op_expr.op1; |
| 632 | 664 | |
| 633 | 665 | TypeTableEntry *op1_type; |
| 666 | |
| 634 | 667 | LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type); |
| 635 | 668 | |
| 636 | 669 | LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2); |
| ... | ... | @@ -957,9 +990,9 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 957 | 990 | case NodeTypeFnCallExpr: |
| 958 | 991 | return gen_fn_call_expr(g, node); |
| 959 | 992 | case NodeTypeArrayAccessExpr: |
| 960 | | return gen_array_access_expr(g, node); |
| 993 | return gen_array_access_expr(g, node, false); |
| 961 | 994 | case NodeTypeFieldAccessExpr: |
| 962 | | return gen_field_access_expr(g, node); |
| 995 | return gen_field_access_expr(g, node, false); |
| 963 | 996 | case NodeTypeUnreachable: |
| 964 | 997 | add_debug_source_node(g, node); |
| 965 | 998 | return LLVMBuildUnreachable(g->builder); |
| ... | ... | @@ -1153,7 +1186,7 @@ static void do_code_gen(CodeGen *g) { |
| 1153 | 1186 | assert(proto_node->type == NodeTypeFnProto); |
| 1154 | 1187 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 1155 | 1188 | |
| 1156 | | LLVMTypeRef ret_type = fn_proto_type_from_type_node(g, fn_proto->return_type); |
| 1189 | LLVMTypeRef ret_type = get_type_for_type_node(g, fn_proto->return_type)->type_ref; |
| 1157 | 1190 | int param_count = count_non_void_params(g, &fn_proto->params); |
| 1158 | 1191 | LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count); |
| 1159 | 1192 | int gen_param_index = 0; |