authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-11-30 09:14:58-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-11-30 09:14:58-07:00
log9e0ff6faa2458a431875b38d24f754def450117e
tree1cc856285f34f880523f395fbaf7b9838a0fcb11
parent020f854f6f794e8f9a39ad9d18c6173650ed5be3

factor analysis code out of codegen


9 files changed, 643 insertions(+), 595 deletions(-)

CMakeLists.txt+1
...@@ -22,6 +22,7 @@ include_directories(...@@ -22,6 +22,7 @@ include_directories(
22)22)
2323
24set(ZIG_SOURCES24set(ZIG_SOURCES
25 "${CMAKE_SOURCE_DIR}/src/analyze.cpp"
25 "${CMAKE_SOURCE_DIR}/src/buffer.cpp"26 "${CMAKE_SOURCE_DIR}/src/buffer.cpp"
26 "${CMAKE_SOURCE_DIR}/src/error.cpp"27 "${CMAKE_SOURCE_DIR}/src/error.cpp"
27 "${CMAKE_SOURCE_DIR}/src/main.cpp"28 "${CMAKE_SOURCE_DIR}/src/main.cpp"
src/analyze.cpp created+498
...@@ -0,0 +1,498 @@
1/*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#include "analyze.hpp"
9#include "semantic_info.hpp"
10#include "error.hpp"
11#include "zig_llvm.hpp"
12
13static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
14 g->errors.add_one();
15 ErrorMsg *last_msg = &g->errors.last();
16 last_msg->line_start = node->line;
17 last_msg->column_start = node->column;
18 last_msg->line_end = -1;
19 last_msg->column_end = -1;
20 last_msg->msg = msg;
21}
22
23static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
24 char *dot1 = strstr(buf_ptr(buf), ".");
25 if (!dot1)
26 return ErrorInvalidFormat;
27 char *dot2 = strstr(dot1 + 1, ".");
28 if (!dot2)
29 return ErrorInvalidFormat;
30
31 *major = (int)strtol(buf_ptr(buf), nullptr, 10);
32 *minor = (int)strtol(dot1 + 1, nullptr, 10);
33 *patch = (int)strtol(dot2 + 1, nullptr, 10);
34
35 return ErrorNone;
36}
37
38static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) {
39 int err;
40 if ((err = parse_version_string(version_buf, &g->version_major, &g->version_minor, &g->version_patch))) {
41 add_node_error(g, node,
42 buf_sprintf("invalid version string"));
43 }
44}
45
46static void find_declarations(CodeGen *g, AstNode *node);
47
48static void resolve_type_and_recurse(CodeGen *g, AstNode *node) {
49 assert(!node->codegen_node);
50 node->codegen_node = allocate<CodeGenNode>(1);
51 TypeNode *type_node = &node->codegen_node->data.type_node;
52 switch (node->data.type.type) {
53 case AstNodeTypeTypePrimitive:
54 {
55 Buf *name = &node->data.type.primitive_name;
56 auto table_entry = g->type_table.maybe_get(name);
57 if (table_entry) {
58 type_node->entry = table_entry->value;
59 } else {
60 add_node_error(g, node,
61 buf_sprintf("invalid type name: '%s'", buf_ptr(name)));
62 type_node->entry = g->invalid_type_entry;
63 }
64 break;
65 }
66 case AstNodeTypeTypePointer:
67 {
68 find_declarations(g, node->data.type.child_type);
69 TypeNode *child_type_node = &node->data.type.child_type->codegen_node->data.type_node;
70 if (child_type_node->entry->id == TypeIdUnreachable) {
71 add_node_error(g, node,
72 buf_create_from_str("pointer to unreachable not allowed"));
73 }
74 TypeTableEntry **parent_pointer = node->data.type.is_const ?
75 &child_type_node->entry->pointer_const_parent :
76 &child_type_node->entry->pointer_mut_parent;
77 const char *const_or_mut_str = node->data.type.is_const ? "const" : "mut";
78 if (*parent_pointer) {
79 type_node->entry = *parent_pointer;
80 } else {
81 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
82 entry->id = TypeIdPointer;
83 entry->type_ref = LLVMPointerType(child_type_node->entry->type_ref, 0);
84 buf_resize(&entry->name, 0);
85 buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type_node->entry->name));
86 entry->di_type = g->dbuilder->createPointerType(child_type_node->entry->di_type,
87 g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name));
88 g->type_table.put(&entry->name, entry);
89 type_node->entry = entry;
90 *parent_pointer = entry;
91 }
92 break;
93 }
94 }
95}
96
97static void find_declarations(CodeGen *g, AstNode *node) {
98 switch (node->type) {
99 case NodeTypeExternBlock:
100 for (int i = 0; i < node->data.extern_block.directives->length; i += 1) {
101 AstNode *directive_node = node->data.extern_block.directives->at(i);
102 Buf *name = &directive_node->data.directive.name;
103 Buf *param = &directive_node->data.directive.param;
104 if (buf_eql_str(name, "link")) {
105 g->link_table.put(param, true);
106 } else {
107 add_node_error(g, directive_node,
108 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
109 }
110 }
111
112 for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
113 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
114 assert(fn_decl->type == NodeTypeFnDecl);
115 AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;
116 find_declarations(g, fn_proto);
117 Buf *name = &fn_proto->data.fn_proto.name;
118
119 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
120 fn_table_entry->proto_node = fn_proto;
121 fn_table_entry->is_extern = true;
122 fn_table_entry->calling_convention = LLVMCCallConv;
123 g->fn_table.put(name, fn_table_entry);
124 }
125 break;
126 case NodeTypeFnDef:
127 {
128 AstNode *proto_node = node->data.fn_def.fn_proto;
129 assert(proto_node->type == NodeTypeFnProto);
130 Buf *proto_name = &proto_node->data.fn_proto.name;
131 auto entry = g->fn_table.maybe_get(proto_name);
132 if (entry) {
133 add_node_error(g, node,
134 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
135 assert(!node->codegen_node);
136 node->codegen_node = allocate<CodeGenNode>(1);
137 node->codegen_node->data.fn_def_node.skip = true;
138 } else {
139 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
140 fn_table_entry->proto_node = proto_node;
141 fn_table_entry->fn_def_node = node;
142 fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;
143 if (fn_table_entry->internal_linkage) {
144 fn_table_entry->calling_convention = LLVMFastCallConv;
145 } else {
146 fn_table_entry->calling_convention = LLVMCCallConv;
147 }
148 g->fn_table.put(proto_name, fn_table_entry);
149 g->fn_defs.append(fn_table_entry);
150
151 find_declarations(g, proto_node);
152 }
153 break;
154 }
155 case NodeTypeFnProto:
156 {
157 for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
158 AstNode *directive_node = node->data.fn_proto.directives->at(i);
159 Buf *name = &directive_node->data.directive.name;
160 add_node_error(g, directive_node,
161 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
162 }
163 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
164 AstNode *child = node->data.fn_proto.params.at(i);
165 find_declarations(g, child);
166 }
167 find_declarations(g, node->data.fn_proto.return_type);
168 break;
169 }
170 break;
171 case NodeTypeParamDecl:
172 find_declarations(g, node->data.param_decl.type);
173 break;
174 case NodeTypeType:
175 resolve_type_and_recurse(g, node);
176 break;
177 case NodeTypeDirective:
178 // we handled directives in the parent function
179 break;
180 case NodeTypeRootExportDecl:
181 for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
182 AstNode *directive_node = node->data.root_export_decl.directives->at(i);
183 Buf *name = &directive_node->data.directive.name;
184 Buf *param = &directive_node->data.directive.param;
185 if (buf_eql_str(name, "version")) {
186 set_root_export_version(g, param, directive_node);
187 } else {
188 add_node_error(g, directive_node,
189 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
190 }
191 }
192 break;
193 case NodeTypeFnDecl:
194 case NodeTypeReturnExpr:
195 case NodeTypeRoot:
196 case NodeTypeBlock:
197 case NodeTypeBinOpExpr:
198 case NodeTypeFnCallExpr:
199 case NodeTypeNumberLiteral:
200 case NodeTypeStringLiteral:
201 case NodeTypeUnreachable:
202 case NodeTypeSymbol:
203 case NodeTypeCastExpr:
204 case NodeTypePrefixOpExpr:
205 zig_unreachable();
206 }
207}
208
209static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {
210 // Follow the execution flow and make sure the code returns appropriately.
211 // * A `return` statement in an unreachable type function should be an error.
212 // * Control flow should not be able to reach the end of an unreachable type function.
213 // * Functions that have a type other than void should not return without a value.
214 // * void functions without explicit return statements at the end need the
215 // add_implicit_return flag set on the codegen node.
216 assert(node->type == NodeTypeFnDef);
217 AstNode *proto_node = node->data.fn_def.fn_proto;
218 assert(proto_node->type == NodeTypeFnProto);
219 AstNode *return_type_node = proto_node->data.fn_proto.return_type;
220 assert(return_type_node->type == NodeTypeType);
221
222 node->codegen_node = allocate<CodeGenNode>(1);
223 FnDefNode *codegen_fn_def = &node->codegen_node->data.fn_def_node;
224
225 assert(return_type_node->codegen_node);
226 TypeTableEntry *type_entry = return_type_node->codegen_node->data.type_node.entry;
227 assert(type_entry);
228 TypeId type_id = type_entry->id;
229
230 AstNode *body_node = node->data.fn_def.body;
231 assert(body_node->type == NodeTypeBlock);
232
233 // TODO once we understand types, do this pass after type checking, and
234 // if an expression has an unreachable value then stop looking at statements after
235 // it. then we can remove the check to `unreachable` in the end of this function.
236 bool prev_statement_return = false;
237 for (int i = 0; i < body_node->data.block.statements.length; i += 1) {
238 AstNode *statement_node = body_node->data.block.statements.at(i);
239 if (statement_node->type == NodeTypeReturnExpr) {
240 if (type_id == TypeIdUnreachable) {
241 add_node_error(g, statement_node,
242 buf_sprintf("return statement in function with unreachable return type"));
243 return;
244 } else {
245 prev_statement_return = true;
246 }
247 } else if (prev_statement_return) {
248 add_node_error(g, statement_node,
249 buf_sprintf("unreachable code"));
250 }
251 }
252
253 if (!prev_statement_return) {
254 if (type_id == TypeIdVoid) {
255 codegen_fn_def->add_implicit_return = true;
256 } else if (type_id != TypeIdUnreachable) {
257 add_node_error(g, node,
258 buf_sprintf("control reaches end of non-void function"));
259 }
260 }
261}
262
263static void analyze_node(CodeGen *g, AstNode *node) {
264 switch (node->type) {
265 case NodeTypeRoot:
266 {
267 // Iterate once over the top level declarations to build the function table
268 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
269 AstNode *child = node->data.root.top_level_decls.at(i);
270 find_declarations(g, child);
271 }
272 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
273 AstNode *child = node->data.root.top_level_decls.at(i);
274 analyze_node(g, child);
275 }
276 if (!g->out_name) {
277 add_node_error(g, node,
278 buf_sprintf("missing export declaration and output name not provided"));
279 } else if (g->out_type == OutTypeUnknown) {
280 add_node_error(g, node,
281 buf_sprintf("missing export declaration and export type not provided"));
282 }
283 break;
284 }
285 case NodeTypeRootExportDecl:
286 if (g->root_export_decl) {
287 add_node_error(g, node,
288 buf_sprintf("only one root export declaration allowed"));
289 } else {
290 g->root_export_decl = node;
291
292 if (!g->out_name)
293 g->out_name = &node->data.root_export_decl.name;
294
295 Buf *out_type = &node->data.root_export_decl.type;
296 OutType export_out_type;
297 if (buf_eql_str(out_type, "executable")) {
298 export_out_type = OutTypeExe;
299 } else if (buf_eql_str(out_type, "library")) {
300 export_out_type = OutTypeLib;
301 } else if (buf_eql_str(out_type, "object")) {
302 export_out_type = OutTypeObj;
303 } else {
304 add_node_error(g, node,
305 buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
306 }
307 if (g->out_type == OutTypeUnknown)
308 g->out_type = export_out_type;
309 }
310 break;
311 case NodeTypeExternBlock:
312 for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
313 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
314 analyze_node(g, fn_decl);
315 }
316 break;
317 case NodeTypeFnDef:
318 {
319 if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) {
320 // we detected an error with this function definition which prevents us
321 // from further analyzing it.
322 break;
323 }
324
325 AstNode *proto_node = node->data.fn_def.fn_proto;
326 assert(proto_node->type == NodeTypeFnProto);
327 analyze_node(g, proto_node);
328
329 check_fn_def_control_flow(g, node);
330 analyze_node(g, node->data.fn_def.body);
331 break;
332 }
333 case NodeTypeFnDecl:
334 {
335 AstNode *proto_node = node->data.fn_decl.fn_proto;
336 assert(proto_node->type == NodeTypeFnProto);
337 analyze_node(g, proto_node);
338 break;
339 }
340 case NodeTypeFnProto:
341 {
342 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
343 AstNode *child = node->data.fn_proto.params.at(i);
344 analyze_node(g, child);
345 }
346 analyze_node(g, node->data.fn_proto.return_type);
347 break;
348 }
349 case NodeTypeParamDecl:
350 analyze_node(g, node->data.param_decl.type);
351 break;
352
353 case NodeTypeType:
354 // ignore; we handled types with find_declarations
355 break;
356 case NodeTypeBlock:
357 for (int i = 0; i < node->data.block.statements.length; i += 1) {
358 AstNode *child = node->data.block.statements.at(i);
359 analyze_node(g, child);
360 }
361 break;
362 case NodeTypeReturnExpr:
363 if (node->data.return_expr.expr) {
364 analyze_node(g, node->data.return_expr.expr);
365 }
366 break;
367 case NodeTypeBinOpExpr:
368 analyze_node(g, node->data.bin_op_expr.op1);
369 analyze_node(g, node->data.bin_op_expr.op2);
370 break;
371 case NodeTypeFnCallExpr:
372 {
373 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
374
375 auto entry = g->fn_table.maybe_get(name);
376 if (!entry) {
377 add_node_error(g, node,
378 buf_sprintf("undefined function: '%s'", buf_ptr(name)));
379 } else {
380 FnTableEntry *fn_table_entry = entry->value;
381 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
382 int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length;
383 int actual_param_count = node->data.fn_call_expr.params.length;
384 if (expected_param_count != actual_param_count) {
385 add_node_error(g, node,
386 buf_sprintf("wrong number of arguments. Expected %d, got %d.",
387 expected_param_count, actual_param_count));
388 }
389 }
390
391 for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
392 AstNode *child = node->data.fn_call_expr.params.at(i);
393 analyze_node(g, child);
394 }
395 break;
396 }
397 case NodeTypeDirective:
398 // we looked at directives in the parent node
399 break;
400 case NodeTypeCastExpr:
401 zig_panic("TODO");
402 break;
403 case NodeTypePrefixOpExpr:
404 zig_panic("TODO");
405 break;
406 case NodeTypeNumberLiteral:
407 case NodeTypeStringLiteral:
408 case NodeTypeUnreachable:
409 case NodeTypeSymbol:
410 // nothing to do
411 break;
412 }
413}
414
415static void add_types(CodeGen *g) {
416 {
417 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
418 entry->id = TypeIdU8;
419 entry->type_ref = LLVMInt8Type();
420 buf_init_from_str(&entry->name, "u8");
421 entry->di_type = g->dbuilder->createBasicType(buf_ptr(&entry->name), 8, 8, llvm::dwarf::DW_ATE_unsigned);
422 g->type_table.put(&entry->name, entry);
423 }
424 {
425 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
426 entry->id = TypeIdI32;
427 entry->type_ref = LLVMInt32Type();
428 buf_init_from_str(&entry->name, "i32");
429 entry->di_type = g->dbuilder->createBasicType(buf_ptr(&entry->name), 32, 32,
430 llvm::dwarf::DW_ATE_signed);
431 g->type_table.put(&entry->name, entry);
432 }
433 {
434 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
435 entry->id = TypeIdVoid;
436 entry->type_ref = LLVMVoidType();
437 buf_init_from_str(&entry->name, "void");
438 entry->di_type = g->dbuilder->createBasicType(buf_ptr(&entry->name), 0, 0,
439 llvm::dwarf::DW_ATE_unsigned);
440 g->type_table.put(&entry->name, entry);
441
442 // invalid types are void
443 g->invalid_type_entry = entry;
444 }
445 {
446 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
447 entry->id = TypeIdUnreachable;
448 entry->type_ref = LLVMVoidType();
449 buf_init_from_str(&entry->name, "unreachable");
450 entry->di_type = g->invalid_type_entry->di_type;
451 g->type_table.put(&entry->name, entry);
452 }
453}
454
455
456void semantic_analyze(CodeGen *g) {
457 LLVMInitializeAllTargets();
458 LLVMInitializeAllTargetMCs();
459 LLVMInitializeAllAsmPrinters();
460 LLVMInitializeAllAsmParsers();
461 LLVMInitializeNativeTarget();
462
463 g->is_native_target = true;
464 char *native_triple = LLVMGetDefaultTargetTriple();
465
466 LLVMTargetRef target_ref;
467 char *err_msg = nullptr;
468 if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) {
469 zig_panic("unable to get target from triple: %s", err_msg);
470 }
471
472 char *native_cpu = LLVMZigGetHostCPUName();
473 char *native_features = LLVMZigGetNativeFeatures();
474
475 LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ?
476 LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive;
477
478 LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC;
479
480 g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple,
481 native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault);
482
483 g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);
484
485
486 g->module = LLVMModuleCreateWithName("ZigModule");
487
488 g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);
489
490 g->builder = LLVMCreateBuilder();
491 g->dbuilder = new llvm::DIBuilder(*llvm::unwrap(g->module), true);
492
493
494 add_types(g);
495
496 analyze_node(g, g->root);
497}
498
src/analyze.hpp created+15
...@@ -0,0 +1,15 @@
1/*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_ANALYZE_HPP
9#define ZIG_ANALYZE_HPP
10
11struct CodeGen;
12
13void semantic_analyze(CodeGen *g);
14
15#endif
src/buffer.cpp+17
...@@ -45,3 +45,20 @@ void buf_appendf(Buf *buf, const char *format, ...) {...@@ -45,3 +45,20 @@ void buf_appendf(Buf *buf, const char *format, ...) {
45 va_end(ap2);45 va_end(ap2);
46 va_end(ap);46 va_end(ap);
47}47}
48
49// these functions are not static inline so they can be better used as template parameters
50bool buf_eql_buf(Buf *buf, Buf *other) {
51 assert(buf->list.length);
52 return buf_eql_mem(buf, buf_ptr(other), buf_len(other));
53}
54
55uint32_t buf_hash(Buf *buf) {
56 assert(buf->list.length);
57 // FNV 32-bit hash
58 uint32_t h = 2166136261;
59 for (int i = 0; i < buf_len(buf); i += 1) {
60 h = h ^ ((uint8_t)buf->list.at(i));
61 h = h * 16777619;
62 }
63 return h;
64}
src/buffer.hpp+2-15
...@@ -132,21 +132,8 @@ static inline bool buf_eql_str(Buf *buf, const char *str) {...@@ -132,21 +132,8 @@ static inline bool buf_eql_str(Buf *buf, const char *str) {
132 return buf_eql_mem(buf, str, strlen(str));132 return buf_eql_mem(buf, str, strlen(str));
133}133}
134134
135static inline bool buf_eql_buf(Buf *buf, Buf *other) {135bool buf_eql_buf(Buf *buf, Buf *other);
136 assert(buf->list.length);136uint32_t buf_hash(Buf *buf);
137 return buf_eql_mem(buf, buf_ptr(other), buf_len(other));
138}
139
140static inline uint32_t buf_hash(Buf *buf) {
141 assert(buf->list.length);
142 // FNV 32-bit hash
143 uint32_t h = 2166136261;
144 for (int i = 0; i < buf_len(buf); i += 1) {
145 h = h ^ ((uint8_t)buf->list.at(i));
146 h = h * 16777619;
147 }
148 return h;
149}
150137
151static inline void buf_upcase(Buf *buf) {138static inline void buf_upcase(Buf *buf) {
152 for (int i = 0; i < buf_len(buf); i += 1) {139 for (int i = 0; i < buf_len(buf); i += 1) {
src/codegen.cpp+3-578
...@@ -12,6 +12,8 @@...@@ -12,6 +12,8 @@
12#include "config.h"12#include "config.h"
13#include "error.hpp"13#include "error.hpp"
1414
15#include "semantic_info.hpp"
16
15#include <stdio.h>17#include <stdio.h>
1618
17#include <llvm/IR/IRBuilder.h>19#include <llvm/IR/IRBuilder.h>
...@@ -21,88 +23,6 @@...@@ -21,88 +23,6 @@
21#include <llvm/Target/TargetMachine.h>23#include <llvm/Target/TargetMachine.h>
22#include <llvm/Support/TargetParser.h>24#include <llvm/Support/TargetParser.h>
2325
24struct FnTableEntry {
25 LLVMValueRef fn_value;
26 AstNode *proto_node;
27 AstNode *fn_def_node;
28 bool is_extern;
29 bool internal_linkage;
30 unsigned calling_convention;
31};
32
33enum TypeId {
34 TypeIdUserDefined,
35 TypeIdPointer,
36 TypeIdU8,
37 TypeIdI32,
38 TypeIdVoid,
39 TypeIdUnreachable,
40};
41
42struct TypeTableEntry {
43 TypeId id;
44 LLVMTypeRef type_ref;
45 llvm::DIType *di_type;
46
47 TypeTableEntry *pointer_child;
48 bool pointer_is_const;
49 int user_defined_id;
50 Buf name;
51 TypeTableEntry *pointer_const_parent;
52 TypeTableEntry *pointer_mut_parent;
53};
54
55struct CodeGen {
56 LLVMModuleRef module;
57 AstNode *root;
58 ZigList<ErrorMsg> errors;
59 LLVMBuilderRef builder;
60 llvm::DIBuilder *dbuilder;
61 llvm::DICompileUnit *compile_unit;
62 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
63 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
64 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
65 HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
66 TypeTableEntry *invalid_type_entry;
67 LLVMTargetDataRef target_data_ref;
68 unsigned pointer_size_bytes;
69 bool is_static;
70 bool strip_debug_symbols;
71 CodeGenBuildType build_type;
72 LLVMTargetMachineRef target_machine;
73 bool is_native_target;
74 Buf in_file;
75 Buf in_dir;
76 ZigList<llvm::DIScope *> block_scopes;
77 llvm::DIFile *di_file;
78 ZigList<FnTableEntry *> fn_defs;
79 Buf *out_name;
80 OutType out_type;
81 FnTableEntry *cur_fn;
82 bool c_stdint_used;
83 AstNode *root_export_decl;
84 int version_major;
85 int version_minor;
86 int version_patch;
87};
88
89struct TypeNode {
90 TypeTableEntry *entry;
91};
92
93struct FnDefNode {
94 bool add_implicit_return;
95 bool skip;
96 LLVMValueRef *params;
97};
98
99struct CodeGenNode {
100 union {
101 TypeNode type_node; // for NodeTypeType
102 FnDefNode fn_def_node; // for NodeTypeFnDef
103 } data;
104};
105
106CodeGen *create_codegen(AstNode *root, Buf *in_full_path) {26CodeGen *create_codegen(AstNode *root, Buf *in_full_path) {
107 CodeGen *g = allocate<CodeGen>(1);27 CodeGen *g = allocate<CodeGen>(1);
108 g->root = root;28 g->root = root;
...@@ -140,15 +60,7 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {...@@ -140,15 +60,7 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
140 g->out_name = out_name;60 g->out_name = out_name;
141}61}
14262
143static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {63static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
144 g->errors.add_one();
145 ErrorMsg *last_msg = &g->errors.last();
146 last_msg->line_start = node->line;
147 last_msg->column_start = node->column;
148 last_msg->line_end = -1;
149 last_msg->column_end = -1;
150 last_msg->msg = msg;
151}
15264
153static LLVMTypeRef to_llvm_type(AstNode *type_node) {65static LLVMTypeRef to_llvm_type(AstNode *type_node) {
154 assert(type_node->type == NodeTypeType);66 assert(type_node->type == NodeTypeType);
...@@ -166,7 +78,6 @@ static llvm::DIType *to_llvm_debug_type(AstNode *type_node) {...@@ -166,7 +78,6 @@ static llvm::DIType *to_llvm_debug_type(AstNode *type_node) {
166 return type_node->codegen_node->data.type_node.entry->di_type;78 return type_node->codegen_node->data.type_node.entry->di_type;
167}79}
16880
169
170static bool type_is_unreachable(AstNode *type_node) {81static bool type_is_unreachable(AstNode *type_node) {
171 assert(type_node->type == NodeTypeType);82 assert(type_node->type == NodeTypeType);
172 assert(type_node->codegen_node);83 assert(type_node->codegen_node);
...@@ -174,492 +85,6 @@ static bool type_is_unreachable(AstNode *type_node) {...@@ -174,492 +85,6 @@ static bool type_is_unreachable(AstNode *type_node) {
174 return type_node->codegen_node->data.type_node.entry->id == TypeIdUnreachable;85 return type_node->codegen_node->data.type_node.entry->id == TypeIdUnreachable;
175}86}
17687
177
178static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
179 char *dot1 = strstr(buf_ptr(buf), ".");
180 if (!dot1)
181 return ErrorInvalidFormat;
182 char *dot2 = strstr(dot1 + 1, ".");
183 if (!dot2)
184 return ErrorInvalidFormat;
185
186 *major = (int)strtol(buf_ptr(buf), nullptr, 10);
187 *minor = (int)strtol(dot1 + 1, nullptr, 10);
188 *patch = (int)strtol(dot2 + 1, nullptr, 10);
189
190 return ErrorNone;
191}
192
193static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) {
194 int err;
195 if ((err = parse_version_string(version_buf, &g->version_major, &g->version_minor, &g->version_patch))) {
196 add_node_error(g, node,
197 buf_sprintf("invalid version string"));
198 }
199}
200
201static void find_declarations(CodeGen *g, AstNode *node);
202
203static void resolve_type_and_recurse(CodeGen *g, AstNode *node) {
204 assert(!node->codegen_node);
205 node->codegen_node = allocate<CodeGenNode>(1);
206 TypeNode *type_node = &node->codegen_node->data.type_node;
207 switch (node->data.type.type) {
208 case AstNodeTypeTypePrimitive:
209 {
210 Buf *name = &node->data.type.primitive_name;
211 auto table_entry = g->type_table.maybe_get(name);
212 if (table_entry) {
213 type_node->entry = table_entry->value;
214 } else {
215 add_node_error(g, node,
216 buf_sprintf("invalid type name: '%s'", buf_ptr(name)));
217 type_node->entry = g->invalid_type_entry;
218 }
219 break;
220 }
221 case AstNodeTypeTypePointer:
222 {
223 find_declarations(g, node->data.type.child_type);
224 TypeNode *child_type_node = &node->data.type.child_type->codegen_node->data.type_node;
225 if (child_type_node->entry->id == TypeIdUnreachable) {
226 add_node_error(g, node,
227 buf_create_from_str("pointer to unreachable not allowed"));
228 }
229 TypeTableEntry **parent_pointer = node->data.type.is_const ?
230 &child_type_node->entry->pointer_const_parent :
231 &child_type_node->entry->pointer_mut_parent;
232 const char *const_or_mut_str = node->data.type.is_const ? "const" : "mut";
233 if (*parent_pointer) {
234 type_node->entry = *parent_pointer;
235 } else {
236 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
237 entry->id = TypeIdPointer;
238 entry->type_ref = LLVMPointerType(child_type_node->entry->type_ref, 0);
239 buf_resize(&entry->name, 0);
240 buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type_node->entry->name));
241 entry->di_type = g->dbuilder->createPointerType(child_type_node->entry->di_type,
242 g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name));
243 g->type_table.put(&entry->name, entry);
244 type_node->entry = entry;
245 *parent_pointer = entry;
246 }
247 break;
248 }
249 }
250}
251
252static void find_declarations(CodeGen *g, AstNode *node) {
253 switch (node->type) {
254 case NodeTypeExternBlock:
255 for (int i = 0; i < node->data.extern_block.directives->length; i += 1) {
256 AstNode *directive_node = node->data.extern_block.directives->at(i);
257 Buf *name = &directive_node->data.directive.name;
258 Buf *param = &directive_node->data.directive.param;
259 if (buf_eql_str(name, "link")) {
260 g->link_table.put(param, true);
261 } else {
262 add_node_error(g, directive_node,
263 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
264 }
265 }
266
267 for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
268 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
269 assert(fn_decl->type == NodeTypeFnDecl);
270 AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;
271 find_declarations(g, fn_proto);
272 Buf *name = &fn_proto->data.fn_proto.name;
273
274 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
275 fn_table_entry->proto_node = fn_proto;
276 fn_table_entry->is_extern = true;
277 fn_table_entry->calling_convention = LLVMCCallConv;
278 g->fn_table.put(name, fn_table_entry);
279 }
280 break;
281 case NodeTypeFnDef:
282 {
283 AstNode *proto_node = node->data.fn_def.fn_proto;
284 assert(proto_node->type == NodeTypeFnProto);
285 Buf *proto_name = &proto_node->data.fn_proto.name;
286 auto entry = g->fn_table.maybe_get(proto_name);
287 if (entry) {
288 add_node_error(g, node,
289 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
290 assert(!node->codegen_node);
291 node->codegen_node = allocate<CodeGenNode>(1);
292 node->codegen_node->data.fn_def_node.skip = true;
293 } else {
294 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
295 fn_table_entry->proto_node = proto_node;
296 fn_table_entry->fn_def_node = node;
297 fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;
298 if (fn_table_entry->internal_linkage) {
299 fn_table_entry->calling_convention = LLVMFastCallConv;
300 } else {
301 fn_table_entry->calling_convention = LLVMCCallConv;
302 }
303 g->fn_table.put(proto_name, fn_table_entry);
304 g->fn_defs.append(fn_table_entry);
305
306 find_declarations(g, proto_node);
307 }
308 break;
309 }
310 case NodeTypeFnProto:
311 {
312 for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
313 AstNode *directive_node = node->data.fn_proto.directives->at(i);
314 Buf *name = &directive_node->data.directive.name;
315 add_node_error(g, directive_node,
316 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
317 }
318 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
319 AstNode *child = node->data.fn_proto.params.at(i);
320 find_declarations(g, child);
321 }
322 find_declarations(g, node->data.fn_proto.return_type);
323 break;
324 }
325 break;
326 case NodeTypeParamDecl:
327 find_declarations(g, node->data.param_decl.type);
328 break;
329 case NodeTypeType:
330 resolve_type_and_recurse(g, node);
331 break;
332 case NodeTypeDirective:
333 // we handled directives in the parent function
334 break;
335 case NodeTypeRootExportDecl:
336 for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
337 AstNode *directive_node = node->data.root_export_decl.directives->at(i);
338 Buf *name = &directive_node->data.directive.name;
339 Buf *param = &directive_node->data.directive.param;
340 if (buf_eql_str(name, "version")) {
341 set_root_export_version(g, param, directive_node);
342 } else {
343 add_node_error(g, directive_node,
344 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
345 }
346 }
347 break;
348 case NodeTypeFnDecl:
349 case NodeTypeReturnExpr:
350 case NodeTypeRoot:
351 case NodeTypeBlock:
352 case NodeTypeBinOpExpr:
353 case NodeTypeFnCallExpr:
354 case NodeTypeNumberLiteral:
355 case NodeTypeStringLiteral:
356 case NodeTypeUnreachable:
357 case NodeTypeSymbol:
358 case NodeTypeCastExpr:
359 case NodeTypePrefixOpExpr:
360 zig_unreachable();
361 }
362}
363
364static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {
365 // Follow the execution flow and make sure the code returns appropriately.
366 // * A `return` statement in an unreachable type function should be an error.
367 // * Control flow should not be able to reach the end of an unreachable type function.
368 // * Functions that have a type other than void should not return without a value.
369 // * void functions without explicit return statements at the end need the
370 // add_implicit_return flag set on the codegen node.
371 assert(node->type == NodeTypeFnDef);
372 AstNode *proto_node = node->data.fn_def.fn_proto;
373 assert(proto_node->type == NodeTypeFnProto);
374 AstNode *return_type_node = proto_node->data.fn_proto.return_type;
375 assert(return_type_node->type == NodeTypeType);
376
377 node->codegen_node = allocate<CodeGenNode>(1);
378 FnDefNode *codegen_fn_def = &node->codegen_node->data.fn_def_node;
379
380 assert(return_type_node->codegen_node);
381 TypeTableEntry *type_entry = return_type_node->codegen_node->data.type_node.entry;
382 assert(type_entry);
383 TypeId type_id = type_entry->id;
384
385 AstNode *body_node = node->data.fn_def.body;
386 assert(body_node->type == NodeTypeBlock);
387
388 // TODO once we understand types, do this pass after type checking, and
389 // if an expression has an unreachable value then stop looking at statements after
390 // it. then we can remove the check to `unreachable` in the end of this function.
391 bool prev_statement_return = false;
392 for (int i = 0; i < body_node->data.block.statements.length; i += 1) {
393 AstNode *statement_node = body_node->data.block.statements.at(i);
394 if (statement_node->type == NodeTypeReturnExpr) {
395 if (type_id == TypeIdUnreachable) {
396 add_node_error(g, statement_node,
397 buf_sprintf("return statement in function with unreachable return type"));
398 return;
399 } else {
400 prev_statement_return = true;
401 }
402 } else if (prev_statement_return) {
403 add_node_error(g, statement_node,
404 buf_sprintf("unreachable code"));
405 }
406 }
407
408 if (!prev_statement_return) {
409 if (type_id == TypeIdVoid) {
410 codegen_fn_def->add_implicit_return = true;
411 } else if (type_id != TypeIdUnreachable) {
412 add_node_error(g, node,
413 buf_sprintf("control reaches end of non-void function"));
414 }
415 }
416}
417
418static Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) {
419 // Assume that the expression evaluates to a simple name and return the buf
420 // TODO after type checking works we should be able to remove this hack
421 assert(node->type == NodeTypeSymbol);
422 return &node->data.symbol;
423}
424
425static void analyze_node(CodeGen *g, AstNode *node) {
426 switch (node->type) {
427 case NodeTypeRoot:
428 {
429 // Iterate once over the top level declarations to build the function table
430 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
431 AstNode *child = node->data.root.top_level_decls.at(i);
432 find_declarations(g, child);
433 }
434 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
435 AstNode *child = node->data.root.top_level_decls.at(i);
436 analyze_node(g, child);
437 }
438 if (!g->out_name) {
439 add_node_error(g, node,
440 buf_sprintf("missing export declaration and output name not provided"));
441 } else if (g->out_type == OutTypeUnknown) {
442 add_node_error(g, node,
443 buf_sprintf("missing export declaration and export type not provided"));
444 }
445 break;
446 }
447 case NodeTypeRootExportDecl:
448 if (g->root_export_decl) {
449 add_node_error(g, node,
450 buf_sprintf("only one root export declaration allowed"));
451 } else {
452 g->root_export_decl = node;
453
454 if (!g->out_name)
455 g->out_name = &node->data.root_export_decl.name;
456
457 Buf *out_type = &node->data.root_export_decl.type;
458 OutType export_out_type;
459 if (buf_eql_str(out_type, "executable")) {
460 export_out_type = OutTypeExe;
461 } else if (buf_eql_str(out_type, "library")) {
462 export_out_type = OutTypeLib;
463 } else if (buf_eql_str(out_type, "object")) {
464 export_out_type = OutTypeObj;
465 } else {
466 add_node_error(g, node,
467 buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
468 }
469 if (g->out_type == OutTypeUnknown)
470 g->out_type = export_out_type;
471 }
472 break;
473 case NodeTypeExternBlock:
474 for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
475 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
476 analyze_node(g, fn_decl);
477 }
478 break;
479 case NodeTypeFnDef:
480 {
481 if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) {
482 // we detected an error with this function definition which prevents us
483 // from further analyzing it.
484 break;
485 }
486
487 AstNode *proto_node = node->data.fn_def.fn_proto;
488 assert(proto_node->type == NodeTypeFnProto);
489 analyze_node(g, proto_node);
490
491 check_fn_def_control_flow(g, node);
492 analyze_node(g, node->data.fn_def.body);
493 break;
494 }
495 case NodeTypeFnDecl:
496 {
497 AstNode *proto_node = node->data.fn_decl.fn_proto;
498 assert(proto_node->type == NodeTypeFnProto);
499 analyze_node(g, proto_node);
500 break;
501 }
502 case NodeTypeFnProto:
503 {
504 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
505 AstNode *child = node->data.fn_proto.params.at(i);
506 analyze_node(g, child);
507 }
508 analyze_node(g, node->data.fn_proto.return_type);
509 break;
510 }
511 case NodeTypeParamDecl:
512 analyze_node(g, node->data.param_decl.type);
513 break;
514
515 case NodeTypeType:
516 // ignore; we handled types with find_declarations
517 break;
518 case NodeTypeBlock:
519 for (int i = 0; i < node->data.block.statements.length; i += 1) {
520 AstNode *child = node->data.block.statements.at(i);
521 analyze_node(g, child);
522 }
523 break;
524 case NodeTypeReturnExpr:
525 if (node->data.return_expr.expr) {
526 analyze_node(g, node->data.return_expr.expr);
527 }
528 break;
529 case NodeTypeBinOpExpr:
530 analyze_node(g, node->data.bin_op_expr.op1);
531 analyze_node(g, node->data.bin_op_expr.op2);
532 break;
533 case NodeTypeFnCallExpr:
534 {
535 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
536
537 auto entry = g->fn_table.maybe_get(name);
538 if (!entry) {
539 add_node_error(g, node,
540 buf_sprintf("undefined function: '%s'", buf_ptr(name)));
541 } else {
542 FnTableEntry *fn_table_entry = entry->value;
543 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
544 int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length;
545 int actual_param_count = node->data.fn_call_expr.params.length;
546 if (expected_param_count != actual_param_count) {
547 add_node_error(g, node,
548 buf_sprintf("wrong number of arguments. Expected %d, got %d.",
549 expected_param_count, actual_param_count));
550 }
551 }
552
553 for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
554 AstNode *child = node->data.fn_call_expr.params.at(i);
555 analyze_node(g, child);
556 }
557 break;
558 }
559 case NodeTypeDirective:
560 // we looked at directives in the parent node
561 break;
562 case NodeTypeCastExpr:
563 zig_panic("TODO");
564 break;
565 case NodeTypePrefixOpExpr:
566 zig_panic("TODO");
567 break;
568 case NodeTypeNumberLiteral:
569 case NodeTypeStringLiteral:
570 case NodeTypeUnreachable:
571 case NodeTypeSymbol:
572 // nothing to do
573 break;
574 }
575}
576
577static void add_types(CodeGen *g) {
578 {
579 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
580 entry->id = TypeIdU8;
581 entry->type_ref = LLVMInt8Type();
582 buf_init_from_str(&entry->name, "u8");
583 entry->di_type = g->dbuilder->createBasicType(buf_ptr(&entry->name), 8, 8, llvm::dwarf::DW_ATE_unsigned);
584 g->type_table.put(&entry->name, entry);
585 }
586 {
587 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
588 entry->id = TypeIdI32;
589 entry->type_ref = LLVMInt32Type();
590 buf_init_from_str(&entry->name, "i32");
591 entry->di_type = g->dbuilder->createBasicType(buf_ptr(&entry->name), 32, 32,
592 llvm::dwarf::DW_ATE_signed);
593 g->type_table.put(&entry->name, entry);
594 }
595 {
596 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
597 entry->id = TypeIdVoid;
598 entry->type_ref = LLVMVoidType();
599 buf_init_from_str(&entry->name, "void");
600 entry->di_type = g->dbuilder->createBasicType(buf_ptr(&entry->name), 0, 0,
601 llvm::dwarf::DW_ATE_unsigned);
602 g->type_table.put(&entry->name, entry);
603
604 // invalid types are void
605 g->invalid_type_entry = entry;
606 }
607 {
608 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
609 entry->id = TypeIdUnreachable;
610 entry->type_ref = LLVMVoidType();
611 buf_init_from_str(&entry->name, "unreachable");
612 entry->di_type = g->invalid_type_entry->di_type;
613 g->type_table.put(&entry->name, entry);
614 }
615}
616
617
618void semantic_analyze(CodeGen *g) {
619 LLVMInitializeAllTargets();
620 LLVMInitializeAllTargetMCs();
621 LLVMInitializeAllAsmPrinters();
622 LLVMInitializeAllAsmParsers();
623 LLVMInitializeNativeTarget();
624
625 g->is_native_target = true;
626 char *native_triple = LLVMGetDefaultTargetTriple();
627
628 LLVMTargetRef target_ref;
629 char *err_msg = nullptr;
630 if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) {
631 zig_panic("unable to get target from triple: %s", err_msg);
632 }
633
634 char *native_cpu = LLVMZigGetHostCPUName();
635 char *native_features = LLVMZigGetNativeFeatures();
636
637 LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ?
638 LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive;
639
640 LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC;
641
642 g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple,
643 native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault);
644
645 g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);
646
647
648 g->module = LLVMModuleCreateWithName("ZigModule");
649
650 g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);
651
652 g->builder = LLVMCreateBuilder();
653 g->dbuilder = new llvm::DIBuilder(*llvm::unwrap(g->module), true);
654
655
656 add_types(g);
657
658 analyze_node(g, g->root);
659}
660
661static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
662
663static void add_debug_source_node(CodeGen *g, AstNode *node) {88static void add_debug_source_node(CodeGen *g, AstNode *node) {
664 llvm::unwrap(g->builder)->SetCurrentDebugLocation(llvm::DebugLoc::get(89 llvm::unwrap(g->builder)->SetCurrentDebugLocation(llvm::DebugLoc::get(
665 node->line + 1, node->column + 1,90 node->line + 1, node->column + 1,
src/codegen.hpp-2
...@@ -41,8 +41,6 @@ void codegen_set_strip(CodeGen *codegen, bool strip);...@@ -41,8 +41,6 @@ void codegen_set_strip(CodeGen *codegen, bool strip);
41void codegen_set_out_type(CodeGen *codegen, OutType out_type);41void codegen_set_out_type(CodeGen *codegen, OutType out_type);
42void codegen_set_out_name(CodeGen *codegen, Buf *out_name);42void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
4343
44void semantic_analyze(CodeGen *g);
45
46void code_gen_optimize(CodeGen *g);44void code_gen_optimize(CodeGen *g);
4745
48void code_gen(CodeGen *g);46void code_gen(CodeGen *g);
src/main.cpp+1
...@@ -13,6 +13,7 @@...@@ -13,6 +13,7 @@
13#include "tokenizer.hpp"13#include "tokenizer.hpp"
14#include "error.hpp"14#include "error.hpp"
15#include "codegen.hpp"15#include "codegen.hpp"
16#include "analyze.hpp"
1617
17#include <stdio.h>18#include <stdio.h>
18#include <string.h>19#include <string.h>
src/semantic_info.hpp created+106
...@@ -0,0 +1,106 @@
1/*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_SEMANTIC_INFO_HPP
9#define ZIG_SEMANTIC_INFO_HPP
10
11#include "codegen.hpp"
12#include "hash_map.hpp"
13
14#include <llvm/IR/DIBuilder.h>
15#include <llvm/IR/DiagnosticInfo.h>
16
17struct FnTableEntry {
18 LLVMValueRef fn_value;
19 AstNode *proto_node;
20 AstNode *fn_def_node;
21 bool is_extern;
22 bool internal_linkage;
23 unsigned calling_convention;
24};
25
26enum TypeId {
27 TypeIdUserDefined,
28 TypeIdPointer,
29 TypeIdU8,
30 TypeIdI32,
31 TypeIdVoid,
32 TypeIdUnreachable,
33};
34
35struct TypeTableEntry {
36 TypeId id;
37 LLVMTypeRef type_ref;
38 llvm::DIType *di_type;
39
40 TypeTableEntry *pointer_child;
41 bool pointer_is_const;
42 int user_defined_id;
43 Buf name;
44 TypeTableEntry *pointer_const_parent;
45 TypeTableEntry *pointer_mut_parent;
46};
47
48struct CodeGen {
49 LLVMModuleRef module;
50 AstNode *root;
51 ZigList<ErrorMsg> errors;
52 LLVMBuilderRef builder;
53 llvm::DIBuilder *dbuilder;
54 llvm::DICompileUnit *compile_unit;
55 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
56 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
57 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
58 HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
59 TypeTableEntry *invalid_type_entry;
60 LLVMTargetDataRef target_data_ref;
61 unsigned pointer_size_bytes;
62 bool is_static;
63 bool strip_debug_symbols;
64 CodeGenBuildType build_type;
65 LLVMTargetMachineRef target_machine;
66 bool is_native_target;
67 Buf in_file;
68 Buf in_dir;
69 ZigList<llvm::DIScope *> block_scopes;
70 llvm::DIFile *di_file;
71 ZigList<FnTableEntry *> fn_defs;
72 Buf *out_name;
73 OutType out_type;
74 FnTableEntry *cur_fn;
75 bool c_stdint_used;
76 AstNode *root_export_decl;
77 int version_major;
78 int version_minor;
79 int version_patch;
80};
81
82struct TypeNode {
83 TypeTableEntry *entry;
84};
85
86struct FnDefNode {
87 bool add_implicit_return;
88 bool skip;
89 LLVMValueRef *params;
90};
91
92struct CodeGenNode {
93 union {
94 TypeNode type_node; // for NodeTypeType
95 FnDefNode fn_def_node; // for NodeTypeFnDef
96 } data;
97};
98
99static inline Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) {
100 // Assume that the expression evaluates to a simple name and return the buf
101 // TODO after type checking works we should be able to remove this hack
102 assert(node->type == NodeTypeSymbol);
103 return &node->data.symbol;
104}
105
106#endif