| ... | ... | @@ -46,7 +46,7 @@ pub const IrVal = union(enum) { |
| 46 | 46 | } |
| 47 | 47 | }; |
| 48 | 48 | |
| 49 | | pub const Instruction = struct { |
| 49 | pub const Inst = struct { |
| 50 | 50 | id: Id, |
| 51 | 51 | scope: *Scope, |
| 52 | 52 | debug_id: usize, |
| ... | ... | @@ -59,15 +59,15 @@ pub const Instruction = struct { |
| 59 | 59 | is_generated: bool, |
| 60 | 60 | |
| 61 | 61 | /// the instruction that is derived from this one in analysis |
| 62 | | child: ?*Instruction, |
| 62 | child: ?*Inst, |
| 63 | 63 | |
| 64 | 64 | /// the instruction that this one derives from in analysis |
| 65 | | parent: ?*Instruction, |
| 65 | parent: ?*Inst, |
| 66 | 66 | |
| 67 | 67 | /// populated durign codegen |
| 68 | 68 | llvm_value: ?llvm.ValueRef, |
| 69 | 69 | |
| 70 | | pub fn cast(base: *Instruction, comptime T: type) ?*T { |
| 70 | pub fn cast(base: *Inst, comptime T: type) ?*T { |
| 71 | 71 | if (base.id == comptime typeToId(T)) { |
| 72 | 72 | return @fieldParentPtr(T, "base", base); |
| 73 | 73 | } |
| ... | ... | @@ -77,18 +77,18 @@ pub const Instruction = struct { |
| 77 | 77 | pub fn typeToId(comptime T: type) Id { |
| 78 | 78 | comptime var i = 0; |
| 79 | 79 | inline while (i < @memberCount(Id)) : (i += 1) { |
| 80 | | if (T == @field(Instruction, @memberName(Id, i))) { |
| 80 | if (T == @field(Inst, @memberName(Id, i))) { |
| 81 | 81 | return @field(Id, @memberName(Id, i)); |
| 82 | 82 | } |
| 83 | 83 | } |
| 84 | 84 | unreachable; |
| 85 | 85 | } |
| 86 | 86 | |
| 87 | | pub fn dump(base: *const Instruction) void { |
| 87 | pub fn dump(base: *const Inst) void { |
| 88 | 88 | comptime var i = 0; |
| 89 | 89 | inline while (i < @memberCount(Id)) : (i += 1) { |
| 90 | 90 | if (base.id == @field(Id, @memberName(Id, i))) { |
| 91 | | const T = @field(Instruction, @memberName(Id, i)); |
| 91 | const T = @field(Inst, @memberName(Id, i)); |
| 92 | 92 | std.debug.warn("#{} = {}(", base.debug_id, @tagName(base.id)); |
| 93 | 93 | @fieldParentPtr(T, "base", base).dump(); |
| 94 | 94 | std.debug.warn(")"); |
| ... | ... | @@ -98,29 +98,29 @@ pub const Instruction = struct { |
| 98 | 98 | unreachable; |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | | pub fn hasSideEffects(base: *const Instruction) bool { |
| 101 | pub fn hasSideEffects(base: *const Inst) bool { |
| 102 | 102 | comptime var i = 0; |
| 103 | 103 | inline while (i < @memberCount(Id)) : (i += 1) { |
| 104 | 104 | if (base.id == @field(Id, @memberName(Id, i))) { |
| 105 | | const T = @field(Instruction, @memberName(Id, i)); |
| 105 | const T = @field(Inst, @memberName(Id, i)); |
| 106 | 106 | return @fieldParentPtr(T, "base", base).hasSideEffects(); |
| 107 | 107 | } |
| 108 | 108 | } |
| 109 | 109 | unreachable; |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | | pub fn analyze(base: *Instruction, ira: *Analyze) Analyze.Error!*Instruction { |
| 112 | pub fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst { |
| 113 | 113 | comptime var i = 0; |
| 114 | 114 | inline while (i < @memberCount(Id)) : (i += 1) { |
| 115 | 115 | if (base.id == @field(Id, @memberName(Id, i))) { |
| 116 | | const T = @field(Instruction, @memberName(Id, i)); |
| 116 | const T = @field(Inst, @memberName(Id, i)); |
| 117 | 117 | return @fieldParentPtr(T, "base", base).analyze(ira); |
| 118 | 118 | } |
| 119 | 119 | } |
| 120 | 120 | unreachable; |
| 121 | 121 | } |
| 122 | 122 | |
| 123 | | pub fn render(base: *Instruction, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) { |
| 123 | pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) { |
| 124 | 124 | switch (base.id) { |
| 125 | 125 | Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val), |
| 126 | 126 | Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val), |
| ... | ... | @@ -133,14 +133,14 @@ pub const Instruction = struct { |
| 133 | 133 | } |
| 134 | 134 | } |
| 135 | 135 | |
| 136 | | fn ref(base: *Instruction, builder: *Builder) void { |
| 136 | fn ref(base: *Inst, builder: *Builder) void { |
| 137 | 137 | base.ref_count += 1; |
| 138 | 138 | if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) { |
| 139 | 139 | base.owner_bb.ref(); |
| 140 | 140 | } |
| 141 | 141 | } |
| 142 | 142 | |
| 143 | | fn getAsParam(param: *Instruction) !*Instruction { |
| 143 | fn getAsParam(param: *Inst) !*Inst { |
| 144 | 144 | const child = param.child orelse return error.SemanticAnalysisFailed; |
| 145 | 145 | switch (child.val) { |
| 146 | 146 | IrVal.Unknown => return error.SemanticAnalysisFailed, |
| ... | ... | @@ -149,7 +149,7 @@ pub const Instruction = struct { |
| 149 | 149 | } |
| 150 | 150 | |
| 151 | 151 | /// asserts that the type is known |
| 152 | | fn getKnownType(self: *Instruction) *Type { |
| 152 | fn getKnownType(self: *Inst) *Type { |
| 153 | 153 | switch (self.val) { |
| 154 | 154 | IrVal.KnownType => |typeof| return typeof, |
| 155 | 155 | IrVal.KnownValue => |value| return value.typeof, |
| ... | ... | @@ -157,11 +157,11 @@ pub const Instruction = struct { |
| 157 | 157 | } |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | | pub fn setGenerated(base: *Instruction) void { |
| 160 | pub fn setGenerated(base: *Inst) void { |
| 161 | 161 | base.is_generated = true; |
| 162 | 162 | } |
| 163 | 163 | |
| 164 | | pub fn isNoReturn(base: *const Instruction) bool { |
| 164 | pub fn isNoReturn(base: *const Inst) bool { |
| 165 | 165 | switch (base.val) { |
| 166 | 166 | IrVal.Unknown => return false, |
| 167 | 167 | IrVal.KnownValue => |x| return x.typeof.id == Type.Id.NoReturn, |
| ... | ... | @@ -169,11 +169,11 @@ pub const Instruction = struct { |
| 169 | 169 | } |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | | pub fn isCompTime(base: *const Instruction) bool { |
| 172 | pub fn isCompTime(base: *const Inst) bool { |
| 173 | 173 | return base.val == IrVal.KnownValue; |
| 174 | 174 | } |
| 175 | 175 | |
| 176 | | pub fn linkToParent(self: *Instruction, parent: *Instruction) void { |
| 176 | pub fn linkToParent(self: *Inst, parent: *Inst) void { |
| 177 | 177 | assert(self.parent == null); |
| 178 | 178 | assert(parent.child == null); |
| 179 | 179 | self.parent = parent; |
| ... | ... | @@ -192,7 +192,7 @@ pub const Instruction = struct { |
| 192 | 192 | }; |
| 193 | 193 | |
| 194 | 194 | pub const Const = struct { |
| 195 | | base: Instruction, |
| 195 | base: Inst, |
| 196 | 196 | params: Params, |
| 197 | 197 | |
| 198 | 198 | const Params = struct {}; |
| ... | ... | @@ -209,7 +209,7 @@ pub const Instruction = struct { |
| 209 | 209 | return false; |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | | pub fn analyze(self: *const Const, ira: *Analyze) !*Instruction { |
| 212 | pub fn analyze(self: *const Const, ira: *Analyze) !*Inst { |
| 213 | 213 | const new_inst = try ira.irb.build(Const, self.base.scope, self.base.span, Params{}); |
| 214 | 214 | new_inst.val = IrVal{ .KnownValue = self.base.val.KnownValue.getRef() }; |
| 215 | 215 | return new_inst; |
| ... | ... | @@ -221,11 +221,11 @@ pub const Instruction = struct { |
| 221 | 221 | }; |
| 222 | 222 | |
| 223 | 223 | pub const Return = struct { |
| 224 | | base: Instruction, |
| 224 | base: Inst, |
| 225 | 225 | params: Params, |
| 226 | 226 | |
| 227 | 227 | const Params = struct { |
| 228 | | return_value: *Instruction, |
| 228 | return_value: *Inst, |
| 229 | 229 | }; |
| 230 | 230 | |
| 231 | 231 | const ir_val_init = IrVal.Init.NoReturn; |
| ... | ... | @@ -238,7 +238,7 @@ pub const Instruction = struct { |
| 238 | 238 | return true; |
| 239 | 239 | } |
| 240 | 240 | |
| 241 | | pub fn analyze(self: *const Return, ira: *Analyze) !*Instruction { |
| 241 | pub fn analyze(self: *const Return, ira: *Analyze) !*Inst { |
| 242 | 242 | const value = try self.params.return_value.getAsParam(); |
| 243 | 243 | const casted_value = try ira.implicitCast(value, ira.explicit_return_type); |
| 244 | 244 | |
| ... | ... | @@ -261,11 +261,11 @@ pub const Instruction = struct { |
| 261 | 261 | }; |
| 262 | 262 | |
| 263 | 263 | pub const Ref = struct { |
| 264 | | base: Instruction, |
| 264 | base: Inst, |
| 265 | 265 | params: Params, |
| 266 | 266 | |
| 267 | 267 | const Params = struct { |
| 268 | | target: *Instruction, |
| 268 | target: *Inst, |
| 269 | 269 | mut: Type.Pointer.Mut, |
| 270 | 270 | volatility: Type.Pointer.Vol, |
| 271 | 271 | }; |
| ... | ... | @@ -278,7 +278,7 @@ pub const Instruction = struct { |
| 278 | 278 | return false; |
| 279 | 279 | } |
| 280 | 280 | |
| 281 | | pub fn analyze(self: *const Ref, ira: *Analyze) !*Instruction { |
| 281 | pub fn analyze(self: *const Ref, ira: *Analyze) !*Inst { |
| 282 | 282 | const target = try self.params.target.getAsParam(); |
| 283 | 283 | |
| 284 | 284 | if (ira.getCompTimeValOrNullUndefOk(target)) |val| { |
| ... | ... | @@ -314,7 +314,7 @@ pub const Instruction = struct { |
| 314 | 314 | }; |
| 315 | 315 | |
| 316 | 316 | pub const DeclVar = struct { |
| 317 | | base: Instruction, |
| 317 | base: Inst, |
| 318 | 318 | params: Params, |
| 319 | 319 | |
| 320 | 320 | const Params = struct { |
| ... | ... | @@ -329,17 +329,17 @@ pub const Instruction = struct { |
| 329 | 329 | return true; |
| 330 | 330 | } |
| 331 | 331 | |
| 332 | | pub fn analyze(self: *const DeclVar, ira: *Analyze) !*Instruction { |
| 332 | pub fn analyze(self: *const DeclVar, ira: *Analyze) !*Inst { |
| 333 | 333 | return error.Unimplemented; // TODO |
| 334 | 334 | } |
| 335 | 335 | }; |
| 336 | 336 | |
| 337 | 337 | pub const CheckVoidStmt = struct { |
| 338 | | base: Instruction, |
| 338 | base: Inst, |
| 339 | 339 | params: Params, |
| 340 | 340 | |
| 341 | 341 | const Params = struct { |
| 342 | | target: *Instruction, |
| 342 | target: *Inst, |
| 343 | 343 | }; |
| 344 | 344 | |
| 345 | 345 | const ir_val_init = IrVal.Init.Unknown; |
| ... | ... | @@ -350,18 +350,18 @@ pub const Instruction = struct { |
| 350 | 350 | return true; |
| 351 | 351 | } |
| 352 | 352 | |
| 353 | | pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Instruction { |
| 353 | pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Inst { |
| 354 | 354 | return error.Unimplemented; // TODO |
| 355 | 355 | } |
| 356 | 356 | }; |
| 357 | 357 | |
| 358 | 358 | pub const Phi = struct { |
| 359 | | base: Instruction, |
| 359 | base: Inst, |
| 360 | 360 | params: Params, |
| 361 | 361 | |
| 362 | 362 | const Params = struct { |
| 363 | 363 | incoming_blocks: []*BasicBlock, |
| 364 | | incoming_values: []*Instruction, |
| 364 | incoming_values: []*Inst, |
| 365 | 365 | }; |
| 366 | 366 | |
| 367 | 367 | const ir_val_init = IrVal.Init.Unknown; |
| ... | ... | @@ -372,18 +372,18 @@ pub const Instruction = struct { |
| 372 | 372 | return false; |
| 373 | 373 | } |
| 374 | 374 | |
| 375 | | pub fn analyze(self: *const Phi, ira: *Analyze) !*Instruction { |
| 375 | pub fn analyze(self: *const Phi, ira: *Analyze) !*Inst { |
| 376 | 376 | return error.Unimplemented; // TODO |
| 377 | 377 | } |
| 378 | 378 | }; |
| 379 | 379 | |
| 380 | 380 | pub const Br = struct { |
| 381 | | base: Instruction, |
| 381 | base: Inst, |
| 382 | 382 | params: Params, |
| 383 | 383 | |
| 384 | 384 | const Params = struct { |
| 385 | 385 | dest_block: *BasicBlock, |
| 386 | | is_comptime: *Instruction, |
| 386 | is_comptime: *Inst, |
| 387 | 387 | }; |
| 388 | 388 | |
| 389 | 389 | const ir_val_init = IrVal.Init.NoReturn; |
| ... | ... | @@ -394,17 +394,41 @@ pub const Instruction = struct { |
| 394 | 394 | return true; |
| 395 | 395 | } |
| 396 | 396 | |
| 397 | | pub fn analyze(self: *const Br, ira: *Analyze) !*Instruction { |
| 397 | pub fn analyze(self: *const Br, ira: *Analyze) !*Inst { |
| 398 | return error.Unimplemented; // TODO |
| 399 | } |
| 400 | }; |
| 401 | |
| 402 | pub const CondBr = struct { |
| 403 | base: Inst, |
| 404 | params: Params, |
| 405 | |
| 406 | const Params = struct { |
| 407 | condition: *Inst, |
| 408 | then_block: *BasicBlock, |
| 409 | else_block: *BasicBlock, |
| 410 | is_comptime: *Inst, |
| 411 | }; |
| 412 | |
| 413 | const ir_val_init = IrVal.Init.NoReturn; |
| 414 | |
| 415 | pub fn dump(inst: *const CondBr) void {} |
| 416 | |
| 417 | pub fn hasSideEffects(inst: *const CondBr) bool { |
| 418 | return true; |
| 419 | } |
| 420 | |
| 421 | pub fn analyze(self: *const CondBr, ira: *Analyze) !*Inst { |
| 398 | 422 | return error.Unimplemented; // TODO |
| 399 | 423 | } |
| 400 | 424 | }; |
| 401 | 425 | |
| 402 | 426 | pub const AddImplicitReturnType = struct { |
| 403 | | base: Instruction, |
| 427 | base: Inst, |
| 404 | 428 | params: Params, |
| 405 | 429 | |
| 406 | 430 | pub const Params = struct { |
| 407 | | target: *Instruction, |
| 431 | target: *Inst, |
| 408 | 432 | }; |
| 409 | 433 | |
| 410 | 434 | const ir_val_init = IrVal.Init.Unknown; |
| ... | ... | @@ -417,12 +441,117 @@ pub const Instruction = struct { |
| 417 | 441 | return true; |
| 418 | 442 | } |
| 419 | 443 | |
| 420 | | pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Instruction { |
| 444 | pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Inst { |
| 421 | 445 | const target = try self.params.target.getAsParam(); |
| 422 | 446 | try ira.src_implicit_return_type_list.append(target); |
| 423 | 447 | return ira.irb.buildConstVoid(self.base.scope, self.base.span, true); |
| 424 | 448 | } |
| 425 | 449 | }; |
| 450 | |
| 451 | pub const TestErr = struct { |
| 452 | base: Inst, |
| 453 | params: Params, |
| 454 | |
| 455 | pub const Params = struct { |
| 456 | target: *Inst, |
| 457 | }; |
| 458 | |
| 459 | const ir_val_init = IrVal.Init.Unknown; |
| 460 | |
| 461 | pub fn dump(inst: *const TestErr) void { |
| 462 | std.debug.warn("#{}", inst.params.target.debug_id); |
| 463 | } |
| 464 | |
| 465 | pub fn hasSideEffects(inst: *const TestErr) bool { |
| 466 | return false; |
| 467 | } |
| 468 | |
| 469 | pub fn analyze(self: *const TestErr, ira: *Analyze) !*Inst { |
| 470 | const target = try self.params.target.getAsParam(); |
| 471 | const target_type = target.getKnownType(); |
| 472 | switch (target_type.id) { |
| 473 | Type.Id.ErrorUnion => { |
| 474 | return error.Unimplemented; |
| 475 | // if (instr_is_comptime(value)) { |
| 476 | // ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad); |
| 477 | // if (!err_union_val) |
| 478 | // return ira->codegen->builtin_types.entry_invalid; |
| 479 | |
| 480 | // if (err_union_val->special != ConstValSpecialRuntime) { |
| 481 | // ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 482 | // out_val->data.x_bool = (err_union_val->data.x_err_union.err != nullptr); |
| 483 | // return ira->codegen->builtin_types.entry_bool; |
| 484 | // } |
| 485 | // } |
| 486 | |
| 487 | // TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type; |
| 488 | // if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) { |
| 489 | // return ira->codegen->builtin_types.entry_invalid; |
| 490 | // } |
| 491 | // if (!type_is_global_error_set(err_set_type) && |
| 492 | // err_set_type->data.error_set.err_count == 0) |
| 493 | // { |
| 494 | // assert(err_set_type->data.error_set.infer_fn == nullptr); |
| 495 | // ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 496 | // out_val->data.x_bool = false; |
| 497 | // return ira->codegen->builtin_types.entry_bool; |
| 498 | // } |
| 499 | |
| 500 | // ir_build_test_err_from(&ira->new_irb, &instruction->base, value); |
| 501 | // return ira->codegen->builtin_types.entry_bool; |
| 502 | }, |
| 503 | Type.Id.ErrorSet => { |
| 504 | return ira.irb.buildConstBool(self.base.scope, self.base.span, true); |
| 505 | }, |
| 506 | else => { |
| 507 | return ira.irb.buildConstBool(self.base.scope, self.base.span, false); |
| 508 | }, |
| 509 | } |
| 510 | } |
| 511 | }; |
| 512 | |
| 513 | pub const TestCompTime = struct { |
| 514 | base: Inst, |
| 515 | params: Params, |
| 516 | |
| 517 | pub const Params = struct { |
| 518 | target: *Inst, |
| 519 | }; |
| 520 | |
| 521 | const ir_val_init = IrVal.Init.Unknown; |
| 522 | |
| 523 | pub fn dump(inst: *const TestCompTime) void { |
| 524 | std.debug.warn("#{}", inst.params.target.debug_id); |
| 525 | } |
| 526 | |
| 527 | pub fn hasSideEffects(inst: *const TestCompTime) bool { |
| 528 | return false; |
| 529 | } |
| 530 | |
| 531 | pub fn analyze(self: *const TestCompTime, ira: *Analyze) !*Inst { |
| 532 | const target = try self.params.target.getAsParam(); |
| 533 | return ira.irb.buildConstBool(self.base.scope, self.base.span, target.isCompTime()); |
| 534 | } |
| 535 | }; |
| 536 | |
| 537 | pub const SaveErrRetAddr = struct { |
| 538 | base: Inst, |
| 539 | params: Params, |
| 540 | |
| 541 | const Params = struct {}; |
| 542 | |
| 543 | const ir_val_init = IrVal.Init.Unknown; |
| 544 | |
| 545 | pub fn dump(inst: *const SaveErrRetAddr) void {} |
| 546 | |
| 547 | pub fn hasSideEffects(inst: *const SaveErrRetAddr) bool { |
| 548 | return true; |
| 549 | } |
| 550 | |
| 551 | pub fn analyze(self: *const SaveErrRetAddr, ira: *Analyze) !*Inst { |
| 552 | return ira.irb.build(Inst.SaveErrRetAddr, self.base.scope, self.base.span, Params{}); |
| 553 | } |
| 554 | }; |
| 426 | 555 | }; |
| 427 | 556 | |
| 428 | 557 | pub const Variable = struct { |
| ... | ... | @@ -434,8 +563,8 @@ pub const BasicBlock = struct { |
| 434 | 563 | name_hint: [*]const u8, // must be a C string literal |
| 435 | 564 | debug_id: usize, |
| 436 | 565 | scope: *Scope, |
| 437 | | instruction_list: std.ArrayList(*Instruction), |
| 438 | | ref_instruction: ?*Instruction, |
| 566 | instruction_list: std.ArrayList(*Inst), |
| 567 | ref_instruction: ?*Inst, |
| 439 | 568 | |
| 440 | 569 | /// for codegen |
| 441 | 570 | llvm_block: llvm.BasicBlockRef, |
| ... | ... | @@ -491,10 +620,12 @@ pub const Builder = struct { |
| 491 | 620 | next_debug_id: usize, |
| 492 | 621 | parsed_file: *ParsedFile, |
| 493 | 622 | is_comptime: bool, |
| 623 | is_async: bool, |
| 624 | begin_scope: ?*Scope, |
| 494 | 625 | |
| 495 | 626 | pub const Error = Analyze.Error; |
| 496 | 627 | |
| 497 | | pub fn init(comp: *Compilation, parsed_file: *ParsedFile) !Builder { |
| 628 | pub fn init(comp: *Compilation, parsed_file: *ParsedFile, begin_scope: ?*Scope) !Builder { |
| 498 | 629 | const code = try comp.gpa().create(Code{ |
| 499 | 630 | .basic_block_list = undefined, |
| 500 | 631 | .arena = std.heap.ArenaAllocator.init(comp.gpa()), |
| ... | ... | @@ -510,6 +641,8 @@ pub const Builder = struct { |
| 510 | 641 | .code = code, |
| 511 | 642 | .next_debug_id = 0, |
| 512 | 643 | .is_comptime = false, |
| 644 | .is_async = false, |
| 645 | .begin_scope = begin_scope, |
| 513 | 646 | }; |
| 514 | 647 | } |
| 515 | 648 | |
| ... | ... | @@ -529,7 +662,7 @@ pub const Builder = struct { |
| 529 | 662 | .name_hint = name_hint, |
| 530 | 663 | .debug_id = self.next_debug_id, |
| 531 | 664 | .scope = scope, |
| 532 | | .instruction_list = std.ArrayList(*Instruction).init(self.arena()), |
| 665 | .instruction_list = std.ArrayList(*Inst).init(self.arena()), |
| 533 | 666 | .child = null, |
| 534 | 667 | .parent = null, |
| 535 | 668 | .ref_instruction = null, |
| ... | ... | @@ -549,66 +682,69 @@ pub const Builder = struct { |
| 549 | 682 | self.current_basic_block = basic_block; |
| 550 | 683 | } |
| 551 | 684 | |
| 552 | | pub fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Instruction { |
| 685 | pub fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst { |
| 553 | 686 | switch (node.id) { |
| 554 | 687 | ast.Node.Id.Root => unreachable, |
| 555 | 688 | ast.Node.Id.Use => unreachable, |
| 556 | 689 | ast.Node.Id.TestDecl => unreachable, |
| 557 | | ast.Node.Id.VarDecl => @panic("TODO"), |
| 558 | | ast.Node.Id.Defer => @panic("TODO"), |
| 559 | | ast.Node.Id.InfixOp => @panic("TODO"), |
| 560 | | ast.Node.Id.PrefixOp => @panic("TODO"), |
| 561 | | ast.Node.Id.SuffixOp => @panic("TODO"), |
| 562 | | ast.Node.Id.Switch => @panic("TODO"), |
| 563 | | ast.Node.Id.While => @panic("TODO"), |
| 564 | | ast.Node.Id.For => @panic("TODO"), |
| 565 | | ast.Node.Id.If => @panic("TODO"), |
| 566 | | ast.Node.Id.ControlFlowExpression => return error.Unimplemented, |
| 567 | | ast.Node.Id.Suspend => @panic("TODO"), |
| 568 | | ast.Node.Id.VarType => @panic("TODO"), |
| 569 | | ast.Node.Id.ErrorType => @panic("TODO"), |
| 570 | | ast.Node.Id.FnProto => @panic("TODO"), |
| 571 | | ast.Node.Id.PromiseType => @panic("TODO"), |
| 572 | | ast.Node.Id.IntegerLiteral => @panic("TODO"), |
| 573 | | ast.Node.Id.FloatLiteral => @panic("TODO"), |
| 574 | | ast.Node.Id.StringLiteral => @panic("TODO"), |
| 575 | | ast.Node.Id.MultilineStringLiteral => @panic("TODO"), |
| 576 | | ast.Node.Id.CharLiteral => @panic("TODO"), |
| 577 | | ast.Node.Id.BoolLiteral => @panic("TODO"), |
| 578 | | ast.Node.Id.NullLiteral => @panic("TODO"), |
| 579 | | ast.Node.Id.UndefinedLiteral => @panic("TODO"), |
| 580 | | ast.Node.Id.ThisLiteral => @panic("TODO"), |
| 581 | | ast.Node.Id.Unreachable => @panic("TODO"), |
| 582 | | ast.Node.Id.Identifier => @panic("TODO"), |
| 690 | ast.Node.Id.VarDecl => return error.Unimplemented, |
| 691 | ast.Node.Id.Defer => return error.Unimplemented, |
| 692 | ast.Node.Id.InfixOp => return error.Unimplemented, |
| 693 | ast.Node.Id.PrefixOp => return error.Unimplemented, |
| 694 | ast.Node.Id.SuffixOp => return error.Unimplemented, |
| 695 | ast.Node.Id.Switch => return error.Unimplemented, |
| 696 | ast.Node.Id.While => return error.Unimplemented, |
| 697 | ast.Node.Id.For => return error.Unimplemented, |
| 698 | ast.Node.Id.If => return error.Unimplemented, |
| 699 | ast.Node.Id.ControlFlowExpression => { |
| 700 | const control_flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", node); |
| 701 | return irb.genControlFlowExpr(control_flow_expr, scope, lval); |
| 702 | }, |
| 703 | ast.Node.Id.Suspend => return error.Unimplemented, |
| 704 | ast.Node.Id.VarType => return error.Unimplemented, |
| 705 | ast.Node.Id.ErrorType => return error.Unimplemented, |
| 706 | ast.Node.Id.FnProto => return error.Unimplemented, |
| 707 | ast.Node.Id.PromiseType => return error.Unimplemented, |
| 708 | ast.Node.Id.IntegerLiteral => return error.Unimplemented, |
| 709 | ast.Node.Id.FloatLiteral => return error.Unimplemented, |
| 710 | ast.Node.Id.StringLiteral => return error.Unimplemented, |
| 711 | ast.Node.Id.MultilineStringLiteral => return error.Unimplemented, |
| 712 | ast.Node.Id.CharLiteral => return error.Unimplemented, |
| 713 | ast.Node.Id.BoolLiteral => return error.Unimplemented, |
| 714 | ast.Node.Id.NullLiteral => return error.Unimplemented, |
| 715 | ast.Node.Id.UndefinedLiteral => return error.Unimplemented, |
| 716 | ast.Node.Id.ThisLiteral => return error.Unimplemented, |
| 717 | ast.Node.Id.Unreachable => return error.Unimplemented, |
| 718 | ast.Node.Id.Identifier => return error.Unimplemented, |
| 583 | 719 | ast.Node.Id.GroupedExpression => { |
| 584 | 720 | const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node); |
| 585 | 721 | return irb.genNode(grouped_expr.expr, scope, lval); |
| 586 | 722 | }, |
| 587 | | ast.Node.Id.BuiltinCall => @panic("TODO"), |
| 588 | | ast.Node.Id.ErrorSetDecl => @panic("TODO"), |
| 589 | | ast.Node.Id.ContainerDecl => @panic("TODO"), |
| 590 | | ast.Node.Id.Asm => @panic("TODO"), |
| 591 | | ast.Node.Id.Comptime => @panic("TODO"), |
| 723 | ast.Node.Id.BuiltinCall => return error.Unimplemented, |
| 724 | ast.Node.Id.ErrorSetDecl => return error.Unimplemented, |
| 725 | ast.Node.Id.ContainerDecl => return error.Unimplemented, |
| 726 | ast.Node.Id.Asm => return error.Unimplemented, |
| 727 | ast.Node.Id.Comptime => return error.Unimplemented, |
| 592 | 728 | ast.Node.Id.Block => { |
| 593 | 729 | const block = @fieldParentPtr(ast.Node.Block, "base", node); |
| 594 | 730 | return irb.lvalWrap(scope, try irb.genBlock(block, scope), lval); |
| 595 | 731 | }, |
| 596 | | ast.Node.Id.DocComment => @panic("TODO"), |
| 597 | | ast.Node.Id.SwitchCase => @panic("TODO"), |
| 598 | | ast.Node.Id.SwitchElse => @panic("TODO"), |
| 599 | | ast.Node.Id.Else => @panic("TODO"), |
| 600 | | ast.Node.Id.Payload => @panic("TODO"), |
| 601 | | ast.Node.Id.PointerPayload => @panic("TODO"), |
| 602 | | ast.Node.Id.PointerIndexPayload => @panic("TODO"), |
| 603 | | ast.Node.Id.StructField => @panic("TODO"), |
| 604 | | ast.Node.Id.UnionTag => @panic("TODO"), |
| 605 | | ast.Node.Id.EnumTag => @panic("TODO"), |
| 606 | | ast.Node.Id.ErrorTag => @panic("TODO"), |
| 607 | | ast.Node.Id.AsmInput => @panic("TODO"), |
| 608 | | ast.Node.Id.AsmOutput => @panic("TODO"), |
| 609 | | ast.Node.Id.AsyncAttribute => @panic("TODO"), |
| 610 | | ast.Node.Id.ParamDecl => @panic("TODO"), |
| 611 | | ast.Node.Id.FieldInitializer => @panic("TODO"), |
| 732 | ast.Node.Id.DocComment => return error.Unimplemented, |
| 733 | ast.Node.Id.SwitchCase => return error.Unimplemented, |
| 734 | ast.Node.Id.SwitchElse => return error.Unimplemented, |
| 735 | ast.Node.Id.Else => return error.Unimplemented, |
| 736 | ast.Node.Id.Payload => return error.Unimplemented, |
| 737 | ast.Node.Id.PointerPayload => return error.Unimplemented, |
| 738 | ast.Node.Id.PointerIndexPayload => return error.Unimplemented, |
| 739 | ast.Node.Id.StructField => return error.Unimplemented, |
| 740 | ast.Node.Id.UnionTag => return error.Unimplemented, |
| 741 | ast.Node.Id.EnumTag => return error.Unimplemented, |
| 742 | ast.Node.Id.ErrorTag => return error.Unimplemented, |
| 743 | ast.Node.Id.AsmInput => return error.Unimplemented, |
| 744 | ast.Node.Id.AsmOutput => return error.Unimplemented, |
| 745 | ast.Node.Id.AsyncAttribute => return error.Unimplemented, |
| 746 | ast.Node.Id.ParamDecl => return error.Unimplemented, |
| 747 | ast.Node.Id.FieldInitializer => return error.Unimplemented, |
| 612 | 748 | } |
| 613 | 749 | } |
| 614 | 750 | |
| ... | ... | @@ -630,7 +766,7 @@ pub const Builder = struct { |
| 630 | 766 | } |
| 631 | 767 | } |
| 632 | 768 | |
| 633 | | pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Instruction { |
| 769 | pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst { |
| 634 | 770 | const block_scope = try Scope.Block.create(irb.comp, parent_scope); |
| 635 | 771 | |
| 636 | 772 | const outer_block_scope = &block_scope.base; |
| ... | ... | @@ -648,7 +784,7 @@ pub const Builder = struct { |
| 648 | 784 | } |
| 649 | 785 | |
| 650 | 786 | if (block.label) |label| { |
| 651 | | block_scope.incoming_values = std.ArrayList(*Instruction).init(irb.arena()); |
| 787 | block_scope.incoming_values = std.ArrayList(*Inst).init(irb.arena()); |
| 652 | 788 | block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena()); |
| 653 | 789 | block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd"); |
| 654 | 790 | block_scope.is_comptime = try irb.buildConstBool( |
| ... | ... | @@ -659,7 +795,7 @@ pub const Builder = struct { |
| 659 | 795 | } |
| 660 | 796 | |
| 661 | 797 | var is_continuation_unreachable = false; |
| 662 | | var noreturn_return_value: ?*Instruction = null; |
| 798 | var noreturn_return_value: ?*Inst = null; |
| 663 | 799 | |
| 664 | 800 | var stmt_it = block.statements.iterator(0); |
| 665 | 801 | while (stmt_it.next()) |statement_node_ptr| { |
| ... | ... | @@ -686,16 +822,16 @@ pub const Builder = struct { |
| 686 | 822 | noreturn_return_value = statement_value; |
| 687 | 823 | } |
| 688 | 824 | |
| 689 | | if (statement_value.cast(Instruction.DeclVar)) |decl_var| { |
| 825 | if (statement_value.cast(Inst.DeclVar)) |decl_var| { |
| 690 | 826 | // variable declarations start a new scope |
| 691 | 827 | child_scope = decl_var.params.variable.child_scope; |
| 692 | 828 | } else if (!is_continuation_unreachable) { |
| 693 | 829 | // this statement's value must be void |
| 694 | 830 | _ = irb.build( |
| 695 | | Instruction.CheckVoidStmt, |
| 831 | Inst.CheckVoidStmt, |
| 696 | 832 | child_scope, |
| 697 | 833 | statement_value.span, |
| 698 | | Instruction.CheckVoidStmt.Params{ .target = statement_value }, |
| 834 | Inst.CheckVoidStmt.Params{ .target = statement_value }, |
| 699 | 835 | ); |
| 700 | 836 | } |
| 701 | 837 | } |
| ... | ... | @@ -707,7 +843,7 @@ pub const Builder = struct { |
| 707 | 843 | } |
| 708 | 844 | |
| 709 | 845 | try irb.setCursorAtEndAndAppendBlock(block_scope.end_block); |
| 710 | | return irb.build(Instruction.Phi, parent_scope, Span.token(block.rbrace), Instruction.Phi.Params{ |
| 846 | return irb.build(Inst.Phi, parent_scope, Span.token(block.rbrace), Inst.Phi.Params{ |
| 711 | 847 | .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(), |
| 712 | 848 | .incoming_values = block_scope.incoming_values.toOwnedSlice(), |
| 713 | 849 | }); |
| ... | ... | @@ -720,14 +856,14 @@ pub const Builder = struct { |
| 720 | 856 | ); |
| 721 | 857 | _ = try irb.genDefersForBlock(child_scope, outer_block_scope, Scope.Defer.Kind.ScopeExit); |
| 722 | 858 | |
| 723 | | _ = try irb.buildGen(Instruction.Br, parent_scope, Span.token(block.rbrace), Instruction.Br.Params{ |
| 859 | _ = try irb.buildGen(Inst.Br, parent_scope, Span.token(block.rbrace), Inst.Br.Params{ |
| 724 | 860 | .dest_block = block_scope.end_block, |
| 725 | 861 | .is_comptime = block_scope.is_comptime, |
| 726 | 862 | }); |
| 727 | 863 | |
| 728 | 864 | try irb.setCursorAtEndAndAppendBlock(block_scope.end_block); |
| 729 | 865 | |
| 730 | | return irb.build(Instruction.Phi, parent_scope, Span.token(block.rbrace), Instruction.Phi.Params{ |
| 866 | return irb.build(Inst.Phi, parent_scope, Span.token(block.rbrace), Inst.Phi.Params{ |
| 731 | 867 | .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(), |
| 732 | 868 | .incoming_values = block_scope.incoming_values.toOwnedSlice(), |
| 733 | 869 | }); |
| ... | ... | @@ -737,6 +873,135 @@ pub const Builder = struct { |
| 737 | 873 | return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true); |
| 738 | 874 | } |
| 739 | 875 | |
| 876 | pub fn genControlFlowExpr( |
| 877 | irb: *Builder, |
| 878 | control_flow_expr: *ast.Node.ControlFlowExpression, |
| 879 | scope: *Scope, |
| 880 | lval: LVal, |
| 881 | ) !*Inst { |
| 882 | switch (control_flow_expr.kind) { |
| 883 | ast.Node.ControlFlowExpression.Kind.Break => |arg| return error.Unimplemented, |
| 884 | ast.Node.ControlFlowExpression.Kind.Continue => |arg| return error.Unimplemented, |
| 885 | ast.Node.ControlFlowExpression.Kind.Return => { |
| 886 | const src_span = Span.token(control_flow_expr.ltoken); |
| 887 | if (scope.findFnDef() == null) { |
| 888 | try irb.comp.addCompileError( |
| 889 | irb.parsed_file, |
| 890 | src_span, |
| 891 | "return expression outside function definition", |
| 892 | ); |
| 893 | return error.SemanticAnalysisFailed; |
| 894 | } |
| 895 | |
| 896 | if (scope.findDeferExpr()) |scope_defer_expr| { |
| 897 | if (!scope_defer_expr.reported_err) { |
| 898 | try irb.comp.addCompileError( |
| 899 | irb.parsed_file, |
| 900 | src_span, |
| 901 | "cannot return from defer expression", |
| 902 | ); |
| 903 | scope_defer_expr.reported_err = true; |
| 904 | } |
| 905 | return error.SemanticAnalysisFailed; |
| 906 | } |
| 907 | |
| 908 | const outer_scope = irb.begin_scope.?; |
| 909 | const return_value = if (control_flow_expr.rhs) |rhs| blk: { |
| 910 | break :blk try irb.genNode(rhs, scope, LVal.None); |
| 911 | } else blk: { |
| 912 | break :blk try irb.buildConstVoid(scope, src_span, true); |
| 913 | }; |
| 914 | |
| 915 | const defer_counts = irb.countDefers(scope, outer_scope); |
| 916 | const have_err_defers = defer_counts.error_exit != 0; |
| 917 | if (have_err_defers or irb.comp.have_err_ret_tracing) { |
| 918 | const err_block = try irb.createBasicBlock(scope, c"ErrRetErr"); |
| 919 | const ok_block = try irb.createBasicBlock(scope, c"ErrRetOk"); |
| 920 | if (!have_err_defers) { |
| 921 | _ = try irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit); |
| 922 | } |
| 923 | |
| 924 | const is_err = try irb.build( |
| 925 | Inst.TestErr, |
| 926 | scope, |
| 927 | src_span, |
| 928 | Inst.TestErr.Params{ .target = return_value }, |
| 929 | ); |
| 930 | |
| 931 | const err_is_comptime = try irb.buildTestCompTime(scope, src_span, is_err); |
| 932 | |
| 933 | _ = try irb.buildGen(Inst.CondBr, scope, src_span, Inst.CondBr.Params{ |
| 934 | .condition = is_err, |
| 935 | .then_block = err_block, |
| 936 | .else_block = ok_block, |
| 937 | .is_comptime = err_is_comptime, |
| 938 | }); |
| 939 | |
| 940 | const ret_stmt_block = try irb.createBasicBlock(scope, c"RetStmt"); |
| 941 | |
| 942 | try irb.setCursorAtEndAndAppendBlock(err_block); |
| 943 | if (have_err_defers) { |
| 944 | _ = try irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ErrorExit); |
| 945 | } |
| 946 | if (irb.comp.have_err_ret_tracing and !irb.isCompTime(scope)) { |
| 947 | _ = try irb.build(Inst.SaveErrRetAddr, scope, src_span, Inst.SaveErrRetAddr.Params{}); |
| 948 | } |
| 949 | _ = try irb.build(Inst.Br, scope, src_span, Inst.Br.Params{ |
| 950 | .dest_block = ret_stmt_block, |
| 951 | .is_comptime = err_is_comptime, |
| 952 | }); |
| 953 | |
| 954 | try irb.setCursorAtEndAndAppendBlock(ok_block); |
| 955 | if (have_err_defers) { |
| 956 | _ = try irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit); |
| 957 | } |
| 958 | _ = try irb.build(Inst.Br, scope, src_span, Inst.Br.Params{ |
| 959 | .dest_block = ret_stmt_block, |
| 960 | .is_comptime = err_is_comptime, |
| 961 | }); |
| 962 | |
| 963 | try irb.setCursorAtEndAndAppendBlock(ret_stmt_block); |
| 964 | return irb.genAsyncReturn(scope, src_span, return_value, false); |
| 965 | } else { |
| 966 | _ = try irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit); |
| 967 | return irb.genAsyncReturn(scope, src_span, return_value, false); |
| 968 | } |
| 969 | }, |
| 970 | } |
| 971 | } |
| 972 | |
| 973 | const DeferCounts = struct { |
| 974 | scope_exit: usize, |
| 975 | error_exit: usize, |
| 976 | }; |
| 977 | |
| 978 | fn countDefers(irb: *Builder, inner_scope: *Scope, outer_scope: *Scope) DeferCounts { |
| 979 | var result = DeferCounts{ .scope_exit = 0, .error_exit = 0 }; |
| 980 | |
| 981 | var scope = inner_scope; |
| 982 | while (scope != outer_scope) { |
| 983 | switch (scope.id) { |
| 984 | Scope.Id.Defer => { |
| 985 | const defer_scope = @fieldParentPtr(Scope.Defer, "base", scope); |
| 986 | switch (defer_scope.kind) { |
| 987 | Scope.Defer.Kind.ScopeExit => result.scope_exit += 1, |
| 988 | Scope.Defer.Kind.ErrorExit => result.error_exit += 1, |
| 989 | } |
| 990 | scope = scope.parent orelse break; |
| 991 | }, |
| 992 | Scope.Id.FnDef => break, |
| 993 | |
| 994 | Scope.Id.CompTime, |
| 995 | Scope.Id.Block, |
| 996 | => scope = scope.parent orelse break, |
| 997 | |
| 998 | Scope.Id.DeferExpr => unreachable, |
| 999 | Scope.Id.Decls => unreachable, |
| 1000 | } |
| 1001 | } |
| 1002 | return result; |
| 1003 | } |
| 1004 | |
| 740 | 1005 | fn genDefersForBlock( |
| 741 | 1006 | irb: *Builder, |
| 742 | 1007 | inner_scope: *Scope, |
| ... | ... | @@ -764,10 +1029,10 @@ pub const Builder = struct { |
| 764 | 1029 | is_noreturn = true; |
| 765 | 1030 | } else { |
| 766 | 1031 | _ = try irb.build( |
| 767 | | Instruction.CheckVoidStmt, |
| 1032 | Inst.CheckVoidStmt, |
| 768 | 1033 | &defer_expr_scope.base, |
| 769 | 1034 | Span.token(defer_expr_scope.expr_node.lastToken()), |
| 770 | | Instruction.CheckVoidStmt.Params{ .target = instruction }, |
| 1035 | Inst.CheckVoidStmt.Params{ .target = instruction }, |
| 771 | 1036 | ); |
| 772 | 1037 | } |
| 773 | 1038 | } |
| ... | ... | @@ -785,13 +1050,13 @@ pub const Builder = struct { |
| 785 | 1050 | } |
| 786 | 1051 | } |
| 787 | 1052 | |
| 788 | | pub fn lvalWrap(irb: *Builder, scope: *Scope, instruction: *Instruction, lval: LVal) !*Instruction { |
| 1053 | pub fn lvalWrap(irb: *Builder, scope: *Scope, instruction: *Inst, lval: LVal) !*Inst { |
| 789 | 1054 | switch (lval) { |
| 790 | 1055 | LVal.None => return instruction, |
| 791 | 1056 | LVal.Ptr => { |
| 792 | 1057 | // We needed a pointer to a value, but we got a value. So we create |
| 793 | 1058 | // an instruction which just makes a const pointer of it. |
| 794 | | return irb.build(Instruction.Ref, scope, instruction.span, Instruction.Ref.Params{ |
| 1059 | return irb.build(Inst.Ref, scope, instruction.span, Inst.Ref.Params{ |
| 795 | 1060 | .target = instruction, |
| 796 | 1061 | .mut = Type.Pointer.Mut.Const, |
| 797 | 1062 | .volatility = Type.Pointer.Vol.Non, |
| ... | ... | @@ -811,10 +1076,10 @@ pub const Builder = struct { |
| 811 | 1076 | span: Span, |
| 812 | 1077 | params: I.Params, |
| 813 | 1078 | is_generated: bool, |
| 814 | | ) !*Instruction { |
| 1079 | ) !*Inst { |
| 815 | 1080 | const inst = try self.arena().create(I{ |
| 816 | | .base = Instruction{ |
| 817 | | .id = Instruction.typeToId(I), |
| 1081 | .base = Inst{ |
| 1082 | .id = Inst.typeToId(I), |
| 818 | 1083 | .is_generated = is_generated, |
| 819 | 1084 | .scope = scope, |
| 820 | 1085 | .debug_id = self.next_debug_id, |
| ... | ... | @@ -838,8 +1103,8 @@ pub const Builder = struct { |
| 838 | 1103 | inline while (i < @memberCount(I.Params)) : (i += 1) { |
| 839 | 1104 | const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i))); |
| 840 | 1105 | switch (FieldType) { |
| 841 | | *Instruction => @field(inst.params, @memberName(I.Params, i)).ref(self), |
| 842 | | ?*Instruction => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self), |
| 1106 | *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self), |
| 1107 | ?*Inst => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self), |
| 843 | 1108 | else => {}, |
| 844 | 1109 | } |
| 845 | 1110 | } |
| ... | ... | @@ -855,7 +1120,7 @@ pub const Builder = struct { |
| 855 | 1120 | scope: *Scope, |
| 856 | 1121 | span: Span, |
| 857 | 1122 | params: I.Params, |
| 858 | | ) !*Instruction { |
| 1123 | ) !*Inst { |
| 859 | 1124 | return self.buildExtra(I, scope, span, params, false); |
| 860 | 1125 | } |
| 861 | 1126 | |
| ... | ... | @@ -865,21 +1130,71 @@ pub const Builder = struct { |
| 865 | 1130 | scope: *Scope, |
| 866 | 1131 | span: Span, |
| 867 | 1132 | params: I.Params, |
| 868 | | ) !*Instruction { |
| 1133 | ) !*Inst { |
| 869 | 1134 | return self.buildExtra(I, scope, span, params, true); |
| 870 | 1135 | } |
| 871 | 1136 | |
| 872 | | fn buildConstBool(self: *Builder, scope: *Scope, span: Span, x: bool) !*Instruction { |
| 873 | | const inst = try self.build(Instruction.Const, scope, span, Instruction.Const.Params{}); |
| 1137 | fn buildConstBool(self: *Builder, scope: *Scope, span: Span, x: bool) !*Inst { |
| 1138 | const inst = try self.build(Inst.Const, scope, span, Inst.Const.Params{}); |
| 874 | 1139 | inst.val = IrVal{ .KnownValue = &Value.Bool.get(self.comp, x).base }; |
| 875 | 1140 | return inst; |
| 876 | 1141 | } |
| 877 | 1142 | |
| 878 | | fn buildConstVoid(self: *Builder, scope: *Scope, span: Span, is_generated: bool) !*Instruction { |
| 879 | | const inst = try self.buildExtra(Instruction.Const, scope, span, Instruction.Const.Params{}, is_generated); |
| 1143 | fn buildConstVoid(self: *Builder, scope: *Scope, span: Span, is_generated: bool) !*Inst { |
| 1144 | const inst = try self.buildExtra(Inst.Const, scope, span, Inst.Const.Params{}, is_generated); |
| 880 | 1145 | inst.val = IrVal{ .KnownValue = &Value.Void.get(self.comp).base }; |
| 881 | 1146 | return inst; |
| 882 | 1147 | } |
| 1148 | |
| 1149 | /// If the code is explicitly set to be comptime, then builds a const bool, |
| 1150 | /// otherwise builds a TestCompTime instruction. |
| 1151 | fn buildTestCompTime(self: *Builder, scope: *Scope, span: Span, target: *Inst) !*Inst { |
| 1152 | if (self.isCompTime(scope)) { |
| 1153 | return self.buildConstBool(scope, span, true); |
| 1154 | } else { |
| 1155 | return self.build( |
| 1156 | Inst.TestCompTime, |
| 1157 | scope, |
| 1158 | span, |
| 1159 | Inst.TestCompTime.Params{ .target = target }, |
| 1160 | ); |
| 1161 | } |
| 1162 | } |
| 1163 | |
| 1164 | fn genAsyncReturn(irb: *Builder, scope: *Scope, span: Span, result: *Inst, is_gen: bool) !*Inst { |
| 1165 | _ = irb.buildGen( |
| 1166 | Inst.AddImplicitReturnType, |
| 1167 | scope, |
| 1168 | span, |
| 1169 | Inst.AddImplicitReturnType.Params{ .target = result }, |
| 1170 | ); |
| 1171 | |
| 1172 | if (!irb.is_async) { |
| 1173 | return irb.buildExtra( |
| 1174 | Inst.Return, |
| 1175 | scope, |
| 1176 | span, |
| 1177 | Inst.Return.Params{ .return_value = result }, |
| 1178 | is_gen, |
| 1179 | ); |
| 1180 | } |
| 1181 | return error.Unimplemented; |
| 1182 | |
| 1183 | //ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value); |
| 1184 | //IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, |
| 1185 | // get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); |
| 1186 | //// TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig |
| 1187 | //IrInstruction *replacement_value = irb->exec->coro_handle; |
| 1188 | //IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, scope, node, |
| 1189 | // promise_type_val, irb->exec->coro_awaiter_field_ptr, nullptr, replacement_value, nullptr, |
| 1190 | // AtomicRmwOp_xchg, AtomicOrderSeqCst); |
| 1191 | //ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, maybe_await_handle); |
| 1192 | //IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_await_handle); |
| 1193 | //IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false); |
| 1194 | //return ir_build_cond_br(irb, scope, node, is_non_null, irb->exec->coro_normal_final, irb->exec->coro_early_final, |
| 1195 | // is_comptime); |
| 1196 | //// the above blocks are rendered by ir_gen after the rest of codegen |
| 1197 | } |
| 883 | 1198 | }; |
| 884 | 1199 | |
| 885 | 1200 | const Analyze = struct { |
| ... | ... | @@ -888,7 +1203,7 @@ const Analyze = struct { |
| 888 | 1203 | const_predecessor_bb: ?*BasicBlock, |
| 889 | 1204 | parent_basic_block: *BasicBlock, |
| 890 | 1205 | instruction_index: usize, |
| 891 | | src_implicit_return_type_list: std.ArrayList(*Instruction), |
| 1206 | src_implicit_return_type_list: std.ArrayList(*Inst), |
| 892 | 1207 | explicit_return_type: ?*Type, |
| 893 | 1208 | |
| 894 | 1209 | pub const Error = error{ |
| ... | ... | @@ -903,7 +1218,7 @@ const Analyze = struct { |
| 903 | 1218 | }; |
| 904 | 1219 | |
| 905 | 1220 | pub fn init(comp: *Compilation, parsed_file: *ParsedFile, explicit_return_type: ?*Type) !Analyze { |
| 906 | | var irb = try Builder.init(comp, parsed_file); |
| 1221 | var irb = try Builder.init(comp, parsed_file, null); |
| 907 | 1222 | errdefer irb.abort(); |
| 908 | 1223 | |
| 909 | 1224 | return Analyze{ |
| ... | ... | @@ -912,7 +1227,7 @@ const Analyze = struct { |
| 912 | 1227 | .const_predecessor_bb = null, |
| 913 | 1228 | .parent_basic_block = undefined, // initialized with startBasicBlock |
| 914 | 1229 | .instruction_index = undefined, // initialized with startBasicBlock |
| 915 | | .src_implicit_return_type_list = std.ArrayList(*Instruction).init(irb.arena()), |
| 1230 | .src_implicit_return_type_list = std.ArrayList(*Inst).init(irb.arena()), |
| 916 | 1231 | .explicit_return_type = explicit_return_type, |
| 917 | 1232 | }; |
| 918 | 1233 | } |
| ... | ... | @@ -921,7 +1236,7 @@ const Analyze = struct { |
| 921 | 1236 | self.irb.abort(); |
| 922 | 1237 | } |
| 923 | 1238 | |
| 924 | | pub fn getNewBasicBlock(self: *Analyze, old_bb: *BasicBlock, ref_old_instruction: ?*Instruction) !*BasicBlock { |
| 1239 | pub fn getNewBasicBlock(self: *Analyze, old_bb: *BasicBlock, ref_old_instruction: ?*Inst) !*BasicBlock { |
| 925 | 1240 | if (old_bb.child) |child| { |
| 926 | 1241 | if (ref_old_instruction == null or child.ref_instruction != ref_old_instruction) |
| 927 | 1242 | return child; |
| ... | ... | @@ -984,18 +1299,18 @@ const Analyze = struct { |
| 984 | 1299 | return self.irb.comp.addCompileError(self.irb.parsed_file, span, fmt, args); |
| 985 | 1300 | } |
| 986 | 1301 | |
| 987 | | fn resolvePeerTypes(self: *Analyze, expected_type: ?*Type, peers: []const *Instruction) Analyze.Error!*Type { |
| 1302 | fn resolvePeerTypes(self: *Analyze, expected_type: ?*Type, peers: []const *Inst) Analyze.Error!*Type { |
| 988 | 1303 | // TODO actual implementation |
| 989 | 1304 | return &Type.Void.get(self.irb.comp).base; |
| 990 | 1305 | } |
| 991 | 1306 | |
| 992 | | fn implicitCast(self: *Analyze, target: *Instruction, optional_dest_type: ?*Type) Analyze.Error!*Instruction { |
| 1307 | fn implicitCast(self: *Analyze, target: *Inst, optional_dest_type: ?*Type) Analyze.Error!*Inst { |
| 993 | 1308 | const dest_type = optional_dest_type orelse return target; |
| 994 | | @panic("TODO implicitCast"); |
| 1309 | return error.Unimplemented; |
| 995 | 1310 | } |
| 996 | 1311 | |
| 997 | | fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Instruction) ?*Value { |
| 998 | | @panic("TODO getCompTimeValOrNullUndefOk"); |
| 1312 | fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value { |
| 1313 | @panic("TODO"); |
| 999 | 1314 | } |
| 1000 | 1315 | |
| 1001 | 1316 | fn getCompTimeRef( |
| ... | ... | @@ -1005,8 +1320,8 @@ const Analyze = struct { |
| 1005 | 1320 | mut: Type.Pointer.Mut, |
| 1006 | 1321 | volatility: Type.Pointer.Vol, |
| 1007 | 1322 | ptr_align: u32, |
| 1008 | | ) Analyze.Error!*Instruction { |
| 1009 | | @panic("TODO getCompTimeRef"); |
| 1323 | ) Analyze.Error!*Inst { |
| 1324 | return error.Unimplemented; |
| 1010 | 1325 | } |
| 1011 | 1326 | }; |
| 1012 | 1327 | |
| ... | ... | @@ -1014,10 +1329,9 @@ pub async fn gen( |
| 1014 | 1329 | comp: *Compilation, |
| 1015 | 1330 | body_node: *ast.Node, |
| 1016 | 1331 | scope: *Scope, |
| 1017 | | end_span: Span, |
| 1018 | 1332 | parsed_file: *ParsedFile, |
| 1019 | 1333 | ) !*Code { |
| 1020 | | var irb = try Builder.init(comp, parsed_file); |
| 1334 | var irb = try Builder.init(comp, parsed_file, scope); |
| 1021 | 1335 | errdefer irb.abort(); |
| 1022 | 1336 | |
| 1023 | 1337 | const entry_block = try irb.createBasicBlock(scope, c"Entry"); |
| ... | ... | @@ -1026,18 +1340,8 @@ pub async fn gen( |
| 1026 | 1340 | |
| 1027 | 1341 | const result = try irb.genNode(body_node, scope, LVal.None); |
| 1028 | 1342 | if (!result.isNoReturn()) { |
| 1029 | | _ = irb.buildGen( |
| 1030 | | Instruction.AddImplicitReturnType, |
| 1031 | | scope, |
| 1032 | | end_span, |
| 1033 | | Instruction.AddImplicitReturnType.Params{ .target = result }, |
| 1034 | | ); |
| 1035 | | _ = irb.buildGen( |
| 1036 | | Instruction.Return, |
| 1037 | | scope, |
| 1038 | | end_span, |
| 1039 | | Instruction.Return.Params{ .return_value = result }, |
| 1040 | | ); |
| 1343 | // no need for save_err_ret_addr because this cannot return error |
| 1344 | _ = try irb.genAsyncReturn(scope, Span.token(body_node.lastToken()), result, true); |
| 1041 | 1345 | } |
| 1042 | 1346 | |
| 1043 | 1347 | return irb.finish(); |