| author | |
| committer | |
| log | adefd1a52b812813dd3e3590d398f927ffc5b9af |
| tree | 1971356295aa4dca151b49ff03e7e2ce10e4a345 |
| parent | 2ea08561cf69dabc99722ffc24cb0e4327605506 |
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"); |
| 6 | const ir = @import("ir.zig"); | 6 | const ir = @import("ir.zig"); |
| 7 | const Value = @import("value.zig").Value; | 7 | const Value = @import("value.zig").Value; |
| 8 | const Type = @import("type.zig").Type; | 8 | const Type = @import("type.zig").Type; |
| 9 | const Scope = @import("scope.zig").Scope; | ||
| 9 | const event = std.event; | 10 | const event = std.event; |
| 10 | const assert = std.debug.assert; | 11 | const assert = std.debug.assert; |
| 11 | const DW = std.dwarf; | 12 | const 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; |
| 158 | 159 | ||
| 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) |
| 227 | 228 | ||
| 228 | // TODO set up error return tracing | 229 | // TODO set up error return tracing |
| 229 | // TODO allocate temporary stack values | 230 | // TODO allocate temporary stack values |
| 230 | // TODO create debug variable declarations for variables and allocate all local variables | 231 | |
| 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 parameters | 281 | |
| 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 | } | ||
| 233 | 311 | ||
| 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 |
| 294 | fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void { | 372 | fn 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 | |||
| 376 | fn 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 | |||
| 392 | fn 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 | |||
| 396 | pub 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 | |||
| 407 | pub 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 | |||
| 423 | pub 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 | |||
| 432 | pub 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 | |||
| 445 | pub 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; |
| 1166 | 1166 | ||
| 1167 | // Define local parameter variables | 1167 | // 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 | |
| 1181 | 1181 | // 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 | // } |
| 1184 | 1184 | ||
| 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( |
| 1188 | 1188 | 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, |
| 1194 | 1194 | ); | |
| 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); |
| 1198 | 1198 | } | |
| 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 | //} | ||
| 1203 | 1199 | ||
| 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()); |
| 1210 | 1206 | ||
| 1207 | assert(fn_val.block_scope != null); | ||
| 1208 | |||
| 1211 | // Kick off rendering to LLVM module, but it doesn't block the fn decl | 1209 | // 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, // TODO | 1267 | .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; |
| 10 | const Token = std.zig.Token; | 10 | const Token = std.zig.Token; |
| 11 | const Span = @import("errmsg.zig").Span; | 11 | const Span = @import("errmsg.zig").Span; |
| 12 | const llvm = @import("llvm.zig"); | 12 | const llvm = @import("llvm.zig"); |
| 13 | const ObjectFile = @import("codegen.zig").ObjectFile; | 13 | const codegen = @import("codegen.zig"); |
| 14 | const ObjectFile = codegen.ObjectFile; | ||
| 14 | const Decl = @import("decl.zig").Decl; | 15 | const Decl = @import("decl.zig").Decl; |
| 16 | const mem = std.mem; | ||
| 15 | 17 | ||
| 16 | pub const LVal = enum { | 18 | pub 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 | } |
| 127 | 131 | ||
| ... | @@ -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 | }; |
| 252 | 260 | ||
| 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 | }; |
| 493 | 501 | ||
| 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; |
| 1262 | 1398 | ||
| 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 | } |
| 1268 | 1404 | ||
| ... | @@ -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 | } |
| 1494 | 1630 | ||
| 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 | // else | 1636 | }); |
| 1501 | // return ir_build_load_ptr(irb, scope, node, var_ptr); | 1637 | }, |
| 1502 | //} | 1638 | Ident.VarScope => |var_scope| { |
| 1503 | 1639 | 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 | } |
| 1510 | 1649 | ||
| 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, |
| 1550 | 1690 | ||
| 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 { |
| 1596 | 1736 | ||
| 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, |
| 1600 | 1741 | ||
| 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 appropriately | 1820 | // 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 codegen | 1916 | //// the above blocks are rendered by ir_gen after the rest of codegen |
| 1774 | } | 1917 | } |
| 1775 | 1918 | ||
| 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; |
| 30 | pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag; | 30 | pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag; |
| 31 | pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; | 31 | pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; |
| 32 | pub const ArrayType = c.LLVMArrayType; | 32 | pub const ArrayType = c.LLVMArrayType; |
| 33 | pub const BuildLoad = c.LLVMBuildLoad; | ||
| 33 | pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; | 34 | pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; |
| 34 | pub const ConstAllOnes = c.LLVMConstAllOnes; | 35 | pub const ConstAllOnes = c.LLVMConstAllOnes; |
| 35 | pub const ConstArray = c.LLVMConstArray; | 36 | pub const ConstArray = c.LLVMConstArray; |
| ... | @@ -95,13 +96,25 @@ pub const SetInitializer = c.LLVMSetInitializer; | ... | @@ -95,13 +96,25 @@ pub const SetInitializer = c.LLVMSetInitializer; |
| 95 | pub const SetLinkage = c.LLVMSetLinkage; | 96 | pub const SetLinkage = c.LLVMSetLinkage; |
| 96 | pub const SetTarget = c.LLVMSetTarget; | 97 | pub const SetTarget = c.LLVMSetTarget; |
| 97 | pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr; | 98 | pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr; |
| 99 | pub const SetVolatile = c.LLVMSetVolatile; | ||
| 98 | pub const StructTypeInContext = c.LLVMStructTypeInContext; | 100 | pub const StructTypeInContext = c.LLVMStructTypeInContext; |
| 99 | pub const TokenTypeInContext = c.LLVMTokenTypeInContext; | 101 | pub const TokenTypeInContext = c.LLVMTokenTypeInContext; |
| 100 | pub const TypeOf = c.LLVMTypeOf; | ||
| 101 | pub const VoidTypeInContext = c.LLVMVoidTypeInContext; | 102 | pub const VoidTypeInContext = c.LLVMVoidTypeInContext; |
| 102 | pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; | 103 | pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; |
| 103 | pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; | 104 | pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; |
| 104 | 105 | ||
| 106 | pub const GetElementType = LLVMGetElementType; | ||
| 107 | extern fn LLVMGetElementType(Ty: TypeRef) TypeRef; | ||
| 108 | |||
| 109 | pub const TypeOf = LLVMTypeOf; | ||
| 110 | extern fn LLVMTypeOf(Val: ValueRef) TypeRef; | ||
| 111 | |||
| 112 | pub const BuildStore = LLVMBuildStore; | ||
| 113 | extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef; | ||
| 114 | |||
| 115 | pub const BuildAlloca = LLVMBuildAlloca; | ||
| 116 | extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef; | ||
| 117 | |||
| 105 | pub const ConstInBoundsGEP = LLVMConstInBoundsGEP; | 118 | pub const ConstInBoundsGEP = LLVMConstInBoundsGEP; |
| 106 | pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef; | 119 | pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef; |
| 107 | 120 |
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; |
| 6 | const mem = std.mem; | 6 | const mem = std.mem; |
| 7 | const ast = std.zig.ast; | 7 | const ast = std.zig.ast; |
| 8 | const Value = @import("value.zig").Value; | 8 | const Value = @import("value.zig").Value; |
| 9 | const Type = @import("type.zig").Type; | ||
| 9 | const ir = @import("ir.zig"); | 10 | const ir = @import("ir.zig"); |
| 10 | const Span = @import("errmsg.zig").Span; | 11 | const Span = @import("errmsg.zig").Span; |
| 11 | const assert = std.debug.assert; | 12 | const assert = std.debug.assert; |
| 12 | const event = std.event; | 13 | const event = std.event; |
| 14 | const llvm = @import("llvm.zig"); | ||
| 13 | 15 | ||
| 14 | pub const Scope = struct { | 16 | pub 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), |
| 18 | 20 | ||
| 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 | } |
| 22 | 25 | ||
| 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, |
| 54 | 58 | ||
| 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), |
| 70 | 74 | ||
| 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 | } |
| 83 | 88 | ||
| 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 | }; |
| 93 | 108 | ||
| 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 realpath | 115 | /// 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); | ||
| 113 | 128 | ||
| 114 | return self; | 129 | return self; |
| 115 | } | 130 | } |
| ... | @@ -137,16 +152,13 @@ pub const Scope = struct { | ... | @@ -137,16 +152,13 @@ pub const Scope = struct { |
| 137 | 152 | ||
| 138 | /// Creates a Decls scope with 1 reference | 153 | /// 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 | } |
| 152 | 164 | ||
| ... | @@ -199,21 +211,16 @@ pub const Scope = struct { | ... | @@ -199,21 +211,16 @@ pub const Scope = struct { |
| 199 | 211 | ||
| 200 | /// Creates a Block scope with 1 reference | 212 | /// 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 | } |
| 219 | 226 | ||
| ... | @@ -226,22 +233,17 @@ pub const Scope = struct { | ... | @@ -226,22 +233,17 @@ pub const Scope = struct { |
| 226 | base: Scope, | 233 | base: Scope, |
| 227 | 234 | ||
| 228 | /// This reference is not counted so that the scope can get destroyed with the function | 235 | /// 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, |
| 230 | 237 | ||
| 231 | /// Creates a FnDef scope with 1 reference | 238 | /// Creates a FnDef scope with 1 reference |
| 232 | /// Must set the fn_val later | 239 | /// 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 | } |
| 247 | 249 | ||
| ... | @@ -255,15 +257,9 @@ pub const Scope = struct { | ... | @@ -255,15 +257,9 @@ pub const Scope = struct { |
| 255 | 257 | ||
| 256 | /// Creates a CompTime scope with 1 reference | 258 | /// 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 | } |
| 269 | 265 | ||
| ... | @@ -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 | } |
| 308 | 298 | ||
| ... | @@ -319,18 +309,13 @@ pub const Scope = struct { | ... | @@ -319,18 +309,13 @@ pub const Scope = struct { |
| 319 | 309 | ||
| 320 | /// Creates a DeferExpr scope with 1 reference | 310 | /// 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 | } |
| 336 | 321 | ||
| ... | @@ -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, |
| 143 | 143 | ||
| 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, |
| 226 | 231 | ||
| 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, |
| 230 | 249 | ||
| 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 | }; |
| 235 | 254 | ||
| 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 { |
| 293 | 333 | ||
| 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 { |
| 310 | 350 | ||
| 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 | }; |
| 328 | 368 | ||
| 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 { |
| 374 | 393 | ||
| 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 | } |
| 381 | 400 | ||
| ... | @@ -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); |
| 396 | 415 | ||
| 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); |
| 403 | 424 | ||
| 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; |
| 408 | 429 | ||
| 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 { |
| 462 | 487 | ||
| 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 | } |
| 467 | 498 |
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, |
| 181 | 181 | ||
| 182 | /// parent is child_scope | 182 | /// parent is child_scope |
| 183 | block_scope: *Scope.Block, | 183 | block_scope: ?*Scope.Block, |
| 184 | 184 | ||
| 185 | /// Path to the object file that contains this function | 185 | /// 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 | }; |
| 235 | 251 | ||
| 236 | pub const Void = struct { | 252 | pub const Void = struct { |