| ... | ... | @@ -77,7 +77,8 @@ struct CodeGen { |
| 77 | 77 | ZigList<FnTableEntry *> fn_defs; |
| 78 | 78 | Buf *out_name; |
| 79 | 79 | OutType out_type; |
| 80 | | LLVMValueRef cur_fn; |
| 80 | FnTableEntry *cur_fn; |
| 81 | bool c_stdint_used; |
| 81 | 82 | }; |
| 82 | 83 | |
| 83 | 84 | struct TypeNode { |
| ... | ... | @@ -87,6 +88,7 @@ struct TypeNode { |
| 87 | 88 | struct FnDefNode { |
| 88 | 89 | bool add_implicit_return; |
| 89 | 90 | bool skip; |
| 91 | LLVMValueRef *params; |
| 90 | 92 | }; |
| 91 | 93 | |
| 92 | 94 | struct CodeGenNode { |
| ... | ... | @@ -639,6 +641,23 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) { |
| 639 | 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 | 661 | static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 643 | 662 | assert(node->type == NodeTypeFnCallExpr); |
| 644 | 663 | |
| ... | ... | @@ -797,9 +816,9 @@ static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) { |
| 797 | 816 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); |
| 798 | 817 | |
| 799 | 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 | 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 | 823 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(val1)); |
| 805 | 824 | add_debug_source_node(g, node); |
| ... | ... | @@ -828,9 +847,9 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) { |
| 828 | 847 | LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1); |
| 829 | 848 | |
| 830 | 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 | 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 | 854 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(val1)); |
| 836 | 855 | add_debug_source_node(g, expr_node); |
| ... | ... | @@ -933,6 +952,11 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 933 | 952 | LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, ""); |
| 934 | 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 | 960 | case NodeTypeRoot: |
| 937 | 961 | case NodeTypeRootExportDecl: |
| 938 | 962 | case NodeTypeFnProto: |
| ... | ... | @@ -943,7 +967,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 943 | 967 | case NodeTypeBlock: |
| 944 | 968 | case NodeTypeExternBlock: |
| 945 | 969 | case NodeTypeDirective: |
| 946 | | case NodeTypeSymbol: |
| 947 | 970 | zig_unreachable(); |
| 948 | 971 | } |
| 949 | 972 | zig_unreachable(); |
| ... | ... | @@ -1047,7 +1070,7 @@ void code_gen(CodeGen *g) { |
| 1047 | 1070 | FnTableEntry *fn_table_entry = g->fn_defs.at(i); |
| 1048 | 1071 | AstNode *fn_def_node = fn_table_entry->fn_def_node; |
| 1049 | 1072 | LLVMValueRef fn = fn_table_entry->fn_value; |
| 1050 | | g->cur_fn = fn; |
| 1073 | g->cur_fn = fn_table_entry; |
| 1051 | 1074 | |
| 1052 | 1075 | AstNode *proto_node = fn_table_entry->proto_node; |
| 1053 | 1076 | assert(proto_node->type == NodeTypeFnProto); |
| ... | ... | @@ -1072,7 +1095,12 @@ void code_gen(CodeGen *g) { |
| 1072 | 1095 | |
| 1073 | 1096 | CodeGenNode *codegen_node = fn_def_node->codegen_node; |
| 1074 | 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 | 1104 | gen_block(g, fn_def_node->data.fn_def.body, add_implicit_return); |
| 1077 | 1105 | |
| 1078 | 1106 | g->block_scopes.pop(); |
| ... | ... | @@ -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 |
| 1222 | | ar cq libfoo.a foo1.o foo2.o |
| 1251 | TypeTableEntry *type_entry = type_node->codegen_node->data.type_node.entry; |
| 1252 | assert(type_entry); |
| 1223 | 1253 | |
| 1224 | | # dynamic link into libfoo.so |
| 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 |
| 1254 | switch (type_entry->id) { |
| 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 | 1354 | void code_gen_link(CodeGen *g, const char *out_file) { |
| 1229 | 1355 | if (!out_file) { |
| 1230 | 1356 | out_file = buf_ptr(g->out_name); |
| ... | ... | @@ -1250,6 +1376,9 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 1250 | 1376 | |
| 1251 | 1377 | if (g->out_type == OutTypeLib && g->is_static) { |
| 1252 | 1378 | // invoke `ar` |
| 1379 | // example: |
| 1380 | // # static link into libfoo.a |
| 1381 | // ar cq libfoo.a foo1.o foo2.o |
| 1253 | 1382 | zig_panic("TODO invoke ar"); |
| 1254 | 1383 | return; |
| 1255 | 1384 | } |
| ... | ... | @@ -1260,10 +1389,6 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 1260 | 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 | 1392 | char *ZIG_NATIVE_DYNAMIC_LINKER = getenv("ZIG_NATIVE_DYNAMIC_LINKER"); |
| 1268 | 1393 | if (g->is_native_target && ZIG_NATIVE_DYNAMIC_LINKER) { |
| 1269 | 1394 | if (ZIG_NATIVE_DYNAMIC_LINKER[0] != 0) { |
| ... | ... | @@ -1275,6 +1400,18 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 1275 | 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 | 1415 | args.append("-o"); |
| 1279 | 1416 | args.append(out_file); |
| 1280 | 1417 | |
| ... | ... | @@ -1291,6 +1428,10 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 1291 | 1428 | } |
| 1292 | 1429 | |
| 1293 | 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 | |