| ... | @@ -77,7 +77,8 @@ struct CodeGen { | ... | @@ -77,7 +77,8 @@ struct CodeGen { |
| 77 | ZigList<FnTableEntry *> fn_defs; | 77 | ZigList<FnTableEntry *> fn_defs; |
| 78 | Buf *out_name; | 78 | Buf *out_name; |
| 79 | OutType out_type; | 79 | OutType out_type; |
| 80 | LLVMValueRef cur_fn; | 80 | FnTableEntry *cur_fn; |
| | 81 | bool c_stdint_used; |
| 81 | }; | 82 | }; |
| 82 | | 83 | |
| 83 | struct TypeNode { | 84 | struct TypeNode { |
| ... | @@ -87,6 +88,7 @@ struct TypeNode { | ... | @@ -87,6 +88,7 @@ struct TypeNode { |
| 87 | struct FnDefNode { | 88 | struct FnDefNode { |
| 88 | bool add_implicit_return; | 89 | bool add_implicit_return; |
| 89 | bool skip; | 90 | bool skip; |
| | 91 | LLVMValueRef *params; |
| 90 | }; | 92 | }; |
| 91 | | 93 | |
| 92 | struct CodeGenNode { | 94 | struct CodeGenNode { |
| ... | @@ -639,6 +641,23 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) { | ... | @@ -639,6 +641,23 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) { |
| 639 | return global_value; | 641 | return global_value; |
| 640 | } | 642 | } |
| 641 | | 643 | |
| | 644 | static LLVMValueRef get_variable_value(CodeGen *g, Buf *name) { |
| | 645 | assert(g->cur_fn->proto_node->type == NodeTypeFnProto); |
| | 646 | int param_count = g->cur_fn->proto_node->data.fn_proto.params.length; |
| | 647 | for (int i = 0; i < param_count; i += 1) { |
| | 648 | AstNode *param_decl_node = g->cur_fn->proto_node->data.fn_proto.params.at(i); |
| | 649 | assert(param_decl_node->type == NodeTypeParamDecl); |
| | 650 | Buf *param_name = &param_decl_node->data.param_decl.name; |
| | 651 | if (buf_eql_buf(name, param_name)) { |
| | 652 | CodeGenNode *codegen_node = g->cur_fn->fn_def_node->codegen_node; |
| | 653 | assert(codegen_node); |
| | 654 | FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node; |
| | 655 | return codegen_fn_def->params[i]; |
| | 656 | } |
| | 657 | } |
| | 658 | zig_unreachable(); |
| | 659 | } |
| | 660 | |
| 642 | static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { | 661 | static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 643 | assert(node->type == NodeTypeFnCallExpr); | 662 | assert(node->type == NodeTypeFnCallExpr); |
| 644 | | 663 | |
| ... | @@ -797,9 +816,9 @@ static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) { | ... | @@ -797,9 +816,9 @@ static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) { |
| 797 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); | 816 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); |
| 798 | | 817 | |
| 799 | // block for when val1 == true | 818 | // block for when val1 == true |
| 800 | LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn, "BoolAndTrue"); | 819 | LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndTrue"); |
| 801 | // block for when val1 == false (don't even evaluate the second part) | 820 | // block for when val1 == false (don't even evaluate the second part) |
| 802 | LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn, "BoolAndFalse"); | 821 | LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndFalse"); |
| 803 | | 822 | |
| 804 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(val1)); | 823 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(val1)); |
| 805 | add_debug_source_node(g, node); | 824 | add_debug_source_node(g, node); |
| ... | @@ -828,9 +847,9 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) { | ... | @@ -828,9 +847,9 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) { |
| 828 | LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1); | 847 | LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1); |
| 829 | | 848 | |
| 830 | // block for when val1 == false | 849 | // block for when val1 == false |
| 831 | LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn, "BoolOrFalse"); | 850 | LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrFalse"); |
| 832 | // block for when val1 == true (don't even evaluate the second part) | 851 | // block for when val1 == true (don't even evaluate the second part) |
| 833 | LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn, "BoolOrTrue"); | 852 | LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrTrue"); |
| 834 | | 853 | |
| 835 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(val1)); | 854 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(val1)); |
| 836 | add_debug_source_node(g, expr_node); | 855 | add_debug_source_node(g, expr_node); |
| ... | @@ -933,6 +952,11 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -933,6 +952,11 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 933 | LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, ""); | 952 | LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, ""); |
| 934 | return ptr_val; | 953 | return ptr_val; |
| 935 | } | 954 | } |
| | 955 | case NodeTypeSymbol: |
| | 956 | { |
| | 957 | Buf *name = &node->data.symbol; |
| | 958 | return get_variable_value(g, name); |
| | 959 | } |
| 936 | case NodeTypeRoot: | 960 | case NodeTypeRoot: |
| 937 | case NodeTypeRootExportDecl: | 961 | case NodeTypeRootExportDecl: |
| 938 | case NodeTypeFnProto: | 962 | case NodeTypeFnProto: |
| ... | @@ -943,7 +967,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -943,7 +967,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 943 | case NodeTypeBlock: | 967 | case NodeTypeBlock: |
| 944 | case NodeTypeExternBlock: | 968 | case NodeTypeExternBlock: |
| 945 | case NodeTypeDirective: | 969 | case NodeTypeDirective: |
| 946 | case NodeTypeSymbol: | | |
| 947 | zig_unreachable(); | 970 | zig_unreachable(); |
| 948 | } | 971 | } |
| 949 | zig_unreachable(); | 972 | zig_unreachable(); |
| ... | @@ -1047,7 +1070,7 @@ void code_gen(CodeGen *g) { | ... | @@ -1047,7 +1070,7 @@ void code_gen(CodeGen *g) { |
| 1047 | FnTableEntry *fn_table_entry = g->fn_defs.at(i); | 1070 | FnTableEntry *fn_table_entry = g->fn_defs.at(i); |
| 1048 | AstNode *fn_def_node = fn_table_entry->fn_def_node; | 1071 | AstNode *fn_def_node = fn_table_entry->fn_def_node; |
| 1049 | LLVMValueRef fn = fn_table_entry->fn_value; | 1072 | LLVMValueRef fn = fn_table_entry->fn_value; |
| 1050 | g->cur_fn = fn; | 1073 | g->cur_fn = fn_table_entry; |
| 1051 | | 1074 | |
| 1052 | AstNode *proto_node = fn_table_entry->proto_node; | 1075 | AstNode *proto_node = fn_table_entry->proto_node; |
| 1053 | assert(proto_node->type == NodeTypeFnProto); | 1076 | assert(proto_node->type == NodeTypeFnProto); |
| ... | @@ -1072,7 +1095,12 @@ void code_gen(CodeGen *g) { | ... | @@ -1072,7 +1095,12 @@ void code_gen(CodeGen *g) { |
| 1072 | | 1095 | |
| 1073 | CodeGenNode *codegen_node = fn_def_node->codegen_node; | 1096 | CodeGenNode *codegen_node = fn_def_node->codegen_node; |
| 1074 | assert(codegen_node); | 1097 | assert(codegen_node); |
| 1075 | bool add_implicit_return = codegen_node->data.fn_def_node.add_implicit_return; | 1098 | |
| | 1099 | FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node; |
| | 1100 | codegen_fn_def->params = allocate<LLVMValueRef>(LLVMCountParams(fn)); |
| | 1101 | LLVMGetParams(fn, codegen_fn_def->params); |
| | 1102 | |
| | 1103 | bool add_implicit_return = codegen_fn_def->add_implicit_return; |
| 1076 | gen_block(g, fn_def_node->data.fn_def.body, add_implicit_return); | 1104 | gen_block(g, fn_def_node->data.fn_def.body, add_implicit_return); |
| 1077 | | 1105 | |
| 1078 | g->block_scopes.pop(); | 1106 | g->block_scopes.pop(); |
| ... | @@ -1216,15 +1244,113 @@ static Buf *get_dynamic_linker(CodeGen *g) { | ... | @@ -1216,15 +1244,113 @@ static Buf *get_dynamic_linker(CodeGen *g) { |
| 1216 | } | 1244 | } |
| 1217 | } | 1245 | } |
| 1218 | | 1246 | |
| 1219 | /* | 1247 | static Buf *to_c_type(CodeGen *g, AstNode *type_node) { |
| | 1248 | assert(type_node->type == NodeTypeType); |
| | 1249 | assert(type_node->codegen_node); |
| 1220 | | 1250 | |
| 1221 | # static link into libfoo.a | 1251 | TypeTableEntry *type_entry = type_node->codegen_node->data.type_node.entry; |
| 1222 | ar cq libfoo.a foo1.o foo2.o | 1252 | assert(type_entry); |
| 1223 | | 1253 | |
| 1224 | # dynamic link into libfoo.so | 1254 | switch (type_entry->id) { |
| 1225 | gcc -fPIC -g -Werror -pedantic -shared -Wl,-soname,libsoundio.so.1 -o libsoundio.so.1.0.3 foo1.o foo2.o -ljack -lpulse -lasound -lpthread | 1255 | case TypeIdUserDefined: |
| | 1256 | zig_panic("TODO"); |
| | 1257 | break; |
| | 1258 | case TypeIdPointer: |
| | 1259 | zig_panic("TODO"); |
| | 1260 | break; |
| | 1261 | case TypeIdU8: |
| | 1262 | g->c_stdint_used = true; |
| | 1263 | return buf_create_from_str("uint8_t"); |
| | 1264 | case TypeIdI32: |
| | 1265 | g->c_stdint_used = true; |
| | 1266 | return buf_create_from_str("int32_t"); |
| | 1267 | case TypeIdVoid: |
| | 1268 | zig_panic("TODO"); |
| | 1269 | break; |
| | 1270 | case TypeIdUnreachable: |
| | 1271 | zig_panic("TODO"); |
| | 1272 | break; |
| | 1273 | } |
| | 1274 | zig_unreachable(); |
| | 1275 | } |
| | 1276 | |
| | 1277 | static void generate_h_file(CodeGen *g) { |
| | 1278 | Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->out_name)); |
| | 1279 | FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb"); |
| | 1280 | if (!out_h) |
| | 1281 | zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno)); |
| | 1282 | |
| | 1283 | Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->out_name)); |
| | 1284 | buf_upcase(export_macro); |
| | 1285 | |
| | 1286 | Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->out_name)); |
| | 1287 | buf_upcase(extern_c_macro); |
| | 1288 | |
| | 1289 | Buf h_buf = BUF_INIT; |
| | 1290 | buf_resize(&h_buf, 0); |
| | 1291 | for (int fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { |
| | 1292 | FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i); |
| | 1293 | AstNode *proto_node = fn_table_entry->proto_node; |
| | 1294 | assert(proto_node->type == NodeTypeFnProto); |
| | 1295 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| | 1296 | |
| | 1297 | if (fn_proto->visib_mod != FnProtoVisibModExport) |
| | 1298 | continue; |
| | 1299 | |
| | 1300 | buf_appendf(&h_buf, "%s %s %s(", |
| | 1301 | buf_ptr(export_macro), |
| | 1302 | buf_ptr(to_c_type(g, fn_proto->return_type)), |
| | 1303 | buf_ptr(&fn_proto->name)); |
| | 1304 | |
| | 1305 | if (fn_proto->params.length) { |
| | 1306 | for (int param_i = 0; param_i < fn_proto->params.length; param_i += 1) { |
| | 1307 | AstNode *param_decl_node = fn_proto->params.at(param_i); |
| | 1308 | AstNode *param_type = param_decl_node->data.param_decl.type; |
| | 1309 | buf_appendf(&h_buf, "%s %s", |
| | 1310 | buf_ptr(to_c_type(g, param_type)), |
| | 1311 | buf_ptr(&param_decl_node->data.param_decl.name)); |
| | 1312 | if (param_i < fn_proto->params.length - 1) |
| | 1313 | buf_appendf(&h_buf, ", "); |
| | 1314 | } |
| | 1315 | buf_appendf(&h_buf, ");\n"); |
| | 1316 | } else { |
| | 1317 | buf_appendf(&h_buf, "void);\n"); |
| | 1318 | } |
| | 1319 | } |
| | 1320 | |
| | 1321 | Buf *ifdef_dance_name = buf_sprintf("%s_%s_H", buf_ptr(g->out_name), buf_ptr(g->out_name)); |
| | 1322 | buf_upcase(ifdef_dance_name); |
| | 1323 | |
| | 1324 | fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name)); |
| | 1325 | fprintf(out_h, "#define %s\n\n", buf_ptr(ifdef_dance_name)); |
| | 1326 | |
| | 1327 | if (g->c_stdint_used) |
| | 1328 | fprintf(out_h, "#include <stdint.h>\n"); |
| | 1329 | |
| | 1330 | fprintf(out_h, "\n"); |
| | 1331 | |
| | 1332 | fprintf(out_h, "#ifdef __cplusplus\n"); |
| | 1333 | fprintf(out_h, "#define %s extern \"C\"\n", buf_ptr(extern_c_macro)); |
| | 1334 | fprintf(out_h, "#else\n"); |
| | 1335 | fprintf(out_h, "#define %s\n", buf_ptr(extern_c_macro)); |
| | 1336 | fprintf(out_h, "#endif\n"); |
| | 1337 | fprintf(out_h, "\n"); |
| | 1338 | fprintf(out_h, "#if defined(_WIN32)\n"); |
| | 1339 | fprintf(out_h, "#define %s %s __declspec(dllimport)\n", buf_ptr(export_macro), buf_ptr(extern_c_macro)); |
| | 1340 | fprintf(out_h, "#else\n"); |
| | 1341 | fprintf(out_h, "#define %s %s __attribute__((visibility (\"default\")))\n", |
| | 1342 | buf_ptr(export_macro), buf_ptr(extern_c_macro)); |
| | 1343 | fprintf(out_h, "#endif\n"); |
| | 1344 | fprintf(out_h, "\n"); |
| | 1345 | |
| | 1346 | fprintf(out_h, "%s", buf_ptr(&h_buf)); |
| | 1347 | |
| | 1348 | fprintf(out_h, "\n#endif\n"); |
| | 1349 | |
| | 1350 | if (fclose(out_h)) |
| | 1351 | zig_panic("unable to close h file: %s", strerror(errno)); |
| | 1352 | } |
| 1226 | | 1353 | |
| 1227 | */ | | |
| 1228 | void code_gen_link(CodeGen *g, const char *out_file) { | 1354 | void code_gen_link(CodeGen *g, const char *out_file) { |
| 1229 | if (!out_file) { | 1355 | if (!out_file) { |
| 1230 | out_file = buf_ptr(g->out_name); | 1356 | out_file = buf_ptr(g->out_name); |
| ... | @@ -1250,6 +1376,9 @@ void code_gen_link(CodeGen *g, const char *out_file) { | ... | @@ -1250,6 +1376,9 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 1250 | | 1376 | |
| 1251 | if (g->out_type == OutTypeLib && g->is_static) { | 1377 | if (g->out_type == OutTypeLib && g->is_static) { |
| 1252 | // invoke `ar` | 1378 | // invoke `ar` |
| | 1379 | // example: |
| | 1380 | // # static link into libfoo.a |
| | 1381 | // ar cq libfoo.a foo1.o foo2.o |
| 1253 | zig_panic("TODO invoke ar"); | 1382 | zig_panic("TODO invoke ar"); |
| 1254 | return; | 1383 | return; |
| 1255 | } | 1384 | } |
| ... | @@ -1260,10 +1389,6 @@ void code_gen_link(CodeGen *g, const char *out_file) { | ... | @@ -1260,10 +1389,6 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 1260 | args.append("-static"); | 1389 | args.append("-static"); |
| 1261 | } | 1390 | } |
| 1262 | | 1391 | |
| 1263 | if (g->out_type == OutTypeLib) { | | |
| 1264 | zig_panic("TODO add ld commands for shared library"); | | |
| 1265 | } | | |
| 1266 | | | |
| 1267 | char *ZIG_NATIVE_DYNAMIC_LINKER = getenv("ZIG_NATIVE_DYNAMIC_LINKER"); | 1392 | char *ZIG_NATIVE_DYNAMIC_LINKER = getenv("ZIG_NATIVE_DYNAMIC_LINKER"); |
| 1268 | if (g->is_native_target && ZIG_NATIVE_DYNAMIC_LINKER) { | 1393 | if (g->is_native_target && ZIG_NATIVE_DYNAMIC_LINKER) { |
| 1269 | if (ZIG_NATIVE_DYNAMIC_LINKER[0] != 0) { | 1394 | if (ZIG_NATIVE_DYNAMIC_LINKER[0] != 0) { |
| ... | @@ -1275,6 +1400,18 @@ void code_gen_link(CodeGen *g, const char *out_file) { | ... | @@ -1275,6 +1400,18 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 1275 | args.append(buf_ptr(get_dynamic_linker(g))); | 1400 | args.append(buf_ptr(get_dynamic_linker(g))); |
| 1276 | } | 1401 | } |
| 1277 | | 1402 | |
| | 1403 | if (g->out_type == OutTypeLib) { |
| | 1404 | int major = 1; |
| | 1405 | int minor = 0; |
| | 1406 | int patch = 0; |
| | 1407 | Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d", buf_ptr(g->out_name), major, minor, patch); |
| | 1408 | Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), major); |
| | 1409 | args.append("-shared"); |
| | 1410 | args.append("-soname"); |
| | 1411 | args.append(buf_ptr(soname)); |
| | 1412 | out_file = buf_ptr(out_lib_so); |
| | 1413 | } |
| | 1414 | |
| 1278 | args.append("-o"); | 1415 | args.append("-o"); |
| 1279 | args.append(out_file); | 1416 | args.append(out_file); |
| 1280 | | 1417 | |
| ... | @@ -1291,6 +1428,10 @@ void code_gen_link(CodeGen *g, const char *out_file) { | ... | @@ -1291,6 +1428,10 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 1291 | } | 1428 | } |
| 1292 | | 1429 | |
| 1293 | os_spawn_process("ld", args, false); | 1430 | os_spawn_process("ld", args, false); |
| | 1431 | |
| | 1432 | if (g->out_type == OutTypeLib) { |
| | 1433 | generate_h_file(g); |
| | 1434 | } |
| 1294 | } | 1435 | } |
| 1295 | | 1436 | |
| 1296 | | 1437 | |