authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-27 15:46:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-27 15:46:06-07:00
log024052b4483b13639e998ef34dc097a24860c612
tree267af11f1d492a1c532a671079ade5520564299a
parent9ca9a2c5540683a54bae597c59152d06d095beef

add pub and export visibility modifiers and optimization


14 files changed, 358 insertions(+), 127 deletions(-)

README.md+5-4
...@@ -27,12 +27,11 @@ readable, safe, optimal, and concise code to solve any computing problem....@@ -27,12 +27,11 @@ readable, safe, optimal, and concise code to solve any computing problem.
27 * Source code is UTF-8.27 * Source code is UTF-8.
28 * Shebang line OK so language can be used for "scripting" as well.28 * Shebang line OK so language can be used for "scripting" as well.
29 * Ability to mark functions as test and automatically run them in test mode.29 * Ability to mark functions as test and automatically run them in test mode.
30 This mode should automatically provide test coverage.
30 * Memory zeroed by default, unless you initialize with "uninitialized".31 * Memory zeroed by default, unless you initialize with "uninitialized".
3132
32## Roadmap33## Roadmap
3334
34 * pub/private/export functions
35 * make sure that release mode optimizes out empty private functions
36 * test framework to test for compile errors35 * test framework to test for compile errors
37 * Simple .so library36 * Simple .so library
38 * Multiple files37 * Multiple files
...@@ -69,11 +68,13 @@ TopLevelDecl : FnDef | ExternBlock...@@ -69,11 +68,13 @@ TopLevelDecl : FnDef | ExternBlock
6968
70ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)69ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)
7170
72FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)71FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
72
73FnVisibleMod : token(Pub) | token(Export)
7374
74FnDecl : FnProto token(Semicolon)75FnDecl : FnProto token(Semicolon)
7576
76FnDef : many(Directive) FnProto Block77FnDef : FnProto Block
7778
78ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)79ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
7980
doc/vim/syntax/zig.vim+1-1
...@@ -7,7 +7,7 @@ if exists("b:current_syntax")...@@ -7,7 +7,7 @@ if exists("b:current_syntax")
7 finish7 finish
8endif8endif
99
10syn keyword zigKeyword fn return mut const extern unreachable10syn keyword zigKeyword fn return mut const extern unreachable export pub
1111
12let b:current_syntax = "zig"12let b:current_syntax = "zig"
1313
example/hello.zig created+10
...@@ -0,0 +1,10 @@
1#link("c")
2extern {
3 fn puts(s: *mut u8) -> i32;
4 fn exit(code: i32) -> unreachable;
5}
6
7export fn _start() -> unreachable {
8 puts("Hello, world!");
9 exit(0);
10}
src/codegen.cpp+34-14
...@@ -26,6 +26,7 @@ struct FnTableEntry {...@@ -26,6 +26,7 @@ struct FnTableEntry {
26 AstNode *fn_def_node;26 AstNode *fn_def_node;
27 bool is_extern;27 bool is_extern;
28 bool internal_linkage;28 bool internal_linkage;
29 unsigned calling_convention;
29};30};
3031
31enum TypeId {32enum TypeId {
...@@ -51,7 +52,7 @@ struct TypeTableEntry {...@@ -51,7 +52,7 @@ struct TypeTableEntry {
51};52};
5253
53struct CodeGen {54struct CodeGen {
54 LLVMModuleRef mod;55 LLVMModuleRef module;
55 AstNode *root;56 AstNode *root;
56 ZigList<ErrorMsg> errors;57 ZigList<ErrorMsg> errors;
57 LLVMBuilderRef builder;58 LLVMBuilderRef builder;
...@@ -228,6 +229,7 @@ static void find_declarations(CodeGen *g, AstNode *node) {...@@ -228,6 +229,7 @@ static void find_declarations(CodeGen *g, AstNode *node) {
228 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);229 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
229 fn_table_entry->proto_node = fn_proto;230 fn_table_entry->proto_node = fn_proto;
230 fn_table_entry->is_extern = true;231 fn_table_entry->is_extern = true;
232 fn_table_entry->calling_convention = LLVMCCallConv;
231 g->fn_table.put(name, fn_table_entry);233 g->fn_table.put(name, fn_table_entry);
232 }234 }
233 break;235 break;
...@@ -244,6 +246,12 @@ static void find_declarations(CodeGen *g, AstNode *node) {...@@ -244,6 +246,12 @@ static void find_declarations(CodeGen *g, AstNode *node) {
244 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);246 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
245 fn_table_entry->proto_node = proto_node;247 fn_table_entry->proto_node = proto_node;
246 fn_table_entry->fn_def_node = node;248 fn_table_entry->fn_def_node = node;
249 fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;
250 if (fn_table_entry->internal_linkage) {
251 fn_table_entry->calling_convention = LLVMFastCallConv;
252 } else {
253 fn_table_entry->calling_convention = LLVMCCallConv;
254 }
247 g->fn_table.put(proto_name, fn_table_entry);255 g->fn_table.put(proto_name, fn_table_entry);
248 g->fn_defs.append(fn_table_entry);256 g->fn_defs.append(fn_table_entry);
249257
...@@ -512,12 +520,12 @@ void semantic_analyze(CodeGen *g) {...@@ -512,12 +520,12 @@ void semantic_analyze(CodeGen *g) {
512 g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);520 g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);
513521
514522
515 g->mod = LLVMModuleCreateWithName("ZigModule");523 g->module = LLVMModuleCreateWithName("ZigModule");
516524
517 g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);525 g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);
518526
519 g->builder = LLVMCreateBuilder();527 g->builder = LLVMCreateBuilder();
520 g->dbuilder = new llvm::DIBuilder(*llvm::unwrap(g->mod), true);528 g->dbuilder = new llvm::DIBuilder(*llvm::unwrap(g->module), true);
521529
522530
523 add_types(g);531 add_types(g);
...@@ -550,8 +558,8 @@ static LLVMValueRef gen_fn_call(CodeGen *g, AstNode *fn_call_node) {...@@ -550,8 +558,8 @@ static LLVMValueRef gen_fn_call(CodeGen *g, AstNode *fn_call_node) {
550 }558 }
551559
552 add_debug_source_node(g, fn_call_node);560 add_debug_source_node(g, fn_call_node);
553 LLVMValueRef result = LLVMBuildCall(g->builder, fn_table_entry->fn_value,561 LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_table_entry->fn_value,
554 param_values, actual_param_count, "");562 param_values, actual_param_count, fn_table_entry->calling_convention, "");
555563
556 if (type_is_unreachable(fn_table_entry->proto_node->data.fn_proto.return_type)) {564 if (type_is_unreachable(fn_table_entry->proto_node->data.fn_proto.return_type)) {
557 return LLVMBuildUnreachable(g->builder);565 return LLVMBuildUnreachable(g->builder);
...@@ -566,7 +574,7 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) {...@@ -566,7 +574,7 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) {
566 return entry->value;574 return entry->value;
567 }575 }
568 LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), false);576 LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), false);
569 LLVMValueRef global_value = LLVMAddGlobal(g->mod, LLVMTypeOf(text), "");577 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(text), "");
570 LLVMSetLinkage(global_value, LLVMPrivateLinkage);578 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
571 LLVMSetInitializer(global_value, text);579 LLVMSetInitializer(global_value, text);
572 LLVMSetGlobalConstant(global_value, true);580 LLVMSetGlobalConstant(global_value, true);
...@@ -615,6 +623,8 @@ static void gen_block(CodeGen *g, AstNode *block_node, bool add_implicit_return)...@@ -615,6 +623,8 @@ static void gen_block(CodeGen *g, AstNode *block_node, bool add_implicit_return)
615 g->di_file, block_node->line + 1, block_node->column + 1);623 g->di_file, block_node->line + 1, block_node->column + 1);
616 g->block_scopes.append(di_block);624 g->block_scopes.append(di_block);
617625
626 add_debug_source_node(g, block_node);
627
618 for (int i = 0; i < block_node->data.block.statements.length; i += 1) {628 for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
619 AstNode *statement_node = block_node->data.block.statements.at(i);629 AstNode *statement_node = block_node->data.block.statements.at(i);
620 switch (statement_node->type) {630 switch (statement_node->type) {
...@@ -714,16 +724,15 @@ void code_gen(CodeGen *g) {...@@ -714,16 +724,15 @@ void code_gen(CodeGen *g) {
714 param_types[param_decl_i] = to_llvm_type(type_node);724 param_types[param_decl_i] = to_llvm_type(type_node);
715 }725 }
716 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, fn_proto->params.length, 0);726 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, fn_proto->params.length, 0);
717 LLVMValueRef fn = LLVMAddFunction(g->mod, buf_ptr(&fn_proto->name), function_type);727 LLVMValueRef fn = LLVMAddFunction(g->module, buf_ptr(&fn_proto->name), function_type);
718728
719 LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMPrivateLinkage : LLVMExternalLinkage);729 LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMInternalLinkage : LLVMExternalLinkage);
720730
721 if (type_is_unreachable(fn_proto->return_type)) {731 if (type_is_unreachable(fn_proto->return_type)) {
722 LLVMAddFunctionAttr(fn, LLVMNoReturnAttribute);732 LLVMAddFunctionAttr(fn, LLVMNoReturnAttribute);
723 }733 }
724 if (fn_table_entry->is_extern) {734 LLVMSetFunctionCallConv(fn, fn_table_entry->calling_convention);
725 LLVMSetFunctionCallConv(fn, LLVMCCallConv);735 if (!fn_table_entry->is_extern) {
726 } else {
727 LLVMAddFunctionAttr(fn, LLVMNoUnwindAttribute);736 LLVMAddFunctionAttr(fn, LLVMNoUnwindAttribute);
728 }737 }
729738
...@@ -768,10 +777,19 @@ void code_gen(CodeGen *g) {...@@ -768,10 +777,19 @@ void code_gen(CodeGen *g) {
768777
769 g->dbuilder->finalize();778 g->dbuilder->finalize();
770779
771 LLVMDumpModule(g->mod);780 LLVMDumpModule(g->module);
772781
782 // in release mode, we're sooooo confident that we've generated correct ir,
783 // that we skip the verify module step in order to get better performance.
784#ifndef NDEBUG
773 char *error = nullptr;785 char *error = nullptr;
774 LLVMVerifyModule(g->mod, LLVMAbortProcessAction, &error);786 LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
787#endif
788}
789
790void code_gen_optimize(CodeGen *g) {
791 LLVMZigOptimizeModule(g->target_machine, g->module);
792 LLVMDumpModule(g->module);
775}793}
776794
777ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) {795ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) {
...@@ -907,7 +925,9 @@ void code_gen_link(CodeGen *g, const char *out_file) {...@@ -907,7 +925,9 @@ void code_gen_link(CodeGen *g, const char *out_file) {
907 buf_append_str(&out_file_o, ".o");925 buf_append_str(&out_file_o, ".o");
908926
909 char *err_msg = nullptr;927 char *err_msg = nullptr;
910 if (LLVMTargetMachineEmitToFile(g->target_machine, g->mod, buf_ptr(&out_file_o), LLVMObjectFile, &err_msg)) {928 if (LLVMZigTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(&out_file_o),
929 LLVMObjectFile, &err_msg))
930 {
911 zig_panic("unable to write object file: %s", err_msg);931 zig_panic("unable to write object file: %s", err_msg);
912 }932 }
913933
src/codegen.hpp+2
...@@ -33,6 +33,8 @@ void codegen_set_strip(CodeGen *codegen, bool strip);...@@ -33,6 +33,8 @@ void codegen_set_strip(CodeGen *codegen, bool strip);
3333
34void semantic_analyze(CodeGen *g);34void semantic_analyze(CodeGen *g);
3535
36void code_gen_optimize(CodeGen *g);
37
36void code_gen(CodeGen *g);38void code_gen(CodeGen *g);
3739
38void code_gen_link(CodeGen *g, const char *out_file);40void code_gen_link(CodeGen *g, const char *out_file);
src/main.cpp+6
...@@ -118,6 +118,12 @@ static int build(const char *arg0, const char *in_file, const char *out_file,...@@ -118,6 +118,12 @@ static int build(const char *arg0, const char *in_file, const char *out_file,
118 fprintf(stderr, "------------------\n");118 fprintf(stderr, "------------------\n");
119 code_gen(codegen);119 code_gen(codegen);
120120
121 if (release) {
122 fprintf(stderr, "\nOptimization:\n");
123 fprintf(stderr, "---------------\n");
124 code_gen_optimize(codegen);
125 }
126
121 fprintf(stderr, "\nLink:\n");127 fprintf(stderr, "\nLink:\n");
122 fprintf(stderr, "-------\n");128 fprintf(stderr, "-------\n");
123 code_gen_link(codegen, out_file);129 code_gen_link(codegen, out_file);
src/parser.cpp+140-94
...@@ -268,6 +268,53 @@ static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {...@@ -268,6 +268,53 @@ static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
268 }268 }
269}269}
270270
271static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_token_index) {
272 Token *number_sign = &pc->tokens->at(token_index);
273 token_index += 1;
274 ast_expect_token(pc, number_sign, TokenIdNumberSign);
275
276 AstNode *node = ast_create_node(NodeTypeDirective, number_sign);
277
278 Token *name_symbol = &pc->tokens->at(token_index);
279 token_index += 1;
280 ast_expect_token(pc, name_symbol, TokenIdSymbol);
281
282 ast_buf_from_token(pc, name_symbol, &node->data.directive.name);
283
284 Token *l_paren = &pc->tokens->at(token_index);
285 token_index += 1;
286 ast_expect_token(pc, l_paren, TokenIdLParen);
287
288 Token *param_str = &pc->tokens->at(token_index);
289 token_index += 1;
290 ast_expect_token(pc, param_str, TokenIdStringLiteral);
291
292 parse_string_literal(pc, param_str, &node->data.directive.param);
293
294 Token *r_paren = &pc->tokens->at(token_index);
295 token_index += 1;
296 ast_expect_token(pc, r_paren, TokenIdRParen);
297
298 *new_token_index = token_index;
299 return node;
300}
301
302static void ast_parse_directives(ParseContext *pc, int *token_index,
303 ZigList<AstNode *> *directives)
304{
305 for (;;) {
306 Token *token = &pc->tokens->at(*token_index);
307 if (token->id == TokenIdNumberSign) {
308 AstNode *directive_node = ast_parse_directive(pc, *token_index, token_index);
309 directives->append(directive_node);
310 } else {
311 return;
312 }
313 }
314 zig_unreachable();
315}
316
317
271/*318/*
272Type : token(Symbol) | PointerType | token(Unreachable)319Type : token(Symbol) | PointerType | token(Unreachable)
273PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type;320PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type;
...@@ -500,48 +547,74 @@ static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_toke...@@ -500,48 +547,74 @@ static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_toke
500}547}
501548
502/*549/*
503FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)550FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
504*/551*/
505static AstNode *ast_parse_fn_proto(ParseContext *pc, int token_index, int *new_token_index) {552static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) {
506 Token *fn_token = &pc->tokens->at(token_index);553 Token *token = &pc->tokens->at(*token_index);
507 token_index += 1;
508 ast_expect_token(pc, fn_token, TokenIdKeywordFn);
509554
510 AstNode *node = ast_create_node(NodeTypeFnProto, fn_token);555 FnProtoVisibMod visib_mod;
511556
557 if (token->id == TokenIdKeywordPub) {
558 visib_mod = FnProtoVisibModPub;
559 *token_index += 1;
512560
513 Token *fn_name = &pc->tokens->at(token_index);561 Token *fn_token = &pc->tokens->at(*token_index);
514 token_index += 1;562 *token_index += 1;
563 ast_expect_token(pc, fn_token, TokenIdKeywordFn);
564 } else if (token->id == TokenIdKeywordExport) {
565 visib_mod = FnProtoVisibModExport;
566 *token_index += 1;
567
568 Token *fn_token = &pc->tokens->at(*token_index);
569 *token_index += 1;
570 ast_expect_token(pc, fn_token, TokenIdKeywordFn);
571 } else if (token->id == TokenIdKeywordFn) {
572 visib_mod = FnProtoVisibModPrivate;
573 *token_index += 1;
574 } else if (mandatory) {
575 ast_invalid_token_error(pc, token);
576 } else {
577 return nullptr;
578 }
579
580 AstNode *node = ast_create_node(NodeTypeFnProto, token);
581 node->data.fn_proto.visib_mod = visib_mod;
582 node->data.fn_proto.directives = pc->directive_list;
583 pc->directive_list = nullptr;
584
585
586 Token *fn_name = &pc->tokens->at(*token_index);
587 *token_index += 1;
515 ast_expect_token(pc, fn_name, TokenIdSymbol);588 ast_expect_token(pc, fn_name, TokenIdSymbol);
516589
517 ast_buf_from_token(pc, fn_name, &node->data.fn_proto.name);590 ast_buf_from_token(pc, fn_name, &node->data.fn_proto.name);
518591
519592
520 ast_parse_param_decl_list(pc, token_index, &token_index, &node->data.fn_proto.params);593 ast_parse_param_decl_list(pc, *token_index, token_index, &node->data.fn_proto.params);
521594
522 Token *arrow = &pc->tokens->at(token_index);595 Token *arrow = &pc->tokens->at(*token_index);
523 if (arrow->id == TokenIdArrow) {596 if (arrow->id == TokenIdArrow) {
524 token_index += 1;597 *token_index += 1;
525 node->data.fn_proto.return_type = ast_parse_type(pc, token_index, &token_index);598 node->data.fn_proto.return_type = ast_parse_type(pc, *token_index, token_index);
526 } else {599 } else {
527 node->data.fn_proto.return_type = ast_create_void_type_node(pc, arrow);600 node->data.fn_proto.return_type = ast_create_void_type_node(pc, arrow);
528 }601 }
529602
530 *new_token_index = token_index;
531 return node;603 return node;
532}604}
533605
534/*606/*
535FnDef : FnProto Block607FnDef : FnProto Block
536*/608*/
537static AstNode *ast_parse_fn_def(ParseContext *pc, int token_index, int *new_token_index) {609static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandatory) {
538 AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, &token_index);610 AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory);
611 if (!fn_proto)
612 return nullptr;
539 AstNode *node = ast_create_node_with_node(NodeTypeFnDef, fn_proto);613 AstNode *node = ast_create_node_with_node(NodeTypeFnDef, fn_proto);
540614
541 node->data.fn_def.fn_proto = fn_proto;615 node->data.fn_def.fn_proto = fn_proto;
542 node->data.fn_def.body = ast_parse_block(pc, token_index, &token_index);616 node->data.fn_def.body = ast_parse_block(pc, *token_index, token_index);
543617
544 *new_token_index = token_index;
545 return node;618 return node;
546}619}
547620
...@@ -549,7 +622,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int token_index, int *new_tok...@@ -549,7 +622,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int token_index, int *new_tok
549FnDecl : FnProto token(Semicolon)622FnDecl : FnProto token(Semicolon)
550*/623*/
551static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) {624static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) {
552 AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, &token_index);625 AstNode *fn_proto = ast_parse_fn_proto(pc, &token_index, true);
553 AstNode *node = ast_create_node_with_node(NodeTypeFnDecl, fn_proto);626 AstNode *node = ast_create_node_with_node(NodeTypeFnDecl, fn_proto);
554627
555 node->data.fn_decl.fn_proto = fn_proto;628 node->data.fn_decl.fn_proto = fn_proto;
...@@ -565,78 +638,45 @@ static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_to...@@ -565,78 +638,45 @@ static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_to
565/*638/*
566Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)639Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
567*/640*/
568static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_token_index) {
569 Token *number_sign = &pc->tokens->at(token_index);
570 token_index += 1;
571 ast_expect_token(pc, number_sign, TokenIdNumberSign);
572
573 AstNode *node = ast_create_node(NodeTypeDirective, number_sign);
574
575 Token *name_symbol = &pc->tokens->at(token_index);
576 token_index += 1;
577 ast_expect_token(pc, name_symbol, TokenIdSymbol);
578
579 ast_buf_from_token(pc, name_symbol, &node->data.directive.name);
580
581 Token *l_paren = &pc->tokens->at(token_index);
582 token_index += 1;
583 ast_expect_token(pc, l_paren, TokenIdLParen);
584
585 Token *param_str = &pc->tokens->at(token_index);
586 token_index += 1;
587 ast_expect_token(pc, param_str, TokenIdStringLiteral);
588
589 parse_string_literal(pc, param_str, &node->data.directive.param);
590
591 Token *r_paren = &pc->tokens->at(token_index);
592 token_index += 1;
593 ast_expect_token(pc, r_paren, TokenIdRParen);
594
595 *new_token_index = token_index;
596 return node;
597}
598
599static void ast_parse_directives(ParseContext *pc, int token_index, int *new_token_index,
600 ZigList<AstNode *> *directives)
601{
602 for (;;) {
603 Token *token = &pc->tokens->at(token_index);
604 if (token->id == TokenIdNumberSign) {
605 AstNode *directive_node = ast_parse_directive(pc, token_index, &token_index);
606 directives->append(directive_node);
607 } else {
608 *new_token_index = token_index;
609 return;
610 }
611 }
612 zig_unreachable();
613}
614
615/*641/*
616ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)642ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)
617*/643*/
618static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *new_token_index) {644static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool mandatory) {
619 Token *extern_kw = &pc->tokens->at(token_index);645 Token *extern_kw = &pc->tokens->at(*token_index);
620 token_index += 1;646 if (extern_kw->id != TokenIdKeywordExtern) {
621 ast_expect_token(pc, extern_kw, TokenIdKeywordExtern);647 if (mandatory)
648 ast_invalid_token_error(pc, extern_kw);
649 else
650 return nullptr;
651 }
652 *token_index += 1;
622653
623 AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw);654 AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw);
624655
625 node->data.extern_block.directives = pc->directive_list;656 node->data.extern_block.directives = pc->directive_list;
626 pc->directive_list = nullptr;657 pc->directive_list = nullptr;
627658
628 Token *l_brace = &pc->tokens->at(token_index);659 Token *l_brace = &pc->tokens->at(*token_index);
629 token_index += 1;660 *token_index += 1;
630 ast_expect_token(pc, l_brace, TokenIdLBrace);661 ast_expect_token(pc, l_brace, TokenIdLBrace);
631662
632 for (;;) {663 for (;;) {
633 Token *token = &pc->tokens->at(token_index);664 Token *directive_token = &pc->tokens->at(*token_index);
665 assert(!pc->directive_list);
666 pc->directive_list = allocate<ZigList<AstNode*>>(1);
667 ast_parse_directives(pc, token_index, pc->directive_list);
668
669 Token *token = &pc->tokens->at(*token_index);
634 if (token->id == TokenIdRBrace) {670 if (token->id == TokenIdRBrace) {
635 token_index += 1;671 if (pc->directive_list->length > 0) {
636 *new_token_index = token_index;672 ast_error(directive_token, "invalid directive");
673 }
674 pc->directive_list = nullptr;
675
676 *token_index += 1;
637 return node;677 return node;
638 } else {678 } else {
639 AstNode *child = ast_parse_fn_decl(pc, token_index, &token_index);679 AstNode *child = ast_parse_fn_decl(pc, *token_index, token_index);
640 node->data.extern_block.fn_decls.append(child);680 node->data.extern_block.fn_decls.append(child);
641 }681 }
642 }682 }
...@@ -645,25 +685,31 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *n...@@ -645,25 +685,31 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *n
645 zig_unreachable();685 zig_unreachable();
646}686}
647687
648static void ast_parse_top_level_decls(ParseContext *pc, int token_index, int *new_token_index,688static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
649 ZigList<AstNode *> *top_level_decls)
650{
651 for (;;) {689 for (;;) {
652 Token *token = &pc->tokens->at(token_index);690 Token *directive_token = &pc->tokens->at(*token_index);
653 if (token->id == TokenIdNumberSign) {691 assert(!pc->directive_list);
654 assert(!pc->directive_list);692 pc->directive_list = allocate<ZigList<AstNode*>>(1);
655 pc->directive_list = allocate<ZigList<AstNode*>>(1);693 ast_parse_directives(pc, token_index, pc->directive_list);
656 ast_parse_directives(pc, token_index, &token_index, pc->directive_list);694
657 } else if (token->id == TokenIdKeywordFn) {695 AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, false);
658 AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, &token_index);696 if (fn_decl_node) {
659 top_level_decls->append(fn_decl_node);697 top_level_decls->append(fn_decl_node);
660 } else if (token->id == TokenIdKeywordExtern) {698 continue;
661 AstNode *extern_node = ast_parse_extern_block(pc, token_index, &token_index);699 }
700
701 AstNode *extern_node = ast_parse_extern_block(pc, token_index, false);
702 if (extern_node) {
662 top_level_decls->append(extern_node);703 top_level_decls->append(extern_node);
663 } else {704 continue;
664 *new_token_index = token_index;
665 return;
666 }705 }
706
707 if (pc->directive_list->length > 0) {
708 ast_error(directive_token, "invalid directive");
709 }
710 pc->directive_list = nullptr;
711
712 return;
667 }713 }
668 zig_unreachable();714 zig_unreachable();
669}715}
...@@ -674,11 +720,11 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {...@@ -674,11 +720,11 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {
674 pc.root = ast_create_node(NodeTypeRoot, &tokens->at(0));720 pc.root = ast_create_node(NodeTypeRoot, &tokens->at(0));
675 pc.tokens = tokens;721 pc.tokens = tokens;
676722
677 int new_token_index;723 int token_index = 0;
678 ast_parse_top_level_decls(&pc, 0, &new_token_index, &pc.root->data.root.top_level_decls);724 ast_parse_top_level_decls(&pc, &token_index, &pc.root->data.root.top_level_decls);
679725
680 if (new_token_index != tokens->length - 1) {726 if (token_index != tokens->length - 1) {
681 ast_invalid_token_error(&pc, &tokens->at(new_token_index));727 ast_invalid_token_error(&pc, &tokens->at(token_index));
682 }728 }
683729
684 return pc.root;730 return pc.root;
src/parser.hpp+8
...@@ -34,7 +34,15 @@ struct AstNodeRoot {...@@ -34,7 +34,15 @@ struct AstNodeRoot {
34 ZigList<AstNode *> top_level_decls;34 ZigList<AstNode *> top_level_decls;
35};35};
3636
37enum FnProtoVisibMod {
38 FnProtoVisibModPrivate,
39 FnProtoVisibModPub,
40 FnProtoVisibModExport,
41};
42
37struct AstNodeFnProto {43struct AstNodeFnProto {
44 ZigList<AstNode *> *directives;
45 FnProtoVisibMod visib_mod;
38 Buf name;46 Buf name;
39 ZigList<AstNode *> params;47 ZigList<AstNode *> params;
40 AstNode *return_type;48 AstNode *return_type;
src/tokenizer.cpp+6
...@@ -163,6 +163,10 @@ static void end_token(Tokenize *t) {...@@ -163,6 +163,10 @@ static void end_token(Tokenize *t) {
163 t->cur_tok->id = TokenIdKeywordExtern;163 t->cur_tok->id = TokenIdKeywordExtern;
164 } else if (mem_eql_str(token_mem, token_len, "unreachable")) {164 } else if (mem_eql_str(token_mem, token_len, "unreachable")) {
165 t->cur_tok->id = TokenIdKeywordUnreachable;165 t->cur_tok->id = TokenIdKeywordUnreachable;
166 } else if (mem_eql_str(token_mem, token_len, "pub")) {
167 t->cur_tok->id = TokenIdKeywordPub;
168 } else if (mem_eql_str(token_mem, token_len, "export")) {
169 t->cur_tok->id = TokenIdKeywordExport;
166 }170 }
167171
168 t->cur_tok = nullptr;172 t->cur_tok = nullptr;
...@@ -407,6 +411,8 @@ static const char * token_name(Token *token) {...@@ -407,6 +411,8 @@ static const char * token_name(Token *token) {
407 case TokenIdKeywordReturn: return "Return";411 case TokenIdKeywordReturn: return "Return";
408 case TokenIdKeywordExtern: return "Extern";412 case TokenIdKeywordExtern: return "Extern";
409 case TokenIdKeywordUnreachable: return "Unreachable";413 case TokenIdKeywordUnreachable: return "Unreachable";
414 case TokenIdKeywordPub: return "Pub";
415 case TokenIdKeywordExport: return "Export";
410 case TokenIdLParen: return "LParen";416 case TokenIdLParen: return "LParen";
411 case TokenIdRParen: return "RParen";417 case TokenIdRParen: return "RParen";
412 case TokenIdComma: return "Comma";418 case TokenIdComma: return "Comma";
src/tokenizer.hpp+2
...@@ -19,6 +19,8 @@ enum TokenId {...@@ -19,6 +19,8 @@ enum TokenId {
19 TokenIdKeywordConst,19 TokenIdKeywordConst,
20 TokenIdKeywordExtern,20 TokenIdKeywordExtern,
21 TokenIdKeywordUnreachable,21 TokenIdKeywordUnreachable,
22 TokenIdKeywordPub,
23 TokenIdKeywordExport,
22 TokenIdLParen,24 TokenIdLParen,
23 TokenIdRParen,25 TokenIdRParen,
24 TokenIdComma,26 TokenIdComma,
src/zig_llvm.cpp+133-1
...@@ -10,7 +10,19 @@...@@ -10,7 +10,19 @@
10#include <llvm/InitializePasses.h>10#include <llvm/InitializePasses.h>
11#include <llvm/PassRegistry.h>11#include <llvm/PassRegistry.h>
12#include <llvm/MC/SubtargetFeature.h>12#include <llvm/MC/SubtargetFeature.h>
1313#include <llvm/Support/raw_ostream.h>
14#include <llvm/Support/FileSystem.h>
15#include <llvm/Target/TargetMachine.h>
16#include <llvm/IR/LegacyPassManager.h>
17#include <llvm/IR/Module.h>
18#include <llvm/IR/Verifier.h>
19#include <llvm/IR/Instructions.h>
20#include <llvm/IR/IRBuilder.h>
21#include <llvm/Analysis/TargetLibraryInfo.h>
22#include <llvm/Analysis/TargetTransformInfo.h>
23#include <llvm/Transforms/IPO.h>
24#include <llvm/Transforms/IPO/PassManagerBuilder.h>
25#include <llvm/Transforms/Scalar.h>
1426
15using namespace llvm;27using namespace llvm;
1628
...@@ -42,3 +54,123 @@ char *LLVMZigGetNativeFeatures(void) {...@@ -42,3 +54,123 @@ char *LLVMZigGetNativeFeatures(void) {
4254
43 return strdup(features.getString().c_str());55 return strdup(features.getString().c_str());
44}56}
57
58static void addAddDiscriminatorsPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) {
59 PM.add(createAddDiscriminatorsPass());
60}
61
62
63void LLVMZigOptimizeModule(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref) {
64 TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref);
65 Module* module = unwrap(module_ref);
66 TargetLibraryInfoImpl tlii(Triple(module->getTargetTriple()));
67
68 PassManagerBuilder *PMBuilder = new PassManagerBuilder();
69 PMBuilder->OptLevel = target_machine->getOptLevel();
70 PMBuilder->SizeLevel = 0;
71 PMBuilder->BBVectorize = true;
72 PMBuilder->SLPVectorize = true;
73 PMBuilder->LoopVectorize = true;
74
75 PMBuilder->DisableUnitAtATime = false;
76 PMBuilder->DisableUnrollLoops = false;
77 PMBuilder->MergeFunctions = true;
78 PMBuilder->PrepareForLTO = true;
79 PMBuilder->RerollLoops = true;
80
81 PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addAddDiscriminatorsPass);
82
83 PMBuilder->LibraryInfo = &tlii;
84
85 PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel);
86
87 // Set up the per-function pass manager.
88 legacy::FunctionPassManager *FPM = new legacy::FunctionPassManager(module);
89 FPM->add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
90#ifndef NDEBUG
91 bool verify_module = true;
92#else
93 bool verify_module = false;
94#endif
95 if (verify_module) {
96 FPM->add(createVerifierPass());
97 }
98 PMBuilder->populateFunctionPassManager(*FPM);
99
100 // Set up the per-module pass manager.
101 legacy::PassManager *MPM = new legacy::PassManager();
102 MPM->add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
103
104 PMBuilder->populateModulePassManager(*MPM);
105
106
107 // run per function optimization passes
108 FPM->doInitialization();
109 for (Function &F : *module)
110 if (!F.isDeclaration())
111 FPM->run(F);
112 FPM->doFinalization();
113
114 // run per module optimization passes
115 MPM->run(*module);
116}
117
118static LLVMBool LLVMZigTargetMachineEmit(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
119 raw_pwrite_stream &out_stream, LLVMCodeGenFileType codegen, char **err_msg)
120{
121 TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref);
122 Module* module = unwrap(module_ref);
123 TargetLibraryInfoImpl tlii(Triple(module->getTargetTriple()));
124
125 legacy::PassManager pass;
126
127 pass.add(new TargetLibraryInfoWrapperPass(tlii));
128
129 const DataLayout *td = target_machine->getDataLayout();
130
131 if (!td) {
132 *err_msg = strdup("No DataLayout in TargetMachine");
133 return true;
134 }
135 module->setDataLayout(*td);
136
137
138 TargetMachine::CodeGenFileType ft;
139 switch (codegen) {
140 case LLVMAssemblyFile:
141 ft = TargetMachine::CGFT_AssemblyFile;
142 break;
143 default:
144 ft = TargetMachine::CGFT_ObjectFile;
145 break;
146 }
147 if (target_machine->addPassesToEmitFile(pass, out_stream, ft)) {
148 *err_msg = strdup("TargetMachine can't emit a file of this type");
149 return true;
150 }
151
152 pass.run(*module);
153
154 out_stream.flush();
155 return false;
156}
157
158LLVMBool LLVMZigTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
159 char* filename, LLVMCodeGenFileType codegen, char** err_msg)
160{
161 std::error_code error_code;
162 raw_fd_ostream dest(filename, error_code, sys::fs::F_None);
163 if (error_code) {
164 *err_msg = strdup(error_code.message().c_str());
165 return true;
166 }
167 return LLVMZigTargetMachineEmit(targ_machine_ref, module_ref, dest, codegen, err_msg);
168}
169
170LLVMValueRef LLVMZigBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
171 unsigned NumArgs, unsigned CC, const char *Name)
172{
173 CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name);
174 call_inst->setCallingConv(CC);
175 return wrap(unwrap(B)->Insert(call_inst));
176}
src/zig_llvm.hpp+8
...@@ -21,4 +21,12 @@ void LLVMZigInitializeUnreachableBlockElimPass(LLVMPassRegistryRef R);...@@ -21,4 +21,12 @@ void LLVMZigInitializeUnreachableBlockElimPass(LLVMPassRegistryRef R);
21char *LLVMZigGetHostCPUName(void);21char *LLVMZigGetHostCPUName(void);
22char *LLVMZigGetNativeFeatures(void);22char *LLVMZigGetNativeFeatures(void);
2323
24LLVMBool LLVMZigTargetMachineEmitToFile(LLVMTargetMachineRef target_machine, LLVMModuleRef module,
25 char* filename, LLVMCodeGenFileType codegen, char** error_msg);
26
27void LLVMZigOptimizeModule(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref);
28
29LLVMValueRef LLVMZigBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
30 unsigned NumArgs, unsigned CC, const char *Name);
31
24#endif32#endif
test/hello.zig deleted-10
...@@ -1,10 +0,0 @@
1#link("c")
2extern {
3 fn puts(s: *mut u8) -> i32;
4 fn exit(code: i32) -> unreachable;
5}
6
7fn _start() -> unreachable {
8 puts("Hello, world!");
9 exit(0);
10}
test/standalone.cpp+3-3
...@@ -53,7 +53,7 @@ static void add_all_test_cases(void) {...@@ -53,7 +53,7 @@ static void add_all_test_cases(void) {
53 fn exit(code: i32) -> unreachable;53 fn exit(code: i32) -> unreachable;
54 }54 }
5555
56 fn _start() -> unreachable {56 export fn _start() -> unreachable {
57 puts("Hello, world!");57 puts("Hello, world!");
58 exit(0);58 exit(0);
59 }59 }
...@@ -69,7 +69,7 @@ static void add_all_test_cases(void) {...@@ -69,7 +69,7 @@ static void add_all_test_cases(void) {
69 fn empty_function_1() {}69 fn empty_function_1() {}
70 fn empty_function_2() { return; }70 fn empty_function_2() { return; }
7171
72 fn _start() -> unreachable {72 export fn _start() -> unreachable {
73 empty_function_1();73 empty_function_1();
74 empty_function_2();74 empty_function_2();
75 this_is_a_function();75 this_is_a_function();
...@@ -95,7 +95,7 @@ static void add_all_test_cases(void) {...@@ -95,7 +95,7 @@ static void add_all_test_cases(void) {
9595
96 /// this is a documentation comment96 /// this is a documentation comment
97 /// doc comment line 297 /// doc comment line 2
98 fn _start() -> unreachable {98 export fn _start() -> unreachable {
99 puts(/* mid-line comment /* nested */ */ "OK");99 puts(/* mid-line comment /* nested */ */ "OK");
100 exit(0);100 exit(0);
101 }101 }