| ... | ... | @@ -49,6 +49,12 @@ pub const Inst = struct { |
| 49 | 49 | }; |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | pub const Unreach = struct { |
| 53 | pub const base_tag = Tag.unreach; |
| 54 | base: Inst, |
| 55 | args: void, |
| 56 | }; |
| 57 | |
| 52 | 58 | pub const Constant = struct { |
| 53 | 59 | pub const base_tag = Tag.constant; |
| 54 | 60 | base: Inst, |
| ... | ... | @@ -63,7 +69,7 @@ pub const Inst = struct { |
| 63 | 69 | args: struct { |
| 64 | 70 | asm_source: []const u8, |
| 65 | 71 | is_volatile: bool, |
| 66 | | output: []const u8, |
| 72 | output: ?[]const u8, |
| 67 | 73 | inputs: []const []const u8, |
| 68 | 74 | clobbers: []const []const u8, |
| 69 | 75 | args: []const *Inst, |
| ... | ... | @@ -260,6 +266,7 @@ const Analyze = struct { |
| 260 | 266 | }); |
| 261 | 267 | } |
| 262 | 268 | |
| 269 | /// TODO should not need the cast on the last parameter at the callsites |
| 263 | 270 | fn addNewInstArgs( |
| 264 | 271 | self: *Analyze, |
| 265 | 272 | func: *Fn, |
| ... | ... | @@ -318,11 +325,18 @@ const Analyze = struct { |
| 318 | 325 | |
| 319 | 326 | fn constType(self: *Analyze, src: usize, ty: Type) !*Inst { |
| 320 | 327 | return self.constInst(src, .{ |
| 321 | | .ty = Type.initTag(.@"type"), |
| 328 | .ty = Type.initTag(.type), |
| 322 | 329 | .val = try ty.toValue(&self.arena.allocator), |
| 323 | 330 | }); |
| 324 | 331 | } |
| 325 | 332 | |
| 333 | fn constVoid(self: *Analyze, src: usize) !*Inst { |
| 334 | return self.constInst(src, .{ |
| 335 | .ty = Type.initTag(.void), |
| 336 | .val = Value.initTag(.void_value), |
| 337 | }); |
| 338 | } |
| 339 | |
| 326 | 340 | fn constIntUnsigned(self: *Analyze, src: usize, ty: Type, int: u64) !*Inst { |
| 327 | 341 | const int_payload = try self.arena.allocator.create(Value.Payload.Int_u64); |
| 328 | 342 | int_payload.* = .{ .int = int }; |
| ... | ... | @@ -385,10 +399,13 @@ const Analyze = struct { |
| 385 | 399 | .fieldptr => return self.analyzeInstFieldPtr(func, old_inst.cast(text.Inst.FieldPtr).?), |
| 386 | 400 | .deref => return self.analyzeInstDeref(func, old_inst.cast(text.Inst.Deref).?), |
| 387 | 401 | .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), |
| 388 | | .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 389 | | .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 402 | .@"asm" => return self.analyzeInstAsm(func, old_inst.cast(text.Inst.Asm).?), |
| 403 | .@"unreachable" => return self.analyzeInstUnreachable(func, old_inst.cast(text.Inst.Unreachable).?), |
| 390 | 404 | .@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?), |
| 391 | | .@"export" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 405 | .@"export" => { |
| 406 | try self.analyzeExport(func, old_inst.cast(text.Inst.Export).?); |
| 407 | return self.constVoid(old_inst.src); |
| 408 | }, |
| 392 | 409 | .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?), |
| 393 | 410 | .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?), |
| 394 | 411 | .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?), |
| ... | ... | @@ -466,7 +483,6 @@ const Analyze = struct { |
| 466 | 483 | // TODO handle known-pointer-address |
| 467 | 484 | const f = try self.requireFunctionBody(func, ptrtoint.base.src); |
| 468 | 485 | const ty = Type.initTag(.usize); |
| 469 | | // TODO should not need the cast on the last parameter |
| 470 | 486 | return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr }); |
| 471 | 487 | } |
| 472 | 488 | |
| ... | ... | @@ -551,6 +567,41 @@ const Analyze = struct { |
| 551 | 567 | return self.fail(deref.base.src, "TODO implement runtime deref", .{}); |
| 552 | 568 | } |
| 553 | 569 | |
| 570 | fn analyzeInstAsm(self: *Analyze, func: ?*Fn, assembly: *text.Inst.Asm) InnerError!*Inst { |
| 571 | const return_type = try self.resolveType(func, assembly.positionals.return_type); |
| 572 | const asm_source = try self.resolveConstString(func, assembly.positionals.asm_source); |
| 573 | const output = if (assembly.kw_args.output) |o| try self.resolveConstString(func, o) else null; |
| 574 | |
| 575 | const inputs = try self.arena.allocator.alloc([]const u8, assembly.kw_args.inputs.len); |
| 576 | const clobbers = try self.arena.allocator.alloc([]const u8, assembly.kw_args.clobbers.len); |
| 577 | const args = try self.arena.allocator.alloc(*Inst, assembly.kw_args.args.len); |
| 578 | |
| 579 | for (inputs) |*elem, i| { |
| 580 | elem.* = try self.resolveConstString(func, assembly.kw_args.inputs[i]); |
| 581 | } |
| 582 | for (clobbers) |*elem, i| { |
| 583 | elem.* = try self.resolveConstString(func, assembly.kw_args.clobbers[i]); |
| 584 | } |
| 585 | for (args) |*elem, i| { |
| 586 | elem.* = try self.resolveInst(func, assembly.kw_args.args[i]); |
| 587 | } |
| 588 | |
| 589 | const f = try self.requireFunctionBody(func, assembly.base.src); |
| 590 | return self.addNewInstArgs(f, assembly.base.src, return_type, Inst.Assembly, Inst.Args(Inst.Assembly){ |
| 591 | .asm_source = asm_source, |
| 592 | .is_volatile = assembly.kw_args.@"volatile", |
| 593 | .output = output, |
| 594 | .inputs = inputs, |
| 595 | .clobbers = clobbers, |
| 596 | .args = args, |
| 597 | }); |
| 598 | } |
| 599 | |
| 600 | fn analyzeInstUnreachable(self: *Analyze, func: ?*Fn, unreach: *text.Inst.Unreachable) InnerError!*Inst { |
| 601 | const f = try self.requireFunctionBody(func, unreach.base.src); |
| 602 | return self.addNewInstArgs(f, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {}); |
| 603 | } |
| 604 | |
| 554 | 605 | fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { |
| 555 | 606 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); |
| 556 | 607 | if (in_memory_result == .ok) { |