| ... | ... | @@ -24,6 +24,7 @@ pub const Inst = struct { |
| 24 | 24 | constant, |
| 25 | 25 | assembly, |
| 26 | 26 | ptrtoint, |
| 27 | bitcast, |
| 27 | 28 | }; |
| 28 | 29 | |
| 29 | 30 | pub fn cast(base: *Inst, comptime T: type) ?*T { |
| ... | ... | @@ -45,6 +46,7 @@ pub const Inst = struct { |
| 45 | 46 | |
| 46 | 47 | .assembly, |
| 47 | 48 | .ptrtoint, |
| 49 | .bitcast, |
| 48 | 50 | => null, |
| 49 | 51 | }; |
| 50 | 52 | } |
| ... | ... | @@ -84,6 +86,15 @@ pub const Inst = struct { |
| 84 | 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 | 100 | pub const TypedValue = struct { |
| ... | ... | @@ -234,7 +245,7 @@ const Analyze = struct { |
| 234 | 245 | fn resolveConstString(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) ![]u8 { |
| 235 | 246 | const new_inst = try self.resolveInst(func, old_inst); |
| 236 | 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 | 249 | const val = try self.resolveConstValue(coerced_inst); |
| 239 | 250 | return val.toAllocatedBytes(&self.arena.allocator); |
| 240 | 251 | } |
| ... | ... | @@ -242,7 +253,7 @@ const Analyze = struct { |
| 242 | 253 | fn resolveType(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) !Type { |
| 243 | 254 | const new_inst = try self.resolveInst(func, old_inst); |
| 244 | 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 | 257 | const val = try self.resolveConstValue(coerced_inst); |
| 247 | 258 | return val.toType(); |
| 248 | 259 | } |
| ... | ... | @@ -409,6 +420,7 @@ const Analyze = struct { |
| 409 | 420 | .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?), |
| 410 | 421 | .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?), |
| 411 | 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 | 484 | fn analyzeInstAs(self: *Analyze, func: ?*Fn, as: *text.Inst.As) InnerError!*Inst { |
| 473 | 485 | const dest_type = try self.resolveType(func, as.positionals.dest_type); |
| 474 | 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 | 490 | fn analyzeInstPtrToInt(self: *Analyze, func: ?*Fn, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst { |
| ... | ... | @@ -545,12 +557,18 @@ const Analyze = struct { |
| 545 | 557 | } |
| 546 | 558 | |
| 547 | 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 | 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 | 572 | fn analyzeInstDeref(self: *Analyze, func: ?*Fn, deref: *text.Inst.Deref) InnerError!*Inst { |
| 555 | 573 | const ptr = try self.resolveInst(func, deref.positionals.ptr); |
| 556 | 574 | const elem_ty = switch (ptr.ty.zigTypeTag()) { |
| ... | ... | @@ -583,7 +601,8 @@ const Analyze = struct { |
| 583 | 601 | elem.* = try self.resolveConstString(func, assembly.kw_args.clobbers[i]); |
| 584 | 602 | } |
| 585 | 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 | 608 | const f = try self.requireFunctionBody(func, assembly.base.src); |
| ... | ... | @@ -602,10 +621,14 @@ const Analyze = struct { |
| 602 | 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 | 629 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); |
| 607 | 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 | 634 | // *[N]T to []T |
| ... | ... | @@ -634,12 +657,14 @@ const Analyze = struct { |
| 634 | 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 | 661 | if (inst.value()) |val| { |
| 639 | 662 | // Keep the comptime Value representation; take the new type. |
| 640 | 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 | 670 | fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { |
| ... | ... | @@ -713,7 +738,7 @@ pub fn main() anyerror!void { |
| 713 | 738 | std.process.exit(1); |
| 714 | 739 | } |
| 715 | 740 | |
| 716 | | const output_zir = false; |
| 741 | const output_zir = true; |
| 717 | 742 | if (output_zir) { |
| 718 | 743 | var new_zir_module = try text.emit_zir(allocator, analyzed_module); |
| 719 | 744 | defer new_zir_module.deinit(allocator); |