authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-10 15:34:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-10 15:34:38-07:00
log0dbee2300ed28c18ecccaf71f10f68eb2da71266
treeac804032eccb2f07258b45023739b694ee937d8c
parent3e8a98fa619516d0617a827a79601264a554d88b

add inline assembly support


15 files changed, 383 insertions(+), 20 deletions(-)

CMakeLists.txt+6
...@@ -115,7 +115,12 @@ set(C_HEADERS...@@ -115,7 +115,12 @@ set(C_HEADERS
115 "${CMAKE_SOURCE_DIR}/c_headers/xtestintrin.h"115 "${CMAKE_SOURCE_DIR}/c_headers/xtestintrin.h"
116)116)
117117
118set(ZIG_STD_SRC
119 "${CMAKE_SOURCE_DIR}/std/bootstrap.zig"
120)
121
118set(C_HEADERS_DEST "lib/zig/include")122set(C_HEADERS_DEST "lib/zig/include")
123set(ZIG_STD_DEST "lib/zig/std")
119set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")124set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
120configure_file (125configure_file (
121 "${CMAKE_SOURCE_DIR}/src/config.h.in"126 "${CMAKE_SOURCE_DIR}/src/config.h.in"
...@@ -142,6 +147,7 @@ target_link_libraries(zig LINK_PUBLIC...@@ -142,6 +147,7 @@ target_link_libraries(zig LINK_PUBLIC
142install(TARGETS zig DESTINATION bin)147install(TARGETS zig DESTINATION bin)
143148
144install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})149install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
150install(FILES ${ZIG_STD_SRC} DESTINATION ${ZIG_STD_DEST})
145151
146add_executable(run_tests ${TEST_SOURCES})152add_executable(run_tests ${TEST_SOURCES})
147target_link_libraries(run_tests)153target_link_libraries(run_tests)
README.md+14-2
...@@ -58,7 +58,6 @@ compromises backward compatibility....@@ -58,7 +58,6 @@ compromises backward compatibility.
58 * structs58 * structs
59 * loops59 * loops
60 * enums60 * enums
61 * inline assembly and syscalls
62 * conditional compilation and ability to check target platform and architecture61 * conditional compilation and ability to check target platform and architecture
63 * main function with command line arguments62 * main function with command line arguments
64 * void pointer constant63 * void pointer constant
...@@ -83,10 +82,23 @@ compromises backward compatibility....@@ -83,10 +82,23 @@ compromises backward compatibility.
8382
84## Building83## Building
8584
85### Debug / Development Build
86
86```87```
87mkdir build88mkdir build
88cd build89cd build
89cmake ..90cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
90make91make
92make install
91./run_tests93./run_tests
92```94```
95
96### Release / Install Build
97
98```
99mkdir build
100cd build
101cmake .. -DCMAKE_BUILD_TYPE=Release
102make
103sudo make install
104```
doc/langref.md+9-1
...@@ -70,7 +70,15 @@ VariableDeclaration : token(Let) option(token(Mut)) token(Symbol) (token(Eq) Exp...@@ -70,7 +70,15 @@ VariableDeclaration : token(Let) option(token(Mut)) token(Symbol) (token(Eq) Exp
7070
71Expression : BlockExpression | NonBlockExpression71Expression : BlockExpression | NonBlockExpression
7272
73NonBlockExpression : ReturnExpression | AssignmentExpression73NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
74
75AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
76
77AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
78
79AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
80
81AsmClobbers: token(Colon) list(token(String), token(Comma))
7482
75AssignmentExpression : BoolOrExpression token(Equal) BoolOrExpression | BoolOrExpression83AssignmentExpression : BoolOrExpression token(Equal) BoolOrExpression | BoolOrExpression
7684
doc/vim/syntax/zig.vim+2-2
...@@ -7,8 +7,8 @@ if exists("b:current_syntax")...@@ -7,8 +7,8 @@ if exists("b:current_syntax")
7 finish7 finish
8endif8endif
99
10syn keyword zigKeyword fn return mut const extern unreachable export pub as use while10syn keyword zigKeyword fn return mut const extern unreachable export pub as use while asm
11syn keyword zigKeyword if else let void goto type enum struct continue break match11syn keyword zigKeyword if else let void goto type enum struct continue break match volatile
12syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f12812syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128
1313
14syn keyword zigConstant null14syn keyword zigConstant null
example/hello_world/hello2.zig created+11
...@@ -0,0 +1,11 @@
1export executable "hello";
2
3#link("c")
4extern {
5 fn printf(__format: *const u8, ...) -> i32;
6}
7
8export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
9 printf("argc = %zu\n", argc);
10 return 0;
11}
src/analyze.cpp+29-2
...@@ -43,6 +43,7 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -43,6 +43,7 @@ static AstNode *first_executing_node(AstNode *node) {
43 case NodeTypeIfExpr:43 case NodeTypeIfExpr:
44 case NodeTypeLabel:44 case NodeTypeLabel:
45 case NodeTypeGoto:45 case NodeTypeGoto:
46 case NodeTypeAsmExpr:
46 return node;47 return node;
47 }48 }
48 zig_panic("unreachable");49 zig_panic("unreachable");
...@@ -205,8 +206,26 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -205,8 +206,26 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
205 for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {206 for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
206 AstNode *directive_node = node->data.fn_proto.directives->at(i);207 AstNode *directive_node = node->data.fn_proto.directives->at(i);
207 Buf *name = &directive_node->data.directive.name;208 Buf *name = &directive_node->data.directive.name;
208 add_node_error(g, directive_node,209
209 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));210 if (buf_eql_str(name, "attribute")) {
211 Buf *attr_name = &directive_node->data.directive.param;
212 if (fn_table_entry->fn_def_node) {
213 if (buf_eql_str(attr_name, "naked")) {
214 fn_table_entry->fn_attr_list.append(FnAttrIdNaked);
215 } else if (buf_eql_str(attr_name, "alwaysinline")) {
216 fn_table_entry->fn_attr_list.append(FnAttrIdAlwaysInline);
217 } else {
218 add_node_error(g, directive_node,
219 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
220 }
221 } else {
222 add_node_error(g, directive_node,
223 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
224 }
225 } else {
226 add_node_error(g, directive_node,
227 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
228 }
210 }229 }
211230
212 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {231 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
...@@ -338,6 +357,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -338,6 +357,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
338357
339 resolve_function_proto(g, proto_node, fn_table_entry);358 resolve_function_proto(g, proto_node, fn_table_entry);
340359
360
341 assert(!proto_node->codegen_node);361 assert(!proto_node->codegen_node);
342 proto_node->codegen_node = allocate<CodeGenNode>(1);362 proto_node->codegen_node = allocate<CodeGenNode>(1);
343 proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;363 proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
...@@ -415,6 +435,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -415,6 +435,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
415 case NodeTypeIfExpr:435 case NodeTypeIfExpr:
416 case NodeTypeLabel:436 case NodeTypeLabel:
417 case NodeTypeGoto:437 case NodeTypeGoto:
438 case NodeTypeAsmExpr:
418 zig_unreachable();439 zig_unreachable();
419 }440 }
420}441}
...@@ -626,6 +647,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -626,6 +647,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
626 return_type = g->builtin_types.entry_unreachable;647 return_type = g->builtin_types.entry_unreachable;
627 break;648 break;
628 }649 }
650 case NodeTypeAsmExpr:
651 {
652 return_type = g->builtin_types.entry_void;
653 break;
654 }
629 case NodeTypeBinOpExpr:655 case NodeTypeBinOpExpr:
630 {656 {
631 switch (node->data.bin_op_expr.bin_op) {657 switch (node->data.bin_op_expr.bin_op) {
...@@ -1004,6 +1030,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -1004,6 +1030,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
1004 case NodeTypeIfExpr:1030 case NodeTypeIfExpr:
1005 case NodeTypeLabel:1031 case NodeTypeLabel:
1006 case NodeTypeGoto:1032 case NodeTypeGoto:
1033 case NodeTypeAsmExpr:
1007 zig_unreachable();1034 zig_unreachable();
1008 }1035 }
1009}1036}
src/analyze.hpp+8
...@@ -82,6 +82,11 @@ struct LabelTableEntry {...@@ -82,6 +82,11 @@ struct LabelTableEntry {
82 bool entered_from_fallthrough;82 bool entered_from_fallthrough;
83};83};
8484
85enum FnAttrId {
86 FnAttrIdNaked,
87 FnAttrIdAlwaysInline,
88};
89
85struct FnTableEntry {90struct FnTableEntry {
86 LLVMValueRef fn_value;91 LLVMValueRef fn_value;
87 AstNode *proto_node;92 AstNode *proto_node;
...@@ -90,6 +95,7 @@ struct FnTableEntry {...@@ -90,6 +95,7 @@ struct FnTableEntry {
90 bool internal_linkage;95 bool internal_linkage;
91 unsigned calling_convention;96 unsigned calling_convention;
92 ImportTableEntry *import_entry;97 ImportTableEntry *import_entry;
98 ZigList<FnAttrId> fn_attr_list;
9399
94 // reminder: hash tables must be initialized before use100 // reminder: hash tables must be initialized before use
95 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;101 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
...@@ -113,6 +119,7 @@ struct CodeGen {...@@ -113,6 +119,7 @@ struct CodeGen {
113 TypeTableEntry *entry_bool;119 TypeTableEntry *entry_bool;
114 TypeTableEntry *entry_u8;120 TypeTableEntry *entry_u8;
115 TypeTableEntry *entry_i32;121 TypeTableEntry *entry_i32;
122 TypeTableEntry *entry_isize;
116 TypeTableEntry *entry_f32;123 TypeTableEntry *entry_f32;
117 TypeTableEntry *entry_string_literal;124 TypeTableEntry *entry_string_literal;
118 TypeTableEntry *entry_void;125 TypeTableEntry *entry_void;
...@@ -124,6 +131,7 @@ struct CodeGen {...@@ -124,6 +131,7 @@ struct CodeGen {
124 unsigned pointer_size_bytes;131 unsigned pointer_size_bytes;
125 bool is_static;132 bool is_static;
126 bool strip_debug_symbols;133 bool strip_debug_symbols;
134 bool insert_bootstrap_code;
127 CodeGenBuildType build_type;135 CodeGenBuildType build_type;
128 LLVMTargetMachineRef target_machine;136 LLVMTargetMachineRef target_machine;
129 bool is_native_target;137 bool is_native_target;
src/codegen.cpp+101-12
...@@ -609,6 +609,41 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i...@@ -609,6 +609,41 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
609 return return_value;609 return return_value;
610}610}
611611
612static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
613 assert(node->type == NodeTypeAsmExpr);
614
615 Buf *src_template = &node->data.asm_expr.asm_template;
616
617 Buf llvm_template = BUF_INIT;
618 buf_resize(&llvm_template, 0);
619
620 for (int token_i = 0; token_i < node->data.asm_expr.token_list.length; token_i += 1) {
621 AsmToken *asm_token = &node->data.asm_expr.token_list.at(token_i);
622 switch (asm_token->id) {
623 case AsmTokenIdTemplate:
624 for (int offset = asm_token->start; offset < asm_token->end; offset += 1) {
625 uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset));
626 if (c == '$') {
627 buf_append_str(&llvm_template, "$$");
628 } else {
629 buf_append_char(&llvm_template, c);
630 }
631 }
632 break;
633 case AsmTokenIdPercent:
634 buf_append_char(&llvm_template, '%');
635 break;
636 }
637 }
638
639 LLVMTypeRef function_type = LLVMFunctionType(LLVMVoidType(), nullptr, 0, false);
640
641 LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), "", true, false);
642
643 add_debug_source_node(g, node);
644 return LLVMBuildCall(g->builder, asm_fn, nullptr, 0, "");
645}
646
612static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {647static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
613 switch (node->type) {648 switch (node->type) {
614 case NodeTypeBinOpExpr:649 case NodeTypeBinOpExpr:
...@@ -663,6 +698,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -663,6 +698,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
663 return LLVMConstNull(LLVMInt1Type());698 return LLVMConstNull(LLVMInt1Type());
664 case NodeTypeIfExpr:699 case NodeTypeIfExpr:
665 return gen_if_expr(g, node);700 return gen_if_expr(g, node);
701 case NodeTypeAsmExpr:
702 return gen_asm_expr(g, node);
666 case NodeTypeNumberLiteral:703 case NodeTypeNumberLiteral:
667 {704 {
668 Buf *number_str = &node->data.number;705 Buf *number_str = &node->data.number;
...@@ -762,6 +799,16 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro...@@ -762,6 +799,16 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro
762 return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0);799 return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0);
763}800}
764801
802static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) {
803 switch (attr_id) {
804 case FnAttrIdNaked:
805 return LLVMNakedAttribute;
806 case FnAttrIdAlwaysInline:
807 return LLVMAlwaysInlineAttribute;
808 }
809 zig_unreachable();
810}
811
765static void do_code_gen(CodeGen *g) {812static void do_code_gen(CodeGen *g) {
766 assert(!g->errors.length);813 assert(!g->errors.length);
767814
...@@ -789,6 +836,11 @@ static void do_code_gen(CodeGen *g) {...@@ -789,6 +836,11 @@ static void do_code_gen(CodeGen *g) {
789 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args);836 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args);
790 LLVMValueRef fn = LLVMAddFunction(g->module, buf_ptr(&fn_proto->name), function_type);837 LLVMValueRef fn = LLVMAddFunction(g->module, buf_ptr(&fn_proto->name), function_type);
791838
839 for (int attr_i = 0; attr_i < fn_table_entry->fn_attr_list.length; attr_i += 1) {
840 FnAttrId attr_id = fn_table_entry->fn_attr_list.at(attr_i);
841 LLVMAddFunctionAttr(fn, to_llvm_fn_attr(attr_id));
842 }
843
792 LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMInternalLinkage : LLVMExternalLinkage);844 LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMInternalLinkage : LLVMExternalLinkage);
793845
794 if (type_is_unreachable(g, fn_proto->return_type)) {846 if (type_is_unreachable(g, fn_proto->return_type)) {
...@@ -966,6 +1018,19 @@ static void define_primitive_types(CodeGen *g) {...@@ -966,6 +1018,19 @@ static void define_primitive_types(CodeGen *g) {
966 g->type_table.put(&entry->name, entry);1018 g->type_table.put(&entry->name, entry);
967 g->builtin_types.entry_i32 = entry;1019 g->builtin_types.entry_i32 = entry;
968 }1020 }
1021 {
1022 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1023 entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
1024 buf_init_from_str(&entry->name, "isize");
1025 entry->size_in_bits = g->pointer_size_bytes * 8;
1026 entry->align_in_bits = g->pointer_size_bytes * 8;
1027 entry->data.integral.is_signed = true;
1028 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1029 entry->size_in_bits, entry->align_in_bits,
1030 LLVMZigEncoding_DW_ATE_signed());
1031 g->type_table.put(&entry->name, entry);
1032 g->builtin_types.entry_isize = entry;
1033 }
969 {1034 {
970 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);1035 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
971 entry->type_ref = LLVMFloatType();1036 entry->type_ref = LLVMFloatType();
...@@ -1121,20 +1186,30 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *source_path, Buf *sou...@@ -1121,20 +1186,30 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *source_path, Buf *sou
1121 assert(import_entry->root->type == NodeTypeRoot);1186 assert(import_entry->root->type == NodeTypeRoot);
1122 for (int decl_i = 0; decl_i < import_entry->root->data.root.top_level_decls.length; decl_i += 1) {1187 for (int decl_i = 0; decl_i < import_entry->root->data.root.top_level_decls.length; decl_i += 1) {
1123 AstNode *top_level_decl = import_entry->root->data.root.top_level_decls.at(decl_i);1188 AstNode *top_level_decl = import_entry->root->data.root.top_level_decls.at(decl_i);
1124 if (top_level_decl->type != NodeTypeUse)
1125 continue;
11261189
1127 auto entry = g->import_table.maybe_get(&top_level_decl->data.use.path);1190 if (top_level_decl->type == NodeTypeUse) {
1128 if (!entry) {1191 auto entry = g->import_table.maybe_get(&top_level_decl->data.use.path);
1129 Buf full_path = BUF_INIT;1192 if (!entry) {
1130 os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);1193 Buf full_path = BUF_INIT;
1131 Buf *import_code = buf_alloc();1194 os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);
1132 if ((err = os_fetch_file_path(&full_path, import_code))) {1195 Buf *import_code = buf_alloc();
1133 add_node_error(g, top_level_decl,1196 if ((err = os_fetch_file_path(&full_path, import_code))) {
1134 buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));1197 add_node_error(g, top_level_decl,
1135 break;1198 buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
1199 break;
1200 }
1201 codegen_add_code(g, &top_level_decl->data.use.path, import_code);
1202 }
1203 } else if (top_level_decl->type == NodeTypeFnDef) {
1204 AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
1205 assert(proto_node->type == NodeTypeFnProto);
1206 Buf *proto_name = &proto_node->data.fn_proto.name;
1207
1208 bool is_exported = (proto_node->data.fn_proto.visib_mod == FnProtoVisibModExport);
1209
1210 if (buf_eql_str(proto_name, "main") && is_exported) {
1211 g->insert_bootstrap_code = true;
1136 }1212 }
1137 codegen_add_code(g, &top_level_decl->data.use.path, import_code);
1138 }1213 }
1139 }1214 }
11401215
...@@ -1146,6 +1221,17 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {...@@ -1146,6 +1221,17 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {
11461221
1147 g->root_import = codegen_add_code(g, source_path, source_code);1222 g->root_import = codegen_add_code(g, source_path, source_code);
11481223
1224 if (g->insert_bootstrap_code) {
1225 Buf *path_to_bootstrap_src = buf_sprintf("%s/bootstrap.zig", ZIG_STD_DIR);
1226 Buf *import_code = buf_alloc();
1227 int err;
1228 if ((err = os_fetch_file_path(path_to_bootstrap_src, import_code))) {
1229 zig_panic("unable to open '%s': %s", buf_ptr(path_to_bootstrap_src), err_str(err));
1230 }
1231
1232 codegen_add_code(g, path_to_bootstrap_src, import_code);
1233 }
1234
1149 if (g->verbose) {1235 if (g->verbose) {
1150 fprintf(stderr, "\nSemantic Analysis:\n");1236 fprintf(stderr, "\nSemantic Analysis:\n");
1151 fprintf(stderr, "--------------------\n");1237 fprintf(stderr, "--------------------\n");
...@@ -1185,6 +1271,9 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {...@@ -1185,6 +1271,9 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
1185 } else if (type_entry == g->builtin_types.entry_i32) {1271 } else if (type_entry == g->builtin_types.entry_i32) {
1186 g->c_stdint_used = true;1272 g->c_stdint_used = true;
1187 buf_init_from_str(out_buf, "int32_t");1273 buf_init_from_str(out_buf, "int32_t");
1274 } else if (type_entry == g->builtin_types.entry_isize) {
1275 g->c_stdint_used = true;
1276 buf_init_from_str(out_buf, "intptr_t");
1188 } else if (type_entry == g->builtin_types.entry_f32) {1277 } else if (type_entry == g->builtin_types.entry_f32) {
1189 buf_init_from_str(out_buf, "float");1278 buf_init_from_str(out_buf, "float");
1190 } else if (type_entry == g->builtin_types.entry_unreachable) {1279 } else if (type_entry == g->builtin_types.entry_unreachable) {
src/config.h.in+1
...@@ -7,5 +7,6 @@...@@ -7,5 +7,6 @@
7#define ZIG_VERSION_STRING "@ZIG_VERSION@"7#define ZIG_VERSION_STRING "@ZIG_VERSION@"
88
9#define ZIG_HEADERS_DIR "@CMAKE_INSTALL_PREFIX@/@C_HEADERS_DEST@"9#define ZIG_HEADERS_DIR "@CMAKE_INSTALL_PREFIX@/@C_HEADERS_DEST@"
10#define ZIG_STD_DIR "@CMAKE_INSTALL_PREFIX@/@ZIG_STD_DEST@"
1011
11#endif12#endif
src/parser.cpp+118-1
...@@ -104,6 +104,8 @@ const char *node_type_str(NodeType node_type) {...@@ -104,6 +104,8 @@ const char *node_type_str(NodeType node_type) {
104 return "Label";104 return "Label";
105 case NodeTypeGoto:105 case NodeTypeGoto:
106 return "Label";106 return "Label";
107 case NodeTypeAsmExpr:
108 return "AsmExpr";
107 }109 }
108 zig_unreachable();110 zig_unreachable();
109}111}
...@@ -290,6 +292,9 @@ void ast_print(AstNode *node, int indent) {...@@ -290,6 +292,9 @@ void ast_print(AstNode *node, int indent) {
290 case NodeTypeGoto:292 case NodeTypeGoto:
291 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name));293 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name));
292 break;294 break;
295 case NodeTypeAsmExpr:
296 fprintf(stderr, "%s\n", node_type_str(node->type));
297 break;
293 }298 }
294}299}
295300
...@@ -360,6 +365,71 @@ static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) {...@@ -360,6 +365,71 @@ static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) {
360 buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos);365 buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos);
361}366}
362367
368static void parse_asm_template(ParseContext *pc, AstNode *node) {
369 Buf *asm_template = &node->data.asm_expr.asm_template;
370
371 enum State {
372 StateStart,
373 StatePercent,
374 StateTemplate,
375 };
376
377 ZigList<AsmToken> *tok_list = &node->data.asm_expr.token_list;
378 assert(tok_list->length == 0);
379
380 AsmToken *cur_tok = nullptr;
381
382 enum State state = StateStart;
383
384 for (int i = 0; i < buf_len(asm_template); i += 1) {
385 uint8_t c = *((uint8_t*)buf_ptr(asm_template) + i);
386 switch (state) {
387 case StateStart:
388 if (c == '%') {
389 tok_list->add_one();
390 cur_tok = &tok_list->last();
391 cur_tok->id = AsmTokenIdPercent;
392 cur_tok->start = i;
393 state = StatePercent;
394 } else {
395 tok_list->add_one();
396 cur_tok = &tok_list->last();
397 cur_tok->id = AsmTokenIdTemplate;
398 cur_tok->start = i;
399 state = StateTemplate;
400 }
401 break;
402 case StatePercent:
403 if (c == '%') {
404 cur_tok->end = i;
405 state = StateStart;
406 } else {
407 zig_panic("TODO handle assembly tokenize error");
408 }
409 break;
410 case StateTemplate:
411 if (c == '%') {
412 cur_tok->end = i;
413 i -= 1;
414 cur_tok = nullptr;
415 state = StateStart;
416 }
417 break;
418 }
419 }
420
421 switch (state) {
422 case StateStart:
423 break;
424 case StatePercent:
425 zig_panic("TODO handle assembly tokenize error eof");
426 break;
427 case StateTemplate:
428 cur_tok->end = buf_len(asm_template);
429 break;
430 }
431}
432
363static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf) {433static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf) {
364 // skip the double quotes at beginning and end434 // skip the double quotes at beginning and end
365 // convert escape sequences435 // convert escape sequences
...@@ -1264,7 +1334,50 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand...@@ -1264,7 +1334,50 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
1264}1334}
12651335
1266/*1336/*
1267NonBlockExpression : ReturnExpression | AssignmentExpression1337AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
1338*/
1339static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mandatory) {
1340 Token *asm_token = &pc->tokens->at(*token_index);
1341
1342 if (asm_token->id != TokenIdKeywordAsm) {
1343 if (mandatory) {
1344 ast_invalid_token_error(pc, asm_token);
1345 } else {
1346 return nullptr;
1347 }
1348 }
1349
1350 AstNode *node = ast_create_node(pc, NodeTypeAsmExpr, asm_token);
1351
1352 *token_index += 1;
1353 Token *lparen_tok = &pc->tokens->at(*token_index);
1354
1355 if (lparen_tok->id == TokenIdKeywordVolatile) {
1356 node->data.asm_expr.is_volatile = true;
1357
1358 *token_index += 1;
1359 lparen_tok = &pc->tokens->at(*token_index);
1360 }
1361
1362 ast_expect_token(pc, lparen_tok, TokenIdLParen);
1363 *token_index += 1;
1364
1365 Token *template_tok = &pc->tokens->at(*token_index);
1366 ast_expect_token(pc, template_tok, TokenIdStringLiteral);
1367 *token_index += 1;
1368
1369 parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template);
1370 parse_asm_template(pc, node);
1371
1372 Token *rparen_tok = &pc->tokens->at(*token_index);
1373 ast_expect_token(pc, rparen_tok, TokenIdRParen);
1374 *token_index += 1;
1375
1376 return node;
1377}
1378
1379/*
1380NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
1268*/1381*/
1269static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) {1382static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
1270 Token *token = &pc->tokens->at(*token_index);1383 Token *token = &pc->tokens->at(*token_index);
...@@ -1277,6 +1390,10 @@ static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, boo...@@ -1277,6 +1390,10 @@ static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, boo
1277 if (ass_expr)1390 if (ass_expr)
1278 return ass_expr;1391 return ass_expr;
12791392
1393 AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false);
1394 if (asm_expr)
1395 return asm_expr;
1396
1280 if (mandatory)1397 if (mandatory)
1281 ast_invalid_token_error(pc, token);1398 ast_invalid_token_error(pc, token);
12821399
src/parser.hpp+20
...@@ -16,6 +16,7 @@...@@ -16,6 +16,7 @@
16struct AstNode;16struct AstNode;
17struct CodeGenNode;17struct CodeGenNode;
18struct ImportTableEntry;18struct ImportTableEntry;
19struct AsmToken;
1920
20enum NodeType {21enum NodeType {
21 NodeTypeRoot,22 NodeTypeRoot,
...@@ -45,6 +46,7 @@ enum NodeType {...@@ -45,6 +46,7 @@ enum NodeType {
45 NodeTypeIfExpr,46 NodeTypeIfExpr,
46 NodeTypeLabel,47 NodeTypeLabel,
47 NodeTypeGoto,48 NodeTypeGoto,
49 NodeTypeAsmExpr,
48};50};
4951
50struct AstNodeRoot {52struct AstNodeRoot {
...@@ -203,6 +205,12 @@ struct AstNodeGoto {...@@ -203,6 +205,12 @@ struct AstNodeGoto {
203 Buf name;205 Buf name;
204};206};
205207
208struct AstNodeAsmExpr {
209 bool is_volatile;
210 Buf asm_template;
211 ZigList<AsmToken> token_list;
212};
213
206struct AstNode {214struct AstNode {
207 enum NodeType type;215 enum NodeType type;
208 int line;216 int line;
...@@ -231,6 +239,7 @@ struct AstNode {...@@ -231,6 +239,7 @@ struct AstNode {
231 AstNodeIfExpr if_expr;239 AstNodeIfExpr if_expr;
232 AstNodeLabel label;240 AstNodeLabel label;
233 AstNodeGoto go_to;241 AstNodeGoto go_to;
242 AstNodeAsmExpr asm_expr;
234 Buf number;243 Buf number;
235 Buf string;244 Buf string;
236 Buf symbol;245 Buf symbol;
...@@ -238,6 +247,17 @@ struct AstNode {...@@ -238,6 +247,17 @@ struct AstNode {
238 } data;247 } data;
239};248};
240249
250enum AsmTokenId {
251 AsmTokenIdTemplate,
252 AsmTokenIdPercent,
253};
254
255struct AsmToken {
256 enum AsmTokenId id;
257 int start;
258 int end;
259};
260
241__attribute__ ((format (printf, 2, 3)))261__attribute__ ((format (printf, 2, 3)))
242void ast_token_error(Token *token, const char *format, ...);262void ast_token_error(Token *token, const char *format, ...);
243263
src/tokenizer.cpp+43
...@@ -197,6 +197,10 @@ static void end_token(Tokenize *t) {...@@ -197,6 +197,10 @@ static void end_token(Tokenize *t) {
197 t->cur_tok->id = TokenIdKeywordElse;197 t->cur_tok->id = TokenIdKeywordElse;
198 } else if (mem_eql_str(token_mem, token_len, "goto")) {198 } else if (mem_eql_str(token_mem, token_len, "goto")) {
199 t->cur_tok->id = TokenIdKeywordGoto;199 t->cur_tok->id = TokenIdKeywordGoto;
200 } else if (mem_eql_str(token_mem, token_len, "volatile")) {
201 t->cur_tok->id = TokenIdKeywordVolatile;
202 } else if (mem_eql_str(token_mem, token_len, "asm")) {
203 t->cur_tok->id = TokenIdKeywordAsm;
200 }204 }
201205
202 t->cur_tok = nullptr;206 t->cur_tok = nullptr;
...@@ -637,6 +641,8 @@ static const char * token_name(Token *token) {...@@ -637,6 +641,8 @@ static const char * token_name(Token *token) {
637 case TokenIdKeywordIf: return "If";641 case TokenIdKeywordIf: return "If";
638 case TokenIdKeywordElse: return "Else";642 case TokenIdKeywordElse: return "Else";
639 case TokenIdKeywordGoto: return "Goto";643 case TokenIdKeywordGoto: return "Goto";
644 case TokenIdKeywordVolatile: return "Volatile";
645 case TokenIdKeywordAsm: return "Asm";
640 case TokenIdLParen: return "LParen";646 case TokenIdLParen: return "LParen";
641 case TokenIdRParen: return "RParen";647 case TokenIdRParen: return "RParen";
642 case TokenIdComma: return "Comma";648 case TokenIdComma: return "Comma";
...@@ -687,3 +693,40 @@ void print_tokens(Buf *buf, ZigList<Token> *tokens) {...@@ -687,3 +693,40 @@ void print_tokens(Buf *buf, ZigList<Token> *tokens) {
687 fprintf(stderr, "\n");693 fprintf(stderr, "\n");
688 }694 }
689}695}
696
697bool is_printable(uint8_t c) {
698 switch (c) {
699 default:
700 return false;
701 case DIGIT:
702 case ALPHA:
703 case '!':
704 case '#':
705 case '$':
706 case '%':
707 case '&':
708 case '\'':
709 case '(':
710 case ')':
711 case '*':
712 case '+':
713 case ',':
714 case '-':
715 case '.':
716 case '/':
717 case ':':
718 case ';':
719 case '<':
720 case '=':
721 case '>':
722 case '?':
723 case '@':
724 case '^':
725 case '_':
726 case '`':
727 case '~':
728 case ' ':
729 return true;
730 }
731}
732
src/tokenizer.hpp+4
...@@ -30,6 +30,8 @@ enum TokenId {...@@ -30,6 +30,8 @@ enum TokenId {
30 TokenIdKeywordIf,30 TokenIdKeywordIf,
31 TokenIdKeywordElse,31 TokenIdKeywordElse,
32 TokenIdKeywordGoto,32 TokenIdKeywordGoto,
33 TokenIdKeywordAsm,
34 TokenIdKeywordVolatile,
33 TokenIdLParen,35 TokenIdLParen,
34 TokenIdRParen,36 TokenIdRParen,
35 TokenIdComma,37 TokenIdComma,
...@@ -90,4 +92,6 @@ void tokenize(Buf *buf, Tokenization *out_tokenization);...@@ -90,4 +92,6 @@ void tokenize(Buf *buf, Tokenization *out_tokenization);
9092
91void print_tokens(Buf *buf, ZigList<Token> *tokens);93void print_tokens(Buf *buf, ZigList<Token> *tokens);
9294
95bool is_printable(uint8_t c);
96
93#endif97#endif
std/bootstrap.zig created+16
...@@ -0,0 +1,16 @@
1
2// TODO conditionally compile this differently for non-ELF
3#attribute("naked")
4export fn _start() -> unreachable {
5 // TODO conditionally compile this differently for other architectures and other OSes
6 asm volatile ("
7 mov (%%rsp), %%rdi // first parameter is argc
8 lea 0x8(%%rsp), %%rsi // second parameter is argv
9 lea 0x10(%%rsp,%%rdi,8), %%rdx // third paremeter is env
10 callq main
11 mov %%rax, %%rdi // return value is the parameter to exit syscall
12 mov $60, %%rax // 60 is exit syscall number
13 syscall
14 ");
15 unreachable
16}
test/run_tests.cpp+1
...@@ -397,6 +397,7 @@ loop_2_end:...@@ -397,6 +397,7 @@ loop_2_end:
397 exit(0);397 exit(0);
398}398}
399 )SOURCE", "OK\n");399 )SOURCE", "OK\n");
400
400}401}
401402
402static void add_compile_failure_test_cases(void) {403static void add_compile_failure_test_cases(void) {