| ... | @@ -111,11 +111,6 @@ const MCValue = union(enum) { | ... | @@ -111,11 +111,6 @@ const MCValue = union(enum) { |
| 111 | /// A pointer-sized integer that fits in a register. | 111 | /// A pointer-sized integer that fits in a register. |
| 112 | /// If the type is a pointer, this is the pointer address in virtual address space. | 112 | /// If the type is a pointer, this is the pointer address in virtual address space. |
| 113 | immediate: u64, | 113 | immediate: u64, |
| 114 | /// The constant was emitted into the code, at this offset. | | |
| 115 | /// If the type is a pointer, it means the pointer address is embedded in the code. | | |
| 116 | embedded_in_code: usize, | | |
| 117 | /// The value is a pointer to a constant which was emitted into the code, at this offset. | | |
| 118 | ptr_embedded_in_code: usize, | | |
| 119 | /// The value is in a target-specific register. | 114 | /// The value is in a target-specific register. |
| 120 | register: Register, | 115 | register: Register, |
| 121 | /// The value is in memory at a hard-coded address. | 116 | /// The value is in memory at a hard-coded address. |
| ... | @@ -129,7 +124,7 @@ const MCValue = union(enum) { | ... | @@ -129,7 +124,7 @@ const MCValue = union(enum) { |
| 129 | | 124 | |
| 130 | fn isMemory(mcv: MCValue) bool { | 125 | fn isMemory(mcv: MCValue) bool { |
| 131 | return switch (mcv) { | 126 | return switch (mcv) { |
| 132 | .embedded_in_code, .memory, .stack_offset => true, | 127 | .memory, .stack_offset => true, |
| 133 | else => false, | 128 | else => false, |
| 134 | }; | 129 | }; |
| 135 | } | 130 | } |
| ... | @@ -148,10 +143,8 @@ const MCValue = union(enum) { | ... | @@ -148,10 +143,8 @@ const MCValue = union(enum) { |
| 148 | .dead => unreachable, | 143 | .dead => unreachable, |
| 149 | | 144 | |
| 150 | .immediate, | 145 | .immediate, |
| 151 | .embedded_in_code, | | |
| 152 | .memory, | 146 | .memory, |
| 153 | .ptr_stack_offset, | 147 | .ptr_stack_offset, |
| 154 | .ptr_embedded_in_code, | | |
| 155 | .undef, | 148 | .undef, |
| 156 | => false, | 149 | => false, |
| 157 | | 150 | |
| ... | @@ -416,14 +409,17 @@ fn gen(self: *Self) !void { | ... | @@ -416,14 +409,17 @@ fn gen(self: *Self) !void { |
| 416 | }); | 409 | }); |
| 417 | | 410 | |
| 418 | // exitlude jumps | 411 | // exitlude jumps |
| 419 | if (self.exitlude_jump_relocs.items.len == 1) { | 412 | if (self.exitlude_jump_relocs.items.len > 0 and |
| 420 | // There is only one relocation. Hence, | 413 | self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2) |
| 421 | // this relocation must be at the end of | 414 | { |
| 422 | // the code. Therefore, we can just delete | 415 | // If the last Mir instruction (apart from the |
| 423 | // the space initially reserved for the | 416 | // dbg_epilogue_begin) is the last exitlude jump |
| 424 | // jump | 417 | // relocation (which would just jump one instruction |
| 425 | self.mir_instructions.len -= 1; | 418 | // further), it can be safely removed |
| 426 | } else for (self.exitlude_jump_relocs.items) |jmp_reloc| { | 419 | self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.pop()); |
| | 420 | } |
| | 421 | |
| | 422 | for (self.exitlude_jump_relocs.items) |jmp_reloc| { |
| 427 | _ = jmp_reloc; | 423 | _ = jmp_reloc; |
| 428 | return self.fail("TODO add branches in RISCV64", .{}); | 424 | return self.fail("TODO add branches in RISCV64", .{}); |
| 429 | } | 425 | } |
| ... | @@ -496,10 +492,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -496,10 +492,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 496 | | 492 | |
| 497 | switch (air_tags[inst]) { | 493 | switch (air_tags[inst]) { |
| 498 | // zig fmt: off | 494 | // zig fmt: off |
| 499 | .add, .ptr_add => try self.airAdd(inst), | 495 | .add, .ptr_add => try self.airBinOp(inst), |
| 500 | .addwrap => try self.airAddWrap(inst), | 496 | .addwrap => try self.airAddWrap(inst), |
| 501 | .add_sat => try self.airAddSat(inst), | 497 | .add_sat => try self.airAddSat(inst), |
| 502 | .sub, .ptr_sub => try self.airSub(inst), | 498 | .sub, .ptr_sub => try self.airBinOp(inst), |
| 503 | .subwrap => try self.airSubWrap(inst), | 499 | .subwrap => try self.airSubWrap(inst), |
| 504 | .sub_sat => try self.airSubSat(inst), | 500 | .sub_sat => try self.airSubSat(inst), |
| 505 | .mul => try self.airMul(inst), | 501 | .mul => try self.airMul(inst), |
| ... | @@ -927,9 +923,182 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -927,9 +923,182 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 927 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 923 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 928 | } | 924 | } |
| 929 | | 925 | |
| 930 | fn airAdd(self: *Self, inst: Air.Inst.Index) !void { | 926 | /// Don't call this function directly. Use binOp instead. |
| | 927 | /// |
| | 928 | /// Calling this function signals an intention to generate a Mir |
| | 929 | /// instruction of the form |
| | 930 | /// |
| | 931 | /// op dest, lhs, rhs |
| | 932 | /// |
| | 933 | /// Asserts that generating an instruction of that form is possible. |
| | 934 | fn binOpRegister( |
| | 935 | self: *Self, |
| | 936 | tag: Air.Inst.Tag, |
| | 937 | maybe_inst: ?Air.Inst.Index, |
| | 938 | lhs: MCValue, |
| | 939 | rhs: MCValue, |
| | 940 | lhs_ty: Type, |
| | 941 | rhs_ty: Type, |
| | 942 | ) !MCValue { |
| | 943 | const lhs_is_register = lhs == .register; |
| | 944 | const rhs_is_register = rhs == .register; |
| | 945 | |
| | 946 | if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register}); |
| | 947 | if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register}); |
| | 948 | |
| | 949 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| | 950 | |
| | 951 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { |
| | 952 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { |
| | 953 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 954 | break :inst Air.refToIndex(bin_op.lhs).?; |
| | 955 | } else null; |
| | 956 | |
| | 957 | const reg = try self.register_manager.allocReg(track_inst); |
| | 958 | self.register_manager.freezeRegs(&.{reg}); |
| | 959 | |
| | 960 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| | 961 | |
| | 962 | break :blk reg; |
| | 963 | }; |
| | 964 | defer self.register_manager.unfreezeRegs(&.{lhs_reg}); |
| | 965 | |
| | 966 | const rhs_reg = if (rhs_is_register) rhs.register else blk: { |
| | 967 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { |
| | 968 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 969 | break :inst Air.refToIndex(bin_op.rhs).?; |
| | 970 | } else null; |
| | 971 | |
| | 972 | const reg = try self.register_manager.allocReg(track_inst); |
| | 973 | self.register_manager.freezeRegs(&.{reg}); |
| | 974 | |
| | 975 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| | 976 | |
| | 977 | break :blk reg; |
| | 978 | }; |
| | 979 | defer self.register_manager.unfreezeRegs(&.{rhs_reg}); |
| | 980 | |
| | 981 | const dest_reg = if (maybe_inst) |inst| blk: { |
| | 982 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 983 | |
| | 984 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { |
| | 985 | break :blk lhs_reg; |
| | 986 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { |
| | 987 | break :blk rhs_reg; |
| | 988 | } else { |
| | 989 | break :blk try self.register_manager.allocReg(inst); |
| | 990 | } |
| | 991 | } else try self.register_manager.allocReg(null); |
| | 992 | |
| | 993 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| | 994 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); |
| | 995 | |
| | 996 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| | 997 | .add => .add, |
| | 998 | .sub => .sub, |
| | 999 | else => unreachable, |
| | 1000 | }; |
| | 1001 | const mir_data: Mir.Inst.Data = switch (tag) { |
| | 1002 | .add, |
| | 1003 | .sub, |
| | 1004 | => .{ .r_type = .{ |
| | 1005 | .rd = dest_reg, |
| | 1006 | .rs1 = lhs_reg, |
| | 1007 | .rs2 = rhs_reg, |
| | 1008 | } }, |
| | 1009 | else => unreachable, |
| | 1010 | }; |
| | 1011 | |
| | 1012 | _ = try self.addInst(.{ |
| | 1013 | .tag = mir_tag, |
| | 1014 | .data = mir_data, |
| | 1015 | }); |
| | 1016 | |
| | 1017 | return MCValue{ .register = dest_reg }; |
| | 1018 | } |
| | 1019 | |
| | 1020 | /// For all your binary operation needs, this function will generate |
| | 1021 | /// the corresponding Mir instruction(s). Returns the location of the |
| | 1022 | /// result. |
| | 1023 | /// |
| | 1024 | /// If the binary operation itself happens to be an Air instruction, |
| | 1025 | /// pass the corresponding index in the inst parameter. That helps |
| | 1026 | /// this function do stuff like reusing operands. |
| | 1027 | /// |
| | 1028 | /// This function does not do any lowering to Mir itself, but instead |
| | 1029 | /// looks at the lhs and rhs and determines which kind of lowering |
| | 1030 | /// would be best suitable and then delegates the lowering to other |
| | 1031 | /// functions. |
| | 1032 | fn binOp( |
| | 1033 | self: *Self, |
| | 1034 | tag: Air.Inst.Tag, |
| | 1035 | maybe_inst: ?Air.Inst.Index, |
| | 1036 | lhs: MCValue, |
| | 1037 | rhs: MCValue, |
| | 1038 | lhs_ty: Type, |
| | 1039 | rhs_ty: Type, |
| | 1040 | ) InnerError!MCValue { |
| | 1041 | switch (tag) { |
| | 1042 | // Arithmetic operations on integers and floats |
| | 1043 | .add, |
| | 1044 | .sub, |
| | 1045 | => { |
| | 1046 | switch (lhs_ty.zigTypeTag()) { |
| | 1047 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| | 1048 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| | 1049 | .Int => { |
| | 1050 | assert(lhs_ty.eql(rhs_ty)); |
| | 1051 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 1052 | if (int_info.bits <= 64) { |
| | 1053 | // TODO immediate operands |
| | 1054 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| | 1055 | } else { |
| | 1056 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| | 1057 | } |
| | 1058 | }, |
| | 1059 | else => unreachable, |
| | 1060 | } |
| | 1061 | }, |
| | 1062 | .ptr_add, |
| | 1063 | .ptr_sub, |
| | 1064 | => { |
| | 1065 | switch (lhs_ty.zigTypeTag()) { |
| | 1066 | .Pointer => { |
| | 1067 | const ptr_ty = lhs_ty; |
| | 1068 | const elem_ty = switch (ptr_ty.ptrSize()) { |
| | 1069 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type |
| | 1070 | else => ptr_ty.childType(), |
| | 1071 | }; |
| | 1072 | const elem_size = elem_ty.abiSize(self.target.*); |
| | 1073 | |
| | 1074 | if (elem_size == 1) { |
| | 1075 | const base_tag: Air.Inst.Tag = switch (tag) { |
| | 1076 | .ptr_add => .add, |
| | 1077 | .ptr_sub => .sub, |
| | 1078 | else => unreachable, |
| | 1079 | }; |
| | 1080 | |
| | 1081 | return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| | 1082 | } else { |
| | 1083 | return self.fail("TODO ptr_add with elem_size > 1", .{}); |
| | 1084 | } |
| | 1085 | }, |
| | 1086 | else => unreachable, |
| | 1087 | } |
| | 1088 | }, |
| | 1089 | else => unreachable, |
| | 1090 | } |
| | 1091 | } |
| | 1092 | |
| | 1093 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| | 1094 | const tag = self.air.instructions.items(.tag)[inst]; |
| 931 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1095 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 932 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add for {}", .{self.target.cpu.arch}); | 1096 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1097 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1098 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| | 1099 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| | 1100 | |
| | 1101 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); |
| 933 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1102 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 934 | } | 1103 | } |
| 935 | | 1104 | |
| ... | @@ -945,12 +1114,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -945,12 +1114,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 945 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1114 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 946 | } | 1115 | } |
| 947 | | 1116 | |
| 948 | fn airSub(self: *Self, inst: Air.Inst.Index) !void { | | |
| 949 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 950 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub for {}", .{self.target.cpu.arch}); | | |
| 951 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 952 | } | | |
| 953 | | | |
| 954 | fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void { | 1117 | fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void { |
| 955 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1118 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 956 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch}); | 1119 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch}); |
| ... | @@ -1283,12 +1446,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1283,12 +1446,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1283 | .dead => unreachable, | 1446 | .dead => unreachable, |
| 1284 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 1447 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 1285 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), | 1448 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| 1286 | .ptr_embedded_in_code => |off| { | | |
| 1287 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .embedded_in_code = off }); | | |
| 1288 | }, | | |
| 1289 | .embedded_in_code => { | | |
| 1290 | return self.fail("TODO implement loading from MCValue.embedded_in_code", .{}); | | |
| 1291 | }, | | |
| 1292 | .register => { | 1449 | .register => { |
| 1293 | return self.fail("TODO implement loading from MCValue.register", .{}); | 1450 | return self.fail("TODO implement loading from MCValue.register", .{}); |
| 1294 | }, | 1451 | }, |
| ... | @@ -1331,27 +1488,19 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1331,27 +1488,19 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1331 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1488 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1332 | } | 1489 | } |
| 1333 | | 1490 | |
| 1334 | fn airStore(self: *Self, inst: Air.Inst.Index) !void { | 1491 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void { |
| 1335 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1492 | _ = ptr_ty; |
| 1336 | const ptr = try self.resolveInst(bin_op.lhs); | 1493 | |
| 1337 | const value = try self.resolveInst(bin_op.rhs); | | |
| 1338 | const elem_ty = self.air.typeOf(bin_op.rhs); | | |
| 1339 | switch (ptr) { | 1494 | switch (ptr) { |
| 1340 | .none => unreachable, | 1495 | .none => unreachable, |
| 1341 | .undef => unreachable, | 1496 | .undef => unreachable, |
| 1342 | .unreach => unreachable, | 1497 | .unreach => unreachable, |
| 1343 | .dead => unreachable, | 1498 | .dead => unreachable, |
| 1344 | .immediate => |imm| { | 1499 | .immediate => |imm| { |
| 1345 | try self.setRegOrMem(elem_ty, .{ .memory = imm }, value); | 1500 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); |
| 1346 | }, | 1501 | }, |
| 1347 | .ptr_stack_offset => |off| { | 1502 | .ptr_stack_offset => |off| { |
| 1348 | try self.genSetStack(elem_ty, off, value); | 1503 | try self.genSetStack(value_ty, off, value); |
| 1349 | }, | | |
| 1350 | .ptr_embedded_in_code => |off| { | | |
| 1351 | try self.setRegOrMem(elem_ty, .{ .embedded_in_code = off }, value); | | |
| 1352 | }, | | |
| 1353 | .embedded_in_code => { | | |
| 1354 | return self.fail("TODO implement storing to MCValue.embedded_in_code", .{}); | | |
| 1355 | }, | 1504 | }, |
| 1356 | .register => { | 1505 | .register => { |
| 1357 | return self.fail("TODO implement storing to MCValue.register", .{}); | 1506 | return self.fail("TODO implement storing to MCValue.register", .{}); |
| ... | @@ -1363,6 +1512,17 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1363,6 +1512,17 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1363 | return self.fail("TODO implement storing to MCValue.stack_offset", .{}); | 1512 | return self.fail("TODO implement storing to MCValue.stack_offset", .{}); |
| 1364 | }, | 1513 | }, |
| 1365 | } | 1514 | } |
| | 1515 | } |
| | 1516 | |
| | 1517 | fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| | 1518 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 1519 | const ptr = try self.resolveInst(bin_op.lhs); |
| | 1520 | const value = try self.resolveInst(bin_op.rhs); |
| | 1521 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| | 1522 | const value_ty = self.air.typeOf(bin_op.rhs); |
| | 1523 | |
| | 1524 | try self.store(ptr, value, ptr_ty, value_ty); |
| | 1525 | |
| 1366 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 1526 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1367 | } | 1527 | } |
| 1368 | | 1528 | |
| ... | @@ -1508,7 +1668,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -1508,7 +1668,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1508 | .immediate => unreachable, | 1668 | .immediate => unreachable, |
| 1509 | .unreach => unreachable, | 1669 | .unreach => unreachable, |
| 1510 | .dead => unreachable, | 1670 | .dead => unreachable, |
| 1511 | .embedded_in_code => unreachable, | | |
| 1512 | .memory => unreachable, | 1671 | .memory => unreachable, |
| 1513 | .register => |reg| { | 1672 | .register => |reg| { |
| 1514 | try self.register_manager.getReg(reg, null); | 1673 | try self.register_manager.getReg(reg, null); |
| ... | @@ -1520,9 +1679,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -1520,9 +1679,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1520 | .ptr_stack_offset => { | 1679 | .ptr_stack_offset => { |
| 1521 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | 1680 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| 1522 | }, | 1681 | }, |
| 1523 | .ptr_embedded_in_code => { | | |
| 1524 | return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); | | |
| 1525 | }, | | |
| 1526 | } | 1682 | } |
| 1527 | } | 1683 | } |
| 1528 | | 1684 | |
| ... | @@ -2052,7 +2208,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -2052,7 +2208,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2052 | switch (mcv) { | 2208 | switch (mcv) { |
| 2053 | .dead => unreachable, | 2209 | .dead => unreachable, |
| 2054 | .ptr_stack_offset => unreachable, | 2210 | .ptr_stack_offset => unreachable, |
| 2055 | .ptr_embedded_in_code => unreachable, | | |
| 2056 | .unreach, .none => return, // Nothing to do. | 2211 | .unreach, .none => return, // Nothing to do. |
| 2057 | .undef => { | 2212 | .undef => { |
| 2058 | if (!self.wantSafety()) | 2213 | if (!self.wantSafety()) |
| ... | @@ -2098,6 +2253,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -2098,6 +2253,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2098 | return self.fail("TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf | 2253 | return self.fail("TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf |
| 2099 | } | 2254 | } |
| 2100 | }, | 2255 | }, |
| | 2256 | .register => |src_reg| { |
| | 2257 | // If the registers are the same, nothing to do. |
| | 2258 | if (src_reg.id() == reg.id()) |
| | 2259 | return; |
| | 2260 | |
| | 2261 | // mov reg, src_reg |
| | 2262 | _ = try self.addInst(.{ |
| | 2263 | .tag = .mv, |
| | 2264 | .data = .{ .rr = .{ |
| | 2265 | .rd = reg, |
| | 2266 | .rs = src_reg, |
| | 2267 | } }, |
| | 2268 | }); |
| | 2269 | }, |
| 2101 | .memory => |addr| { | 2270 | .memory => |addr| { |
| 2102 | // The value is in memory at a hard-coded address. | 2271 | // The value is in memory at a hard-coded address. |
| 2103 | // If the type is a pointer, it means the pointer address is at this memory location. | 2272 | // If the type is a pointer, it means the pointer address is at this memory location. |
| ... | @@ -2321,27 +2490,6 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | ... | @@ -2321,27 +2490,6 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 2321 | } | 2490 | } |
| 2322 | } | 2491 | } |
| 2323 | | 2492 | |
| 2324 | /// If the MCValue is an immediate, and it does not fit within this type, | | |
| 2325 | /// we put it in a register. | | |
| 2326 | /// A potential opportunity for future optimization here would be keeping track | | |
| 2327 | /// of the fact that the instruction is available both as an immediate | | |
| 2328 | /// and as a register. | | |
| 2329 | fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCValue { | | |
| 2330 | const mcv = try self.resolveInst(operand); | | |
| 2331 | const ti = @typeInfo(T).Int; | | |
| 2332 | switch (mcv) { | | |
| 2333 | .immediate => |imm| { | | |
| 2334 | // This immediate is unsigned. | | |
| 2335 | const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed)); | | |
| 2336 | if (imm >= math.maxInt(U)) { | | |
| 2337 | return MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.usize), mcv) }; | | |
| 2338 | } | | |
| 2339 | }, | | |
| 2340 | else => {}, | | |
| 2341 | } | | |
| 2342 | return mcv; | | |
| 2343 | } | | |
| 2344 | | | |
| 2345 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue { | 2493 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue { |
| 2346 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 2494 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 2347 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 2495 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |