authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-11 23:38:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-20 12:19:16-07:00
logee6432537ee29485c5de6c8b0911ef1482d752a7
tree76c65539c8f7a52ad1aa0754fd807998a433953b
parentef7080aed1a1a4dc54cb837938e462b4e6720734

stage2: first pass over codegen.zig for AIR memory layout


4 files changed, 769 insertions(+), 666 deletions(-)

BRANCH_TODO-38
......@@ -1,48 +1,10 @@
11 * be sure to test debug info of parameters
22
33
4 pub fn isUnused(self: Inst) bool {
5 return (self.deaths & (1 << unreferenced_bit_index)) != 0;
6 }
7
8 pub fn operandDies(self: Inst, index: DeathsBitIndex) bool {
9 assert(index < deaths_bits);
10 return @truncate(u1, self.deaths >> index) != 0;
11 }
12
13 pub fn clearOperandDeath(self: *Inst, index: DeathsBitIndex) void {
14 assert(index < deaths_bits);
15 self.deaths &= ~(@as(DeathsInt, 1) << index);
16 }
17
184 pub fn specialOperandDeaths(self: Inst) bool {
195 return (self.deaths & (1 << deaths_bits)) != 0;
206 }
217
22 pub fn operandCount(base: *Inst) usize {
23 inline for (@typeInfo(Tag).Enum.fields) |field| {
24 const tag = @intToEnum(Tag, field.value);
25 if (tag == base.tag) {
26 return @fieldParentPtr(tag.Type(), "base", base).operandCount();
27 }
28 }
29 unreachable;
30 }
31
32 pub fn getOperand(base: *Inst, index: usize) ?*Inst {
33 inline for (@typeInfo(Tag).Enum.fields) |field| {
34 const tag = @intToEnum(Tag, field.value);
35 if (tag == base.tag) {
36 return @fieldParentPtr(tag.Type(), "base", base).getOperand(index);
37 }
38 }
39 unreachable;
40 }
41
42 pub fn Args(comptime T: type) type {
43 return std.meta.fieldInfo(T, .args).field_type;
44 }
45
468 /// Returns `null` if runtime-known.
479 /// Should be called by codegen, not by Sema. Sema functions should call
4810 /// `resolvePossiblyUndefinedValue` or `resolveDefinedValue` instead.
src/Liveness.zig+21
......@@ -74,6 +74,26 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness {
7474 };
7575}
7676
77pub fn isUnused(l: Liveness, inst: Air.Inst.Index) bool {
78 const usize_index = (inst * bpi) / @bitSizeOf(usize);
79 const mask = @as(usize, 1) << ((inst % (@bitSizeOf(usize) / bpi)) * bpi + (bpi - 1));
80 return (l.tomb_bits[usize_index] & mask) != 0;
81}
82
83pub fn operandDies(l: Liveness, inst: Air.Inst.Index, operand: OperandInt) bool {
84 assert(operand < bpi - 1);
85 const usize_index = (inst * bpi) / @bitSizeOf(usize);
86 const mask = @as(usize, 1) << ((inst % (@bitSizeOf(usize) / bpi)) * bpi + operand);
87 return (l.tomb_bits[usize_index] & mask) != 0;
88}
89
90pub fn clearOperandDeath(l: *Liveness, inst: Air.Inst.Index, operand: OperandInt) void {
91 assert(operand < bpi - 1);
92 const usize_index = (inst * bpi) / @bitSizeOf(usize);
93 const mask = @as(usize, 1) << ((inst % (@bitSizeOf(usize) / bpi)) * bpi + operand);
94 l.tomb_bits[usize_index] |= mask;
95}
96
7797pub fn deinit(l: *Liveness, gpa: *Allocator) void {
7898 gpa.free(l.tomb_bits);
7999 gpa.free(l.extra);
......@@ -83,6 +103,7 @@ pub fn deinit(l: *Liveness, gpa: *Allocator) void {
83103/// How many tomb bits per AIR instruction.
84104const bpi = 4;
85105const Bpi = std.meta.Int(.unsigned, bpi);
106const OperandInt = std.math.Log2Int(Bpi);
86107
87108/// In-progress data; on successful analysis converted into `Liveness`.
88109const Analysis = struct {
src/codegen.zig+743-622
......@@ -722,16 +722,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
722722 }
723723
724724 fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
725 for (body.instructions) |inst| {
726 try self.ensureProcessDeathCapacity(@popCount(@TypeOf(inst.deaths), inst.deaths));
725 for (body) |inst| {
726 const tomb_bits = self.liveness.getTombBits(inst);
727 try self.ensureProcessDeathCapacity(@popCount(@TypeOf(tomb_bits), tomb_bits));
727728
728729 const mcv = try self.genFuncInst(inst);
729 if (!inst.isUnused()) {
730 log.debug("{*} => {}", .{ inst, mcv });
730 if (!self.liveness.isUnused(inst)) {
731 log.debug("{} => {}", .{ inst, mcv });
731732 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
732733 try branch.inst_table.putNoClobber(self.gpa, inst, mcv);
733734 }
734735
736 // TODO inline this logic into every instruction
735737 var i: ir.Inst.DeathsBitIndex = 0;
736738 while (inst.getOperand(i)) |operand| : (i += 1) {
737739 if (inst.operandDies(i))
......@@ -785,8 +787,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
785787 }
786788
787789 /// Asserts there is already capacity to insert into top branch inst_table.
788 fn processDeath(self: *Self, inst: *ir.Inst) void {
789 if (inst.tag == .constant) return; // Constants are immortal.
790 fn processDeath(self: *Self, inst: Air.Inst.Index) void {
791 const air_tags = self.air.instructions.items(.tag);
792 if (air_tags[inst] == .constant) return; // Constants are immortal.
790793 // When editing this function, note that the logic must synchronize with `reuseOperand`.
791794 const prev_value = self.getResolvedInstValue(inst);
792795 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
......@@ -827,74 +830,82 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
827830 }
828831 }
829832
830 fn genFuncInst(self: *Self, inst: *ir.Inst) !MCValue {
831 switch (inst.tag) {
832 .add => return self.genAdd(inst.castTag(.add).?),
833 fn genFuncInst(self: *Self, inst: Air.Inst.Index) !MCValue {
834 const air_tags = self.air.instructions.items(.tag);
835 switch (air_tags[inst]) {
836 // zig fmt: off
837 .add => return self.genAdd(inst.castTag(.add).?),
833838 .addwrap => return self.genAddWrap(inst.castTag(.addwrap).?),
834 .alloc => return self.genAlloc(inst.castTag(.alloc).?),
835 .arg => return self.genArg(inst.castTag(.arg).?),
836 .assembly => return self.genAsm(inst.castTag(.assembly).?),
837 .bitcast => return self.genBitCast(inst.castTag(.bitcast).?),
838 .bit_and => return self.genBitAnd(inst.castTag(.bit_and).?),
839 .bit_or => return self.genBitOr(inst.castTag(.bit_or).?),
840 .block => return self.genBlock(inst.castTag(.block).?),
841 .br => return self.genBr(inst.castTag(.br).?),
842 .br_block_flat => return self.genBrBlockFlat(inst.castTag(.br_block_flat).?),
843 .breakpoint => return self.genBreakpoint(inst.src),
844 .br_void => return self.genBrVoid(inst.castTag(.br_void).?),
845 .bool_and => return self.genBoolOp(inst.castTag(.bool_and).?),
846 .bool_or => return self.genBoolOp(inst.castTag(.bool_or).?),
847 .call => return self.genCall(inst.castTag(.call).?),
848 .cmp_lt => return self.genCmp(inst.castTag(.cmp_lt).?, .lt),
839 .sub => return self.genSub(inst.castTag(.sub).?),
840 .subwrap => return self.genSubWrap(inst.castTag(.subwrap).?),
841 .mul => return self.genMul(inst.castTag(.mul).?),
842 .mulwrap => return self.genMulWrap(inst.castTag(.mulwrap).?),
843 .div => return self.genDiv(inst.castTag(.div).?),
844
845 .cmp_lt => return self.genCmp(inst.castTag(.cmp_lt).?, .lt),
849846 .cmp_lte => return self.genCmp(inst.castTag(.cmp_lte).?, .lte),
850 .cmp_eq => return self.genCmp(inst.castTag(.cmp_eq).?, .eq),
847 .cmp_eq => return self.genCmp(inst.castTag(.cmp_eq).?, .eq),
851848 .cmp_gte => return self.genCmp(inst.castTag(.cmp_gte).?, .gte),
852 .cmp_gt => return self.genCmp(inst.castTag(.cmp_gt).?, .gt),
849 .cmp_gt => return self.genCmp(inst.castTag(.cmp_gt).?, .gt),
853850 .cmp_neq => return self.genCmp(inst.castTag(.cmp_neq).?, .neq),
854 .condbr => return self.genCondBr(inst.castTag(.condbr).?),
855 .constant => unreachable, // excluded from function bodies
856 .dbg_stmt => return self.genDbgStmt(inst.castTag(.dbg_stmt).?),
857 .floatcast => return self.genFloatCast(inst.castTag(.floatcast).?),
858 .intcast => return self.genIntCast(inst.castTag(.intcast).?),
859 .is_non_null => return self.genIsNonNull(inst.castTag(.is_non_null).?),
851
852 .bool_and => return self.genBoolOp(inst.castTag(.bool_and).?),
853 .bool_or => return self.genBoolOp(inst.castTag(.bool_or).?),
854 .bit_and => return self.genBitAnd(inst.castTag(.bit_and).?),
855 .bit_or => return self.genBitOr(inst.castTag(.bit_or).?),
856 .xor => return self.genXor(inst.castTag(.xor).?),
857
858 .alloc => return self.genAlloc(inst.castTag(.alloc).?),
859 .arg => return self.genArg(inst.castTag(.arg).?),
860 .assembly => return self.genAsm(inst.castTag(.assembly).?),
861 .bitcast => return self.genBitCast(inst.castTag(.bitcast).?),
862 .block => return self.genBlock(inst.castTag(.block).?),
863 .br => return self.genBr(inst.castTag(.br).?),
864 .br_block_flat => return self.genBrBlockFlat(inst.castTag(.br_block_flat).?),
865 .breakpoint => return self.genBreakpoint(inst.src),
866 .call => return self.genCall(inst.castTag(.call).?),
867 .cond_br => return self.genCondBr(inst.castTag(.condbr).?),
868 .dbg_stmt => return self.genDbgStmt(inst.castTag(.dbg_stmt).?),
869 .floatcast => return self.genFloatCast(inst.castTag(.floatcast).?),
870 .intcast => return self.genIntCast(inst.castTag(.intcast).?),
871 .is_non_null => return self.genIsNonNull(inst.castTag(.is_non_null).?),
860872 .is_non_null_ptr => return self.genIsNonNullPtr(inst.castTag(.is_non_null_ptr).?),
861 .is_null => return self.genIsNull(inst.castTag(.is_null).?),
862 .is_null_ptr => return self.genIsNullPtr(inst.castTag(.is_null_ptr).?),
863 .is_non_err => return self.genIsNonErr(inst.castTag(.is_non_err).?),
864 .is_non_err_ptr => return self.genIsNonErrPtr(inst.castTag(.is_non_err_ptr).?),
865 .is_err => return self.genIsErr(inst.castTag(.is_err).?),
866 .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?),
867 .load => return self.genLoad(inst.castTag(.load).?),
868 .loop => return self.genLoop(inst.castTag(.loop).?),
869 .not => return self.genNot(inst.castTag(.not).?),
870 .mul => return self.genMul(inst.castTag(.mul).?),
871 .mulwrap => return self.genMulWrap(inst.castTag(.mulwrap).?),
872 .div => return self.genDiv(inst.castTag(.div).?),
873 .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
874 .ref => return self.genRef(inst.castTag(.ref).?),
875 .ret => return self.genRet(inst.castTag(.ret).?),
876 .retvoid => return self.genRetVoid(inst.castTag(.retvoid).?),
877 .store => return self.genStore(inst.castTag(.store).?),
878 .struct_field_ptr => return self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),
879 .sub => return self.genSub(inst.castTag(.sub).?),
880 .subwrap => return self.genSubWrap(inst.castTag(.subwrap).?),
881 .switchbr => return self.genSwitch(inst.castTag(.switchbr).?),
882 .unreach => return MCValue{ .unreach = {} },
883 .optional_payload => return self.genOptionalPayload(inst.castTag(.optional_payload).?),
884 .optional_payload_ptr => return self.genOptionalPayloadPtr(inst.castTag(.optional_payload_ptr).?),
885 .unwrap_errunion_err => return self.genUnwrapErrErr(inst.castTag(.unwrap_errunion_err).?),
886 .unwrap_errunion_payload => return self.genUnwrapErrPayload(inst.castTag(.unwrap_errunion_payload).?),
887 .unwrap_errunion_err_ptr => return self.genUnwrapErrErrPtr(inst.castTag(.unwrap_errunion_err_ptr).?),
888 .unwrap_errunion_payload_ptr => return self.genUnwrapErrPayloadPtr(inst.castTag(.unwrap_errunion_payload_ptr).?),
889 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
873 .is_null => return self.genIsNull(inst.castTag(.is_null).?),
874 .is_null_ptr => return self.genIsNullPtr(inst.castTag(.is_null_ptr).?),
875 .is_non_err => return self.genIsNonErr(inst.castTag(.is_non_err).?),
876 .is_non_err_ptr => return self.genIsNonErrPtr(inst.castTag(.is_non_err_ptr).?),
877 .is_err => return self.genIsErr(inst.castTag(.is_err).?),
878 .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?),
879 .load => return self.genLoad(inst.castTag(.load).?),
880 .loop => return self.genLoop(inst.castTag(.loop).?),
881 .not => return self.genNot(inst.castTag(.not).?),
882 .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
883 .ref => return self.genRef(inst.castTag(.ref).?),
884 .ret => return self.genRet(inst.castTag(.ret).?),
885 .store => return self.genStore(inst.castTag(.store).?),
886 .struct_field_ptr=> return self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),
887 .switchbr => return self.genSwitch(inst.castTag(.switchbr).?),
888 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),
889
890 .constant => unreachable, // excluded from function bodies
891 .unreach => return MCValue{ .unreach = {} },
892
893 .optional_payload => return self.genOptionalPayload(inst.castTag(.optional_payload).?),
894 .optional_payload_ptr => return self.genOptionalPayloadPtr(inst.castTag(.optional_payload_ptr).?),
895 .unwrap_errunion_err => return self.genUnwrapErrErr(inst.castTag(.unwrap_errunion_err).?),
896 .unwrap_errunion_payload => return self.genUnwrapErrPayload(inst.castTag(.unwrap_errunion_payload).?),
897 .unwrap_errunion_err_ptr => return self.genUnwrapErrErrPtr(inst.castTag(.unwrap_errunion_err_ptr).?),
898 .unwrap_errunion_payload_ptr=> return self.genUnwrapErrPayloadPtr(inst.castTag(.unwrap_errunion_payload_ptr).?),
899
900 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
890901 .wrap_errunion_payload => return self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?),
891 .wrap_errunion_err => return self.genWrapErrUnionErr(inst.castTag(.wrap_errunion_err).?),
892 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),
893 .xor => return self.genXor(inst.castTag(.xor).?),
902 .wrap_errunion_err => return self.genWrapErrUnionErr(inst.castTag(.wrap_errunion_err).?),
903
904 // zig fmt: on
894905 }
895906 }
896907
897 fn allocMem(self: *Self, inst: *ir.Inst, abi_size: u32, abi_align: u32) !u32 {
908 fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
898909 if (abi_align > self.stack_align)
899910 self.stack_align = abi_align;
900911 // TODO find a free slot instead of always appending
......@@ -910,20 +921,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
910921 }
911922
912923 /// Use a pointer instruction as the basis for allocating stack memory.
913 fn allocMemPtr(self: *Self, inst: *ir.Inst) !u32 {
914 const elem_ty = inst.ty.elemType();
924 fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
925 const elem_ty = self.air.getType(inst).elemType();
915926 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
916 return self.fail(inst.src, "type '{}' too big to fit into stack frame", .{elem_ty});
927 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});
917928 };
918929 // TODO swap this for inst.ty.ptrAlign
919930 const abi_align = elem_ty.abiAlignment(self.target.*);
920931 return self.allocMem(inst, abi_size, abi_align);
921932 }
922933
923 fn allocRegOrMem(self: *Self, inst: *ir.Inst, reg_ok: bool) !MCValue {
934 fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
924935 const elem_ty = inst.ty;
925936 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
926 return self.fail(inst.src, "type '{}' too big to fit into stack frame", .{elem_ty});
937 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});
927938 };
928939 const abi_align = elem_ty.abiAlignment(self.target.*);
929940 if (abi_align > self.stack_align)
......@@ -943,72 +954,75 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
943954 return MCValue{ .stack_offset = stack_offset };
944955 }
945956
946 pub fn spillInstruction(self: *Self, src: LazySrcLoc, reg: Register, inst: *ir.Inst) !void {
957 pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
947958 const stack_mcv = try self.allocRegOrMem(inst, false);
948959 log.debug("spilling {*} to stack mcv {any}", .{ inst, stack_mcv });
949960 const reg_mcv = self.getResolvedInstValue(inst);
950961 assert(reg == toCanonicalReg(reg_mcv.register));
951962 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
952963 try branch.inst_table.put(self.gpa, inst, stack_mcv);
953 try self.genSetStack(src, inst.ty, stack_mcv.stack_offset, reg_mcv);
964 try self.genSetStack(inst.ty, stack_mcv.stack_offset, reg_mcv);
954965 }
955966
956967 /// Copies a value to a register without tracking the register. The register is not considered
957968 /// allocated. A second call to `copyToTmpRegister` may return the same register.
958969 /// This can have a side effect of spilling instructions to the stack to free up a register.
959 fn copyToTmpRegister(self: *Self, src: LazySrcLoc, ty: Type, mcv: MCValue) !Register {
970 fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
960971 const reg = try self.register_manager.allocReg(null, &.{});
961 try self.genSetReg(src, ty, reg, mcv);
972 try self.genSetReg(ty, reg, mcv);
962973 return reg;
963974 }
964975
965976 /// Allocates a new register and copies `mcv` into it.
966977 /// `reg_owner` is the instruction that gets associated with the register in the register table.
967978 /// This can have a side effect of spilling instructions to the stack to free up a register.
968 fn copyToNewRegister(self: *Self, reg_owner: *ir.Inst, mcv: MCValue) !MCValue {
979 fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
969980 const reg = try self.register_manager.allocReg(reg_owner, &.{});
970 try self.genSetReg(reg_owner.src, reg_owner.ty, reg, mcv);
981 try self.genSetReg(reg_owner.ty, reg, mcv);
971982 return MCValue{ .register = reg };
972983 }
973984
974 fn genAlloc(self: *Self, inst: *ir.Inst.NoOp) !MCValue {
975 const stack_offset = try self.allocMemPtr(&inst.base);
985 fn genAlloc(self: *Self, inst: Air.Inst.Index) !MCValue {
986 const stack_offset = try self.allocMemPtr(inst);
976987 return MCValue{ .ptr_stack_offset = stack_offset };
977988 }
978989
979 fn genFloatCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
990 fn genFloatCast(self: *Self, inst: Air.Inst.Index) !MCValue {
980991 // No side effects, so if it's unreferenced, do nothing.
981 if (inst.base.isUnused())
992 if (self.liveness.isUnused(inst))
982993 return MCValue.dead;
983994 switch (arch) {
984 else => return self.fail(inst.base.src, "TODO implement floatCast for {}", .{self.target.cpu.arch}),
995 else => return self.fail("TODO implement floatCast for {}", .{self.target.cpu.arch}),
985996 }
986997 }
987998
988 fn genIntCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
999 fn genIntCast(self: *Self, inst: Air.Inst.Index) !MCValue {
9891000 // No side effects, so if it's unreferenced, do nothing.
990 if (inst.base.isUnused())
1001 if (self.liveness.isUnused(inst))
9911002 return MCValue.dead;
9921003
993 const operand = try self.resolveInst(inst.operand);
994 const info_a = inst.operand.ty.intInfo(self.target.*);
995 const info_b = inst.base.ty.intInfo(self.target.*);
1004 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1005 const operand_ty = self.air.getType(ty_op.operand);
1006 const operand = try self.resolveInst(ty_op.operand);
1007 const info_a = operand_ty.intInfo(self.target.*);
1008 const info_b = self.air.getType(inst).intInfo(self.target.*);
9961009 if (info_a.signedness != info_b.signedness)
997 return self.fail(inst.base.src, "TODO gen intcast sign safety in semantic analysis", .{});
1010 return self.fail("TODO gen intcast sign safety in semantic analysis", .{});
9981011
9991012 if (info_a.bits == info_b.bits)
10001013 return operand;
10011014
10021015 switch (arch) {
1003 else => return self.fail(inst.base.src, "TODO implement intCast for {}", .{self.target.cpu.arch}),
1016 else => return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch}),
10041017 }
10051018 }
10061019
1007 fn genNot(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1020 fn genNot(self: *Self, inst: Air.Inst.Index) !MCValue {
10081021 // No side effects, so if it's unreferenced, do nothing.
1009 if (inst.base.isUnused())
1022 if (self.liveness.isUnused(inst))
10101023 return MCValue.dead;
1011 const operand = try self.resolveInst(inst.operand);
1024 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1025 const operand = try self.resolveInst(ty_op.operand);
10121026 switch (operand) {
10131027 .dead => unreachable,
10141028 .unreach => unreachable,
......@@ -1037,216 +1051,209 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10371051
10381052 switch (arch) {
10391053 .x86_64 => {
1040 var imm = ir.Inst.Constant{
1041 .base = .{
1042 .tag = .constant,
1043 .deaths = 0,
1044 .ty = inst.operand.ty,
1045 .src = inst.operand.src,
1046 },
1047 .val = Value.initTag(.bool_true),
1048 };
1049 return try self.genX8664BinMath(&inst.base, inst.operand, &imm.base);
1054 return try self.genX8664BinMath(inst, ty_op.operand, .bool_true);
10501055 },
10511056 .arm, .armeb => {
1052 var imm = ir.Inst.Constant{
1053 .base = .{
1054 .tag = .constant,
1055 .deaths = 0,
1056 .ty = inst.operand.ty,
1057 .src = inst.operand.src,
1058 },
1059 .val = Value.initTag(.bool_true),
1060 };
1061 return try self.genArmBinOp(&inst.base, inst.operand, &imm.base, .not);
1057 return try self.genArmBinOp(inst, ty_op.operand, .bool_true, .not);
10621058 },
1063 else => return self.fail(inst.base.src, "TODO implement NOT for {}", .{self.target.cpu.arch}),
1059 else => return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch}),
10641060 }
10651061 }
10661062
1067 fn genAdd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1063 fn genAdd(self: *Self, inst: Air.Inst.Index) !MCValue {
10681064 // No side effects, so if it's unreferenced, do nothing.
1069 if (inst.base.isUnused())
1065 if (self.liveness.isUnused(inst))
10701066 return MCValue.dead;
1067 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
10711068 switch (arch) {
10721069 .x86_64 => {
1073 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs);
1070 return try self.genX8664BinMath(inst, bin_op.lhs, bin_op.rhs);
10741071 },
1075 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .add),
1076 else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}),
1072 .arm, .armeb => return try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .add),
1073 else => return self.fail("TODO implement add for {}", .{self.target.cpu.arch}),
10771074 }
10781075 }
10791076
1080 fn genAddWrap(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1077 fn genAddWrap(self: *Self, inst: Air.Inst.Index) !MCValue {
10811078 // No side effects, so if it's unreferenced, do nothing.
1082 if (inst.base.isUnused())
1079 if (self.liveness.isUnused(inst))
10831080 return MCValue.dead;
1081 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1082 _ = bin_op;
10841083 switch (arch) {
1085 else => return self.fail(inst.base.src, "TODO implement addwrap for {}", .{self.target.cpu.arch}),
1084 else => return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch}),
10861085 }
10871086 }
10881087
1089 fn genMul(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1088 fn genMul(self: *Self, inst: Air.Inst.Index) !MCValue {
10901089 // No side effects, so if it's unreferenced, do nothing.
1091 if (inst.base.isUnused())
1090 if (self.liveness.isUnused(inst))
10921091 return MCValue.dead;
1092 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
10931093 switch (arch) {
1094 .x86_64 => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs),
1095 .arm, .armeb => return try self.genArmMul(&inst.base, inst.lhs, inst.rhs),
1096 else => return self.fail(inst.base.src, "TODO implement mul for {}", .{self.target.cpu.arch}),
1094 .x86_64 => return try self.genX8664BinMath(inst, bin_op.lhs, bin_op.rhs),
1095 .arm, .armeb => return try self.genArmMul(inst, bin_op.lhs, bin_op.rhs),
1096 else => return self.fail("TODO implement mul for {}", .{self.target.cpu.arch}),
10971097 }
10981098 }
10991099
1100 fn genMulWrap(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1100 fn genMulWrap(self: *Self, inst: Air.Inst.Index) !MCValue {
11011101 // No side effects, so if it's unreferenced, do nothing.
1102 if (inst.base.isUnused())
1102 if (self.liveness.isUnused(inst))
11031103 return MCValue.dead;
1104 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1105 _ = bin_op;
11041106 switch (arch) {
1105 else => return self.fail(inst.base.src, "TODO implement mulwrap for {}", .{self.target.cpu.arch}),
1107 else => return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch}),
11061108 }
11071109 }
11081110
1109 fn genDiv(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1111 fn genDiv(self: *Self, inst: Air.Inst.Index) !MCValue {
11101112 // No side effects, so if it's unreferenced, do nothing.
1111 if (inst.base.isUnused())
1113 if (self.liveness.isUnused(inst))
11121114 return MCValue.dead;
1115 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1116 _ = bin_op;
11131117 switch (arch) {
1114 else => return self.fail(inst.base.src, "TODO implement div for {}", .{self.target.cpu.arch}),
1118 else => return self.fail("TODO implement div for {}", .{self.target.cpu.arch}),
11151119 }
11161120 }
11171121
1118 fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1122 fn genBitAnd(self: *Self, inst: Air.Inst.Index) !MCValue {
11191123 // No side effects, so if it's unreferenced, do nothing.
1120 if (inst.base.isUnused())
1124 if (self.liveness.isUnused(inst))
11211125 return MCValue.dead;
1126 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
11221127 switch (arch) {
1123 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bit_and),
1124 else => return self.fail(inst.base.src, "TODO implement bitwise and for {}", .{self.target.cpu.arch}),
1128 .arm, .armeb => return try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .bit_and),
1129 else => return self.fail("TODO implement bitwise and for {}", .{self.target.cpu.arch}),
11251130 }
11261131 }
11271132
1128 fn genBitOr(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1133 fn genBitOr(self: *Self, inst: Air.Inst.Index) !MCValue {
11291134 // No side effects, so if it's unreferenced, do nothing.
1130 if (inst.base.isUnused())
1135 if (self.liveness.isUnused(inst))
11311136 return MCValue.dead;
1137 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
11321138 switch (arch) {
1133 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bit_or),
1134 else => return self.fail(inst.base.src, "TODO implement bitwise or for {}", .{self.target.cpu.arch}),
1139 .arm, .armeb => return try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .bit_or),
1140 else => return self.fail("TODO implement bitwise or for {}", .{self.target.cpu.arch}),
11351141 }
11361142 }
11371143
1138 fn genXor(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1144 fn genXor(self: *Self, inst: Air.Inst.Index) !MCValue {
11391145 // No side effects, so if it's unreferenced, do nothing.
1140 if (inst.base.isUnused())
1146 if (self.liveness.isUnused(inst))
11411147 return MCValue.dead;
1148 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
11421149 switch (arch) {
1143 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .xor),
1144 else => return self.fail(inst.base.src, "TODO implement xor for {}", .{self.target.cpu.arch}),
1150 .arm, .armeb => return try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .xor),
1151 else => return self.fail("TODO implement xor for {}", .{self.target.cpu.arch}),
11451152 }
11461153 }
11471154
1148 fn genOptionalPayload(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1155 fn genOptionalPayload(self: *Self, inst: Air.Inst.Index) !MCValue {
11491156 // No side effects, so if it's unreferenced, do nothing.
1150 if (inst.base.isUnused())
1157 if (self.liveness.isUnused(inst))
11511158 return MCValue.dead;
11521159 switch (arch) {
1153 else => return self.fail(inst.base.src, "TODO implement .optional_payload for {}", .{self.target.cpu.arch}),
1160 else => return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch}),
11541161 }
11551162 }
11561163
1157 fn genOptionalPayloadPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1164 fn genOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !MCValue {
11581165 // No side effects, so if it's unreferenced, do nothing.
1159 if (inst.base.isUnused())
1166 if (self.liveness.isUnused(inst))
11601167 return MCValue.dead;
11611168 switch (arch) {
1162 else => return self.fail(inst.base.src, "TODO implement .optional_payload_ptr for {}", .{self.target.cpu.arch}),
1169 else => return self.fail("TODO implement .optional_payload_ptr for {}", .{self.target.cpu.arch}),
11631170 }
11641171 }
11651172
1166 fn genUnwrapErrErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1173 fn genUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !MCValue {
11671174 // No side effects, so if it's unreferenced, do nothing.
1168 if (inst.base.isUnused())
1175 if (self.liveness.isUnused(inst))
11691176 return MCValue.dead;
11701177 switch (arch) {
1171 else => return self.fail(inst.base.src, "TODO implement unwrap error union error for {}", .{self.target.cpu.arch}),
1178 else => return self.fail("TODO implement unwrap error union error for {}", .{self.target.cpu.arch}),
11721179 }
11731180 }
11741181
1175 fn genUnwrapErrPayload(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1182 fn genUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !MCValue {
11761183 // No side effects, so if it's unreferenced, do nothing.
1177 if (inst.base.isUnused())
1184 if (self.liveness.isUnused(inst))
11781185 return MCValue.dead;
11791186 switch (arch) {
1180 else => return self.fail(inst.base.src, "TODO implement unwrap error union payload for {}", .{self.target.cpu.arch}),
1187 else => return self.fail("TODO implement unwrap error union payload for {}", .{self.target.cpu.arch}),
11811188 }
11821189 }
11831190 // *(E!T) -> E
1184 fn genUnwrapErrErrPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1191 fn genUnwrapErrErrPtr(self: *Self, inst: Air.Inst.Index) !MCValue {
11851192 // No side effects, so if it's unreferenced, do nothing.
1186 if (inst.base.isUnused())
1193 if (self.liveness.isUnused(inst))
11871194 return MCValue.dead;
11881195 switch (arch) {
1189 else => return self.fail(inst.base.src, "TODO implement unwrap error union error ptr for {}", .{self.target.cpu.arch}),
1196 else => return self.fail("TODO implement unwrap error union error ptr for {}", .{self.target.cpu.arch}),
11901197 }
11911198 }
11921199 // *(E!T) -> *T
1193 fn genUnwrapErrPayloadPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1200 fn genUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !MCValue {
11941201 // No side effects, so if it's unreferenced, do nothing.
1195 if (inst.base.isUnused())
1202 if (self.liveness.isUnused(inst))
11961203 return MCValue.dead;
11971204 switch (arch) {
1198 else => return self.fail(inst.base.src, "TODO implement unwrap error union payload ptr for {}", .{self.target.cpu.arch}),
1205 else => return self.fail("TODO implement unwrap error union payload ptr for {}", .{self.target.cpu.arch}),
11991206 }
12001207 }
1201 fn genWrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1202 const optional_ty = inst.base.ty;
1203
1208 fn genWrapOptional(self: *Self, inst: Air.Inst.Index) !MCValue {
12041209 // No side effects, so if it's unreferenced, do nothing.
1205 if (inst.base.isUnused())
1210 if (self.liveness.isUnused(inst))
12061211 return MCValue.dead;
12071212
1213 const optional_ty = self.air.getType(inst);
1214
12081215 // Optional type is just a boolean true
12091216 if (optional_ty.abiSize(self.target.*) == 1)
12101217 return MCValue{ .immediate = 1 };
12111218
12121219 switch (arch) {
1213 else => return self.fail(inst.base.src, "TODO implement wrap optional for {}", .{self.target.cpu.arch}),
1220 else => return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch}),
12141221 }
12151222 }
12161223
12171224 /// T to E!T
1218 fn genWrapErrUnionPayload(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1225 fn genWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !MCValue {
12191226 // No side effects, so if it's unreferenced, do nothing.
1220 if (inst.base.isUnused())
1227 if (self.liveness.isUnused(inst))
12211228 return MCValue.dead;
12221229
12231230 switch (arch) {
1224 else => return self.fail(inst.base.src, "TODO implement wrap errunion payload for {}", .{self.target.cpu.arch}),
1231 else => return self.fail("TODO implement wrap errunion payload for {}", .{self.target.cpu.arch}),
12251232 }
12261233 }
12271234
12281235 /// E to E!T
1229 fn genWrapErrUnionErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1236 fn genWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !MCValue {
12301237 // No side effects, so if it's unreferenced, do nothing.
1231 if (inst.base.isUnused())
1238 if (self.liveness.isUnused(inst))
12321239 return MCValue.dead;
12331240
12341241 switch (arch) {
1235 else => return self.fail(inst.base.src, "TODO implement wrap errunion error for {}", .{self.target.cpu.arch}),
1242 else => return self.fail("TODO implement wrap errunion error for {}", .{self.target.cpu.arch}),
12361243 }
12371244 }
1238 fn genVarPtr(self: *Self, inst: *ir.Inst.VarPtr) !MCValue {
1245 fn genVarPtr(self: *Self, inst: Air.Inst.Index) !MCValue {
12391246 // No side effects, so if it's unreferenced, do nothing.
1240 if (inst.base.isUnused())
1247 if (self.liveness.isUnused(inst))
12411248 return MCValue.dead;
12421249
12431250 switch (arch) {
1244 else => return self.fail(inst.base.src, "TODO implement varptr for {}", .{self.target.cpu.arch}),
1251 else => return self.fail("TODO implement varptr for {}", .{self.target.cpu.arch}),
12451252 }
12461253 }
12471254
1248 fn reuseOperand(self: *Self, inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool {
1249 if (!inst.operandDies(op_index))
1255 fn reuseOperand(self: *Self, inst: Air.Inst.Index, op_index: u2, mcv: MCValue) bool {
1256 if (!self.liveness.operandDies(inst, op_index))
12501257 return false;
12511258
12521259 switch (mcv) {
......@@ -1258,16 +1265,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
12581265 self.register_manager.registers[index] = inst;
12591266 }
12601267 }
1261 log.debug("reusing {} => {*}", .{ reg, inst });
1268 log.debug("reusing {} => {}", .{ reg, inst });
12621269 },
12631270 .stack_offset => |off| {
1264 log.debug("reusing stack offset {} => {*}", .{ off, inst });
1271 log.debug("reusing stack offset {} => {}", .{ off, inst });
12651272 },
12661273 else => return false,
12671274 }
12681275
12691276 // Prevent the operand deaths processing code from deallocating it.
1270 inst.clearOperandDeath(op_index);
1277 self.liveness.clearOperandDeath(inst, op_index);
12711278
12721279 // That makes us responsible for doing the rest of the stuff that processDeath would have done.
12731280 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
......@@ -1276,22 +1283,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
12761283 return true;
12771284 }
12781285
1279 fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1280 const elem_ty = inst.base.ty;
1281 if (!elem_ty.hasCodeGenBits())
1282 return MCValue.none;
1283 const ptr = try self.resolveInst(inst.operand);
1284 const is_volatile = inst.operand.ty.isVolatilePtr();
1285 if (inst.base.isUnused() and !is_volatile)
1286 return MCValue.dead;
1287 const dst_mcv: MCValue = blk: {
1288 if (self.reuseOperand(&inst.base, 0, ptr)) {
1289 // The MCValue that holds the pointer can be re-used as the value.
1290 break :blk ptr;
1291 } else {
1292 break :blk try self.allocRegOrMem(&inst.base, true);
1293 }
1294 };
1286 fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue) !void {
12951287 switch (ptr) {
12961288 .none => unreachable,
12971289 .undef => unreachable,
......@@ -1299,31 +1291,51 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
12991291 .dead => unreachable,
13001292 .compare_flags_unsigned => unreachable,
13011293 .compare_flags_signed => unreachable,
1302 .immediate => |imm| try self.setRegOrMem(inst.base.src, elem_ty, dst_mcv, .{ .memory = imm }),
1303 .ptr_stack_offset => |off| try self.setRegOrMem(inst.base.src, elem_ty, dst_mcv, .{ .stack_offset = off }),
1294 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
1295 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),
13041296 .ptr_embedded_in_code => |off| {
1305 try self.setRegOrMem(inst.base.src, elem_ty, dst_mcv, .{ .embedded_in_code = off });
1297 try self.setRegOrMem(elem_ty, dst_mcv, .{ .embedded_in_code = off });
13061298 },
13071299 .embedded_in_code => {
1308 return self.fail(inst.base.src, "TODO implement loading from MCValue.embedded_in_code", .{});
1300 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
13091301 },
13101302 .register => {
1311 return self.fail(inst.base.src, "TODO implement loading from MCValue.register", .{});
1303 return self.fail("TODO implement loading from MCValue.register", .{});
13121304 },
13131305 .memory => {
1314 return self.fail(inst.base.src, "TODO implement loading from MCValue.memory", .{});
1306 return self.fail("TODO implement loading from MCValue.memory", .{});
13151307 },
13161308 .stack_offset => {
1317 return self.fail(inst.base.src, "TODO implement loading from MCValue.stack_offset", .{});
1309 return self.fail("TODO implement loading from MCValue.stack_offset", .{});
13181310 },
13191311 }
1312 }
1313
1314 fn genLoad(self: *Self, inst: Air.Inst.Index) !MCValue {
1315 const elem_ty = self.air.getType(inst);
1316 if (!elem_ty.hasCodeGenBits())
1317 return MCValue.none;
1318 const ptr = try self.resolveInst(inst.operand);
1319 const is_volatile = inst.operand.ty.isVolatilePtr();
1320 if (self.liveness.isUnused(inst) and !is_volatile)
1321 return MCValue.dead;
1322 const dst_mcv: MCValue = blk: {
1323 if (self.reuseOperand(inst, 0, ptr)) {
1324 // The MCValue that holds the pointer can be re-used as the value.
1325 break :blk ptr;
1326 } else {
1327 break :blk try self.allocRegOrMem(inst, true);
1328 }
1329 };
1330 self.load(dst_mcv, ptr);
13201331 return dst_mcv;
13211332 }
13221333
1323 fn genStore(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1324 const ptr = try self.resolveInst(inst.lhs);
1325 const value = try self.resolveInst(inst.rhs);
1326 const elem_ty = inst.rhs.ty;
1334 fn genStore(self: *Self, inst: Air.Inst.Index) !MCValue {
1335 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1336 const ptr = try self.resolveInst(bin_op.lhs);
1337 const value = try self.resolveInst(bin_op.rhs);
1338 const elem_ty = self.getType(bin_op.rhs);
13271339 switch (ptr) {
13281340 .none => unreachable,
13291341 .undef => unreachable,
......@@ -1332,57 +1344,60 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13321344 .compare_flags_unsigned => unreachable,
13331345 .compare_flags_signed => unreachable,
13341346 .immediate => |imm| {
1335 try self.setRegOrMem(inst.base.src, elem_ty, .{ .memory = imm }, value);
1347 try self.setRegOrMem(elem_ty, .{ .memory = imm }, value);
13361348 },
13371349 .ptr_stack_offset => |off| {
1338 try self.genSetStack(inst.base.src, elem_ty, off, value);
1350 try self.genSetStack(elem_ty, off, value);
13391351 },
13401352 .ptr_embedded_in_code => |off| {
1341 try self.setRegOrMem(inst.base.src, elem_ty, .{ .embedded_in_code = off }, value);
1353 try self.setRegOrMem(elem_ty, .{ .embedded_in_code = off }, value);
13421354 },
13431355 .embedded_in_code => {
1344 return self.fail(inst.base.src, "TODO implement storing to MCValue.embedded_in_code", .{});
1356 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
13451357 },
13461358 .register => {
1347 return self.fail(inst.base.src, "TODO implement storing to MCValue.register", .{});
1359 return self.fail("TODO implement storing to MCValue.register", .{});
13481360 },
13491361 .memory => {
1350 return self.fail(inst.base.src, "TODO implement storing to MCValue.memory", .{});
1362 return self.fail("TODO implement storing to MCValue.memory", .{});
13511363 },
13521364 .stack_offset => {
1353 return self.fail(inst.base.src, "TODO implement storing to MCValue.stack_offset", .{});
1365 return self.fail("TODO implement storing to MCValue.stack_offset", .{});
13541366 },
13551367 }
13561368 return .none;
13571369 }
13581370
1359 fn genStructFieldPtr(self: *Self, inst: *ir.Inst.StructFieldPtr) !MCValue {
1360 return self.fail(inst.base.src, "TODO implement codegen struct_field_ptr", .{});
1371 fn genStructFieldPtr(self: *Self, inst: Air.Inst.Index) !MCValue {
1372 const struct_field_ptr = self.air.instructions.items(.data)[inst].struct_field_ptr;
1373 _ = struct_field_ptr;
1374 return self.fail("TODO implement codegen struct_field_ptr", .{});
13611375 }
13621376
1363 fn genSub(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1377 fn genSub(self: *Self, inst: Air.Inst.Index) !MCValue {
13641378 // No side effects, so if it's unreferenced, do nothing.
1365 if (inst.base.isUnused())
1379 if (self.liveness.isUnused(inst))
13661380 return MCValue.dead;
1381 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
13671382 switch (arch) {
1368 .x86_64 => {
1369 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs);
1370 },
1371 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .sub),
1372 else => return self.fail(inst.base.src, "TODO implement sub for {}", .{self.target.cpu.arch}),
1383 .x86_64 => return self.genX8664BinMath(inst, bin_op.lhs, bin_op.rhs),
1384 .arm, .armeb => return self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .sub),
1385 else => return self.fail("TODO implement sub for {}", .{self.target.cpu.arch}),
13731386 }
13741387 }
13751388
1376 fn genSubWrap(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1389 fn genSubWrap(self: *Self, inst: Air.Inst.Index) !MCValue {
13771390 // No side effects, so if it's unreferenced, do nothing.
1378 if (inst.base.isUnused())
1391 if (self.liveness.isUnused(inst))
13791392 return MCValue.dead;
1393 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1394 _ = bin_op;
13801395 switch (arch) {
1381 else => return self.fail(inst.base.src, "TODO implement subwrap for {}", .{self.target.cpu.arch}),
1396 else => return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch}),
13821397 }
13831398 }
13841399
1385 fn armOperandShouldBeRegister(self: *Self, src: LazySrcLoc, mcv: MCValue) !bool {
1400 fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool {
13861401 return switch (mcv) {
13871402 .none => unreachable,
13881403 .undef => unreachable,
......@@ -1392,7 +1407,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13921407 .ptr_stack_offset => unreachable,
13931408 .ptr_embedded_in_code => unreachable,
13941409 .immediate => |imm| blk: {
1395 if (imm > std.math.maxInt(u32)) return self.fail(src, "TODO ARM binary arithmetic immediate larger than u32", .{});
1410 if (imm > std.math.maxInt(u32)) return self.fail("TODO ARM binary arithmetic immediate larger than u32", .{});
13961411
13971412 // Load immediate into register if it doesn't fit
13981413 // in an operand
......@@ -1406,14 +1421,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14061421 };
14071422 }
14081423
1409 fn genArmBinOp(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, op: ir.Inst.Tag) !MCValue {
1424 fn genArmBinOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref, op: ir.Inst.Tag) !MCValue {
14101425 const lhs = try self.resolveInst(op_lhs);
14111426 const rhs = try self.resolveInst(op_rhs);
14121427
14131428 const lhs_is_register = lhs == .register;
14141429 const rhs_is_register = rhs == .register;
1415 const lhs_should_be_register = try self.armOperandShouldBeRegister(op_lhs.src, lhs);
1416 const rhs_should_be_register = try self.armOperandShouldBeRegister(op_rhs.src, rhs);
1430 const lhs_should_be_register = try self.armOperandShouldBeRegister(lhs);
1431 const rhs_should_be_register = try self.armOperandShouldBeRegister(rhs);
14171432 const reuse_lhs = lhs_is_register and self.reuseOperand(inst, 0, lhs);
14181433 const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, 1, rhs);
14191434
......@@ -1486,14 +1501,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14861501
14871502 // Move the operands to the newly allocated registers
14881503 if (lhs_mcv == .register and !lhs_is_register) {
1489 try self.genSetReg(op_lhs.src, op_lhs.ty, lhs_mcv.register, lhs);
1504 try self.genSetReg(op_lhs.ty, lhs_mcv.register, lhs);
14901505 }
14911506 if (rhs_mcv == .register and !rhs_is_register) {
1492 try self.genSetReg(op_rhs.src, op_rhs.ty, rhs_mcv.register, rhs);
1507 try self.genSetReg(op_rhs.ty, rhs_mcv.register, rhs);
14931508 }
14941509
14951510 try self.genArmBinOpCode(
1496 inst.src,
14971511 dst_mcv.register,
14981512 lhs_mcv,
14991513 rhs_mcv,
......@@ -1505,14 +1519,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
15051519
15061520 fn genArmBinOpCode(
15071521 self: *Self,
1508 src: LazySrcLoc,
15091522 dst_reg: Register,
15101523 lhs_mcv: MCValue,
15111524 rhs_mcv: MCValue,
15121525 swap_lhs_and_rhs: bool,
15131526 op: ir.Inst.Tag,
15141527 ) !void {
1515 _ = src;
15161528 assert(lhs_mcv == .register or rhs_mcv == .register);
15171529
15181530 const op1 = if (swap_lhs_and_rhs) rhs_mcv.register else lhs_mcv.register;
......@@ -1561,7 +1573,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
15611573 }
15621574 }
15631575
1564 fn genArmMul(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst) !MCValue {
1576 fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Index, op_rhs: Air.Inst.Index) !MCValue {
15651577 const lhs = try self.resolveInst(op_lhs);
15661578 const rhs = try self.resolveInst(op_rhs);
15671579
......@@ -1618,10 +1630,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16181630
16191631 // Move the operands to the newly allocated registers
16201632 if (!lhs_is_register) {
1621 try self.genSetReg(op_lhs.src, op_lhs.ty, lhs_mcv.register, lhs);
1633 try self.genSetReg(op_lhs.ty, lhs_mcv.register, lhs);
16221634 }
16231635 if (!rhs_is_register) {
1624 try self.genSetReg(op_rhs.src, op_rhs.ty, rhs_mcv.register, rhs);
1636 try self.genSetReg(op_rhs.ty, rhs_mcv.register, rhs);
16251637 }
16261638
16271639 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mul(.al, dst_mcv.register, lhs_mcv.register, rhs_mcv.register).toU32());
......@@ -1631,7 +1643,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16311643 /// Perform "binary" operators, excluding comparisons.
16321644 /// Currently, the following ops are supported:
16331645 /// ADD, SUB, XOR, OR, AND
1634 fn genX8664BinMath(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst) !MCValue {
1646 fn genX8664BinMath(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
16351647 // We'll handle these ops in two steps.
16361648 // 1) Prepare an output location (register or memory)
16371649 // This location will be the location of the operand that dies (if one exists)
......@@ -1654,7 +1666,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16541666 // as the result MCValue.
16551667 var dst_mcv: MCValue = undefined;
16561668 var src_mcv: MCValue = undefined;
1657 var src_inst: *ir.Inst = undefined;
1669 var src_inst: Air.Inst.Index = undefined;
16581670 if (self.reuseOperand(inst, 0, lhs)) {
16591671 // LHS dies; use it as the destination.
16601672 // Both operands cannot be memory.
......@@ -1696,20 +1708,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16961708 switch (src_mcv) {
16971709 .immediate => |imm| {
16981710 if (imm > math.maxInt(u31)) {
1699 src_mcv = MCValue{ .register = try self.copyToTmpRegister(src_inst.src, Type.initTag(.u64), src_mcv) };
1711 src_mcv = MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.u64), src_mcv) };
17001712 }
17011713 },
17021714 else => {},
17031715 }
17041716
17051717 // Now for step 2, we perform the actual op
1706 switch (inst.tag) {
1718 const air_tags = self.air.instructions.items(.tag);
1719 switch (air_tags[inst]) {
17071720 // TODO: Generate wrapping and non-wrapping versions separately
1708 .add, .addwrap => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 0, 0x00),
1709 .bool_or, .bit_or => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 1, 0x08),
1710 .bool_and, .bit_and => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 4, 0x20),
1711 .sub, .subwrap => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 5, 0x28),
1712 .xor, .not => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 6, 0x30),
1721 .add, .addwrap => try self.genX8664BinMathCode(inst.ty, dst_mcv, src_mcv, 0, 0x00),
1722 .bool_or, .bit_or => try self.genX8664BinMathCode(inst.ty, dst_mcv, src_mcv, 1, 0x08),
1723 .bool_and, .bit_and => try self.genX8664BinMathCode(inst.ty, dst_mcv, src_mcv, 4, 0x20),
1724 .sub, .subwrap => try self.genX8664BinMathCode(inst.ty, dst_mcv, src_mcv, 5, 0x28),
1725 .xor, .not => try self.genX8664BinMathCode(inst.ty, dst_mcv, src_mcv, 6, 0x30),
17131726
17141727 .mul, .mulwrap => try self.genX8664Imul(inst.src, inst.ty, dst_mcv, src_mcv),
17151728 else => unreachable,
......@@ -1719,16 +1732,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
17191732 }
17201733
17211734 /// Wrap over Instruction.encodeInto to translate errors
1722 fn encodeX8664Instruction(
1723 self: *Self,
1724 src: LazySrcLoc,
1725 inst: Instruction,
1726 ) !void {
1735 fn encodeX8664Instruction(self: *Self, inst: Instruction) !void {
17271736 inst.encodeInto(self.code) catch |err| {
17281737 if (err == error.OutOfMemory)
17291738 return error.OutOfMemory
17301739 else
1731 return self.fail(src, "Instruction.encodeInto failed because {s}", .{@errorName(err)});
1740 return self.fail("Instruction.encodeInto failed because {s}", .{@errorName(err)});
17321741 };
17331742 }
17341743
......@@ -1800,7 +1809,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18001809 /// d3 /opx | *r/m16/32/64*, CL (for context, CL is register 1)
18011810 fn genX8664BinMathCode(
18021811 self: *Self,
1803 src: LazySrcLoc,
18041812 dst_ty: Type,
18051813 dst_mcv: MCValue,
18061814 src_mcv: MCValue,
......@@ -1818,7 +1826,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18181826 .register => |dst_reg| {
18191827 switch (src_mcv) {
18201828 .none => unreachable,
1821 .undef => try self.genSetReg(src, dst_ty, dst_reg, .undef),
1829 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),
18221830 .dead, .unreach => unreachable,
18231831 .ptr_stack_offset => unreachable,
18241832 .ptr_embedded_in_code => unreachable,
......@@ -1872,7 +1880,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18721880 }
18731881 },
18741882 .embedded_in_code, .memory => {
1875 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source memory", .{});
1883 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
18761884 },
18771885 .stack_offset => |off| {
18781886 // register, indirect use mr + 3
......@@ -1880,7 +1888,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18801888 const abi_size = dst_ty.abiSize(self.target.*);
18811889 const adj_off = off + abi_size;
18821890 if (off > math.maxInt(i32)) {
1883 return self.fail(src, "stack offset too large", .{});
1891 return self.fail("stack offset too large", .{});
18841892 }
18851893 const encoder = try X8664Encoder.init(self.code, 7);
18861894 encoder.rex(.{
......@@ -1903,17 +1911,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19031911 }
19041912 },
19051913 .compare_flags_unsigned => {
1906 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});
1914 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});
19071915 },
19081916 .compare_flags_signed => {
1909 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source compare flag (signed)", .{});
1917 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (signed)", .{});
19101918 },
19111919 }
19121920 },
19131921 .stack_offset => |off| {
19141922 switch (src_mcv) {
19151923 .none => unreachable,
1916 .undef => return self.genSetStack(src, dst_ty, off, .undef),
1924 .undef => return self.genSetStack(dst_ty, off, .undef),
19171925 .dead, .unreach => unreachable,
19181926 .ptr_stack_offset => unreachable,
19191927 .ptr_embedded_in_code => unreachable,
......@@ -1922,21 +1930,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19221930 },
19231931 .immediate => |imm| {
19241932 _ = imm;
1925 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source immediate", .{});
1933 return self.fail("TODO implement x86 ADD/SUB/CMP source immediate", .{});
19261934 },
19271935 .embedded_in_code, .memory, .stack_offset => {
1928 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source memory", .{});
1936 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
19291937 },
19301938 .compare_flags_unsigned => {
1931 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});
1939 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});
19321940 },
19331941 .compare_flags_signed => {
1934 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source compare flag (signed)", .{});
1942 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (signed)", .{});
19351943 },
19361944 }
19371945 },
19381946 .embedded_in_code, .memory => {
1939 return self.fail(src, "TODO implement x86 ADD/SUB/CMP destination memory", .{});
1947 return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});
19401948 },
19411949 }
19421950 }
......@@ -1960,7 +1968,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19601968 .register => |dst_reg| {
19611969 switch (src_mcv) {
19621970 .none => unreachable,
1963 .undef => try self.genSetReg(src, dst_ty, dst_reg, .undef),
1971 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),
19641972 .dead, .unreach => unreachable,
19651973 .ptr_stack_offset => unreachable,
19661974 .ptr_embedded_in_code => unreachable,
......@@ -2026,31 +2034,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20262034 );
20272035 encoder.imm32(@intCast(i32, imm));
20282036 } else {
2029 const src_reg = try self.copyToTmpRegister(src, dst_ty, src_mcv);
2037 const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);
20302038 return self.genX8664Imul(src, dst_ty, dst_mcv, MCValue{ .register = src_reg });
20312039 }
20322040 },
20332041 .embedded_in_code, .memory, .stack_offset => {
2034 return self.fail(src, "TODO implement x86 multiply source memory", .{});
2042 return self.fail("TODO implement x86 multiply source memory", .{});
20352043 },
20362044 .compare_flags_unsigned => {
2037 return self.fail(src, "TODO implement x86 multiply source compare flag (unsigned)", .{});
2045 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});
20382046 },
20392047 .compare_flags_signed => {
2040 return self.fail(src, "TODO implement x86 multiply source compare flag (signed)", .{});
2048 return self.fail("TODO implement x86 multiply source compare flag (signed)", .{});
20412049 },
20422050 }
20432051 },
20442052 .stack_offset => |off| {
20452053 switch (src_mcv) {
20462054 .none => unreachable,
2047 .undef => return self.genSetStack(src, dst_ty, off, .undef),
2055 .undef => return self.genSetStack(dst_ty, off, .undef),
20482056 .dead, .unreach => unreachable,
20492057 .ptr_stack_offset => unreachable,
20502058 .ptr_embedded_in_code => unreachable,
20512059 .register => |src_reg| {
20522060 // copy dst to a register
2053 const dst_reg = try self.copyToTmpRegister(src, dst_ty, dst_mcv);
2061 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
20542062 // multiply into dst_reg
20552063 // register, register
20562064 // Use the following imul opcode
......@@ -2068,34 +2076,34 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20682076 src_reg.low_id(),
20692077 );
20702078 // copy dst_reg back out
2071 return self.genSetStack(src, dst_ty, off, MCValue{ .register = dst_reg });
2079 return self.genSetStack(dst_ty, off, MCValue{ .register = dst_reg });
20722080 },
20732081 .immediate => |imm| {
20742082 _ = imm;
2075 return self.fail(src, "TODO implement x86 multiply source immediate", .{});
2083 return self.fail("TODO implement x86 multiply source immediate", .{});
20762084 },
20772085 .embedded_in_code, .memory, .stack_offset => {
2078 return self.fail(src, "TODO implement x86 multiply source memory", .{});
2086 return self.fail("TODO implement x86 multiply source memory", .{});
20792087 },
20802088 .compare_flags_unsigned => {
2081 return self.fail(src, "TODO implement x86 multiply source compare flag (unsigned)", .{});
2089 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});
20822090 },
20832091 .compare_flags_signed => {
2084 return self.fail(src, "TODO implement x86 multiply source compare flag (signed)", .{});
2092 return self.fail("TODO implement x86 multiply source compare flag (signed)", .{});
20852093 },
20862094 }
20872095 },
20882096 .embedded_in_code, .memory => {
2089 return self.fail(src, "TODO implement x86 multiply destination memory", .{});
2097 return self.fail("TODO implement x86 multiply destination memory", .{});
20902098 },
20912099 }
20922100 }
20932101
2094 fn genX8664ModRMRegToStack(self: *Self, src: LazySrcLoc, ty: Type, off: u32, reg: Register, opcode: u8) !void {
2102 fn genX8664ModRMRegToStack(self: *Self, ty: Type, off: u32, reg: Register, opcode: u8) !void {
20952103 const abi_size = ty.abiSize(self.target.*);
20962104 const adj_off = off + abi_size;
20972105 if (off > math.maxInt(i32)) {
2098 return self.fail(src, "stack offset too large", .{});
2106 return self.fail("stack offset too large", .{});
20992107 }
21002108
21012109 const i_adj_off = -@intCast(i32, adj_off);
......@@ -2122,8 +2130,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21222130 }
21232131 }
21242132
2125 fn genArgDbgInfo(self: *Self, inst: *ir.Inst.Arg, mcv: MCValue) !void {
2133 fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void {
21262134 const name_with_null = inst.name[0 .. mem.lenZ(inst.name) + 1];
2135 const ty = self.air.getType(inst);
21272136
21282137 switch (mcv) {
21292138 .register => |reg| {
......@@ -2136,7 +2145,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21362145 reg.dwarfLocOp(),
21372146 });
21382147 try dbg_out.dbg_info.ensureCapacity(dbg_out.dbg_info.items.len + 5 + name_with_null.len);
2139 try self.addDbgInfoTypeReloc(inst.base.ty); // DW.AT_type, DW.FORM_ref4
2148 try self.addDbgInfoTypeReloc(ty); // DW.AT_type, DW.FORM_ref4
21402149 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT_name, DW.FORM_string
21412150 },
21422151 .none => {},
......@@ -2147,12 +2156,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21472156 .dwarf => |dbg_out| {
21482157 switch (arch) {
21492158 .arm, .armeb => {
2150 const ty = inst.base.ty;
21512159 const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch {
2152 return self.fail(inst.base.src, "type '{}' too big to fit into stack frame", .{ty});
2160 return self.fail("type '{}' too big to fit into stack frame", .{ty});
21532161 };
21542162 const adjusted_stack_offset = math.negateCast(offset + abi_size) catch {
2155 return self.fail(inst.base.src, "Stack offset too large for arguments", .{});
2163 return self.fail("Stack offset too large for arguments", .{});
21562164 };
21572165
21582166 try dbg_out.dbg_info.append(link.File.Elf.abbrev_parameter);
......@@ -2168,7 +2176,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21682176 try leb128.writeILEB128(dbg_out.dbg_info.writer(), adjusted_stack_offset);
21692177
21702178 try dbg_out.dbg_info.ensureCapacity(dbg_out.dbg_info.items.len + 5 + name_with_null.len);
2171 try self.addDbgInfoTypeReloc(inst.base.ty); // DW.AT_type, DW.FORM_ref4
2179 try self.addDbgInfoTypeReloc(ty); // DW.AT_type, DW.FORM_ref4
21722180 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT_name, DW.FORM_string
21732181 },
21742182 else => {},
......@@ -2181,23 +2189,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21812189 }
21822190 }
21832191
2184 fn genArg(self: *Self, inst: *ir.Inst.Arg) !MCValue {
2192 fn genArg(self: *Self, inst: Air.Inst.Index) !MCValue {
21852193 const arg_index = self.arg_index;
21862194 self.arg_index += 1;
21872195
2196 const ty = self.air.getType(inst);
2197
21882198 const result = self.args[arg_index];
21892199 const mcv = switch (arch) {
21902200 // TODO support stack-only arguments on all target architectures
21912201 .arm, .armeb, .aarch64, .aarch64_32, .aarch64_be => switch (result) {
21922202 // Copy registers to the stack
21932203 .register => |reg| blk: {
2194 const ty = inst.base.ty;
21952204 const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch {
2196 return self.fail(inst.base.src, "type '{}' too big to fit into stack frame", .{ty});
2205 return self.fail("type '{}' too big to fit into stack frame", .{ty});
21972206 };
21982207 const abi_align = ty.abiAlignment(self.target.*);
2199 const stack_offset = try self.allocMem(&inst.base, abi_size, abi_align);
2200 try self.genSetStack(inst.base.src, ty, stack_offset, MCValue{ .register = reg });
2208 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
2209 try self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
22012210
22022211 break :blk MCValue{ .stack_offset = stack_offset };
22032212 },
......@@ -2207,12 +2216,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22072216 };
22082217 try self.genArgDbgInfo(inst, mcv);
22092218
2210 if (inst.base.isUnused())
2219 if (self.liveness.isUnused(inst))
22112220 return MCValue.dead;
22122221
22132222 switch (mcv) {
22142223 .register => |reg| {
2215 self.register_manager.getRegAssumeFree(toCanonicalReg(reg), &inst.base);
2224 self.register_manager.getRegAssumeFree(toCanonicalReg(reg), inst);
22162225 },
22172226 else => {},
22182227 }
......@@ -2220,7 +2229,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22202229 return mcv;
22212230 }
22222231
2223 fn genBreakpoint(self: *Self, src: LazySrcLoc) !MCValue {
2232 fn genBreakpoint(self: *Self) !MCValue {
22242233 switch (arch) {
22252234 .i386, .x86_64 => {
22262235 try self.code.append(0xcc); // int3
......@@ -2234,13 +2243,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22342243 .aarch64 => {
22352244 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.brk(1).toU32());
22362245 },
2237 else => return self.fail(src, "TODO implement @breakpoint() for {}", .{self.target.cpu.arch}),
2246 else => return self.fail("TODO implement @breakpoint() for {}", .{self.target.cpu.arch}),
22382247 }
22392248 return .none;
22402249 }
22412250
2242 fn genCall(self: *Self, inst: *ir.Inst.Call) !MCValue {
2243 var info = try self.resolveCallingConventionValues(inst.base.src, inst.func.ty);
2251 fn genCall(self: *Self, inst: Air.Inst.Index) !MCValue {
2252 const inst_datas = self.air.instructions.items(.data);
2253 const pl_op = inst_datas[inst].pl_op;
2254 const fn_ty = self.air.getType(pl_op.operand);
2255 const callee = pl_op.operand;
2256 const extra = self.air.extraData(Air.Call, inst_data.payload);
2257 const args = self.air.extra[extra.end..][0..extra.data.args_len];
2258
2259 var info = try self.resolveCallingConventionValues(fn_ty);
22442260 defer info.deinit(self);
22452261
22462262 // Due to incremental compilation, how function calls are generated depends
......@@ -2249,26 +2265,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22492265 switch (arch) {
22502266 .x86_64 => {
22512267 for (info.args) |mc_arg, arg_i| {
2252 const arg = inst.args[arg_i];
2253 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
2268 const arg = args[arg_i];
2269 const arg_mcv = try self.resolveInst(args[arg_i]);
22542270 // Here we do not use setRegOrMem even though the logic is similar, because
22552271 // the function call will move the stack pointer, so the offsets are different.
22562272 switch (mc_arg) {
22572273 .none => continue,
22582274 .register => |reg| {
22592275 try self.register_manager.getReg(reg, null);
2260 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2276 try self.genSetReg(arg.ty, reg, arg_mcv);
22612277 },
22622278 .stack_offset => |off| {
22632279 // Here we need to emit instructions like this:
22642280 // mov qword ptr [rsp + stack_offset], x
2265 try self.genSetStack(arg.src, arg.ty, off, arg_mcv);
2281 try self.genSetStack(arg.ty, off, arg_mcv);
22662282 },
22672283 .ptr_stack_offset => {
2268 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
2284 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
22692285 },
22702286 .ptr_embedded_in_code => {
2271 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
2287 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
22722288 },
22732289 .undef => unreachable,
22742290 .immediate => unreachable,
......@@ -2281,7 +2297,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22812297 }
22822298 }
22832299
2284 if (inst.func.value()) |func_value| {
2300 if (self.air.value(callee)) |func_value| {
22852301 if (func_value.castTag(.function)) |func_payload| {
22862302 const func = func_payload.data;
22872303
......@@ -2300,18 +2316,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
23002316 self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
23012317 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr);
23022318 } else if (func_value.castTag(.extern_fn)) |_| {
2303 return self.fail(inst.base.src, "TODO implement calling extern functions", .{});
2319 return self.fail("TODO implement calling extern functions", .{});
23042320 } else {
2305 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
2321 return self.fail("TODO implement calling bitcasted functions", .{});
23062322 }
23072323 } else {
2308 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
2324 return self.fail("TODO implement calling runtime known function pointer", .{});
23092325 }
23102326 },
23112327 .riscv64 => {
2312 if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
2328 if (info.args.len > 0) return self.fail("TODO implement fn args for {}", .{self.target.cpu.arch});
23132329
2314 if (inst.func.value()) |func_value| {
2330 if (self.air.value(callee)) |func_value| {
23152331 if (func_value.castTag(.function)) |func_payload| {
23162332 const func = func_payload.data;
23172333
......@@ -2325,21 +2341,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
23252341 else
23262342 unreachable;
23272343
2328 try self.genSetReg(inst.base.src, Type.initTag(.usize), .ra, .{ .memory = got_addr });
2344 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
23292345 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());
23302346 } else if (func_value.castTag(.extern_fn)) |_| {
2331 return self.fail(inst.base.src, "TODO implement calling extern functions", .{});
2347 return self.fail("TODO implement calling extern functions", .{});
23322348 } else {
2333 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
2349 return self.fail("TODO implement calling bitcasted functions", .{});
23342350 }
23352351 } else {
2336 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
2352 return self.fail("TODO implement calling runtime known function pointer", .{});
23372353 }
23382354 },
23392355 .arm, .armeb => {
23402356 for (info.args) |mc_arg, arg_i| {
2341 const arg = inst.args[arg_i];
2342 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
2357 const arg = args[arg_i];
2358 const arg_mcv = try self.resolveInst(args[arg_i]);
23432359
23442360 switch (mc_arg) {
23452361 .none => continue,
......@@ -2353,21 +2369,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
23532369 .compare_flags_unsigned => unreachable,
23542370 .register => |reg| {
23552371 try self.register_manager.getReg(reg, null);
2356 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2372 try self.genSetReg(arg.ty, reg, arg_mcv);
23572373 },
23582374 .stack_offset => {
2359 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
2375 return self.fail("TODO implement calling with parameters in memory", .{});
23602376 },
23612377 .ptr_stack_offset => {
2362 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
2378 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
23632379 },
23642380 .ptr_embedded_in_code => {
2365 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
2381 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
23662382 },
23672383 }
23682384 }
23692385
2370 if (inst.func.value()) |func_value| {
2386 if (self.air.value(callee)) |func_value| {
23712387 if (func_value.castTag(.function)) |func_payload| {
23722388 const func = func_payload.data;
23732389 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
......@@ -2380,7 +2396,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
23802396 else
23812397 unreachable;
23822398
2383 try self.genSetReg(inst.base.src, Type.initTag(.usize), .lr, .{ .memory = got_addr });
2399 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
23842400
23852401 // TODO: add Instruction.supportedOn
23862402 // function for ARM
......@@ -2391,18 +2407,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
23912407 writeInt(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32());
23922408 }
23932409 } else if (func_value.castTag(.extern_fn)) |_| {
2394 return self.fail(inst.base.src, "TODO implement calling extern functions", .{});
2410 return self.fail("TODO implement calling extern functions", .{});
23952411 } else {
2396 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
2412 return self.fail("TODO implement calling bitcasted functions", .{});
23972413 }
23982414 } else {
2399 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
2415 return self.fail("TODO implement calling runtime known function pointer", .{});
24002416 }
24012417 },
24022418 .aarch64 => {
24032419 for (info.args) |mc_arg, arg_i| {
2404 const arg = inst.args[arg_i];
2405 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
2420 const arg = args[arg_i];
2421 const arg_mcv = try self.resolveInst(args[arg_i]);
24062422
24072423 switch (mc_arg) {
24082424 .none => continue,
......@@ -2416,21 +2432,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
24162432 .compare_flags_unsigned => unreachable,
24172433 .register => |reg| {
24182434 try self.register_manager.getReg(reg, null);
2419 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2435 try self.genSetReg(arg.ty, reg, arg_mcv);
24202436 },
24212437 .stack_offset => {
2422 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
2438 return self.fail("TODO implement calling with parameters in memory", .{});
24232439 },
24242440 .ptr_stack_offset => {
2425 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
2441 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
24262442 },
24272443 .ptr_embedded_in_code => {
2428 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
2444 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
24292445 },
24302446 }
24312447 }
24322448
2433 if (inst.func.value()) |func_value| {
2449 if (self.air.value(callee)) |func_value| {
24342450 if (func_value.castTag(.function)) |func_payload| {
24352451 const func = func_payload.data;
24362452 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
......@@ -2443,24 +2459,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
24432459 else
24442460 unreachable;
24452461
2446 try self.genSetReg(inst.base.src, Type.initTag(.usize), .x30, .{ .memory = got_addr });
2462 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
24472463
24482464 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
24492465 } else if (func_value.castTag(.extern_fn)) |_| {
2450 return self.fail(inst.base.src, "TODO implement calling extern functions", .{});
2466 return self.fail("TODO implement calling extern functions", .{});
24512467 } else {
2452 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
2468 return self.fail("TODO implement calling bitcasted functions", .{});
24532469 }
24542470 } else {
2455 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
2471 return self.fail("TODO implement calling runtime known function pointer", .{});
24562472 }
24572473 },
2458 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
2474 else => return self.fail("TODO implement call for {}", .{self.target.cpu.arch}),
24592475 }
24602476 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
24612477 for (info.args) |mc_arg, arg_i| {
2462 const arg = inst.args[arg_i];
2463 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
2478 const arg = args[arg_i];
2479 const arg_mcv = try self.resolveInst(args[arg_i]);
24642480 // Here we do not use setRegOrMem even though the logic is similar, because
24652481 // the function call will move the stack pointer, so the offsets are different.
24662482 switch (mc_arg) {
......@@ -2471,18 +2487,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
24712487 .x86_64, .aarch64 => try self.register_manager.getReg(reg, null),
24722488 else => unreachable,
24732489 }
2474 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2490 try self.genSetReg(arg.ty, reg, arg_mcv);
24752491 },
24762492 .stack_offset => {
24772493 // Here we need to emit instructions like this:
24782494 // mov qword ptr [rsp + stack_offset], x
2479 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
2495 return self.fail("TODO implement calling with parameters in memory", .{});
24802496 },
24812497 .ptr_stack_offset => {
2482 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
2498 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
24832499 },
24842500 .ptr_embedded_in_code => {
2485 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
2501 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
24862502 },
24872503 .undef => unreachable,
24882504 .immediate => unreachable,
......@@ -2495,7 +2511,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
24952511 }
24962512 }
24972513
2498 if (inst.func.value()) |func_value| {
2514 if (self.air.value(callee)) |func_value| {
24992515 if (func_value.castTag(.function)) |func_payload| {
25002516 const func = func_payload.data;
25012517 const got_addr = blk: {
......@@ -2506,13 +2522,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
25062522 log.debug("got_addr = 0x{x}", .{got_addr});
25072523 switch (arch) {
25082524 .x86_64 => {
2509 try self.genSetReg(inst.base.src, Type.initTag(.u64), .rax, .{ .memory = got_addr });
2525 try self.genSetReg(Type.initTag(.u64), .rax, .{ .memory = got_addr });
25102526 // callq *%rax
25112527 try self.code.ensureCapacity(self.code.items.len + 2);
25122528 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
25132529 },
25142530 .aarch64 => {
2515 try self.genSetReg(inst.base.src, Type.initTag(.u64), .x30, .{ .memory = got_addr });
2531 try self.genSetReg(Type.initTag(.u64), .x30, .{ .memory = got_addr });
25162532 // blr x30
25172533 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
25182534 },
......@@ -2552,35 +2568,35 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
25522568 });
25532569 // We mark the space and fix it up later.
25542570 } else {
2555 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
2571 return self.fail("TODO implement calling bitcasted functions", .{});
25562572 }
25572573 } else {
2558 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
2574 return self.fail("TODO implement calling runtime known function pointer", .{});
25592575 }
25602576 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
25612577 switch (arch) {
25622578 .x86_64 => {
25632579 for (info.args) |mc_arg, arg_i| {
2564 const arg = inst.args[arg_i];
2565 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
2580 const arg = args[arg_i];
2581 const arg_mcv = try self.resolveInst(args[arg_i]);
25662582 // Here we do not use setRegOrMem even though the logic is similar, because
25672583 // the function call will move the stack pointer, so the offsets are different.
25682584 switch (mc_arg) {
25692585 .none => continue,
25702586 .register => |reg| {
25712587 try self.register_manager.getReg(reg, null);
2572 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2588 try self.genSetReg(arg.ty, reg, arg_mcv);
25732589 },
25742590 .stack_offset => {
25752591 // Here we need to emit instructions like this:
25762592 // mov qword ptr [rsp + stack_offset], x
2577 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
2593 return self.fail("TODO implement calling with parameters in memory", .{});
25782594 },
25792595 .ptr_stack_offset => {
2580 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
2596 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
25812597 },
25822598 .ptr_embedded_in_code => {
2583 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
2599 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
25842600 },
25852601 .undef => unreachable,
25862602 .immediate => unreachable,
......@@ -2592,7 +2608,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
25922608 .compare_flags_unsigned => unreachable,
25932609 }
25942610 }
2595 if (inst.func.value()) |func_value| {
2611 if (self.air.value(callee)) |func_value| {
25962612 if (func_value.castTag(.function)) |func_payload| {
25972613 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
25982614 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
......@@ -2603,9 +2619,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26032619 self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
26042620 const fn_got_addr = got_addr + got_index * ptr_bytes;
26052621 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), @intCast(u32, fn_got_addr));
2606 } else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{});
2622 } else return self.fail("TODO implement calling extern fn on plan9", .{});
26072623 } else {
2608 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
2624 return self.fail("TODO implement calling runtime known function pointer", .{});
26092625 }
26102626 },
26112627 .aarch64 => {
......@@ -2628,13 +2644,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26282644 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
26292645 },
26302646 .stack_offset => {
2631 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
2647 return self.fail("TODO implement calling with parameters in memory", .{});
26322648 },
26332649 .ptr_stack_offset => {
2634 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
2650 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
26352651 },
26362652 .ptr_embedded_in_code => {
2637 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
2653 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
26382654 },
26392655 }
26402656 }
......@@ -2650,15 +2666,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26502666
26512667 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
26522668 } else if (func_value.castTag(.extern_fn)) |_| {
2653 return self.fail(inst.base.src, "TODO implement calling extern functions", .{});
2669 return self.fail("TODO implement calling extern functions", .{});
26542670 } else {
2655 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
2671 return self.fail("TODO implement calling bitcasted functions", .{});
26562672 }
26572673 } else {
2658 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
2674 return self.fail("TODO implement calling runtime known function pointer", .{});
26592675 }
26602676 },
2661 else => return self.fail(inst.base.src, "TODO implement call on plan9 for {}", .{self.target.cpu.arch}),
2677 else => return self.fail("TODO implement call on plan9 for {}", .{self.target.cpu.arch}),
26622678 }
26632679 } else unreachable;
26642680
......@@ -2666,7 +2682,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26662682 .register => |reg| {
26672683 if (Register.allocIndex(reg) == null) {
26682684 // Save function return value in a callee saved register
2669 return try self.copyToNewRegister(&inst.base, info.return_value);
2685 return try self.copyToNewRegister(inst, info.return_value);
26702686 }
26712687 },
26722688 else => {},
......@@ -2675,8 +2691,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26752691 return info.return_value;
26762692 }
26772693
2678 fn genRef(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
2679 const operand = try self.resolveInst(inst.operand);
2694 fn genRef(self: *Self, inst: Air.Inst.Index) !MCValue {
2695 if (self.liveness.isUnused(inst))
2696 return MCValue.dead;
2697 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2698 const operand_ty = self.air.getType(ty_op.operand);
2699 const operand = try self.resolveInst(ty_op.operand);
26802700 switch (operand) {
26812701 .unreach => unreachable,
26822702 .dead => unreachable,
......@@ -2689,8 +2709,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26892709 .compare_flags_unsigned,
26902710 .compare_flags_signed,
26912711 => {
2692 const stack_offset = try self.allocMemPtr(&inst.base);
2693 try self.genSetStack(inst.base.src, inst.operand.ty, stack_offset, operand);
2712 const stack_offset = try self.allocMemPtr(inst);
2713 try self.genSetStack(operand_ty, stack_offset, operand);
26942714 return MCValue{ .ptr_stack_offset = stack_offset };
26952715 },
26962716
......@@ -2698,13 +2718,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26982718 .embedded_in_code => |offset| return MCValue{ .ptr_embedded_in_code = offset },
26992719 .memory => |vaddr| return MCValue{ .immediate = vaddr },
27002720
2701 .undef => return self.fail(inst.base.src, "TODO implement ref on an undefined value", .{}),
2721 .undef => return self.fail("TODO implement ref on an undefined value", .{}),
27022722 }
27032723 }
27042724
2705 fn ret(self: *Self, src: LazySrcLoc, mcv: MCValue) !MCValue {
2725 fn ret(self: *Self, mcv: MCValue) !MCValue {
27062726 const ret_ty = self.fn_type.fnReturnType();
2707 try self.setRegOrMem(src, ret_ty, self.ret_mcv, mcv);
2727 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
27082728 switch (arch) {
27092729 .i386 => {
27102730 try self.code.append(0xc3); // ret
......@@ -2730,58 +2750,54 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27302750 try self.code.resize(self.code.items.len + 4);
27312751 try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);
27322752 },
2733 else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
2753 else => return self.fail("TODO implement return for {}", .{self.target.cpu.arch}),
27342754 }
27352755 return .unreach;
27362756 }
27372757
2738 fn genRet(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
2739 const operand = try self.resolveInst(inst.operand);
2758 fn genRet(self: *Self, inst: Air.Inst.Index) !MCValue {
2759 const operand = try self.resolveInst(self.air.instructions.items(.data)[inst].un_op);
27402760 return self.ret(inst.base.src, operand);
27412761 }
27422762
2743 fn genRetVoid(self: *Self, inst: *ir.Inst.NoOp) !MCValue {
2744 return self.ret(inst.base.src, .none);
2745 }
2746
2747 fn genCmp(self: *Self, inst: *ir.Inst.BinOp, op: math.CompareOperator) !MCValue {
2763 fn genCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !MCValue {
27482764 // No side effects, so if it's unreferenced, do nothing.
2749 if (inst.base.isUnused())
2750 return MCValue{ .dead = {} };
2751 if (inst.lhs.ty.zigTypeTag() == .ErrorSet or inst.rhs.ty.zigTypeTag() == .ErrorSet)
2752 return self.fail(inst.base.src, "TODO implement cmp for errors", .{});
2765 if (self.liveness.isUnused(inst))
2766 return MCValue.dead;
2767 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2768 const ty = self.air.getType(bin_op.lhs);
2769 assert(ty.eql(self.air.getType(bin_op.rhs)));
2770 if (ty.zigTypeTag() == .ErrorSet)
2771 return self.fail("TODO implement cmp for errors", .{});
2772
2773 const lhs = try self.resolveInst(bin_op.lhs);
2774 const rhs = try self.resolveInst(bin_op.rhs);
27532775 switch (arch) {
27542776 .x86_64 => {
27552777 try self.code.ensureCapacity(self.code.items.len + 8);
27562778
2757 const lhs = try self.resolveInst(inst.lhs);
2758 const rhs = try self.resolveInst(inst.rhs);
2759
27602779 // There are 2 operands, destination and source.
27612780 // Either one, but not both, can be a memory operand.
27622781 // Source operand can be an immediate, 8 bits or 32 bits.
27632782 const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory()))
2764 try self.copyToNewRegister(&inst.base, lhs)
2783 try self.copyToNewRegister(inst, lhs)
27652784 else
27662785 lhs;
27672786 // This instruction supports only signed 32-bit immediates at most.
2768 const src_mcv = try self.limitImmediateType(inst.rhs, i32);
2787 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);
27692788
2770 try self.genX8664BinMathCode(inst.base.src, inst.base.ty, dst_mcv, src_mcv, 7, 0x38);
2771 const info = inst.lhs.ty.intInfo(self.target.*);
2789 try self.genX8664BinMathCode(Type.initTag(.bool), dst_mcv, src_mcv, 7, 0x38);
2790 const info = ty.intInfo(self.target.*);
27722791 return switch (info.signedness) {
27732792 .signed => MCValue{ .compare_flags_signed = op },
27742793 .unsigned => MCValue{ .compare_flags_unsigned = op },
27752794 };
27762795 },
27772796 .arm, .armeb => {
2778 const lhs = try self.resolveInst(inst.lhs);
2779 const rhs = try self.resolveInst(inst.rhs);
2780
27812797 const lhs_is_register = lhs == .register;
27822798 const rhs_is_register = rhs == .register;
27832799 // lhs should always be a register
2784 const rhs_should_be_register = try self.armOperandShouldBeRegister(inst.rhs.src, rhs);
2800 const rhs_should_be_register = try self.armOperandShouldBeRegister(rhs);
27852801
27862802 var lhs_mcv = lhs;
27872803 var rhs_mcv = rhs;
......@@ -2789,49 +2805,55 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27892805 // Allocate registers
27902806 if (rhs_should_be_register) {
27912807 if (!lhs_is_register and !rhs_is_register) {
2792 const regs = try self.register_manager.allocRegs(2, .{ inst.rhs, inst.lhs }, &.{});
2808 const regs = try self.register_manager.allocRegs(2, .{ bin_op.rhs, bin_op.lhs }, &.{});
27932809 lhs_mcv = MCValue{ .register = regs[0] };
27942810 rhs_mcv = MCValue{ .register = regs[1] };
27952811 } else if (!rhs_is_register) {
2796 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(inst.rhs, &.{}) };
2812 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(bin_op.rhs, &.{}) };
27972813 }
27982814 }
27992815 if (!lhs_is_register) {
2800 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(inst.lhs, &.{}) };
2816 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(bin_op.lhs, &.{}) };
28012817 }
28022818
28032819 // Move the operands to the newly allocated registers
28042820 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
28052821 if (lhs_mcv == .register and !lhs_is_register) {
2806 try self.genSetReg(inst.lhs.src, inst.lhs.ty, lhs_mcv.register, lhs);
2807 branch.inst_table.putAssumeCapacity(inst.lhs, lhs);
2822 try self.genSetReg(ty, lhs_mcv.register, lhs);
2823 branch.inst_table.putAssumeCapacity(bin_op.lhs, lhs);
28082824 }
28092825 if (rhs_mcv == .register and !rhs_is_register) {
2810 try self.genSetReg(inst.rhs.src, inst.rhs.ty, rhs_mcv.register, rhs);
2811 branch.inst_table.putAssumeCapacity(inst.rhs, rhs);
2826 try self.genSetReg(ty, rhs_mcv.register, rhs);
2827 branch.inst_table.putAssumeCapacity(bin_op.rhs, rhs);
28122828 }
28132829
28142830 // The destination register is not present in the cmp instruction
2815 try self.genArmBinOpCode(inst.base.src, undefined, lhs_mcv, rhs_mcv, false, .cmp_eq);
2831 try self.genArmBinOpCode(undefined, lhs_mcv, rhs_mcv, false, .cmp_eq);
28162832
2817 const info = inst.lhs.ty.intInfo(self.target.*);
2833 const info = ty.intInfo(self.target.*);
28182834 return switch (info.signedness) {
28192835 .signed => MCValue{ .compare_flags_signed = op },
28202836 .unsigned => MCValue{ .compare_flags_unsigned = op },
28212837 };
28222838 },
2823 else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}),
2839 else => return self.fail("TODO implement cmp for {}", .{self.target.cpu.arch}),
28242840 }
28252841 }
28262842
2827 fn genDbgStmt(self: *Self, inst: *ir.Inst.DbgStmt) !MCValue {
2828 try self.dbgAdvancePCAndLine(inst.line, inst.column);
2829 assert(inst.base.isUnused());
2843 fn genDbgStmt(self: *Self, inst: Air.Inst.Index) !MCValue {
2844 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
2845 try self.dbgAdvancePCAndLine(dbg_stmt.line, dbg_stmt.column);
2846 assert(self.liveness.isUnused(inst));
28302847 return MCValue.dead;
28312848 }
28322849
2833 fn genCondBr(self: *Self, inst: *ir.Inst.CondBr) !MCValue {
2834 const cond = try self.resolveInst(inst.condition);
2850 fn genCondBr(self: *Self, inst: Air.Inst.Index) !MCValue {
2851 const inst_datas = self.air.instructions.items(.data);
2852 const pl_op = inst_datas[inst].pl_op;
2853 const cond = try self.resolveInst(pl_op.operand);
2854 const extra = self.air.extraData(Air.CondBr, inst_data.payload);
2855 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
2856 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
28352857
28362858 const reloc: Reloc = switch (arch) {
28372859 .i386, .x86_64 => reloc: {
......@@ -2880,7 +2902,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
28802902 encoder.disp8(1);
28812903 break :blk 0x84;
28822904 },
2883 else => return self.fail(inst.base.src, "TODO implement condbr {s} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }),
2905 else => return self.fail("TODO implement condbr {s} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }),
28842906 };
28852907 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x0f, opcode });
28862908 const reloc = Reloc{ .rel32 = self.code.items.len };
......@@ -2906,7 +2928,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29062928 writeInt(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, reg, op).toU32());
29072929 break :blk .ne;
29082930 },
2909 else => return self.fail(inst.base.src, "TODO implement condbr {} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }),
2931 else => return self.fail("TODO implement condbr {} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }),
29102932 };
29112933
29122934 const reloc = Reloc{
......@@ -2918,7 +2940,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29182940 try self.code.resize(self.code.items.len + 4);
29192941 break :reloc reloc;
29202942 },
2921 else => return self.fail(inst.base.src, "TODO implement condbr {}", .{self.target.cpu.arch}),
2943 else => return self.fail("TODO implement condbr {}", .{self.target.cpu.arch}),
29222944 };
29232945
29242946 // Capture the state of register and stack allocation state so that we can revert to it.
......@@ -2930,12 +2952,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29302952
29312953 try self.branch_stack.append(.{});
29322954
2933 const then_deaths = inst.thenDeaths();
2955 const then_deaths = self.liveness.thenDeaths(inst);
29342956 try self.ensureProcessDeathCapacity(then_deaths.len);
29352957 for (then_deaths) |operand| {
29362958 self.processDeath(operand);
29372959 }
2938 try self.genBody(inst.then_body);
2960 try self.genBody(then_body);
29392961
29402962 // Revert to the previous register and stack allocation state.
29412963
......@@ -2951,16 +2973,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29512973 self.next_stack_offset = parent_next_stack_offset;
29522974 self.register_manager.free_registers = parent_free_registers;
29532975
2954 try self.performReloc(inst.base.src, reloc);
2976 try self.performReloc(reloc);
29552977 const else_branch = self.branch_stack.addOneAssumeCapacity();
29562978 else_branch.* = .{};
29572979
2958 const else_deaths = inst.elseDeaths();
2980 const else_deaths = self.liveness.elseDeaths(inst);
29592981 try self.ensureProcessDeathCapacity(else_deaths.len);
29602982 for (else_deaths) |operand| {
29612983 self.processDeath(operand);
29622984 }
2963 try self.genBody(inst.else_body);
2985 try self.genBody(else_body);
29642986
29652987 // At this point, each branch will possibly have conflicting values for where
29662988 // each instruction is stored. They agree, however, on which instructions are alive/dead.
......@@ -3003,7 +3025,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
30033025 log.debug("consolidating else_entry {*} {}=>{}", .{ else_key, else_value, canon_mcv });
30043026 // TODO make sure the destination stack offset / register does not already have something
30053027 // going on there.
3006 try self.setRegOrMem(inst.base.src, else_key.ty, canon_mcv, else_value);
3028 try self.setRegOrMem(else_key.ty, canon_mcv, else_value);
30073029 // TODO track the new register / stack allocation
30083030 }
30093031 try parent_branch.inst_table.ensureCapacity(self.gpa, parent_branch.inst_table.count() +
......@@ -3031,7 +3053,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
30313053 log.debug("consolidating then_entry {*} {}=>{}", .{ then_key, parent_mcv, then_value });
30323054 // TODO make sure the destination stack offset / register does not already have something
30333055 // going on there.
3034 try self.setRegOrMem(inst.base.src, then_key.ty, parent_mcv, then_value);
3056 try self.setRegOrMem(then_key.ty, parent_mcv, then_value);
30353057 // TODO track the new register / stack allocation
30363058 }
30373059
......@@ -3040,58 +3062,155 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
30403062 return MCValue.unreach;
30413063 }
30423064
3043 fn genIsNull(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
3065 fn isNull(self: *Self, operand: MCValue) !MCValue {
3066 _ = operand;
3067 // Here you can specialize this instruction if it makes sense to, otherwise the default
3068 // will call isNonNull and invert the result.
30443069 switch (arch) {
3045 else => return self.fail(inst.base.src, "TODO implement isnull for {}", .{self.target.cpu.arch}),
3070 else => return self.fail("TODO call isNonNull and invert the result", .{}),
30463071 }
30473072 }
30483073
3049 fn genIsNullPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
3050 return self.fail(inst.base.src, "TODO load the operand and call genIsNull", .{});
3051 }
3052
3053 fn genIsNonNull(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
3074 fn isNonNull(self: *Self, operand: MCValue) !MCValue {
3075 _ = operand;
30543076 // Here you can specialize this instruction if it makes sense to, otherwise the default
3055 // will call genIsNull and invert the result.
3077 // will call isNull and invert the result.
30563078 switch (arch) {
3057 else => return self.fail(inst.base.src, "TODO call genIsNull and invert the result ", .{}),
3079 else => return self.fail("TODO call isNull and invert the result", .{}),
30583080 }
30593081 }
30603082
3061 fn genIsNonNullPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
3062 return self.fail(inst.base.src, "TODO load the operand and call genIsNonNull", .{});
3083 fn isErr(self: *Self, operand: MCValue) !MCValue {
3084 _ = operand;
3085 // Here you can specialize this instruction if it makes sense to, otherwise the default
3086 // will call isNonNull and invert the result.
3087 switch (arch) {
3088 else => return self.fail("TODO call isNonErr and invert the result", .{}),
3089 }
30633090 }
30643091
3065 fn genIsErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
3092 fn isNonErr(self: *Self, operand: MCValue) !MCValue {
3093 _ = operand;
3094 // Here you can specialize this instruction if it makes sense to, otherwise the default
3095 // will call isNull and invert the result.
30663096 switch (arch) {
3067 else => return self.fail(inst.base.src, "TODO implement iserr for {}", .{self.target.cpu.arch}),
3097 else => return self.fail("TODO call isErr and invert the result", .{}),
30683098 }
30693099 }
30703100
3071 fn genIsErrPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
3072 return self.fail(inst.base.src, "TODO load the operand and call genIsErr", .{});
3101 fn genIsNull(self: *Self, inst: Air.Inst.Index) !MCValue {
3102 if (self.liveness.isUnused(inst))
3103 return MCValue.dead;
3104 const inst_datas = self.air.instructions.items(.data);
3105 const operand = try self.resolveInst(inst_datas[inst].un_op);
3106 return self.isNull(operand);
30733107 }
30743108
3075 fn genIsNonErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
3076 switch (arch) {
3077 else => return self.fail(inst.base.src, "TODO implement is_non_err for {}", .{self.target.cpu.arch}),
3078 }
3109 fn genIsNullPtr(self: *Self, inst: Air.Inst.Index) !MCValue {
3110 if (self.liveness.isUnused(inst))
3111 return MCValue.dead;
3112 const inst_datas = self.air.instructions.items(.data);
3113 const operand_ptr = try self.resolveInst(inst_datas[inst].un_op);
3114 const operand: MCValue = blk: {
3115 if (self.reuseOperand(inst, 0, operand_ptr)) {
3116 // The MCValue that holds the pointer can be re-used as the value.
3117 break :blk operand_ptr;
3118 } else {
3119 break :blk try self.allocRegOrMem(inst, true);
3120 }
3121 };
3122 try self.load(operand, ptr);
3123 return self.isNull(operand);
30793124 }
30803125
3081 fn genIsNonErrPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
3082 return self.fail(inst.base.src, "TODO load the operand and call genIsNonErr", .{});
3126 fn genIsNonNull(self: *Self, inst: Air.Inst.Index) !MCValue {
3127 if (self.liveness.isUnused(inst))
3128 return MCValue.dead;
3129 const inst_datas = self.air.instructions.items(.data);
3130 const operand = try self.resolveInst(inst_datas[inst].un_op);
3131 return self.isNonNull(operand);
30833132 }
30843133
3085 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {
3134 fn genIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !MCValue {
3135 if (self.liveness.isUnused(inst))
3136 return MCValue.dead;
3137 const inst_datas = self.air.instructions.items(.data);
3138 const operand_ptr = try self.resolveInst(inst_datas[inst].un_op);
3139 const operand: MCValue = blk: {
3140 if (self.reuseOperand(inst, 0, operand_ptr)) {
3141 // The MCValue that holds the pointer can be re-used as the value.
3142 break :blk operand_ptr;
3143 } else {
3144 break :blk try self.allocRegOrMem(inst, true);
3145 }
3146 };
3147 try self.load(operand, ptr);
3148 return self.isNonNull(operand);
3149 }
3150
3151 fn genIsErr(self: *Self, inst: Air.Inst.Index) !MCValue {
3152 if (self.liveness.isUnused(inst))
3153 return MCValue.dead;
3154 const inst_datas = self.air.instructions.items(.data);
3155 const operand = try self.resolveInst(inst_datas[inst].un_op);
3156 return self.isErr(operand);
3157 }
3158
3159 fn genIsErrPtr(self: *Self, inst: Air.Inst.Index) !MCValue {
3160 if (self.liveness.isUnused(inst))
3161 return MCValue.dead;
3162 const inst_datas = self.air.instructions.items(.data);
3163 const operand_ptr = try self.resolveInst(inst_datas[inst].un_op);
3164 const operand: MCValue = blk: {
3165 if (self.reuseOperand(inst, 0, operand_ptr)) {
3166 // The MCValue that holds the pointer can be re-used as the value.
3167 break :blk operand_ptr;
3168 } else {
3169 break :blk try self.allocRegOrMem(inst, true);
3170 }
3171 };
3172 try self.load(operand, ptr);
3173 return self.isErr(operand);
3174 }
3175
3176 fn genIsNonErr(self: *Self, inst: Air.Inst.Index) !MCValue {
3177 if (self.liveness.isUnused(inst))
3178 return MCValue.dead;
3179 const inst_datas = self.air.instructions.items(.data);
3180 const operand = try self.resolveInst(inst_datas[inst].un_op);
3181 return self.isNonErr(operand);
3182 }
3183
3184 fn genIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !MCValue {
3185 if (self.liveness.isUnused(inst))
3186 return MCValue.dead;
3187 const inst_datas = self.air.instructions.items(.data);
3188 const operand_ptr = try self.resolveInst(inst_datas[inst].un_op);
3189 const operand: MCValue = blk: {
3190 if (self.reuseOperand(inst, 0, operand_ptr)) {
3191 // The MCValue that holds the pointer can be re-used as the value.
3192 break :blk operand_ptr;
3193 } else {
3194 break :blk try self.allocRegOrMem(inst, true);
3195 }
3196 };
3197 try self.load(operand, ptr);
3198 return self.isNonErr(operand);
3199 }
3200
3201 fn genLoop(self: *Self, inst: Air.Inst.Index) !MCValue {
30863202 // A loop is a setup to be able to jump back to the beginning.
3203 const inst_datas = self.air.instructions.items(.data);
3204 const loop = self.air.extraData(Air.Block, inst_datas[inst].ty_pl.payload);
3205 const body = self.air.extra[loop.end..][0..loop.data.body_len];
30873206 const start_index = self.code.items.len;
3088 try self.genBody(inst.body);
3089 try self.jump(inst.base.src, start_index);
3207 try self.genBody(body);
3208 try self.jump(start_index);
30903209 return MCValue.unreach;
30913210 }
30923211
30933212 /// Send control flow to the `index` of `self.code`.
3094 fn jump(self: *Self, src: LazySrcLoc, index: usize) !void {
3213 fn jump(self: *Self, index: usize) !void {
30953214 switch (arch) {
30963215 .i386, .x86_64 => {
30973216 try self.code.ensureCapacity(self.code.items.len + 5);
......@@ -3108,21 +3227,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31083227 if (math.cast(i26, @intCast(i32, index) - @intCast(i32, self.code.items.len + 8))) |delta| {
31093228 writeInt(u32, try self.code.addManyAsArray(4), Instruction.b(.al, delta).toU32());
31103229 } else |_| {
3111 return self.fail(src, "TODO: enable larger branch offset", .{});
3230 return self.fail("TODO: enable larger branch offset", .{});
31123231 }
31133232 },
31143233 .aarch64, .aarch64_be, .aarch64_32 => {
31153234 if (math.cast(i28, @intCast(i32, index) - @intCast(i32, self.code.items.len + 8))) |delta| {
31163235 writeInt(u32, try self.code.addManyAsArray(4), Instruction.b(delta).toU32());
31173236 } else |_| {
3118 return self.fail(src, "TODO: enable larger branch offset", .{});
3237 return self.fail("TODO: enable larger branch offset", .{});
31193238 }
31203239 },
3121 else => return self.fail(src, "TODO implement jump for {}", .{self.target.cpu.arch}),
3240 else => return self.fail("TODO implement jump for {}", .{self.target.cpu.arch}),
31223241 }
31233242 }
31243243
3125 fn genBlock(self: *Self, inst: *ir.Inst.Block) !MCValue {
3244 fn genBlock(self: *Self, inst: Air.Inst.Index) !MCValue {
31263245 try self.blocks.putNoClobber(self.gpa, inst, .{
31273246 // A block is a setup to be able to jump to the end.
31283247 .relocs = .{},
......@@ -3136,20 +3255,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31363255 const block_data = self.blocks.getPtr(inst).?;
31373256 defer block_data.relocs.deinit(self.gpa);
31383257
3139 try self.genBody(inst.body);
3258 const ty_pl = self.air.instructions.items(.data).ty_pl;
3259 const extra = self.air.extraData(Air.Block, ty_pl.payload);
3260 const body = self.air.extra[extra.end..][0..extra.data.body_len];
3261 try self.genBody(body);
31403262
3141 for (block_data.relocs.items) |reloc| try self.performReloc(inst.base.src, reloc);
3263 for (block_data.relocs.items) |reloc| try self.performReloc(reloc);
31423264
31433265 return @bitCast(MCValue, block_data.mcv);
31443266 }
31453267
3146 fn genSwitch(self: *Self, inst: *ir.Inst.SwitchBr) !MCValue {
3268 fn genSwitch(self: *Self, inst: Air.Inst.Index) !MCValue {
3269 _ = inst;
31473270 switch (arch) {
3148 else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}),
3271 else => return self.fail("TODO genSwitch for {}", .{self.target.cpu.arch}),
31493272 }
31503273 }
31513274
3152 fn performReloc(self: *Self, src: LazySrcLoc, reloc: Reloc) !void {
3275 fn performReloc(self: *Self, reloc: Reloc) !void {
31533276 switch (reloc) {
31543277 .rel32 => |pos| {
31553278 const amt = self.code.items.len - (pos + 4);
......@@ -3160,7 +3283,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31603283 // best place to elide jumps will be in semantic analysis, by inlining blocks that only
31613284 // only have 1 break instruction.
31623285 const s32_amt = math.cast(i32, amt) catch
3163 return self.fail(src, "unable to perform relocation: jump too far", .{});
3286 return self.fail("unable to perform relocation: jump too far", .{});
31643287 mem.writeIntLittle(i32, self.code.items[pos..][0..4], s32_amt);
31653288 },
31663289 .arm_branch => |info| {
......@@ -3170,7 +3293,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31703293 if (math.cast(i26, amt)) |delta| {
31713294 writeInt(u32, self.code.items[info.pos..][0..4], Instruction.b(info.cond, delta).toU32());
31723295 } else |_| {
3173 return self.fail(src, "TODO: enable larger branch offset", .{});
3296 return self.fail("TODO: enable larger branch offset", .{});
31743297 }
31753298 },
31763299 else => unreachable, // attempting to perfrom an ARM relocation on a non-ARM target arch
......@@ -3179,41 +3302,39 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31793302 }
31803303 }
31813304
3182 fn genBrBlockFlat(self: *Self, inst: *ir.Inst.BrBlockFlat) !MCValue {
3305 fn genBrBlockFlat(self: *Self, inst: Air.Inst.Index) !MCValue {
31833306 try self.genBody(inst.body);
31843307 const last = inst.body.instructions[inst.body.instructions.len - 1];
3185 return self.br(inst.base.src, inst.block, last);
3186 }
3187
3188 fn genBr(self: *Self, inst: *ir.Inst.Br) !MCValue {
3189 return self.br(inst.base.src, inst.block, inst.operand);
3308 return self.br(inst.block, last);
31903309 }
31913310
3192 fn genBrVoid(self: *Self, inst: *ir.Inst.BrVoid) !MCValue {
3193 return self.brVoid(inst.base.src, inst.block);
3311 fn genBr(self: *Self, inst: Air.Inst.Index) !MCValue {
3312 return self.br(inst.block, inst.operand);
31943313 }
31953314
3196 fn genBoolOp(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
3197 if (inst.base.isUnused())
3315 fn genBoolOp(self: *Self, inst: Air.Inst.Index) !MCValue {
3316 if (self.liveness.isUnused(inst))
31983317 return MCValue.dead;
3318 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3319 const air_tags = self.air.instructions.items(.tag);
31993320 switch (arch) {
3200 .x86_64 => switch (inst.base.tag) {
3321 .x86_64 => switch (air_tags[inst]) {
32013322 // lhs AND rhs
3202 .bool_and => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs),
3323 .bool_and => return try self.genX8664BinMath(inst, bin_op.lhs, bin_op.rhs),
32033324 // lhs OR rhs
3204 .bool_or => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs),
3325 .bool_or => return try self.genX8664BinMath(inst, bin_op.lhs, bin_op.rhs),
32053326 else => unreachable, // Not a boolean operation
32063327 },
3207 .arm, .armeb => switch (inst.base.tag) {
3208 .bool_and => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bool_and),
3209 .bool_or => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .bool_or),
3328 .arm, .armeb => switch (air_tags[inst]) {
3329 .bool_and => return try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .bool_and),
3330 .bool_or => return try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .bool_or),
32103331 else => unreachable, // Not a boolean operation
32113332 },
3212 else => return self.fail(inst.base.src, "TODO implement boolean operations for {}", .{self.target.cpu.arch}),
3333 else => return self.fail("TODO implement boolean operations for {}", .{self.target.cpu.arch}),
32133334 }
32143335 }
32153336
3216 fn br(self: *Self, src: LazySrcLoc, block: *ir.Inst.Block, operand: *ir.Inst) !MCValue {
3337 fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Index) !MCValue {
32173338 const block_data = self.blocks.getPtr(block).?;
32183339
32193340 if (operand.ty.hasCodeGenBits()) {
......@@ -3222,13 +3343,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
32223343 if (block_mcv == .none) {
32233344 block_data.mcv = operand_mcv;
32243345 } else {
3225 try self.setRegOrMem(src, block.base.ty, block_mcv, operand_mcv);
3346 try self.setRegOrMem(block.base.ty, block_mcv, operand_mcv);
32263347 }
32273348 }
3228 return self.brVoid(src, block);
3349 return self.brVoid(block);
32293350 }
32303351
3231 fn brVoid(self: *Self, src: LazySrcLoc, block: *ir.Inst.Block) !MCValue {
3352 fn brVoid(self: *Self, block: Air.Inst.Index) !MCValue {
32323353 const block_data = self.blocks.getPtr(block).?;
32333354
32343355 // Emit a jump with a relocation. It will be patched up after the block ends.
......@@ -3252,43 +3373,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
32523373 },
32533374 });
32543375 },
3255 else => return self.fail(src, "TODO implement brvoid for {}", .{self.target.cpu.arch}),
3376 else => return self.fail("TODO implement brvoid for {}", .{self.target.cpu.arch}),
32563377 }
32573378 return .none;
32583379 }
32593380
3260 fn genAsm(self: *Self, inst: *ir.Inst.Assembly) !MCValue {
3261 if (!inst.is_volatile and inst.base.isUnused())
3381 fn genAsm(self: *Self, inst: Air.Inst.Index) !MCValue {
3382 if (!inst.is_volatile and self.liveness.isUnused(inst))
32623383 return MCValue.dead;
32633384 switch (arch) {
32643385 .arm, .armeb => {
32653386 for (inst.inputs) |input, i| {
32663387 if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {
3267 return self.fail(inst.base.src, "unrecognized asm input constraint: '{s}'", .{input});
3388 return self.fail("unrecognized asm input constraint: '{s}'", .{input});
32683389 }
32693390 const reg_name = input[1 .. input.len - 1];
32703391 const reg = parseRegName(reg_name) orelse
3271 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3392 return self.fail("unrecognized register: '{s}'", .{reg_name});
32723393
32733394 const arg = inst.args[i];
32743395 const arg_mcv = try self.resolveInst(arg);
32753396 try self.register_manager.getReg(reg, null);
3276 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
3397 try self.genSetReg(arg.ty, reg, arg_mcv);
32773398 }
32783399
32793400 if (mem.eql(u8, inst.asm_source, "svc #0")) {
32803401 writeInt(u32, try self.code.addManyAsArray(4), Instruction.svc(.al, 0).toU32());
32813402 } else {
3282 return self.fail(inst.base.src, "TODO implement support for more arm assembly instructions", .{});
3403 return self.fail("TODO implement support for more arm assembly instructions", .{});
32833404 }
32843405
32853406 if (inst.output_constraint) |output| {
32863407 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
3287 return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output});
3408 return self.fail("unrecognized asm output constraint: '{s}'", .{output});
32883409 }
32893410 const reg_name = output[2 .. output.len - 1];
32903411 const reg = parseRegName(reg_name) orelse
3291 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3412 return self.fail("unrecognized register: '{s}'", .{reg_name});
32923413 return MCValue{ .register = reg };
32933414 } else {
32943415 return MCValue.none;
......@@ -3297,16 +3418,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
32973418 .aarch64 => {
32983419 for (inst.inputs) |input, i| {
32993420 if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {
3300 return self.fail(inst.base.src, "unrecognized asm input constraint: '{s}'", .{input});
3421 return self.fail("unrecognized asm input constraint: '{s}'", .{input});
33013422 }
33023423 const reg_name = input[1 .. input.len - 1];
33033424 const reg = parseRegName(reg_name) orelse
3304 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3425 return self.fail("unrecognized register: '{s}'", .{reg_name});
33053426
33063427 const arg = inst.args[i];
33073428 const arg_mcv = try self.resolveInst(arg);
33083429 try self.register_manager.getReg(reg, null);
3309 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
3430 try self.genSetReg(arg.ty, reg, arg_mcv);
33103431 }
33113432
33123433 if (mem.eql(u8, inst.asm_source, "svc #0")) {
......@@ -3314,16 +3435,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
33143435 } else if (mem.eql(u8, inst.asm_source, "svc #0x80")) {
33153436 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(0x80).toU32());
33163437 } else {
3317 return self.fail(inst.base.src, "TODO implement support for more aarch64 assembly instructions", .{});
3438 return self.fail("TODO implement support for more aarch64 assembly instructions", .{});
33183439 }
33193440
33203441 if (inst.output_constraint) |output| {
33213442 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
3322 return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output});
3443 return self.fail("unrecognized asm output constraint: '{s}'", .{output});
33233444 }
33243445 const reg_name = output[2 .. output.len - 1];
33253446 const reg = parseRegName(reg_name) orelse
3326 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3447 return self.fail("unrecognized register: '{s}'", .{reg_name});
33273448 return MCValue{ .register = reg };
33283449 } else {
33293450 return MCValue.none;
......@@ -3332,31 +3453,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
33323453 .riscv64 => {
33333454 for (inst.inputs) |input, i| {
33343455 if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {
3335 return self.fail(inst.base.src, "unrecognized asm input constraint: '{s}'", .{input});
3456 return self.fail("unrecognized asm input constraint: '{s}'", .{input});
33363457 }
33373458 const reg_name = input[1 .. input.len - 1];
33383459 const reg = parseRegName(reg_name) orelse
3339 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3460 return self.fail("unrecognized register: '{s}'", .{reg_name});
33403461
33413462 const arg = inst.args[i];
33423463 const arg_mcv = try self.resolveInst(arg);
33433464 try self.register_manager.getReg(reg, null);
3344 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
3465 try self.genSetReg(arg.ty, reg, arg_mcv);
33453466 }
33463467
33473468 if (mem.eql(u8, inst.asm_source, "ecall")) {
33483469 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ecall.toU32());
33493470 } else {
3350 return self.fail(inst.base.src, "TODO implement support for more riscv64 assembly instructions", .{});
3471 return self.fail("TODO implement support for more riscv64 assembly instructions", .{});
33513472 }
33523473
33533474 if (inst.output_constraint) |output| {
33543475 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
3355 return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output});
3476 return self.fail("unrecognized asm output constraint: '{s}'", .{output});
33563477 }
33573478 const reg_name = output[2 .. output.len - 1];
33583479 const reg = parseRegName(reg_name) orelse
3359 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3480 return self.fail("unrecognized register: '{s}'", .{reg_name});
33603481 return MCValue{ .register = reg };
33613482 } else {
33623483 return MCValue.none;
......@@ -3365,16 +3486,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
33653486 .x86_64, .i386 => {
33663487 for (inst.inputs) |input, i| {
33673488 if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {
3368 return self.fail(inst.base.src, "unrecognized asm input constraint: '{s}'", .{input});
3489 return self.fail("unrecognized asm input constraint: '{s}'", .{input});
33693490 }
33703491 const reg_name = input[1 .. input.len - 1];
33713492 const reg = parseRegName(reg_name) orelse
3372 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3493 return self.fail("unrecognized register: '{s}'", .{reg_name});
33733494
33743495 const arg = inst.args[i];
33753496 const arg_mcv = try self.resolveInst(arg);
33763497 try self.register_manager.getReg(reg, null);
3377 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
3498 try self.genSetReg(arg.ty, reg, arg_mcv);
33783499 }
33793500
33803501 {
......@@ -3385,68 +3506,68 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
33853506 } else if (mem.indexOf(u8, ins, "push")) |_| {
33863507 const arg = ins[4..];
33873508 if (mem.indexOf(u8, arg, "$")) |l| {
3388 const n = std.fmt.parseInt(u8, ins[4 + l + 1 ..], 10) catch return self.fail(inst.base.src, "TODO implement more inline asm int parsing", .{});
3509 const n = std.fmt.parseInt(u8, ins[4 + l + 1 ..], 10) catch return self.fail("TODO implement more inline asm int parsing", .{});
33893510 try self.code.appendSlice(&.{ 0x6a, n });
33903511 } else if (mem.indexOf(u8, arg, "%%")) |l| {
33913512 const reg_name = ins[4 + l + 2 ..];
33923513 const reg = parseRegName(reg_name) orelse
3393 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3514 return self.fail("unrecognized register: '{s}'", .{reg_name});
33943515 const low_id: u8 = reg.low_id();
33953516 if (reg.isExtended()) {
33963517 try self.code.appendSlice(&.{ 0x41, 0b1010000 | low_id });
33973518 } else {
33983519 try self.code.append(0b1010000 | low_id);
33993520 }
3400 } else return self.fail(inst.base.src, "TODO more push operands", .{});
3521 } else return self.fail("TODO more push operands", .{});
34013522 } else if (mem.indexOf(u8, ins, "pop")) |_| {
34023523 const arg = ins[3..];
34033524 if (mem.indexOf(u8, arg, "%%")) |l| {
34043525 const reg_name = ins[3 + l + 2 ..];
34053526 const reg = parseRegName(reg_name) orelse
3406 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3527 return self.fail("unrecognized register: '{s}'", .{reg_name});
34073528 const low_id: u8 = reg.low_id();
34083529 if (reg.isExtended()) {
34093530 try self.code.appendSlice(&.{ 0x41, 0b1011000 | low_id });
34103531 } else {
34113532 try self.code.append(0b1011000 | low_id);
34123533 }
3413 } else return self.fail(inst.base.src, "TODO more pop operands", .{});
3534 } else return self.fail("TODO more pop operands", .{});
34143535 } else {
3415 return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{});
3536 return self.fail("TODO implement support for more x86 assembly instructions", .{});
34163537 }
34173538 }
34183539 }
34193540
34203541 if (inst.output_constraint) |output| {
34213542 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
3422 return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output});
3543 return self.fail("unrecognized asm output constraint: '{s}'", .{output});
34233544 }
34243545 const reg_name = output[2 .. output.len - 1];
34253546 const reg = parseRegName(reg_name) orelse
3426 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
3547 return self.fail("unrecognized register: '{s}'", .{reg_name});
34273548 return MCValue{ .register = reg };
34283549 } else {
34293550 return MCValue.none;
34303551 }
34313552 },
3432 else => return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{}),
3553 else => return self.fail("TODO implement inline asm support for more architectures", .{}),
34333554 }
34343555 }
34353556
34363557 /// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
3437 fn setRegOrMem(self: *Self, src: LazySrcLoc, ty: Type, loc: MCValue, val: MCValue) !void {
3558 fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
34383559 switch (loc) {
34393560 .none => return,
3440 .register => |reg| return self.genSetReg(src, ty, reg, val),
3441 .stack_offset => |off| return self.genSetStack(src, ty, off, val),
3561 .register => |reg| return self.genSetReg(ty, reg, val),
3562 .stack_offset => |off| return self.genSetStack(ty, off, val),
34423563 .memory => {
3443 return self.fail(src, "TODO implement setRegOrMem for memory", .{});
3564 return self.fail("TODO implement setRegOrMem for memory", .{});
34443565 },
34453566 else => unreachable,
34463567 }
34473568 }
34483569
3449 fn genSetStack(self: *Self, src: LazySrcLoc, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {
3570 fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {
34503571 switch (arch) {
34513572 .arm, .armeb => switch (mcv) {
34523573 .dead => unreachable,
......@@ -3458,28 +3579,28 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
34583579 return; // The already existing value will do just fine.
34593580 // TODO Upgrade this to a memset call when we have that available.
34603581 switch (ty.abiSize(self.target.*)) {
3461 1 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaa }),
3462 2 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaa }),
3463 4 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
3464 8 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3465 else => return self.fail(src, "TODO implement memset", .{}),
3582 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
3583 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
3584 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
3585 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3586 else => return self.fail("TODO implement memset", .{}),
34663587 }
34673588 },
34683589 .compare_flags_unsigned => |op| {
34693590 _ = op;
3470 return self.fail(src, "TODO implement set stack variable with compare flags value (unsigned)", .{});
3591 return self.fail("TODO implement set stack variable with compare flags value (unsigned)", .{});
34713592 },
34723593 .compare_flags_signed => |op| {
34733594 _ = op;
3474 return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{});
3595 return self.fail("TODO implement set stack variable with compare flags value (signed)", .{});
34753596 },
34763597 .immediate => {
3477 const reg = try self.copyToTmpRegister(src, ty, mcv);
3478 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
3598 const reg = try self.copyToTmpRegister(ty, mcv);
3599 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
34793600 },
34803601 .embedded_in_code => |code_offset| {
34813602 _ = code_offset;
3482 return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{});
3603 return self.fail("TODO implement set stack variable from embedded_in_code", .{});
34833604 },
34843605 .register => |reg| {
34853606 const abi_size = ty.abiSize(self.target.*);
......@@ -3489,7 +3610,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
34893610 1, 4 => {
34903611 const offset = if (math.cast(u12, adj_off)) |imm| blk: {
34913612 break :blk Instruction.Offset.imm(imm);
3492 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0);
3613 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0);
34933614 const str = switch (abi_size) {
34943615 1 => Instruction.strb,
34953616 4 => Instruction.str,
......@@ -3504,26 +3625,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
35043625 2 => {
35053626 const offset = if (adj_off <= math.maxInt(u8)) blk: {
35063627 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3507 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }));
3628 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
35083629
35093630 writeInt(u32, try self.code.addManyAsArray(4), Instruction.strh(.al, reg, .fp, .{
35103631 .offset = offset,
35113632 .positive = false,
35123633 }).toU32());
35133634 },
3514 else => return self.fail(src, "TODO implement storing other types abi_size={}", .{abi_size}),
3635 else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}),
35153636 }
35163637 },
35173638 .memory => |vaddr| {
35183639 _ = vaddr;
3519 return self.fail(src, "TODO implement set stack variable from memory vaddr", .{});
3640 return self.fail("TODO implement set stack variable from memory vaddr", .{});
35203641 },
35213642 .stack_offset => |off| {
35223643 if (stack_offset == off)
35233644 return; // Copy stack variable to itself; nothing to do.
35243645
3525 const reg = try self.copyToTmpRegister(src, ty, mcv);
3526 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
3646 const reg = try self.copyToTmpRegister(ty, mcv);
3647 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
35273648 },
35283649 },
35293650 .x86_64 => switch (mcv) {
......@@ -3536,34 +3657,34 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
35363657 return; // The already existing value will do just fine.
35373658 // TODO Upgrade this to a memset call when we have that available.
35383659 switch (ty.abiSize(self.target.*)) {
3539 1 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaa }),
3540 2 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaa }),
3541 4 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
3542 8 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3543 else => return self.fail(src, "TODO implement memset", .{}),
3660 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
3661 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
3662 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
3663 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3664 else => return self.fail("TODO implement memset", .{}),
35443665 }
35453666 },
35463667 .compare_flags_unsigned => |op| {
35473668 _ = op;
3548 return self.fail(src, "TODO implement set stack variable with compare flags value (unsigned)", .{});
3669 return self.fail("TODO implement set stack variable with compare flags value (unsigned)", .{});
35493670 },
35503671 .compare_flags_signed => |op| {
35513672 _ = op;
3552 return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{});
3673 return self.fail("TODO implement set stack variable with compare flags value (signed)", .{});
35533674 },
35543675 .immediate => |x_big| {
35553676 const abi_size = ty.abiSize(self.target.*);
35563677 const adj_off = stack_offset + abi_size;
35573678 if (adj_off > 128) {
3558 return self.fail(src, "TODO implement set stack variable with large stack offset", .{});
3679 return self.fail("TODO implement set stack variable with large stack offset", .{});
35593680 }
35603681 try self.code.ensureCapacity(self.code.items.len + 8);
35613682 switch (abi_size) {
35623683 1 => {
3563 return self.fail(src, "TODO implement set abi_size=1 stack variable with immediate", .{});
3684 return self.fail("TODO implement set abi_size=1 stack variable with immediate", .{});
35643685 },
35653686 2 => {
3566 return self.fail(src, "TODO implement set abi_size=2 stack variable with immediate", .{});
3687 return self.fail("TODO implement set abi_size=2 stack variable with immediate", .{});
35673688 },
35683689 4 => {
35693690 const x = @intCast(u32, x_big);
......@@ -3596,22 +3717,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
35963717 self.code.appendSliceAssumeCapacity(buf[0..4]);
35973718 },
35983719 else => {
3599 return self.fail(src, "TODO implement set abi_size=large stack variable with immediate", .{});
3720 return self.fail("TODO implement set abi_size=large stack variable with immediate", .{});
36003721 },
36013722 }
36023723 },
36033724 .embedded_in_code => {
36043725 // TODO this and `.stack_offset` below need to get improved to support types greater than
36053726 // register size, and do general memcpy
3606 const reg = try self.copyToTmpRegister(src, ty, mcv);
3607 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
3727 const reg = try self.copyToTmpRegister(ty, mcv);
3728 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
36083729 },
36093730 .register => |reg| {
36103731 try self.genX8664ModRMRegToStack(src, ty, stack_offset, reg, 0x89);
36113732 },
36123733 .memory => |vaddr| {
36133734 _ = vaddr;
3614 return self.fail(src, "TODO implement set stack variable from memory vaddr", .{});
3735 return self.fail("TODO implement set stack variable from memory vaddr", .{});
36153736 },
36163737 .stack_offset => |off| {
36173738 // TODO this and `.embedded_in_code` above need to get improved to support types greater than
......@@ -3620,8 +3741,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
36203741 if (stack_offset == off)
36213742 return; // Copy stack variable to itself; nothing to do.
36223743
3623 const reg = try self.copyToTmpRegister(src, ty, mcv);
3624 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
3744 const reg = try self.copyToTmpRegister(ty, mcv);
3745 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
36253746 },
36263747 },
36273748 .aarch64, .aarch64_be, .aarch64_32 => switch (mcv) {
......@@ -3634,28 +3755,28 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
36343755 return; // The already existing value will do just fine.
36353756 // TODO Upgrade this to a memset call when we have that available.
36363757 switch (ty.abiSize(self.target.*)) {
3637 1 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaa }),
3638 2 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaa }),
3639 4 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
3640 8 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3641 else => return self.fail(src, "TODO implement memset", .{}),
3758 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
3759 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
3760 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
3761 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3762 else => return self.fail("TODO implement memset", .{}),
36423763 }
36433764 },
36443765 .compare_flags_unsigned => |op| {
36453766 _ = op;
3646 return self.fail(src, "TODO implement set stack variable with compare flags value (unsigned)", .{});
3767 return self.fail("TODO implement set stack variable with compare flags value (unsigned)", .{});
36473768 },
36483769 .compare_flags_signed => |op| {
36493770 _ = op;
3650 return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{});
3771 return self.fail("TODO implement set stack variable with compare flags value (signed)", .{});
36513772 },
36523773 .immediate => {
3653 const reg = try self.copyToTmpRegister(src, ty, mcv);
3654 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
3774 const reg = try self.copyToTmpRegister(ty, mcv);
3775 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
36553776 },
36563777 .embedded_in_code => |code_offset| {
36573778 _ = code_offset;
3658 return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{});
3779 return self.fail("TODO implement set stack variable from embedded_in_code", .{});
36593780 },
36603781 .register => |reg| {
36613782 const abi_size = ty.abiSize(self.target.*);
......@@ -3666,7 +3787,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
36663787 const offset = if (math.cast(i9, adj_off)) |imm|
36673788 Instruction.LoadStoreOffset.imm_post_index(-imm)
36683789 else |_|
3669 Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u64), MCValue{ .immediate = adj_off }));
3790 Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u64), MCValue{ .immediate = adj_off }));
36703791 const rn: Register = switch (arch) {
36713792 .aarch64, .aarch64_be => .x29,
36723793 .aarch64_32 => .w29,
......@@ -3683,26 +3804,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
36833804 .offset = offset,
36843805 }).toU32());
36853806 },
3686 else => return self.fail(src, "TODO implement storing other types abi_size={}", .{abi_size}),
3807 else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}),
36873808 }
36883809 },
36893810 .memory => |vaddr| {
36903811 _ = vaddr;
3691 return self.fail(src, "TODO implement set stack variable from memory vaddr", .{});
3812 return self.fail("TODO implement set stack variable from memory vaddr", .{});
36923813 },
36933814 .stack_offset => |off| {
36943815 if (stack_offset == off)
36953816 return; // Copy stack variable to itself; nothing to do.
36963817
3697 const reg = try self.copyToTmpRegister(src, ty, mcv);
3698 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
3818 const reg = try self.copyToTmpRegister(ty, mcv);
3819 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
36993820 },
37003821 },
3701 else => return self.fail(src, "TODO implement getSetStack for {}", .{self.target.cpu.arch}),
3822 else => return self.fail("TODO implement getSetStack for {}", .{self.target.cpu.arch}),
37023823 }
37033824 }
37043825
3705 fn genSetReg(self: *Self, src: LazySrcLoc, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
3826 fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
37063827 switch (arch) {
37073828 .arm, .armeb => switch (mcv) {
37083829 .dead => unreachable,
......@@ -3713,7 +3834,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
37133834 if (!self.wantSafety())
37143835 return; // The already existing value will do just fine.
37153836 // Write the debug undefined value.
3716 return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa });
3837 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa });
37173838 },
37183839 .compare_flags_unsigned,
37193840 .compare_flags_signed,
......@@ -3732,7 +3853,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
37323853 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(condition, reg, one).toU32());
37333854 },
37343855 .immediate => |x| {
3735 if (x > math.maxInt(u32)) return self.fail(src, "ARM registers are 32-bit wide", .{});
3856 if (x > math.maxInt(u32)) return self.fail("ARM registers are 32-bit wide", .{});
37363857
37373858 if (Instruction.Operand.fromU32(@intCast(u32, x))) |op| {
37383859 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, op).toU32());
......@@ -3778,7 +3899,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
37783899 .memory => |addr| {
37793900 // The value is in memory at a hard-coded address.
37803901 // If the type is a pointer, it means the pointer address is at this memory location.
3781 try self.genSetReg(src, ty, reg, .{ .immediate = addr });
3902 try self.genSetReg(ty, reg, .{ .immediate = addr });
37823903 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, reg, .{ .offset = Instruction.Offset.none }).toU32());
37833904 },
37843905 .stack_offset => |unadjusted_off| {
......@@ -3790,7 +3911,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
37903911 1, 4 => {
37913912 const offset = if (adj_off <= math.maxInt(u12)) blk: {
37923913 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
3793 } else Instruction.Offset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0);
3914 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0);
37943915 const ldr = switch (abi_size) {
37953916 1 => Instruction.ldrb,
37963917 4 => Instruction.ldr,
......@@ -3805,17 +3926,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
38053926 2 => {
38063927 const offset = if (adj_off <= math.maxInt(u8)) blk: {
38073928 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3808 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }));
3929 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
38093930
38103931 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrh(.al, reg, .fp, .{
38113932 .offset = offset,
38123933 .positive = false,
38133934 }).toU32());
38143935 },
3815 else => return self.fail(src, "TODO a type of size {} is not allowed in a register", .{abi_size}),
3936 else => return self.fail("TODO a type of size {} is not allowed in a register", .{abi_size}),
38163937 }
38173938 },
3818 else => return self.fail(src, "TODO implement getSetReg for arm {}", .{mcv}),
3939 else => return self.fail("TODO implement getSetReg for arm {}", .{mcv}),
38193940 },
38203941 .aarch64 => switch (mcv) {
38213942 .dead => unreachable,
......@@ -3827,8 +3948,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
38273948 return; // The already existing value will do just fine.
38283949 // Write the debug undefined value.
38293950 switch (reg.size()) {
3830 32 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa }),
3831 64 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3951 32 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa }),
3952 64 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
38323953 else => unreachable, // unexpected register size
38333954 }
38343955 },
......@@ -3876,7 +3997,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
38763997 .size = 4,
38773998 });
38783999 } else {
3879 return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});
4000 return self.fail("TODO implement genSetReg for PIE GOT indirection on this platform", .{});
38804001 }
38814002 mem.writeIntLittle(
38824003 u32,
......@@ -3893,7 +4014,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
38934014 } else {
38944015 // The value is in memory at a hard-coded address.
38954016 // If the type is a pointer, it means the pointer address is at this memory location.
3896 try self.genSetReg(src, Type.initTag(.usize), reg, .{ .immediate = addr });
4017 try self.genSetReg(Type.initTag(.usize), reg, .{ .immediate = addr });
38974018 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());
38984019 }
38994020 },
......@@ -3911,7 +4032,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
39114032 const offset = if (math.cast(i9, adj_off)) |imm|
39124033 Instruction.LoadStoreOffset.imm_post_index(-imm)
39134034 else |_|
3914 Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u64), MCValue{ .immediate = adj_off }));
4035 Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u64), MCValue{ .immediate = adj_off }));
39154036
39164037 switch (abi_size) {
39174038 1, 2 => {
......@@ -3931,10 +4052,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
39314052 .offset = offset,
39324053 } }).toU32());
39334054 },
3934 else => return self.fail(src, "TODO implement genSetReg other types abi_size={}", .{abi_size}),
4055 else => return self.fail("TODO implement genSetReg other types abi_size={}", .{abi_size}),
39354056 }
39364057 },
3937 else => return self.fail(src, "TODO implement genSetReg for aarch64 {}", .{mcv}),
4058 else => return self.fail("TODO implement genSetReg for aarch64 {}", .{mcv}),
39384059 },
39394060 .riscv64 => switch (mcv) {
39404061 .dead => unreachable,
......@@ -3945,7 +4066,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
39454066 if (!self.wantSafety())
39464067 return; // The already existing value will do just fine.
39474068 // Write the debug undefined value.
3948 return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
4069 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
39494070 },
39504071 .immediate => |unsigned_x| {
39514072 const x = @bitCast(i64, unsigned_x);
......@@ -3965,19 +4086,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
39654086 }
39664087 // li rd, immediate
39674088 // "Myriad sequences"
3968 return self.fail(src, "TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf
4089 return self.fail("TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf
39694090 },
39704091 .memory => |addr| {
39714092 // The value is in memory at a hard-coded address.
39724093 // If the type is a pointer, it means the pointer address is at this memory location.
3973 try self.genSetReg(src, ty, reg, .{ .immediate = addr });
4094 try self.genSetReg(ty, reg, .{ .immediate = addr });
39744095
39754096 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ld(reg, 0, reg).toU32());
39764097 // LOAD imm=[i12 offset = 0], rs1 =
39774098
39784099 // return self.fail("TODO implement genSetReg memory for riscv64");
39794100 },
3980 else => return self.fail(src, "TODO implement getSetReg for riscv64 {}", .{mcv}),
4101 else => return self.fail("TODO implement getSetReg for riscv64 {}", .{mcv}),
39814102 },
39824103 .x86_64 => switch (mcv) {
39834104 .dead => unreachable,
......@@ -3989,10 +4110,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
39894110 return; // The already existing value will do just fine.
39904111 // Write the debug undefined value.
39914112 switch (reg.size()) {
3992 8 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaa }),
3993 16 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaa }),
3994 32 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa }),
3995 64 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
4113 8 => return self.genSetReg(ty, reg, .{ .immediate = 0xaa }),
4114 16 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaa }),
4115 32 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa }),
4116 64 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
39964117 else => unreachable,
39974118 }
39984119 },
......@@ -4019,7 +4140,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
40194140 },
40204141 .compare_flags_signed => |op| {
40214142 _ = op;
4022 return self.fail(src, "TODO set register with compare flags value (signed)", .{});
4143 return self.fail("TODO set register with compare flags value (signed)", .{});
40234144 },
40244145 .immediate => |x| {
40254146 // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
......@@ -4152,7 +4273,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
41524273 .size = 4,
41534274 });
41544275 } else {
4155 return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});
4276 return self.fail("TODO implement genSetReg for PIE GOT indirection on this platform", .{});
41564277 }
41574278
41584279 // MOV reg, [reg]
......@@ -4208,7 +4329,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
42084329 assert(id3 != 4 and id3 != 5);
42094330
42104331 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.
4211 try self.genSetReg(src, ty, reg, MCValue{ .immediate = x });
4332 try self.genSetReg(ty, reg, MCValue{ .immediate = x });
42124333
42134334 // Now, the register contains the address of the value to load into it
42144335 // Currently, we're only allowing 64-bit registers, so we need the `REX.W 8B /r` variant.
......@@ -4231,7 +4352,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
42314352 const abi_size = ty.abiSize(self.target.*);
42324353 const off = unadjusted_off + abi_size;
42334354 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
4234 return self.fail(src, "stack offset too large", .{});
4355 return self.fail("stack offset too large", .{});
42354356 }
42364357 const ioff = -@intCast(i32, off);
42374358 const encoder = try X8664Encoder.init(self.code, 3);
......@@ -4251,21 +4372,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
42514372 }
42524373 },
42534374 },
4254 else => return self.fail(src, "TODO implement getSetReg for {}", .{self.target.cpu.arch}),
4375 else => return self.fail("TODO implement getSetReg for {}", .{self.target.cpu.arch}),
42554376 }
42564377 }
42574378
4258 fn genPtrToInt(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
4259 // no-op
4260 return self.resolveInst(inst.operand);
4379 fn genPtrToInt(self: *Self, inst: Air.Inst.Index) !MCValue {
4380 const inst_datas = self.air.instructions.items(.data);
4381 return self.resolveInst(inst_datas[inst].un_op);
42614382 }
42624383
4263 fn genBitCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
4264 const operand = try self.resolveInst(inst.operand);
4265 return operand;
4384 fn genBitCast(self: *Self, inst: Air.Inst.Index) !MCValue {
4385 const inst_datas = self.air.instructions.items(.data);
4386 return self.resolveInst(inst_datas[inst].ty_op.operand);
42664387 }
42674388
4268 fn resolveInst(self: *Self, inst: *ir.Inst) !MCValue {
4389 fn resolveInst(self: *Self, inst: Air.Inst.Index) !MCValue {
42694390 // If the type has no codegen bits, no need to store it.
42704391 if (!inst.ty.hasCodeGenBits())
42714392 return MCValue.none;
......@@ -4283,7 +4404,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
42834404 return self.getResolvedInstValue(inst);
42844405 }
42854406
4286 fn getResolvedInstValue(self: *Self, inst: *ir.Inst) MCValue {
4407 fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
42874408 // Treat each stack item as a "layer" on top of the previous one.
42884409 var i: usize = self.branch_stack.items.len;
42894410 while (true) {
......@@ -4300,7 +4421,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
43004421 /// A potential opportunity for future optimization here would be keeping track
43014422 /// of the fact that the instruction is available both as an immediate
43024423 /// and as a register.
4303 fn limitImmediateType(self: *Self, inst: *ir.Inst, comptime T: type) !MCValue {
4424 fn limitImmediateType(self: *Self, inst: Air.Inst.Index, comptime T: type) !MCValue {
43044425 const mcv = try self.resolveInst(inst);
43054426 const ti = @typeInfo(T).Int;
43064427 switch (mcv) {
......@@ -4308,7 +4429,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
43084429 // This immediate is unsigned.
43094430 const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed));
43104431 if (imm >= math.maxInt(U)) {
4311 return MCValue{ .register = try self.copyToTmpRegister(inst.src, Type.initTag(.usize), mcv) };
4432 return MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.usize), mcv) };
43124433 }
43134434 },
43144435 else => {},
......@@ -4334,7 +4455,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
43344455 _ = slice_len;
43354456 _ = ptr_imm;
43364457 // We need more general support for const data being stored in memory to make this work.
4337 return self.fail(src, "TODO codegen for const slices", .{});
4458 return self.fail("TODO codegen for const slices", .{});
43384459 },
43394460 else => {
43404461 if (typed_value.val.castTag(.decl_ref)) |payload| {
......@@ -4360,19 +4481,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
43604481 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
43614482 return MCValue{ .memory = got_addr };
43624483 } else {
4363 return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});
4484 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
43644485 }
43654486 }
43664487 if (typed_value.val.tag() == .int_u64) {
43674488 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
43684489 }
4369 return self.fail(src, "TODO codegen more kinds of const pointers", .{});
4490 return self.fail("TODO codegen more kinds of const pointers", .{});
43704491 },
43714492 },
43724493 .Int => {
43734494 const info = typed_value.ty.intInfo(self.target.*);
43744495 if (info.bits > ptr_bits or info.signedness == .signed) {
4375 return self.fail(src, "TODO const int bigger than ptr and signed int", .{});
4496 return self.fail("TODO const int bigger than ptr and signed int", .{});
43764497 }
43774498 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
43784499 },
......@@ -4394,9 +4515,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
43944515 } else if (typed_value.ty.abiSize(self.target.*) == 1) {
43954516 return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) };
43964517 }
4397 return self.fail(src, "TODO non pointer optionals", .{});
4518 return self.fail("TODO non pointer optionals", .{});
43984519 },
4399 else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),
4520 else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}),
44004521 }
44014522 }
44024523
......@@ -4413,7 +4534,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
44134534 };
44144535
44154536 /// Caller must call `CallMCValues.deinit`.
4416 fn resolveCallingConventionValues(self: *Self, src: LazySrcLoc, fn_ty: Type) !CallMCValues {
4537 fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
44174538 const cc = fn_ty.fnCallingConvention();
44184539 const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen());
44194540 defer self.gpa.free(param_types);
......@@ -4482,7 +4603,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
44824603 result.stack_byte_count = next_stack_offset;
44834604 result.stack_align = 16;
44844605 },
4485 else => return self.fail(src, "TODO implement function parameters for {} on x86_64", .{cc}),
4606 else => return self.fail("TODO implement function parameters for {} on x86_64", .{cc}),
44864607 }
44874608 },
44884609 .arm, .armeb => {
......@@ -4509,10 +4630,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
45094630 result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] };
45104631 ncrn += 1;
45114632 } else {
4512 return self.fail(src, "TODO MCValues with multiple registers", .{});
4633 return self.fail("TODO MCValues with multiple registers", .{});
45134634 }
45144635 } else if (ncrn < 4 and nsaa == 0) {
4515 return self.fail(src, "TODO MCValues split between registers and stack", .{});
4636 return self.fail("TODO MCValues split between registers and stack", .{});
45164637 } else {
45174638 ncrn = 4;
45184639 if (ty.abiAlignment(self.target.*) == 8)
......@@ -4526,7 +4647,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
45264647 result.stack_byte_count = nsaa;
45274648 result.stack_align = 4;
45284649 },
4529 else => return self.fail(src, "TODO implement function parameters for {} on arm", .{cc}),
4650 else => return self.fail("TODO implement function parameters for {} on arm", .{cc}),
45304651 }
45314652 },
45324653 .aarch64 => {
......@@ -4557,10 +4678,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
45574678 result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] };
45584679 ncrn += 1;
45594680 } else {
4560 return self.fail(src, "TODO MCValues with multiple registers", .{});
4681 return self.fail("TODO MCValues with multiple registers", .{});
45614682 }
45624683 } else if (ncrn < 8 and nsaa == 0) {
4563 return self.fail(src, "TODO MCValues split between registers and stack", .{});
4684 return self.fail("TODO MCValues split between registers and stack", .{});
45644685 } else {
45654686 ncrn = 8;
45664687 // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided
......@@ -4579,11 +4700,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
45794700 result.stack_byte_count = nsaa;
45804701 result.stack_align = 16;
45814702 },
4582 else => return self.fail(src, "TODO implement function parameters for {} on aarch64", .{cc}),
4703 else => return self.fail("TODO implement function parameters for {} on aarch64", .{cc}),
45834704 }
45844705 },
45854706 else => if (param_types.len != 0)
4586 return self.fail(src, "TODO implement codegen parameters for {}", .{self.target.cpu.arch}),
4707 return self.fail("TODO implement codegen parameters for {}", .{self.target.cpu.arch}),
45874708 }
45884709
45894710 if (ret_ty.zigTypeTag() == .NoReturn) {
......@@ -4598,7 +4719,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
45984719 const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size);
45994720 result.return_value = .{ .register = aliased_reg };
46004721 },
4601 else => return self.fail(src, "TODO implement function return values for {}", .{cc}),
4722 else => return self.fail("TODO implement function return values for {}", .{cc}),
46024723 },
46034724 .arm, .armeb => switch (cc) {
46044725 .Naked => unreachable,
......@@ -4607,10 +4728,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
46074728 if (ret_ty_size <= 4) {
46084729 result.return_value = .{ .register = c_abi_int_return_regs[0] };
46094730 } else {
4610 return self.fail(src, "TODO support more return types for ARM backend", .{});
4731 return self.fail("TODO support more return types for ARM backend", .{});
46114732 }
46124733 },
4613 else => return self.fail(src, "TODO implement function return values for {}", .{cc}),
4734 else => return self.fail("TODO implement function return values for {}", .{cc}),
46144735 },
46154736 .aarch64 => switch (cc) {
46164737 .Naked => unreachable,
......@@ -4619,12 +4740,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
46194740 if (ret_ty_size <= 8) {
46204741 result.return_value = .{ .register = c_abi_int_return_regs[0] };
46214742 } else {
4622 return self.fail(src, "TODO support more return types for ARM backend", .{});
4743 return self.fail("TODO support more return types for ARM backend", .{});
46234744 }
46244745 },
4625 else => return self.fail(src, "TODO implement function return values for {}", .{cc}),
4746 else => return self.fail("TODO implement function return values for {}", .{cc}),
46264747 },
4627 else => return self.fail(src, "TODO implement codegen return values for {}", .{self.target.cpu.arch}),
4748 else => return self.fail("TODO implement codegen return values for {}", .{self.target.cpu.arch}),
46284749 }
46294750 return result;
46304751 }
src/register_manager.zig+5-6
......@@ -147,14 +147,14 @@ pub fn RegisterManager(
147147 self.markRegUsed(reg);
148148 } else {
149149 const spilled_inst = self.registers[index].?;
150 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
150 try self.getFunction().spillInstruction(reg, spilled_inst);
151151 }
152152 self.registers[index] = inst;
153153 } else {
154154 // Don't track the register
155155 if (!self.isRegFree(reg)) {
156156 const spilled_inst = self.registers[index].?;
157 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
157 try self.getFunction().spillInstruction(reg, spilled_inst);
158158 self.freeReg(reg);
159159 }
160160 }
......@@ -184,7 +184,7 @@ pub fn RegisterManager(
184184 // stack allocation.
185185 const spilled_inst = self.registers[index].?;
186186 self.registers[index] = tracked_inst;
187 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
187 try self.getFunction().spillInstruction(reg, spilled_inst);
188188 } else {
189189 self.getRegAssumeFree(reg, tracked_inst);
190190 }
......@@ -193,7 +193,7 @@ pub fn RegisterManager(
193193 // Move the instruction that was previously there to a
194194 // stack allocation.
195195 const spilled_inst = self.registers[index].?;
196 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
196 try self.getFunction().spillInstruction(reg, spilled_inst);
197197 self.freeReg(reg);
198198 }
199199 }
......@@ -264,8 +264,7 @@ fn MockFunction(comptime Register: type) type {
264264 self.spilled.deinit(self.allocator);
265265 }
266266
267 pub fn spillInstruction(self: *Self, src: LazySrcLoc, reg: Register, inst: *ir.Inst) !void {
268 _ = src;
267 pub fn spillInstruction(self: *Self, reg: Register, inst: *ir.Inst) !void {
269268 _ = inst;
270269 try self.spilled.append(self.allocator, reg);
271270 }