| ... | @@ -49,6 +49,12 @@ pub const Inst = struct { | ... | @@ -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 | pub const Constant = struct { | 58 | pub const Constant = struct { |
| 53 | pub const base_tag = Tag.constant; | 59 | pub const base_tag = Tag.constant; |
| 54 | base: Inst, | 60 | base: Inst, |
| ... | @@ -63,7 +69,7 @@ pub const Inst = struct { | ... | @@ -63,7 +69,7 @@ pub const Inst = struct { |
| 63 | args: struct { | 69 | args: struct { |
| 64 | asm_source: []const u8, | 70 | asm_source: []const u8, |
| 65 | is_volatile: bool, | 71 | is_volatile: bool, |
| 66 | output: []const u8, | 72 | output: ?[]const u8, |
| 67 | inputs: []const []const u8, | 73 | inputs: []const []const u8, |
| 68 | clobbers: []const []const u8, | 74 | clobbers: []const []const u8, |
| 69 | args: []const *Inst, | 75 | args: []const *Inst, |
| ... | @@ -260,6 +266,7 @@ const Analyze = struct { | ... | @@ -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 | fn addNewInstArgs( | 270 | fn addNewInstArgs( |
| 264 | self: *Analyze, | 271 | self: *Analyze, |
| 265 | func: *Fn, | 272 | func: *Fn, |
| ... | @@ -318,11 +325,18 @@ const Analyze = struct { | ... | @@ -318,11 +325,18 @@ const Analyze = struct { |
| 318 | | 325 | |
| 319 | fn constType(self: *Analyze, src: usize, ty: Type) !*Inst { | 326 | fn constType(self: *Analyze, src: usize, ty: Type) !*Inst { |
| 320 | return self.constInst(src, .{ | 327 | return self.constInst(src, .{ |
| 321 | .ty = Type.initTag(.@"type"), | 328 | .ty = Type.initTag(.type), |
| 322 | .val = try ty.toValue(&self.arena.allocator), | 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 | fn constIntUnsigned(self: *Analyze, src: usize, ty: Type, int: u64) !*Inst { | 340 | fn constIntUnsigned(self: *Analyze, src: usize, ty: Type, int: u64) !*Inst { |
| 327 | const int_payload = try self.arena.allocator.create(Value.Payload.Int_u64); | 341 | const int_payload = try self.arena.allocator.create(Value.Payload.Int_u64); |
| 328 | int_payload.* = .{ .int = int }; | 342 | int_payload.* = .{ .int = int }; |
| ... | @@ -385,10 +399,13 @@ const Analyze = struct { | ... | @@ -385,10 +399,13 @@ const Analyze = struct { |
| 385 | .fieldptr => return self.analyzeInstFieldPtr(func, old_inst.cast(text.Inst.FieldPtr).?), | 399 | .fieldptr => return self.analyzeInstFieldPtr(func, old_inst.cast(text.Inst.FieldPtr).?), |
| 386 | .deref => return self.analyzeInstDeref(func, old_inst.cast(text.Inst.Deref).?), | 400 | .deref => return self.analyzeInstDeref(func, old_inst.cast(text.Inst.Deref).?), |
| 387 | .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), | 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)}), | 402 | .@"asm" => return self.analyzeInstAsm(func, old_inst.cast(text.Inst.Asm).?), |
| 389 | .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 403 | .@"unreachable" => return self.analyzeInstUnreachable(func, old_inst.cast(text.Inst.Unreachable).?), |
| 390 | .@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?), | 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 | .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?), | 409 | .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?), |
| 393 | .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?), | 410 | .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?), |
| 394 | .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?), | 411 | .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?), |
| ... | @@ -466,7 +483,6 @@ const Analyze = struct { | ... | @@ -466,7 +483,6 @@ const Analyze = struct { |
| 466 | // TODO handle known-pointer-address | 483 | // TODO handle known-pointer-address |
| 467 | const f = try self.requireFunctionBody(func, ptrtoint.base.src); | 484 | const f = try self.requireFunctionBody(func, ptrtoint.base.src); |
| 468 | const ty = Type.initTag(.usize); | 485 | const ty = Type.initTag(.usize); |
| 469 | // TODO should not need the cast on the last parameter | | |
| 470 | return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr }); | 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,6 +567,41 @@ const Analyze = struct { |
| 551 | return self.fail(deref.base.src, "TODO implement runtime deref", .{}); | 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 | fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { | 605 | fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { |
| 555 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); | 606 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); |
| 556 | if (in_memory_result == .ok) { | 607 | if (in_memory_result == .ok) { |