authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-24 20:24:05-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-24 20:24:05-04:00
logadefd1a52b812813dd3e3590d398f927ffc5b9af
tree1971356295aa4dca151b49ff03e7e2ce10e4a345
parent2ea08561cf69dabc99722ffc24cb0e4327605506

self-hosted: function calling another function


7 files changed, 597 insertions(+), 175 deletions(-)

src-self-hosted/codegen.zig+157-3
...@@ -6,6 +6,7 @@ const c = @import("c.zig");...@@ -6,6 +6,7 @@ const c = @import("c.zig");
6const ir = @import("ir.zig");6const ir = @import("ir.zig");
7const Value = @import("value.zig").Value;7const Value = @import("value.zig").Value;
8const Type = @import("type.zig").Type;8const Type = @import("type.zig").Type;
9const Scope = @import("scope.zig").Scope;
9const event = std.event;10const event = std.event;
10const assert = std.debug.assert;11const assert = std.debug.assert;
11const DW = std.dwarf;12const DW = std.dwarf;
...@@ -156,7 +157,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)...@@ -156,7 +157,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
156 llvm_fn_type,157 llvm_fn_type,
157 ) orelse return error.OutOfMemory;158 ) orelse return error.OutOfMemory;
158159
159 const want_fn_safety = fn_val.block_scope.safety.get(ofile.comp);160 const want_fn_safety = fn_val.block_scope.?.safety.get(ofile.comp);
160 if (want_fn_safety and ofile.comp.haveLibC()) {161 if (want_fn_safety and ofile.comp.haveLibC()) {
161 try addLLVMFnAttr(ofile, llvm_fn, "sspstrong");162 try addLLVMFnAttr(ofile, llvm_fn, "sspstrong");
162 try addLLVMFnAttrStr(ofile, llvm_fn, "stack-protector-buffer-size", "4");163 try addLLVMFnAttrStr(ofile, llvm_fn, "stack-protector-buffer-size", "4");
...@@ -227,9 +228,86 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)...@@ -227,9 +228,86 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
227228
228 // TODO set up error return tracing229 // TODO set up error return tracing
229 // TODO allocate temporary stack values230 // TODO allocate temporary stack values
230 // TODO create debug variable declarations for variables and allocate all local variables231
232 const var_list = fn_type.non_key.Normal.variable_list.toSliceConst();
233 // create debug variable declarations for variables and allocate all local variables
234 for (var_list) |var_scope, i| {
235 const var_type = switch (var_scope.data) {
236 Scope.Var.Data.Const => unreachable,
237 Scope.Var.Data.Param => |param| param.typ,
238 };
239 // if (!type_has_bits(var->value->type)) {
240 // continue;
241 // }
242 // if (ir_get_var_is_comptime(var))
243 // continue;
244 // if (type_requires_comptime(var->value->type))
245 // continue;
246 // if (var->src_arg_index == SIZE_MAX) {
247 // var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
248
249 // var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
250 // buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
251 // var->value->type->di_type, !g->strip_debug_symbols, 0);
252
253 // } else {
254 // it's a parameter
255 // assert(var->gen_arg_index != SIZE_MAX);
256 // TypeTableEntry *gen_type;
257 // FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
258
259 if (var_type.handleIsPtr()) {
260 // if (gen_info->is_byval) {
261 // gen_type = var->value->type;
262 // } else {
263 // gen_type = gen_info->type;
264 // }
265 var_scope.data.Param.llvm_value = llvm.GetParam(llvm_fn, @intCast(c_uint, i));
266 } else {
267 // gen_type = var->value->type;
268 var_scope.data.Param.llvm_value = try renderAlloca(ofile, var_type, var_scope.name, Type.Pointer.Align.Abi);
269 }
270 // if (var->decl_node) {
271 // var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
272 // buf_ptr(&var->name), import->di_file,
273 // (unsigned)(var->decl_node->line + 1),
274 // gen_type->di_type, !g->strip_debug_symbols, 0, (unsigned)(var->gen_arg_index + 1));
275 // }
276
277 // }
278 }
279
231 // TODO finishing error return trace setup. we have to do this after all the allocas.280 // TODO finishing error return trace setup. we have to do this after all the allocas.
232 // TODO create debug variable declarations for parameters281
282 // create debug variable declarations for parameters
283 // rely on the first variables in the variable_list being parameters.
284 //size_t next_var_i = 0;
285 for (fn_type.key.data.Normal.params) |param, i| {
286 //FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
287 //if (info->gen_index == SIZE_MAX)
288 // continue;
289 const scope_var = var_list[i];
290 //assert(variable->src_arg_index != SIZE_MAX);
291 //next_var_i += 1;
292 //assert(variable);
293 //assert(variable->value_ref);
294
295 if (!param.typ.handleIsPtr()) {
296 //clear_debug_source_node(g);
297 const llvm_param = llvm.GetParam(llvm_fn, @intCast(c_uint, i));
298 _ = renderStoreUntyped(
299 ofile,
300 llvm_param,
301 scope_var.data.Param.llvm_value,
302 Type.Pointer.Align.Abi,
303 Type.Pointer.Vol.Non,
304 );
305 }
306
307 //if (variable->decl_node) {
308 // gen_var_debug_decl(g, variable);
309 //}
310 }
233311
234 for (code.basic_block_list.toSlice()) |current_block| {312 for (code.basic_block_list.toSlice()) |current_block| {
235 llvm.PositionBuilderAtEnd(ofile.builder, current_block.llvm_block);313 llvm.PositionBuilderAtEnd(ofile.builder, current_block.llvm_block);
...@@ -294,3 +372,79 @@ fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []cons...@@ -294,3 +372,79 @@ fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []cons
294fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void {372fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void {
295 return addLLVMAttrInt(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name, attr_val);373 return addLLVMAttrInt(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name, attr_val);
296}374}
375
376fn renderLoadUntyped(
377 ofile: *ObjectFile,
378 ptr: llvm.ValueRef,
379 alignment: Type.Pointer.Align,
380 vol: Type.Pointer.Vol,
381 name: [*]const u8,
382) !llvm.ValueRef {
383 const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
384 switch (vol) {
385 Type.Pointer.Vol.Non => {},
386 Type.Pointer.Vol.Volatile => llvm.SetVolatile(result, 1),
387 }
388 llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm.GetElementType(llvm.TypeOf(ptr))));
389 return result;
390}
391
392fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef {
393 return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
394}
395
396pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef {
397 const child_type = ptr_type.key.child_type;
398 if (!child_type.hasBits()) {
399 return null;
400 }
401 if (child_type.handleIsPtr()) {
402 return ptr;
403 }
404 return try renderLoad(ofile, ptr, ptr_type, c"");
405}
406
407pub fn renderStoreUntyped(
408 ofile: *ObjectFile,
409 value: llvm.ValueRef,
410 ptr: llvm.ValueRef,
411 alignment: Type.Pointer.Align,
412 vol: Type.Pointer.Vol,
413) !llvm.ValueRef {
414 const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory;
415 switch (vol) {
416 Type.Pointer.Vol.Non => {},
417 Type.Pointer.Vol.Volatile => llvm.SetVolatile(result, 1),
418 }
419 llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm.TypeOf(value)));
420 return result;
421}
422
423pub fn renderStore(
424 ofile: *ObjectFile,
425 value: llvm.ValueRef,
426 ptr: llvm.ValueRef,
427 ptr_type: *Type.Pointer,
428) !llvm.ValueRef {
429 return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol);
430}
431
432pub fn renderAlloca(
433 ofile: *ObjectFile,
434 var_type: *Type,
435 name: []const u8,
436 alignment: Type.Pointer.Align,
437) !llvm.ValueRef {
438 const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
439 const name_with_null = try std.cstr.addNullByte(ofile.arena, name);
440 const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory;
441 llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm_var_type));
442 return result;
443}
444
445pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 {
446 return switch (alignment) {
447 Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type),
448 Type.Pointer.Align.Override => |a| a,
449 };
450}
src-self-hosted/compilation.zig+35-37
...@@ -1165,49 +1165,47 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {...@@ -1165,49 +1165,47 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1165 symbol_name_consumed = true;1165 symbol_name_consumed = true;
11661166
1167 // Define local parameter variables1167 // Define local parameter variables
1168 //for (size_t i = 0; i < fn_type_id->param_count; i += 1) {1168 const root_scope = fn_decl.base.findRootScope();
1169 // FnTypeParamInfo *param_info = &fn_type_id->param_info[i];1169 for (fn_type.key.data.Normal.params) |param, i| {
1170 // AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);1170 //AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);
1171 // Buf *param_name;1171 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", fn_decl.fn_proto.params.at(i).*);
1172 // bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;1172 const name_token = param_decl.name_token orelse {
1173 // if (param_decl_node && !is_var_args) {1173 try comp.addCompileError(root_scope, Span{
1174 // param_name = param_decl_node->data.param_decl.name;1174 .first = param_decl.firstToken(),
1175 // } else {1175 .last = param_decl.type_node.firstToken(),
1176 // param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i);1176 }, "missing parameter name");
1177 // }1177 return error.SemanticAnalysisFailed;
1178 // if (param_name == nullptr) {1178 };
1179 // continue;1179 const param_name = root_scope.tree.tokenSlice(name_token);
1180 // }1180
11811181 // if (is_noalias && get_codegen_ptr_type(param_type) == nullptr) {
1182 // TypeTableEntry *param_type = param_info->type;1182 // add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
1183 // bool is_noalias = param_info->is_noalias;1183 // }
11841184
1185 // if (is_noalias && get_codegen_ptr_type(param_type) == nullptr) {1185 // TODO check for shadowing
1186 // add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));1186
1187 // }1187 const var_scope = try Scope.Var.createParam(
11881188 comp,
1189 // VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,1189 fn_val.child_scope,
1190 // param_name, true, create_const_runtime(param_type), nullptr);1190 param_name,
1191 // var->src_arg_index = i;1191 &param_decl.base,
1192 // fn_table_entry->child_scope = var->child_scope;1192 i,
1193 // var->shadowable = var->shadowable || is_var_args;1193 param.typ,
11941194 );
1195 // if (type_has_bits(param_type)) {1195 fn_val.child_scope = &var_scope.base;
1196 // fn_table_entry->variable_list.append(var);1196
1197 // }1197 try fn_type.non_key.Normal.variable_list.append(var_scope);
11981198 }
1199 // if (fn_type->data.fn.gen_param_info) {
1200 // var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
1201 // }
1202 //}
12031199
1204 const analyzed_code = try await (async comp.genAndAnalyzeCode(1200 const analyzed_code = try await (async comp.genAndAnalyzeCode(
1205 &fndef_scope.base,1201 fn_val.child_scope,
1206 body_node,1202 body_node,
1207 fn_type.key.data.Normal.return_type,1203 fn_type.key.data.Normal.return_type,
1208 ) catch unreachable);1204 ) catch unreachable);
1209 errdefer analyzed_code.destroy(comp.gpa());1205 errdefer analyzed_code.destroy(comp.gpa());
12101206
1207 assert(fn_val.block_scope != null);
1208
1211 // Kick off rendering to LLVM module, but it doesn't block the fn decl1209 // Kick off rendering to LLVM module, but it doesn't block the fn decl
1212 // analysis from being complete.1210 // analysis from being complete.
1213 try comp.prelink_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code);1211 try comp.prelink_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code);
...@@ -1263,7 +1261,7 @@ async fn analyzeFnType(comp: *Compilation, scope: *Scope, fn_proto: *ast.Node.Fn...@@ -1263,7 +1261,7 @@ async fn analyzeFnType(comp: *Compilation, scope: *Scope, fn_proto: *ast.Node.Fn
1263 const key = Type.Fn.Key{1261 const key = Type.Fn.Key{
1264 .alignment = null,1262 .alignment = null,
1265 .data = Type.Fn.Key.Data{1263 .data = Type.Fn.Key.Data{
1266 .Normal = Type.Fn.Normal{1264 .Normal = Type.Fn.Key.Normal{
1267 .return_type = return_type,1265 .return_type = return_type,
1268 .params = params.toOwnedSlice(),1266 .params = params.toOwnedSlice(),
1269 .is_var_args = false, // TODO1267 .is_var_args = false, // TODO
src-self-hosted/ir.zig+176-21
...@@ -10,8 +10,10 @@ const assert = std.debug.assert;...@@ -10,8 +10,10 @@ const assert = std.debug.assert;
10const Token = std.zig.Token;10const Token = std.zig.Token;
11const Span = @import("errmsg.zig").Span;11const Span = @import("errmsg.zig").Span;
12const llvm = @import("llvm.zig");12const llvm = @import("llvm.zig");
13const ObjectFile = @import("codegen.zig").ObjectFile;13const codegen = @import("codegen.zig");
14const ObjectFile = codegen.ObjectFile;
14const Decl = @import("decl.zig").Decl;15const Decl = @import("decl.zig").Decl;
16const mem = std.mem;
1517
16pub const LVal = enum {18pub const LVal = enum {
17 None,19 None,
...@@ -122,6 +124,8 @@ pub const Inst = struct {...@@ -122,6 +124,8 @@ pub const Inst = struct {
122 Id.Br => return @fieldParentPtr(Br, "base", base).analyze(ira),124 Id.Br => return @fieldParentPtr(Br, "base", base).analyze(ira),
123 Id.AddImplicitReturnType => return @fieldParentPtr(AddImplicitReturnType, "base", base).analyze(ira),125 Id.AddImplicitReturnType => return @fieldParentPtr(AddImplicitReturnType, "base", base).analyze(ira),
124 Id.PtrType => return await (async @fieldParentPtr(PtrType, "base", base).analyze(ira) catch unreachable),126 Id.PtrType => return await (async @fieldParentPtr(PtrType, "base", base).analyze(ira) catch unreachable),
127 Id.VarPtr => return await (async @fieldParentPtr(VarPtr, "base", base).analyze(ira) catch unreachable),
128 Id.LoadPtr => return await (async @fieldParentPtr(LoadPtr, "base", base).analyze(ira) catch unreachable),
125 }129 }
126 }130 }
127131
...@@ -130,6 +134,8 @@ pub const Inst = struct {...@@ -130,6 +134,8 @@ pub const Inst = struct {
130 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),134 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
131 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),135 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
132 Id.Call => return @fieldParentPtr(Call, "base", base).render(ofile, fn_val),136 Id.Call => return @fieldParentPtr(Call, "base", base).render(ofile, fn_val),
137 Id.VarPtr => return @fieldParentPtr(VarPtr, "base", base).render(ofile, fn_val),
138 Id.LoadPtr => return @fieldParentPtr(LoadPtr, "base", base).render(ofile, fn_val),
133 Id.DeclRef => unreachable,139 Id.DeclRef => unreachable,
134 Id.PtrType => unreachable,140 Id.PtrType => unreachable,
135 Id.Ref => @panic("TODO"),141 Id.Ref => @panic("TODO"),
...@@ -248,6 +254,8 @@ pub const Inst = struct {...@@ -248,6 +254,8 @@ pub const Inst = struct {
248 Call,254 Call,
249 DeclRef,255 DeclRef,
250 PtrType,256 PtrType,
257 VarPtr,
258 LoadPtr,
251 };259 };
252260
253 pub const Call = struct {261 pub const Call = struct {
...@@ -491,6 +499,133 @@ pub const Inst = struct {...@@ -491,6 +499,133 @@ pub const Inst = struct {
491 }499 }
492 };500 };
493501
502 pub const VarPtr = struct {
503 base: Inst,
504 params: Params,
505
506 const Params = struct {
507 var_scope: *Scope.Var,
508 };
509
510 const ir_val_init = IrVal.Init.Unknown;
511
512 pub fn dump(inst: *const VarPtr) void {
513 std.debug.warn("{}", inst.params.var_scope.name);
514 }
515
516 pub fn hasSideEffects(inst: *const VarPtr) bool {
517 return false;
518 }
519
520 pub async fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst {
521 switch (self.params.var_scope.data) {
522 Scope.Var.Data.Const => @panic("TODO"),
523 Scope.Var.Data.Param => |param| {
524 const new_inst = try ira.irb.build(
525 Inst.VarPtr,
526 self.base.scope,
527 self.base.span,
528 Inst.VarPtr.Params{ .var_scope = self.params.var_scope },
529 );
530 const ptr_type = try await (async Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
531 .child_type = param.typ,
532 .mut = Type.Pointer.Mut.Const,
533 .vol = Type.Pointer.Vol.Non,
534 .size = Type.Pointer.Size.One,
535 .alignment = Type.Pointer.Align.Abi,
536 }) catch unreachable);
537 new_inst.val = IrVal{ .KnownType = &ptr_type.base };
538 return new_inst;
539 },
540 }
541 }
542
543 pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) llvm.ValueRef {
544 switch (self.params.var_scope.data) {
545 Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass
546 Scope.Var.Data.Param => |param| return param.llvm_value,
547 }
548 }
549 };
550
551 pub const LoadPtr = struct {
552 base: Inst,
553 params: Params,
554
555 const Params = struct {
556 target: *Inst,
557 };
558
559 const ir_val_init = IrVal.Init.Unknown;
560
561 pub fn dump(inst: *const LoadPtr) void {}
562
563 pub fn hasSideEffects(inst: *const LoadPtr) bool {
564 return false;
565 }
566
567 pub async fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst {
568 const target = try self.params.target.getAsParam();
569 const target_type = target.getKnownType();
570 if (target_type.id != Type.Id.Pointer) {
571 try ira.addCompileError(self.base.span, "dereference of non pointer type '{}'", target_type.name);
572 return error.SemanticAnalysisFailed;
573 }
574 const ptr_type = @fieldParentPtr(Type.Pointer, "base", target_type);
575 // if (instr_is_comptime(ptr)) {
576 // if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
577 // ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
578 // {
579 // ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &ptr->value);
580 // if (pointee->special != ConstValSpecialRuntime) {
581 // IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
582 // source_instruction->source_node, child_type);
583 // copy_const_val(&result->value, pointee, ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
584 // result->value.type = child_type;
585 // return result;
586 // }
587 // }
588 // }
589 const new_inst = try ira.irb.build(
590 Inst.LoadPtr,
591 self.base.scope,
592 self.base.span,
593 Inst.LoadPtr.Params{ .target = target },
594 );
595 new_inst.val = IrVal{ .KnownType = ptr_type.key.child_type };
596 return new_inst;
597 }
598
599 pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
600 const child_type = self.base.getKnownType();
601 if (!child_type.hasBits()) {
602 return null;
603 }
604 const ptr = self.params.target.llvm_value.?;
605 const ptr_type = self.params.target.getKnownType().cast(Type.Pointer).?;
606
607 return try codegen.getHandleValue(ofile, ptr, ptr_type);
608
609 //uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
610 //if (unaligned_bit_count == 0)
611 // return get_handle_value(g, ptr, child_type, ptr_type);
612
613 //bool big_endian = g->is_big_endian;
614
615 //assert(!handle_is_ptr(child_type));
616 //LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
617
618 //uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
619 //uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
620 //uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - unaligned_bit_count : bit_offset;
621
622 //LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
623 //LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
624
625 //return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
626 }
627 };
628
494 pub const PtrType = struct {629 pub const PtrType = struct {
495 base: Inst,630 base: Inst,
496 params: Params,631 params: Params,
...@@ -1160,6 +1295,7 @@ pub const Builder = struct {...@@ -1160,6 +1295,7 @@ pub const Builder = struct {
1160 Scope.Id.Block,1295 Scope.Id.Block,
1161 Scope.Id.Defer,1296 Scope.Id.Defer,
1162 Scope.Id.DeferExpr,1297 Scope.Id.DeferExpr,
1298 Scope.Id.Var,
1163 => scope = scope.parent.?,1299 => scope = scope.parent.?,
1164 }1300 }
1165 }1301 }
...@@ -1261,8 +1397,8 @@ pub const Builder = struct {...@@ -1261,8 +1397,8 @@ pub const Builder = struct {
1261 var child_scope = outer_block_scope;1397 var child_scope = outer_block_scope;
12621398
1263 if (parent_scope.findFnDef()) |fndef_scope| {1399 if (parent_scope.findFnDef()) |fndef_scope| {
1264 if (fndef_scope.fn_val.child_scope == parent_scope) {1400 if (fndef_scope.fn_val.?.block_scope == null) {
1265 fndef_scope.fn_val.block_scope = block_scope;1401 fndef_scope.fn_val.?.block_scope = block_scope;
1266 }1402 }
1267 }1403 }
12681404
...@@ -1492,20 +1628,23 @@ pub const Builder = struct {...@@ -1492,20 +1628,23 @@ pub const Builder = struct {
1492 error.OutOfMemory => return error.OutOfMemory,1628 error.OutOfMemory => return error.OutOfMemory,
1493 }1629 }
14941630
1495 //VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name);1631 switch (await (async irb.findIdent(scope, name) catch unreachable)) {
1496 //if (var) {1632 Ident.Decl => |decl| {
1497 // IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, node, var);1633 return irb.build(Inst.DeclRef, scope, src_span, Inst.DeclRef.Params{
1498 // if (lval == LValPtr)1634 .decl = decl,
1499 // return var_ptr;1635 .lval = lval,
1500 // else1636 });
1501 // return ir_build_load_ptr(irb, scope, node, var_ptr);1637 },
1502 //}1638 Ident.VarScope => |var_scope| {
15031639 const var_ptr = try irb.build(Inst.VarPtr, scope, src_span, Inst.VarPtr.Params{ .var_scope = var_scope });
1504 if (await (async irb.findDecl(scope, name) catch unreachable)) |decl| {1640 switch (lval) {
1505 return irb.build(Inst.DeclRef, scope, src_span, Inst.DeclRef.Params{1641 LVal.Ptr => return var_ptr,
1506 .decl = decl,1642 LVal.None => {
1507 .lval = lval,1643 return irb.build(Inst.LoadPtr, scope, src_span, Inst.LoadPtr.Params{ .target = var_ptr });
1508 });1644 },
1645 }
1646 },
1647 Ident.NotFound => {},
1509 }1648 }
15101649
1511 //if (node->owner->any_imports_failed) {1650 //if (node->owner->any_imports_failed) {
...@@ -1546,6 +1685,7 @@ pub const Builder = struct {...@@ -1546,6 +1685,7 @@ pub const Builder = struct {
1546 Scope.Id.Block,1685 Scope.Id.Block,
1547 Scope.Id.Decls,1686 Scope.Id.Decls,
1548 Scope.Id.Root,1687 Scope.Id.Root,
1688 Scope.Id.Var,
1549 => scope = scope.parent orelse break,1689 => scope = scope.parent orelse break,
15501690
1551 Scope.Id.DeferExpr => unreachable,1691 Scope.Id.DeferExpr => unreachable,
...@@ -1596,6 +1736,7 @@ pub const Builder = struct {...@@ -1596,6 +1736,7 @@ pub const Builder = struct {
15961736
1597 Scope.Id.CompTime,1737 Scope.Id.CompTime,
1598 Scope.Id.Block,1738 Scope.Id.Block,
1739 Scope.Id.Var,
1599 => scope = scope.parent orelse return is_noreturn,1740 => scope = scope.parent orelse return is_noreturn,
16001741
1601 Scope.Id.DeferExpr => unreachable,1742 Scope.Id.DeferExpr => unreachable,
...@@ -1674,8 +1815,10 @@ pub const Builder = struct {...@@ -1674,8 +1815,10 @@ pub const Builder = struct {
1674 Type.Pointer.Size,1815 Type.Pointer.Size,
1675 LVal,1816 LVal,
1676 *Decl,1817 *Decl,
1818 *Scope.Var,
1677 => {},1819 => {},
1678 // it's ok to add more types here, just make sure any instructions are ref'd appropriately1820 // it's ok to add more types here, just make sure that
1821 // any instructions and basic blocks are ref'd appropriately
1679 else => @compileError("unrecognized type in Params: " ++ @typeName(FieldType)),1822 else => @compileError("unrecognized type in Params: " ++ @typeName(FieldType)),
1680 }1823 }
1681 }1824 }
...@@ -1773,18 +1916,30 @@ pub const Builder = struct {...@@ -1773,18 +1916,30 @@ pub const Builder = struct {
1773 //// the above blocks are rendered by ir_gen after the rest of codegen1916 //// the above blocks are rendered by ir_gen after the rest of codegen
1774 }1917 }
17751918
1776 async fn findDecl(irb: *Builder, scope: *Scope, name: []const u8) ?*Decl {1919 const Ident = union(enum) {
1920 NotFound,
1921 Decl: *Decl,
1922 VarScope: *Scope.Var,
1923 };
1924
1925 async fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident {
1777 var s = scope;1926 var s = scope;
1778 while (true) {1927 while (true) {
1779 switch (s.id) {1928 switch (s.id) {
1929 Scope.Id.Root => return Ident.NotFound,
1780 Scope.Id.Decls => {1930 Scope.Id.Decls => {
1781 const decls = @fieldParentPtr(Scope.Decls, "base", s);1931 const decls = @fieldParentPtr(Scope.Decls, "base", s);
1782 const table = await (async decls.getTableReadOnly() catch unreachable);1932 const table = await (async decls.getTableReadOnly() catch unreachable);
1783 if (table.get(name)) |entry| {1933 if (table.get(name)) |entry| {
1784 return entry.value;1934 return Ident{ .Decl = entry.value };
1935 }
1936 },
1937 Scope.Id.Var => {
1938 const var_scope = @fieldParentPtr(Scope.Var, "base", s);
1939 if (mem.eql(u8, var_scope.name, name)) {
1940 return Ident{ .VarScope = var_scope };
1785 }1941 }
1786 },1942 },
1787 Scope.Id.Root => return null,
1788 else => {},1943 else => {},
1789 }1944 }
1790 s = s.parent.?;1945 s = s.parent.?;
src-self-hosted/llvm.zig+14-1
...@@ -30,6 +30,7 @@ pub const AddGlobal = c.LLVMAddGlobal;...@@ -30,6 +30,7 @@ pub const AddGlobal = c.LLVMAddGlobal;
30pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;30pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
31pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;31pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
32pub const ArrayType = c.LLVMArrayType;32pub const ArrayType = c.LLVMArrayType;
33pub const BuildLoad = c.LLVMBuildLoad;
33pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;34pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
34pub const ConstAllOnes = c.LLVMConstAllOnes;35pub const ConstAllOnes = c.LLVMConstAllOnes;
35pub const ConstArray = c.LLVMConstArray;36pub const ConstArray = c.LLVMConstArray;
...@@ -95,13 +96,25 @@ pub const SetInitializer = c.LLVMSetInitializer;...@@ -95,13 +96,25 @@ pub const SetInitializer = c.LLVMSetInitializer;
95pub const SetLinkage = c.LLVMSetLinkage;96pub const SetLinkage = c.LLVMSetLinkage;
96pub const SetTarget = c.LLVMSetTarget;97pub const SetTarget = c.LLVMSetTarget;
97pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;98pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
99pub const SetVolatile = c.LLVMSetVolatile;
98pub const StructTypeInContext = c.LLVMStructTypeInContext;100pub const StructTypeInContext = c.LLVMStructTypeInContext;
99pub const TokenTypeInContext = c.LLVMTokenTypeInContext;101pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
100pub const TypeOf = c.LLVMTypeOf;
101pub const VoidTypeInContext = c.LLVMVoidTypeInContext;102pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
102pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;103pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
103pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;104pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
104105
106pub const GetElementType = LLVMGetElementType;
107extern fn LLVMGetElementType(Ty: TypeRef) TypeRef;
108
109pub const TypeOf = LLVMTypeOf;
110extern fn LLVMTypeOf(Val: ValueRef) TypeRef;
111
112pub const BuildStore = LLVMBuildStore;
113extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef;
114
115pub const BuildAlloca = LLVMBuildAlloca;
116extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef;
117
105pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;118pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
106pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;119pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;
107120
src-self-hosted/scope.zig+128-73
...@@ -6,23 +6,26 @@ const Compilation = @import("compilation.zig").Compilation;...@@ -6,23 +6,26 @@ const Compilation = @import("compilation.zig").Compilation;
6const mem = std.mem;6const mem = std.mem;
7const ast = std.zig.ast;7const ast = std.zig.ast;
8const Value = @import("value.zig").Value;8const Value = @import("value.zig").Value;
9const Type = @import("type.zig").Type;
9const ir = @import("ir.zig");10const ir = @import("ir.zig");
10const Span = @import("errmsg.zig").Span;11const Span = @import("errmsg.zig").Span;
11const assert = std.debug.assert;12const assert = std.debug.assert;
12const event = std.event;13const event = std.event;
14const llvm = @import("llvm.zig");
1315
14pub const Scope = struct {16pub const Scope = struct {
15 id: Id,17 id: Id,
16 parent: ?*Scope,18 parent: ?*Scope,
17 ref_count: usize,19 ref_count: std.atomic.Int(usize),
1820
21 /// Thread-safe
19 pub fn ref(base: *Scope) void {22 pub fn ref(base: *Scope) void {
20 base.ref_count += 1;23 _ = base.ref_count.incr();
21 }24 }
2225
26 /// Thread-safe
23 pub fn deref(base: *Scope, comp: *Compilation) void {27 pub fn deref(base: *Scope, comp: *Compilation) void {
24 base.ref_count -= 1;28 if (base.ref_count.decr() == 1) {
25 if (base.ref_count == 0) {
26 if (base.parent) |parent| parent.deref(comp);29 if (base.parent) |parent| parent.deref(comp);
27 switch (base.id) {30 switch (base.id) {
28 Id.Root => @fieldParentPtr(Root, "base", base).destroy(comp),31 Id.Root => @fieldParentPtr(Root, "base", base).destroy(comp),
...@@ -32,6 +35,7 @@ pub const Scope = struct {...@@ -32,6 +35,7 @@ pub const Scope = struct {
32 Id.CompTime => @fieldParentPtr(CompTime, "base", base).destroy(comp),35 Id.CompTime => @fieldParentPtr(CompTime, "base", base).destroy(comp),
33 Id.Defer => @fieldParentPtr(Defer, "base", base).destroy(comp),36 Id.Defer => @fieldParentPtr(Defer, "base", base).destroy(comp),
34 Id.DeferExpr => @fieldParentPtr(DeferExpr, "base", base).destroy(comp),37 Id.DeferExpr => @fieldParentPtr(DeferExpr, "base", base).destroy(comp),
38 Id.Var => @fieldParentPtr(Var, "base", base).destroy(comp),
35 }39 }
36 }40 }
37 }41 }
...@@ -49,15 +53,15 @@ pub const Scope = struct {...@@ -49,15 +53,15 @@ pub const Scope = struct {
49 var scope = base;53 var scope = base;
50 while (true) {54 while (true) {
51 switch (scope.id) {55 switch (scope.id) {
52 Id.FnDef => return @fieldParentPtr(FnDef, "base", base),56 Id.FnDef => return @fieldParentPtr(FnDef, "base", scope),
53 Id.Decls => return null,57 Id.Root, Id.Decls => return null,
5458
55 Id.Block,59 Id.Block,
56 Id.Defer,60 Id.Defer,
57 Id.DeferExpr,61 Id.DeferExpr,
58 Id.CompTime,62 Id.CompTime,
59 Id.Root,63 Id.Var,
60 => scope = scope.parent orelse return null,64 => scope = scope.parent.?,
61 }65 }
62 }66 }
63 }67 }
...@@ -66,7 +70,7 @@ pub const Scope = struct {...@@ -66,7 +70,7 @@ pub const Scope = struct {
66 var scope = base;70 var scope = base;
67 while (true) {71 while (true) {
68 switch (scope.id) {72 switch (scope.id) {
69 Id.DeferExpr => return @fieldParentPtr(DeferExpr, "base", base),73 Id.DeferExpr => return @fieldParentPtr(DeferExpr, "base", scope),
7074
71 Id.FnDef,75 Id.FnDef,
72 Id.Decls,76 Id.Decls,
...@@ -76,11 +80,21 @@ pub const Scope = struct {...@@ -76,11 +80,21 @@ pub const Scope = struct {
76 Id.Defer,80 Id.Defer,
77 Id.CompTime,81 Id.CompTime,
78 Id.Root,82 Id.Root,
83 Id.Var,
79 => scope = scope.parent orelse return null,84 => scope = scope.parent orelse return null,
80 }85 }
81 }86 }
82 }87 }
8388
89 fn init(base: *Scope, id: Id, parent: *Scope) void {
90 base.* = Scope{
91 .id = id,
92 .parent = parent,
93 .ref_count = std.atomic.Int(usize).init(1),
94 };
95 parent.ref();
96 }
97
84 pub const Id = enum {98 pub const Id = enum {
85 Root,99 Root,
86 Decls,100 Decls,
...@@ -89,6 +103,7 @@ pub const Scope = struct {...@@ -89,6 +103,7 @@ pub const Scope = struct {
89 CompTime,103 CompTime,
90 Defer,104 Defer,
91 DeferExpr,105 DeferExpr,
106 Var,
92 };107 };
93108
94 pub const Root = struct {109 pub const Root = struct {
...@@ -100,16 +115,16 @@ pub const Scope = struct {...@@ -100,16 +115,16 @@ pub const Scope = struct {
100 /// Takes ownership of realpath115 /// Takes ownership of realpath
101 /// Takes ownership of tree, will deinit and destroy when done.116 /// Takes ownership of tree, will deinit and destroy when done.
102 pub fn create(comp: *Compilation, tree: *ast.Tree, realpath: []u8) !*Root {117 pub fn create(comp: *Compilation, tree: *ast.Tree, realpath: []u8) !*Root {
103 const self = try comp.gpa().create(Root{118 const self = try comp.gpa().createOne(Root);
119 self.* = Root{
104 .base = Scope{120 .base = Scope{
105 .id = Id.Root,121 .id = Id.Root,
106 .parent = null,122 .parent = null,
107 .ref_count = 1,123 .ref_count = std.atomic.Int(usize).init(1),
108 },124 },
109 .tree = tree,125 .tree = tree,
110 .realpath = realpath,126 .realpath = realpath,
111 });127 };
112 errdefer comp.gpa().destroy(self);
113128
114 return self;129 return self;
115 }130 }
...@@ -137,16 +152,13 @@ pub const Scope = struct {...@@ -137,16 +152,13 @@ pub const Scope = struct {
137152
138 /// Creates a Decls scope with 1 reference153 /// Creates a Decls scope with 1 reference
139 pub fn create(comp: *Compilation, parent: *Scope) !*Decls {154 pub fn create(comp: *Compilation, parent: *Scope) !*Decls {
140 const self = try comp.gpa().create(Decls{155 const self = try comp.gpa().createOne(Decls);
141 .base = Scope{156 self.* = Decls{
142 .id = Id.Decls,157 .base = undefined,
143 .parent = parent,
144 .ref_count = 1,
145 },
146 .table = event.Locked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())),158 .table = event.Locked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())),
147 .name_future = event.Future(void).init(comp.loop),159 .name_future = event.Future(void).init(comp.loop),
148 });160 };
149 parent.ref();161 self.base.init(Id.Decls, parent);
150 return self;162 return self;
151 }163 }
152164
...@@ -199,21 +211,16 @@ pub const Scope = struct {...@@ -199,21 +211,16 @@ pub const Scope = struct {
199211
200 /// Creates a Block scope with 1 reference212 /// Creates a Block scope with 1 reference
201 pub fn create(comp: *Compilation, parent: *Scope) !*Block {213 pub fn create(comp: *Compilation, parent: *Scope) !*Block {
202 const self = try comp.gpa().create(Block{214 const self = try comp.gpa().createOne(Block);
203 .base = Scope{215 self.* = Block{
204 .id = Id.Block,216 .base = undefined,
205 .parent = parent,
206 .ref_count = 1,
207 },
208 .incoming_values = undefined,217 .incoming_values = undefined,
209 .incoming_blocks = undefined,218 .incoming_blocks = undefined,
210 .end_block = undefined,219 .end_block = undefined,
211 .is_comptime = undefined,220 .is_comptime = undefined,
212 .safety = Safety.Auto,221 .safety = Safety.Auto,
213 });222 };
214 errdefer comp.gpa().destroy(self);223 self.base.init(Id.Block, parent);
215
216 parent.ref();
217 return self;224 return self;
218 }225 }
219226
...@@ -226,22 +233,17 @@ pub const Scope = struct {...@@ -226,22 +233,17 @@ pub const Scope = struct {
226 base: Scope,233 base: Scope,
227234
228 /// This reference is not counted so that the scope can get destroyed with the function235 /// This reference is not counted so that the scope can get destroyed with the function
229 fn_val: *Value.Fn,236 fn_val: ?*Value.Fn,
230237
231 /// Creates a FnDef scope with 1 reference238 /// Creates a FnDef scope with 1 reference
232 /// Must set the fn_val later239 /// Must set the fn_val later
233 pub fn create(comp: *Compilation, parent: *Scope) !*FnDef {240 pub fn create(comp: *Compilation, parent: *Scope) !*FnDef {
234 const self = try comp.gpa().create(FnDef{241 const self = try comp.gpa().createOne(FnDef);
235 .base = Scope{242 self.* = FnDef{
236 .id = Id.FnDef,243 .base = undefined,
237 .parent = parent,244 .fn_val = null,
238 .ref_count = 1,245 };
239 },246 self.base.init(Id.FnDef, parent);
240 .fn_val = undefined,
241 });
242
243 parent.ref();
244
245 return self;247 return self;
246 }248 }
247249
...@@ -255,15 +257,9 @@ pub const Scope = struct {...@@ -255,15 +257,9 @@ pub const Scope = struct {
255257
256 /// Creates a CompTime scope with 1 reference258 /// Creates a CompTime scope with 1 reference
257 pub fn create(comp: *Compilation, parent: *Scope) !*CompTime {259 pub fn create(comp: *Compilation, parent: *Scope) !*CompTime {
258 const self = try comp.gpa().create(CompTime{260 const self = try comp.gpa().createOne(CompTime);
259 .base = Scope{261 self.* = CompTime{ .base = undefined };
260 .id = Id.CompTime,262 self.base.init(Id.CompTime, parent);
261 .parent = parent,
262 .ref_count = 1,
263 },
264 });
265
266 parent.ref();
267 return self;263 return self;
268 }264 }
269265
...@@ -289,20 +285,14 @@ pub const Scope = struct {...@@ -289,20 +285,14 @@ pub const Scope = struct {
289 kind: Kind,285 kind: Kind,
290 defer_expr_scope: *DeferExpr,286 defer_expr_scope: *DeferExpr,
291 ) !*Defer {287 ) !*Defer {
292 const self = try comp.gpa().create(Defer{288 const self = try comp.gpa().createOne(Defer);
293 .base = Scope{289 self.* = Defer{
294 .id = Id.Defer,290 .base = undefined,
295 .parent = parent,
296 .ref_count = 1,
297 },
298 .defer_expr_scope = defer_expr_scope,291 .defer_expr_scope = defer_expr_scope,
299 .kind = kind,292 .kind = kind,
300 });293 };
301 errdefer comp.gpa().destroy(self);294 self.base.init(Id.Defer, parent);
302
303 defer_expr_scope.base.ref();295 defer_expr_scope.base.ref();
304
305 parent.ref();
306 return self;296 return self;
307 }297 }
308298
...@@ -319,18 +309,13 @@ pub const Scope = struct {...@@ -319,18 +309,13 @@ pub const Scope = struct {
319309
320 /// Creates a DeferExpr scope with 1 reference310 /// Creates a DeferExpr scope with 1 reference
321 pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr {311 pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr {
322 const self = try comp.gpa().create(DeferExpr{312 const self = try comp.gpa().createOne(DeferExpr);
323 .base = Scope{313 self.* = DeferExpr{
324 .id = Id.DeferExpr,314 .base = undefined,
325 .parent = parent,
326 .ref_count = 1,
327 },
328 .expr_node = expr_node,315 .expr_node = expr_node,
329 .reported_err = false,316 .reported_err = false,
330 });317 };
331 errdefer comp.gpa().destroy(self);318 self.base.init(Id.DeferExpr, parent);
332
333 parent.ref();
334 return self;319 return self;
335 }320 }
336321
...@@ -338,4 +323,74 @@ pub const Scope = struct {...@@ -338,4 +323,74 @@ pub const Scope = struct {
338 comp.gpa().destroy(self);323 comp.gpa().destroy(self);
339 }324 }
340 };325 };
326
327 pub const Var = struct {
328 base: Scope,
329 name: []const u8,
330 src_node: *ast.Node,
331 data: Data,
332
333 pub const Data = union(enum) {
334 Param: Param,
335 Const: *Value,
336 };
337
338 pub const Param = struct {
339 index: usize,
340 typ: *Type,
341 llvm_value: llvm.ValueRef,
342 };
343
344 pub fn createParam(
345 comp: *Compilation,
346 parent: *Scope,
347 name: []const u8,
348 src_node: *ast.Node,
349 param_index: usize,
350 param_type: *Type,
351 ) !*Var {
352 const self = try create(comp, parent, name, src_node);
353 self.data = Data{
354 .Param = Param{
355 .index = param_index,
356 .typ = param_type,
357 .llvm_value = undefined,
358 },
359 };
360 return self;
361 }
362
363 pub fn createConst(
364 comp: *Compilation,
365 parent: *Scope,
366 name: []const u8,
367 src_node: *ast.Node,
368 value: *Value,
369 ) !*Var {
370 const self = try create(comp, parent, name, src_node);
371 self.data = Data{ .Const = value };
372 value.ref();
373 return self;
374 }
375
376 fn create(comp: *Compilation, parent: *Scope, name: []const u8, src_node: *ast.Node) !*Var {
377 const self = try comp.gpa().createOne(Var);
378 self.* = Var{
379 .base = undefined,
380 .name = name,
381 .src_node = src_node,
382 .data = undefined,
383 };
384 self.base.init(Id.Var, parent);
385 return self;
386 }
387
388 pub fn destroy(self: *Var, comp: *Compilation) void {
389 switch (self.data) {
390 Data.Param => {},
391 Data.Const => |value| value.deref(comp),
392 }
393 comp.gpa().destroy(self);
394 }
395 };
341};396};
src-self-hosted/type.zig+68-37
...@@ -141,9 +141,13 @@ pub const Type = struct {...@@ -141,9 +141,13 @@ pub const Type = struct {
141 Id.Promise,141 Id.Promise,
142 => return true,142 => return true,
143143
144 Id.Pointer => {
145 const ptr_type = @fieldParentPtr(Pointer, "base", base);
146 return ptr_type.key.child_type.hasBits();
147 },
148
144 Id.ErrorSet => @panic("TODO"),149 Id.ErrorSet => @panic("TODO"),
145 Id.Enum => @panic("TODO"),150 Id.Enum => @panic("TODO"),
146 Id.Pointer => @panic("TODO"),
147 Id.Struct => @panic("TODO"),151 Id.Struct => @panic("TODO"),
148 Id.Array => @panic("TODO"),152 Id.Array => @panic("TODO"),
149 Id.Optional => @panic("TODO"),153 Id.Optional => @panic("TODO"),
...@@ -222,29 +226,65 @@ pub const Type = struct {...@@ -222,29 +226,65 @@ pub const Type = struct {
222 pub const Fn = struct {226 pub const Fn = struct {
223 base: Type,227 base: Type,
224 key: Key,228 key: Key,
229 non_key: NonKey,
225 garbage_node: std.atomic.Stack(*Fn).Node,230 garbage_node: std.atomic.Stack(*Fn).Node,
226231
232 pub const Kind = enum {
233 Normal,
234 Generic,
235 };
236
237 pub const NonKey = union {
238 Normal: Normal,
239 Generic: void,
240
241 pub const Normal = struct {
242 variable_list: std.ArrayList(*Scope.Var),
243 };
244 };
245
227 pub const Key = struct {246 pub const Key = struct {
228 data: Data,247 data: Data,
229 alignment: ?u32,248 alignment: ?u32,
230249
231 pub const Data = union(enum) {250 pub const Data = union(Kind) {
232 Generic: Generic,251 Generic: Generic,
233 Normal: Normal,252 Normal: Normal,
234 };253 };
235254
255 pub const Normal = struct {
256 params: []Param,
257 return_type: *Type,
258 is_var_args: bool,
259 cc: CallingConvention,
260 };
261
262 pub const Generic = struct {
263 param_count: usize,
264 cc: CC,
265
266 pub const CC = union(CallingConvention) {
267 Auto,
268 C,
269 Cold,
270 Naked,
271 Stdcall,
272 Async: *Type, // allocator type
273 };
274 };
275
236 pub fn hash(self: *const Key) u32 {276 pub fn hash(self: *const Key) u32 {
237 var result: u32 = 0;277 var result: u32 = 0;
238 result +%= hashAny(self.alignment, 0);278 result +%= hashAny(self.alignment, 0);
239 switch (self.data) {279 switch (self.data) {
240 Data.Generic => |generic| {280 Kind.Generic => |generic| {
241 result +%= hashAny(generic.param_count, 1);281 result +%= hashAny(generic.param_count, 1);
242 switch (generic.cc) {282 switch (generic.cc) {
243 CallingConvention.Async => |allocator_type| result +%= hashAny(allocator_type, 2),283 CallingConvention.Async => |allocator_type| result +%= hashAny(allocator_type, 2),
244 else => result +%= hashAny(CallingConvention(generic.cc), 3),284 else => result +%= hashAny(CallingConvention(generic.cc), 3),
245 }285 }
246 },286 },
247 Data.Normal => |normal| {287 Kind.Normal => |normal| {
248 result +%= hashAny(normal.return_type, 4);288 result +%= hashAny(normal.return_type, 4);
249 result +%= hashAny(normal.is_var_args, 5);289 result +%= hashAny(normal.is_var_args, 5);
250 result +%= hashAny(normal.cc, 6);290 result +%= hashAny(normal.cc, 6);
...@@ -264,7 +304,7 @@ pub const Type = struct {...@@ -264,7 +304,7 @@ pub const Type = struct {
264 }304 }
265 if (@TagType(Data)(self.data) != @TagType(Data)(other.data)) return false;305 if (@TagType(Data)(self.data) != @TagType(Data)(other.data)) return false;
266 switch (self.data) {306 switch (self.data) {
267 Data.Generic => |*self_generic| {307 Kind.Generic => |*self_generic| {
268 const other_generic = &other.data.Generic;308 const other_generic = &other.data.Generic;
269 if (self_generic.param_count != other_generic.param_count) return false;309 if (self_generic.param_count != other_generic.param_count) return false;
270 if (CallingConvention(self_generic.cc) != CallingConvention(other_generic.cc)) return false;310 if (CallingConvention(self_generic.cc) != CallingConvention(other_generic.cc)) return false;
...@@ -276,7 +316,7 @@ pub const Type = struct {...@@ -276,7 +316,7 @@ pub const Type = struct {
276 else => {},316 else => {},
277 }317 }
278 },318 },
279 Data.Normal => |*self_normal| {319 Kind.Normal => |*self_normal| {
280 const other_normal = &other.data.Normal;320 const other_normal = &other.data.Normal;
281 if (self_normal.cc != other_normal.cc) return false;321 if (self_normal.cc != other_normal.cc) return false;
282 if (self_normal.is_var_args != other_normal.is_var_args) return false;322 if (self_normal.is_var_args != other_normal.is_var_args) return false;
...@@ -293,13 +333,13 @@ pub const Type = struct {...@@ -293,13 +333,13 @@ pub const Type = struct {
293333
294 pub fn deref(key: Key, comp: *Compilation) void {334 pub fn deref(key: Key, comp: *Compilation) void {
295 switch (key.data) {335 switch (key.data) {
296 Key.Data.Generic => |generic| {336 Kind.Generic => |generic| {
297 switch (generic.cc) {337 switch (generic.cc) {
298 CallingConvention.Async => |allocator_type| allocator_type.base.deref(comp),338 CallingConvention.Async => |allocator_type| allocator_type.base.deref(comp),
299 else => {},339 else => {},
300 }340 }
301 },341 },
302 Key.Data.Normal => |normal| {342 Kind.Normal => |normal| {
303 normal.return_type.base.deref(comp);343 normal.return_type.base.deref(comp);
304 for (normal.params) |param| {344 for (normal.params) |param| {
305 param.typ.base.deref(comp);345 param.typ.base.deref(comp);
...@@ -310,13 +350,13 @@ pub const Type = struct {...@@ -310,13 +350,13 @@ pub const Type = struct {
310350
311 pub fn ref(key: Key) void {351 pub fn ref(key: Key) void {
312 switch (key.data) {352 switch (key.data) {
313 Key.Data.Generic => |generic| {353 Kind.Generic => |generic| {
314 switch (generic.cc) {354 switch (generic.cc) {
315 CallingConvention.Async => |allocator_type| allocator_type.base.ref(),355 CallingConvention.Async => |allocator_type| allocator_type.base.ref(),
316 else => {},356 else => {},
317 }357 }
318 },358 },
319 Key.Data.Normal => |normal| {359 Kind.Normal => |normal| {
320 normal.return_type.base.ref();360 normal.return_type.base.ref();
321 for (normal.params) |param| {361 for (normal.params) |param| {
322 param.typ.base.ref();362 param.typ.base.ref();
...@@ -326,27 +366,6 @@ pub const Type = struct {...@@ -326,27 +366,6 @@ pub const Type = struct {
326 }366 }
327 };367 };
328368
329 pub const Normal = struct {
330 params: []Param,
331 return_type: *Type,
332 is_var_args: bool,
333 cc: CallingConvention,
334 };
335
336 pub const Generic = struct {
337 param_count: usize,
338 cc: CC,
339
340 pub const CC = union(CallingConvention) {
341 Auto,
342 C,
343 Cold,
344 Naked,
345 Stdcall,
346 Async: *Type, // allocator type
347 };
348 };
349
350 pub const CallingConvention = enum {369 pub const CallingConvention = enum {
351 Auto,370 Auto,
352 C,371 C,
...@@ -374,8 +393,8 @@ pub const Type = struct {...@@ -374,8 +393,8 @@ pub const Type = struct {
374393
375 pub fn paramCount(self: *Fn) usize {394 pub fn paramCount(self: *Fn) usize {
376 return switch (self.key.data) {395 return switch (self.key.data) {
377 Key.Data.Generic => |generic| generic.param_count,396 Kind.Generic => |generic| generic.param_count,
378 Key.Data.Normal => |normal| normal.params.len,397 Kind.Normal => |normal| normal.params.len,
379 };398 };
380 }399 }
381400
...@@ -394,11 +413,13 @@ pub const Type = struct {...@@ -394,11 +413,13 @@ pub const Type = struct {
394 key.ref();413 key.ref();
395 errdefer key.deref(comp);414 errdefer key.deref(comp);
396415
397 const self = try comp.gpa().create(Fn{416 const self = try comp.gpa().createOne(Fn);
417 self.* = Fn{
398 .base = undefined,418 .base = undefined,
399 .key = key,419 .key = key,
420 .non_key = undefined,
400 .garbage_node = undefined,421 .garbage_node = undefined,
401 });422 };
402 errdefer comp.gpa().destroy(self);423 errdefer comp.gpa().destroy(self);
403424
404 var name_buf = try std.Buffer.initSize(comp.gpa(), 0);425 var name_buf = try std.Buffer.initSize(comp.gpa(), 0);
...@@ -407,7 +428,8 @@ pub const Type = struct {...@@ -407,7 +428,8 @@ pub const Type = struct {
407 const name_stream = &std.io.BufferOutStream.init(&name_buf).stream;428 const name_stream = &std.io.BufferOutStream.init(&name_buf).stream;
408429
409 switch (key.data) {430 switch (key.data) {
410 Key.Data.Generic => |generic| {431 Kind.Generic => |generic| {
432 self.non_key = NonKey{ .Generic = {} };
411 switch (generic.cc) {433 switch (generic.cc) {
412 CallingConvention.Async => |async_allocator_type| {434 CallingConvention.Async => |async_allocator_type| {
413 try name_stream.print("async<{}> ", async_allocator_type.name);435 try name_stream.print("async<{}> ", async_allocator_type.name);
...@@ -429,7 +451,10 @@ pub const Type = struct {...@@ -429,7 +451,10 @@ pub const Type = struct {
429 }451 }
430 try name_stream.write(" var");452 try name_stream.write(" var");
431 },453 },
432 Key.Data.Normal => |normal| {454 Kind.Normal => |normal| {
455 self.non_key = NonKey{
456 .Normal = NonKey.Normal{ .variable_list = std.ArrayList(*Scope.Var).init(comp.gpa()) },
457 };
433 const cc_str = ccFnTypeStr(normal.cc);458 const cc_str = ccFnTypeStr(normal.cc);
434 try name_stream.print("{}fn(", cc_str);459 try name_stream.print("{}fn(", cc_str);
435 for (normal.params) |param, i| {460 for (normal.params) |param, i| {
...@@ -462,6 +487,12 @@ pub const Type = struct {...@@ -462,6 +487,12 @@ pub const Type = struct {
462487
463 pub fn destroy(self: *Fn, comp: *Compilation) void {488 pub fn destroy(self: *Fn, comp: *Compilation) void {
464 self.key.deref(comp);489 self.key.deref(comp);
490 switch (self.key.data) {
491 Kind.Generic => {},
492 Kind.Normal => {
493 self.non_key.Normal.variable_list.deinit();
494 },
495 }
465 comp.gpa().destroy(self);496 comp.gpa().destroy(self);
466 }497 }
467498
src-self-hosted/value.zig+19-3
...@@ -60,7 +60,7 @@ pub const Value = struct {...@@ -60,7 +60,7 @@ pub const Value = struct {
60 pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) {60 pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) {
61 switch (base.id) {61 switch (base.id) {
62 Id.Type => unreachable,62 Id.Type => unreachable,
63 Id.Fn => @panic("TODO"),63 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile),
64 Id.FnProto => return @fieldParentPtr(FnProto, "base", base).getLlvmConst(ofile),64 Id.FnProto => return @fieldParentPtr(FnProto, "base", base).getLlvmConst(ofile),
65 Id.Void => return null,65 Id.Void => return null,
66 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),66 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),
...@@ -180,7 +180,7 @@ pub const Value = struct {...@@ -180,7 +180,7 @@ pub const Value = struct {
180 child_scope: *Scope,180 child_scope: *Scope,
181181
182 /// parent is child_scope182 /// parent is child_scope
183 block_scope: *Scope.Block,183 block_scope: ?*Scope.Block,
184184
185 /// Path to the object file that contains this function185 /// Path to the object file that contains this function
186 containing_object: Buffer,186 containing_object: Buffer,
...@@ -205,7 +205,7 @@ pub const Value = struct {...@@ -205,7 +205,7 @@ pub const Value = struct {
205 },205 },
206 .fndef_scope = fndef_scope,206 .fndef_scope = fndef_scope,
207 .child_scope = &fndef_scope.base,207 .child_scope = &fndef_scope.base,
208 .block_scope = undefined,208 .block_scope = null,
209 .symbol_name = symbol_name,209 .symbol_name = symbol_name,
210 .containing_object = Buffer.initNull(comp.gpa()),210 .containing_object = Buffer.initNull(comp.gpa()),
211 .link_set_node = link_set_node,211 .link_set_node = link_set_node,
...@@ -231,6 +231,22 @@ pub const Value = struct {...@@ -231,6 +231,22 @@ pub const Value = struct {
231 self.symbol_name.deinit();231 self.symbol_name.deinit();
232 comp.gpa().destroy(self);232 comp.gpa().destroy(self);
233 }233 }
234
235 /// We know that the function definition will end up in an .o file somewhere.
236 /// Here, all we have to do is generate a global prototype.
237 /// TODO cache the prototype per ObjectFile
238 pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?llvm.ValueRef {
239 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
240 const llvm_fn = llvm.AddFunction(
241 ofile.module,
242 self.symbol_name.ptr(),
243 llvm_fn_type,
244 ) orelse return error.OutOfMemory;
245
246 // TODO port more logic from codegen.cpp:fn_llvm_value
247
248 return llvm_fn;
249 }
234 };250 };
235251
236 pub const Void = struct {252 pub const Void = struct {