| ... | @@ -24,6 +24,7 @@ pub const Inst = struct { | ... | @@ -24,6 +24,7 @@ pub const Inst = struct { |
| 24 | constant, | 24 | constant, |
| 25 | assembly, | 25 | assembly, |
| 26 | ptrtoint, | 26 | ptrtoint, |
| | 27 | bitcast, |
| 27 | }; | 28 | }; |
| 28 | | 29 | |
| 29 | pub fn cast(base: *Inst, comptime T: type) ?*T { | 30 | pub fn cast(base: *Inst, comptime T: type) ?*T { |
| ... | @@ -45,6 +46,7 @@ pub const Inst = struct { | ... | @@ -45,6 +46,7 @@ pub const Inst = struct { |
| 45 | | 46 | |
| 46 | .assembly, | 47 | .assembly, |
| 47 | .ptrtoint, | 48 | .ptrtoint, |
| | 49 | .bitcast, |
| 48 | => null, | 50 | => null, |
| 49 | }; | 51 | }; |
| 50 | } | 52 | } |
| ... | @@ -84,6 +86,15 @@ pub const Inst = struct { | ... | @@ -84,6 +86,15 @@ pub const Inst = struct { |
| 84 | ptr: *Inst, | 86 | ptr: *Inst, |
| 85 | }, | 87 | }, |
| 86 | }; | 88 | }; |
| | 89 | |
| | 90 | pub const BitCast = struct { |
| | 91 | pub const base_tag = Tag.bitcast; |
| | 92 | |
| | 93 | base: Inst, |
| | 94 | args: struct { |
| | 95 | operand: *Inst, |
| | 96 | }, |
| | 97 | }; |
| 87 | }; | 98 | }; |
| 88 | | 99 | |
| 89 | pub const TypedValue = struct { | 100 | pub const TypedValue = struct { |
| ... | @@ -234,7 +245,7 @@ const Analyze = struct { | ... | @@ -234,7 +245,7 @@ const Analyze = struct { |
| 234 | fn resolveConstString(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) ![]u8 { | 245 | fn resolveConstString(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) ![]u8 { |
| 235 | const new_inst = try self.resolveInst(func, old_inst); | 246 | const new_inst = try self.resolveInst(func, old_inst); |
| 236 | const wanted_type = Type.initTag(.const_slice_u8); | 247 | const wanted_type = Type.initTag(.const_slice_u8); |
| 237 | const coerced_inst = try self.coerce(wanted_type, new_inst); | 248 | const coerced_inst = try self.coerce(func, wanted_type, new_inst); |
| 238 | const val = try self.resolveConstValue(coerced_inst); | 249 | const val = try self.resolveConstValue(coerced_inst); |
| 239 | return val.toAllocatedBytes(&self.arena.allocator); | 250 | return val.toAllocatedBytes(&self.arena.allocator); |
| 240 | } | 251 | } |
| ... | @@ -242,7 +253,7 @@ const Analyze = struct { | ... | @@ -242,7 +253,7 @@ const Analyze = struct { |
| 242 | fn resolveType(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) !Type { | 253 | fn resolveType(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) !Type { |
| 243 | const new_inst = try self.resolveInst(func, old_inst); | 254 | const new_inst = try self.resolveInst(func, old_inst); |
| 244 | const wanted_type = Type.initTag(.@"type"); | 255 | const wanted_type = Type.initTag(.@"type"); |
| 245 | const coerced_inst = try self.coerce(wanted_type, new_inst); | 256 | const coerced_inst = try self.coerce(func, wanted_type, new_inst); |
| 246 | const val = try self.resolveConstValue(coerced_inst); | 257 | const val = try self.resolveConstValue(coerced_inst); |
| 247 | return val.toType(); | 258 | return val.toType(); |
| 248 | } | 259 | } |
| ... | @@ -409,6 +420,7 @@ const Analyze = struct { | ... | @@ -409,6 +420,7 @@ const Analyze = struct { |
| 409 | .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?), | 420 | .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?), |
| 410 | .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?), | 421 | .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?), |
| 411 | .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?), | 422 | .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?), |
| | 423 | .bitcast => return self.analyzeInstBitCast(func, old_inst.cast(text.Inst.BitCast).?), |
| 412 | } | 424 | } |
| 413 | } | 425 | } |
| 414 | | 426 | |
| ... | @@ -472,7 +484,7 @@ const Analyze = struct { | ... | @@ -472,7 +484,7 @@ const Analyze = struct { |
| 472 | fn analyzeInstAs(self: *Analyze, func: ?*Fn, as: *text.Inst.As) InnerError!*Inst { | 484 | fn analyzeInstAs(self: *Analyze, func: ?*Fn, as: *text.Inst.As) InnerError!*Inst { |
| 473 | const dest_type = try self.resolveType(func, as.positionals.dest_type); | 485 | const dest_type = try self.resolveType(func, as.positionals.dest_type); |
| 474 | const new_inst = try self.resolveInst(func, as.positionals.value); | 486 | const new_inst = try self.resolveInst(func, as.positionals.value); |
| 475 | return self.coerce(dest_type, new_inst); | 487 | return self.coerce(func, dest_type, new_inst); |
| 476 | } | 488 | } |
| 477 | | 489 | |
| 478 | fn analyzeInstPtrToInt(self: *Analyze, func: ?*Fn, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst { | 490 | fn analyzeInstPtrToInt(self: *Analyze, func: ?*Fn, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst { |
| ... | @@ -545,12 +557,18 @@ const Analyze = struct { | ... | @@ -545,12 +557,18 @@ const Analyze = struct { |
| 545 | } | 557 | } |
| 546 | | 558 | |
| 547 | if (dest_is_comptime_int or new_inst.value() != null) { | 559 | if (dest_is_comptime_int or new_inst.value() != null) { |
| 548 | return self.coerce(dest_type, new_inst); | 560 | return self.coerce(func, dest_type, new_inst); |
| 549 | } | 561 | } |
| 550 | | 562 | |
| 551 | return self.fail(intcast.base.src, "TODO implement analyze widen or shorten int", .{}); | 563 | return self.fail(intcast.base.src, "TODO implement analyze widen or shorten int", .{}); |
| 552 | } | 564 | } |
| 553 | | 565 | |
| | 566 | fn analyzeInstBitCast(self: *Analyze, func: ?*Fn, inst: *text.Inst.BitCast) InnerError!*Inst { |
| | 567 | const dest_type = try self.resolveType(func, inst.positionals.dest_type); |
| | 568 | const operand = try self.resolveInst(func, inst.positionals.operand); |
| | 569 | return self.bitcast(func, dest_type, operand); |
| | 570 | } |
| | 571 | |
| 554 | fn analyzeInstDeref(self: *Analyze, func: ?*Fn, deref: *text.Inst.Deref) InnerError!*Inst { | 572 | fn analyzeInstDeref(self: *Analyze, func: ?*Fn, deref: *text.Inst.Deref) InnerError!*Inst { |
| 555 | const ptr = try self.resolveInst(func, deref.positionals.ptr); | 573 | const ptr = try self.resolveInst(func, deref.positionals.ptr); |
| 556 | const elem_ty = switch (ptr.ty.zigTypeTag()) { | 574 | const elem_ty = switch (ptr.ty.zigTypeTag()) { |
| ... | @@ -583,7 +601,8 @@ const Analyze = struct { | ... | @@ -583,7 +601,8 @@ const Analyze = struct { |
| 583 | elem.* = try self.resolveConstString(func, assembly.kw_args.clobbers[i]); | 601 | elem.* = try self.resolveConstString(func, assembly.kw_args.clobbers[i]); |
| 584 | } | 602 | } |
| 585 | for (args) |*elem, i| { | 603 | for (args) |*elem, i| { |
| 586 | elem.* = try self.resolveInst(func, assembly.kw_args.args[i]); | 604 | const arg = try self.resolveInst(func, assembly.kw_args.args[i]); |
| | 605 | elem.* = try self.coerce(func, Type.initTag(.usize), arg); |
| 587 | } | 606 | } |
| 588 | | 607 | |
| 589 | const f = try self.requireFunctionBody(func, assembly.base.src); | 608 | const f = try self.requireFunctionBody(func, assembly.base.src); |
| ... | @@ -602,10 +621,14 @@ const Analyze = struct { | ... | @@ -602,10 +621,14 @@ const Analyze = struct { |
| 602 | return self.addNewInstArgs(f, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {}); | 621 | return self.addNewInstArgs(f, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {}); |
| 603 | } | 622 | } |
| 604 | | 623 | |
| 605 | fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { | 624 | fn coerce(self: *Analyze, func: ?*Fn, dest_type: Type, inst: *Inst) !*Inst { |
| | 625 | // If the types are the same, we can return the operand. |
| | 626 | if (dest_type.eql(inst.ty)) |
| | 627 | return inst; |
| | 628 | |
| 606 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); | 629 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); |
| 607 | if (in_memory_result == .ok) { | 630 | if (in_memory_result == .ok) { |
| 608 | return self.bitcast(dest_type, inst); | 631 | return self.bitcast(func, dest_type, inst); |
| 609 | } | 632 | } |
| 610 | | 633 | |
| 611 | // *[N]T to []T | 634 | // *[N]T to []T |
| ... | @@ -634,12 +657,14 @@ const Analyze = struct { | ... | @@ -634,12 +657,14 @@ const Analyze = struct { |
| 634 | return self.fail(inst.src, "TODO implement type coercion", .{}); | 657 | return self.fail(inst.src, "TODO implement type coercion", .{}); |
| 635 | } | 658 | } |
| 636 | | 659 | |
| 637 | fn bitcast(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { | 660 | fn bitcast(self: *Analyze, func: ?*Fn, dest_type: Type, inst: *Inst) !*Inst { |
| 638 | if (inst.value()) |val| { | 661 | if (inst.value()) |val| { |
| 639 | // Keep the comptime Value representation; take the new type. | 662 | // Keep the comptime Value representation; take the new type. |
| 640 | return self.constInst(inst.src, .{ .ty = dest_type, .val = val }); | 663 | return self.constInst(inst.src, .{ .ty = dest_type, .val = val }); |
| 641 | } | 664 | } |
| 642 | return self.fail(inst.src, "TODO implement runtime bitcast", .{}); | 665 | // TODO validate the type size and other compile errors |
| | 666 | const f = try self.requireFunctionBody(func, inst.src); |
| | 667 | return self.addNewInstArgs(f, inst.src, dest_type, Inst.BitCast, Inst.Args(Inst.BitCast){ .operand = inst }); |
| 643 | } | 668 | } |
| 644 | | 669 | |
| 645 | fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { | 670 | fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { |
| ... | @@ -713,7 +738,7 @@ pub fn main() anyerror!void { | ... | @@ -713,7 +738,7 @@ pub fn main() anyerror!void { |
| 713 | std.process.exit(1); | 738 | std.process.exit(1); |
| 714 | } | 739 | } |
| 715 | | 740 | |
| 716 | const output_zir = false; | 741 | const output_zir = true; |
| 717 | if (output_zir) { | 742 | if (output_zir) { |
| 718 | var new_zir_module = try text.emit_zir(allocator, analyzed_module); | 743 | var new_zir_module = try text.emit_zir(allocator, analyzed_module); |
| 719 | defer new_zir_module.deinit(allocator); | 744 | defer new_zir_module.deinit(allocator); |