| ... | ... | @@ -21,6 +21,9 @@ |
| 21 | 21 | struct FnTableEntry { |
| 22 | 22 | LLVMValueRef fn_value; |
| 23 | 23 | AstNode *proto_node; |
| 24 | AstNode *fn_def_node; |
| 25 | bool is_extern; |
| 26 | bool internal_linkage; |
| 24 | 27 | }; |
| 25 | 28 | |
| 26 | 29 | enum TypeId { |
| ... | ... | @@ -48,7 +51,6 @@ struct TypeTableEntry { |
| 48 | 51 | struct CodeGen { |
| 49 | 52 | LLVMModuleRef mod; |
| 50 | 53 | AstNode *root; |
| 51 | | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> fn_defs; |
| 52 | 54 | ZigList<ErrorMsg> errors; |
| 53 | 55 | LLVMBuilderRef builder; |
| 54 | 56 | llvm::DIBuilder *dbuilder; |
| ... | ... | @@ -68,6 +70,7 @@ struct CodeGen { |
| 68 | 70 | Buf in_dir; |
| 69 | 71 | ZigList<llvm::DIScope *> block_scopes; |
| 70 | 72 | llvm::DIFile *di_file; |
| 73 | ZigList<FnTableEntry *> fn_defs; |
| 71 | 74 | }; |
| 72 | 75 | |
| 73 | 76 | struct TypeNode { |
| ... | ... | @@ -83,7 +86,6 @@ struct CodeGenNode { |
| 83 | 86 | CodeGen *create_codegen(AstNode *root, Buf *in_full_path) { |
| 84 | 87 | CodeGen *g = allocate<CodeGen>(1); |
| 85 | 88 | g->root = root; |
| 86 | | g->fn_defs.init(32); |
| 87 | 89 | g->fn_table.init(32); |
| 88 | 90 | g->str_table.init(32); |
| 89 | 91 | g->type_table.init(32); |
| ... | ... | @@ -137,11 +139,12 @@ static llvm::DIType *to_llvm_debug_type(AstNode *type_node) { |
| 137 | 139 | |
| 138 | 140 | static bool type_is_unreachable(AstNode *type_node) { |
| 139 | 141 | assert(type_node->type == NodeTypeType); |
| 140 | | return type_node->data.type.type == AstNodeTypeTypePrimitive && |
| 141 | | buf_eql_str(&type_node->data.type.primitive_name, "unreachable"); |
| 142 | assert(type_node->codegen_node); |
| 143 | assert(type_node->codegen_node->data.type_node.entry); |
| 144 | return type_node->codegen_node->data.type_node.entry->id == TypeIdUnreachable; |
| 142 | 145 | } |
| 143 | 146 | |
| 144 | | static void analyze_node(CodeGen *g, AstNode *node); |
| 147 | static void find_declarations(CodeGen *g, AstNode *node); |
| 145 | 148 | |
| 146 | 149 | static void resolve_type_and_recurse(CodeGen *g, AstNode *node) { |
| 147 | 150 | assert(!node->codegen_node); |
| ... | ... | @@ -163,7 +166,7 @@ static void resolve_type_and_recurse(CodeGen *g, AstNode *node) { |
| 163 | 166 | } |
| 164 | 167 | case AstNodeTypeTypePointer: |
| 165 | 168 | { |
| 166 | | analyze_node(g, node->data.type.child_type); |
| 169 | find_declarations(g, node->data.type.child_type); |
| 167 | 170 | TypeNode *child_type_node = &node->data.type.child_type->codegen_node->data.type_node; |
| 168 | 171 | if (child_type_node->entry->id == TypeIdUnreachable) { |
| 169 | 172 | add_node_error(g, node, |
| ... | ... | @@ -192,14 +195,8 @@ static void resolve_type_and_recurse(CodeGen *g, AstNode *node) { |
| 192 | 195 | } |
| 193 | 196 | } |
| 194 | 197 | |
| 195 | | static void analyze_node(CodeGen *g, AstNode *node) { |
| 198 | static void find_declarations(CodeGen *g, AstNode *node) { |
| 196 | 199 | switch (node->type) { |
| 197 | | case NodeTypeRoot: |
| 198 | | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { |
| 199 | | AstNode *child = node->data.root.top_level_decls.at(i); |
| 200 | | analyze_node(g, child); |
| 201 | | } |
| 202 | | break; |
| 203 | 200 | case NodeTypeExternBlock: |
| 204 | 201 | for (int i = 0; i < node->data.extern_block.directives->length; i += 1) { |
| 205 | 202 | AstNode *directive_node = node->data.extern_block.directives->at(i); |
| ... | ... | @@ -215,34 +212,14 @@ static void analyze_node(CodeGen *g, AstNode *node) { |
| 215 | 212 | |
| 216 | 213 | for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) { |
| 217 | 214 | AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i); |
| 218 | | analyze_node(g, fn_decl); |
| 219 | | |
| 215 | assert(fn_decl->type == NodeTypeFnDecl); |
| 220 | 216 | AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto; |
| 217 | find_declarations(g, fn_proto); |
| 221 | 218 | Buf *name = &fn_proto->data.fn_proto.name; |
| 222 | | ZigList<AstNode *> *params = &fn_proto->data.fn_proto.params; |
| 223 | | |
| 224 | | LLVMTypeRef *fn_param_values = allocate<LLVMTypeRef>(params->length); |
| 225 | | for (int param_i = 0; param_i < params->length; param_i += 1) { |
| 226 | | AstNode *param_node = params->at(param_i); |
| 227 | | assert(param_node->type == NodeTypeParamDecl); |
| 228 | | AstNode *param_type = param_node->data.param_decl.type; |
| 229 | | fn_param_values[param_i] = to_llvm_type(param_type); |
| 230 | | } |
| 231 | | AstNode *return_type_node = fn_proto->data.fn_proto.return_type; |
| 232 | | LLVMTypeRef return_type = to_llvm_type(return_type_node); |
| 233 | | |
| 234 | | LLVMTypeRef fn_type = LLVMFunctionType(return_type, fn_param_values, params->length, 0); |
| 235 | | LLVMValueRef fn_val = LLVMAddFunction(g->mod, buf_ptr(name), fn_type); |
| 236 | | LLVMSetLinkage(fn_val, LLVMExternalLinkage); |
| 237 | | LLVMSetFunctionCallConv(fn_val, LLVMCCallConv); |
| 238 | | |
| 239 | | if (type_is_unreachable(return_type_node)) { |
| 240 | | LLVMAddFunctionAttr(fn_val, LLVMNoReturnAttribute); |
| 241 | | } |
| 242 | 219 | |
| 243 | 220 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); |
| 244 | | fn_table_entry->fn_value = fn_val; |
| 245 | 221 | fn_table_entry->proto_node = fn_proto; |
| 222 | fn_table_entry->is_extern = true; |
| 246 | 223 | g->fn_table.put(name, fn_table_entry); |
| 247 | 224 | } |
| 248 | 225 | break; |
| ... | ... | @@ -251,14 +228,74 @@ static void analyze_node(CodeGen *g, AstNode *node) { |
| 251 | 228 | AstNode *proto_node = node->data.fn_def.fn_proto; |
| 252 | 229 | assert(proto_node->type == NodeTypeFnProto); |
| 253 | 230 | Buf *proto_name = &proto_node->data.fn_proto.name; |
| 254 | | auto entry = g->fn_defs.maybe_get(proto_name); |
| 231 | auto entry = g->fn_table.maybe_get(proto_name); |
| 255 | 232 | if (entry) { |
| 256 | 233 | add_node_error(g, node, |
| 257 | 234 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 258 | 235 | } else { |
| 259 | | g->fn_defs.put(proto_name, node); |
| 260 | | analyze_node(g, proto_node); |
| 236 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); |
| 237 | fn_table_entry->proto_node = proto_node; |
| 238 | fn_table_entry->fn_def_node = node; |
| 239 | g->fn_table.put(proto_name, fn_table_entry); |
| 240 | g->fn_defs.append(fn_table_entry); |
| 241 | |
| 242 | find_declarations(g, proto_node); |
| 243 | } |
| 244 | break; |
| 245 | } |
| 246 | case NodeTypeFnProto: |
| 247 | { |
| 248 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { |
| 249 | AstNode *child = node->data.fn_proto.params.at(i); |
| 250 | find_declarations(g, child); |
| 261 | 251 | } |
| 252 | find_declarations(g, node->data.fn_proto.return_type); |
| 253 | break; |
| 254 | } |
| 255 | break; |
| 256 | case NodeTypeParamDecl: |
| 257 | find_declarations(g, node->data.param_decl.type); |
| 258 | break; |
| 259 | case NodeTypeType: |
| 260 | resolve_type_and_recurse(g, node); |
| 261 | break; |
| 262 | case NodeTypeDirective: |
| 263 | // we handled directives in the parent function |
| 264 | break; |
| 265 | case NodeTypeFnDecl: |
| 266 | case NodeTypeStatementReturn: |
| 267 | case NodeTypeRoot: |
| 268 | case NodeTypeBlock: |
| 269 | case NodeTypeExpression: |
| 270 | case NodeTypeFnCall: |
| 271 | zig_unreachable(); |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | static void analyze_node(CodeGen *g, AstNode *node) { |
| 276 | switch (node->type) { |
| 277 | case NodeTypeRoot: |
| 278 | // Iterate once over the top level declarations to build the function table |
| 279 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { |
| 280 | AstNode *child = node->data.root.top_level_decls.at(i); |
| 281 | find_declarations(g, child); |
| 282 | } |
| 283 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { |
| 284 | AstNode *child = node->data.root.top_level_decls.at(i); |
| 285 | analyze_node(g, child); |
| 286 | } |
| 287 | break; |
| 288 | case NodeTypeExternBlock: |
| 289 | for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) { |
| 290 | AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i); |
| 291 | analyze_node(g, fn_decl); |
| 292 | } |
| 293 | break; |
| 294 | case NodeTypeFnDef: |
| 295 | { |
| 296 | AstNode *proto_node = node->data.fn_def.fn_proto; |
| 297 | assert(proto_node->type == NodeTypeFnProto); |
| 298 | analyze_node(g, proto_node); |
| 262 | 299 | break; |
| 263 | 300 | } |
| 264 | 301 | case NodeTypeFnDecl: |
| ... | ... | @@ -282,10 +319,8 @@ static void analyze_node(CodeGen *g, AstNode *node) { |
| 282 | 319 | break; |
| 283 | 320 | |
| 284 | 321 | case NodeTypeType: |
| 285 | | { |
| 286 | | resolve_type_and_recurse(g, node); |
| 287 | | break; |
| 288 | | } |
| 322 | // ignore; we handled types with find_declarations |
| 323 | break; |
| 289 | 324 | case NodeTypeBlock: |
| 290 | 325 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| 291 | 326 | AstNode *child = node->data.block.statements.at(i); |
| ... | ... | @@ -309,12 +344,33 @@ static void analyze_node(CodeGen *g, AstNode *node) { |
| 309 | 344 | } |
| 310 | 345 | break; |
| 311 | 346 | case NodeTypeFnCall: |
| 312 | | for (int i = 0; i < node->data.fn_call.params.length; i += 1) { |
| 313 | | AstNode *child = node->data.fn_call.params.at(i); |
| 314 | | analyze_node(g, child); |
| 347 | { |
| 348 | Buf *name = &node->data.fn_call.name; |
| 349 | |
| 350 | auto entry = g->fn_table.maybe_get(name); |
| 351 | if (!entry) { |
| 352 | add_node_error(g, node, |
| 353 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); |
| 354 | } else { |
| 355 | FnTableEntry *fn_table_entry = entry->value; |
| 356 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| 357 | int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length; |
| 358 | int actual_param_count = node->data.fn_call.params.length; |
| 359 | if (expected_param_count != actual_param_count) { |
| 360 | add_node_error(g, node, |
| 361 | buf_sprintf("wrong number of arguments. Expected %d, got %d.", |
| 362 | expected_param_count, actual_param_count)); |
| 363 | } |
| 364 | } |
| 365 | |
| 366 | for (int i = 0; i < node->data.fn_call.params.length; i += 1) { |
| 367 | AstNode *child = node->data.fn_call.params.at(i); |
| 368 | analyze_node(g, child); |
| 369 | } |
| 370 | break; |
| 315 | 371 | } |
| 316 | | break; |
| 317 | 372 | case NodeTypeDirective: |
| 373 | // we looked at directives in the parent node |
| 318 | 374 | break; |
| 319 | 375 | } |
| 320 | 376 | } |
| ... | ... | @@ -399,7 +455,6 @@ void semantic_analyze(CodeGen *g) { |
| 399 | 455 | |
| 400 | 456 | add_types(g); |
| 401 | 457 | |
| 402 | | // Pass 1. |
| 403 | 458 | analyze_node(g, g->root); |
| 404 | 459 | } |
| 405 | 460 | |
| ... | ... | @@ -415,23 +470,11 @@ static LLVMValueRef gen_fn_call(CodeGen *g, AstNode *fn_call_node) { |
| 415 | 470 | assert(fn_call_node->type == NodeTypeFnCall); |
| 416 | 471 | |
| 417 | 472 | Buf *name = &fn_call_node->data.fn_call.name; |
| 418 | | |
| 419 | | auto entry = g->fn_table.maybe_get(name); |
| 420 | | if (!entry) { |
| 421 | | add_node_error(g, fn_call_node, |
| 422 | | buf_sprintf("undefined function: '%s'", buf_ptr(name))); |
| 423 | | return LLVMConstNull(LLVMInt32Type()); |
| 424 | | } |
| 425 | | FnTableEntry *fn_table_entry = entry->value; |
| 473 | FnTableEntry *fn_table_entry = g->fn_table.get(name); |
| 426 | 474 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| 427 | 475 | int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length; |
| 428 | 476 | int actual_param_count = fn_call_node->data.fn_call.params.length; |
| 429 | | if (expected_param_count != actual_param_count) { |
| 430 | | add_node_error(g, fn_call_node, |
| 431 | | buf_sprintf("wrong number of arguments. Expected %d, got %d.", |
| 432 | | expected_param_count, actual_param_count)); |
| 433 | | return LLVMConstNull(LLVMInt32Type()); |
| 434 | | } |
| 477 | assert(expected_param_count == actual_param_count); |
| 435 | 478 | |
| 436 | 479 | LLVMValueRef *param_values = allocate<LLVMValueRef>(actual_param_count); |
| 437 | 480 | for (int i = 0; i < actual_param_count; i += 1) { |
| ... | ... | @@ -557,6 +600,8 @@ static llvm::DISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnProt |
| 557 | 600 | } |
| 558 | 601 | |
| 559 | 602 | void code_gen(CodeGen *g) { |
| 603 | assert(!g->errors.length); |
| 604 | |
| 560 | 605 | Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING); |
| 561 | 606 | bool is_optimized = g->build_type == CodeGenBuildTypeRelease; |
| 562 | 607 | const char *flags = ""; |
| ... | ... | @@ -570,16 +615,19 @@ void code_gen(CodeGen *g) { |
| 570 | 615 | |
| 571 | 616 | g->di_file = g->dbuilder->createFile(g->compile_unit->getFilename(), g->compile_unit->getDirectory()); |
| 572 | 617 | |
| 573 | | auto it = g->fn_defs.entry_iterator(); |
| 618 | |
| 619 | // Generate function prototypes |
| 620 | auto it = g->fn_table.entry_iterator(); |
| 574 | 621 | for (;;) { |
| 575 | 622 | auto *entry = it.next(); |
| 576 | 623 | if (!entry) |
| 577 | 624 | break; |
| 578 | 625 | |
| 579 | | AstNode *fn_def_node = entry->value; |
| 580 | | AstNodeFnDef *fn_def = &fn_def_node->data.fn_def; |
| 581 | | assert(fn_def->fn_proto->type == NodeTypeFnProto); |
| 582 | | AstNodeFnProto *fn_proto = &fn_def->fn_proto->data.fn_proto; |
| 626 | FnTableEntry *fn_table_entry = entry->value; |
| 627 | |
| 628 | AstNode *proto_node = fn_table_entry->proto_node; |
| 629 | assert(proto_node->type == NodeTypeFnProto); |
| 630 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 583 | 631 | |
| 584 | 632 | LLVMTypeRef ret_type = to_llvm_type(fn_proto->return_type); |
| 585 | 633 | LLVMTypeRef *param_types = allocate<LLVMTypeRef>(fn_proto->params.length); |
| ... | ... | @@ -592,13 +640,29 @@ void code_gen(CodeGen *g) { |
| 592 | 640 | LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, fn_proto->params.length, 0); |
| 593 | 641 | LLVMValueRef fn = LLVMAddFunction(g->mod, buf_ptr(&fn_proto->name), function_type); |
| 594 | 642 | |
| 595 | | bool internal_linkage = false; |
| 596 | | LLVMSetLinkage(fn, internal_linkage ? LLVMPrivateLinkage : LLVMExternalLinkage); |
| 643 | LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMPrivateLinkage : LLVMExternalLinkage); |
| 597 | 644 | |
| 598 | 645 | if (type_is_unreachable(fn_proto->return_type)) { |
| 599 | 646 | LLVMAddFunctionAttr(fn, LLVMNoReturnAttribute); |
| 600 | 647 | } |
| 601 | | LLVMAddFunctionAttr(fn, LLVMNoUnwindAttribute); |
| 648 | if (fn_table_entry->is_extern) { |
| 649 | LLVMSetFunctionCallConv(fn, LLVMCCallConv); |
| 650 | } else { |
| 651 | LLVMAddFunctionAttr(fn, LLVMNoUnwindAttribute); |
| 652 | } |
| 653 | |
| 654 | fn_table_entry->fn_value = fn; |
| 655 | } |
| 656 | |
| 657 | // Generate function definitions. |
| 658 | for (int i = 0; i < g->fn_defs.length; i += 1) { |
| 659 | FnTableEntry *fn_table_entry = g->fn_defs.at(i); |
| 660 | AstNode *fn_def_node = fn_table_entry->fn_def_node; |
| 661 | LLVMValueRef fn = fn_table_entry->fn_value; |
| 662 | |
| 663 | AstNode *proto_node = fn_table_entry->proto_node; |
| 664 | assert(proto_node->type == NodeTypeFnProto); |
| 665 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 602 | 666 | |
| 603 | 667 | // Add debug info. |
| 604 | 668 | llvm::DIScope *fn_scope = g->di_file; |
| ... | ... | @@ -609,17 +673,19 @@ void code_gen(CodeGen *g) { |
| 609 | 673 | llvm::Function *unwrapped_function = reinterpret_cast<llvm::Function*>(llvm::unwrap(fn)); |
| 610 | 674 | llvm::DISubprogram *subprogram = g->dbuilder->createFunction( |
| 611 | 675 | fn_scope, buf_ptr(&fn_proto->name), "", g->di_file, line_number, |
| 612 | | create_di_function_type(g, fn_proto, g->di_file), internal_linkage, |
| 676 | create_di_function_type(g, fn_proto, g->di_file), fn_table_entry->internal_linkage, |
| 613 | 677 | is_definition, scope_line, flags, is_optimized, unwrapped_function); |
| 614 | 678 | |
| 615 | 679 | g->block_scopes.append(subprogram); |
| 616 | 680 | |
| 617 | | |
| 618 | 681 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry"); |
| 619 | 682 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 620 | 683 | |
| 621 | | gen_block(g, fn_def->body); |
| 684 | gen_block(g, fn_def_node->data.fn_def.body); |
| 685 | |
| 686 | g->block_scopes.pop(); |
| 622 | 687 | } |
| 688 | assert(!g->errors.length); |
| 623 | 689 | |
| 624 | 690 | g->dbuilder->finalize(); |
| 625 | 691 | |