| ... | @@ -91,7 +91,7 @@ register_manager: RegisterManager = .{}, | ... | @@ -91,7 +91,7 @@ register_manager: RegisterManager = .{}, |
| 91 | /// Maps offset to what is stored there. | 91 | /// Maps offset to what is stored there. |
| 92 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, | 92 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, |
| 93 | /// Tracks the current instruction allocated to the compare flags | 93 | /// Tracks the current instruction allocated to the compare flags |
| 94 | condition_flags_inst: ?Air.Inst.Index = null, | 94 | compare_flags_inst: ?Air.Inst.Index = null, |
| 95 | | 95 | |
| 96 | /// Offset from the stack base, representing the end of the stack frame. | 96 | /// Offset from the stack base, representing the end of the stack frame. |
| 97 | max_end_stack: u32 = 0, | 97 | max_end_stack: u32 = 0, |
| ... | @@ -154,7 +154,7 @@ const MCValue = union(enum) { | ... | @@ -154,7 +154,7 @@ const MCValue = union(enum) { |
| 154 | /// The value resides in the N, Z, C, V flags. The value is 1 (if | 154 | /// The value resides in the N, Z, C, V flags. The value is 1 (if |
| 155 | /// the type is u1) or true (if the type in bool) iff the | 155 | /// the type is u1) or true (if the type in bool) iff the |
| 156 | /// specified condition is true. | 156 | /// specified condition is true. |
| 157 | condition_flags: Condition, | 157 | compare_flags: Condition, |
| 158 | /// The value is a function argument passed via the stack. | 158 | /// The value is a function argument passed via the stack. |
| 159 | stack_argument_offset: u32, | 159 | stack_argument_offset: u32, |
| 160 | }; | 160 | }; |
| ... | @@ -201,6 +201,29 @@ const BigTomb = struct { | ... | @@ -201,6 +201,29 @@ const BigTomb = struct { |
| 201 | log.debug("%{d} => {}", .{ bt.inst, result }); | 201 | log.debug("%{d} => {}", .{ bt.inst, result }); |
| 202 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; | 202 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; |
| 203 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); | 203 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); |
| | 204 | |
| | 205 | switch (result) { |
| | 206 | .register => |reg| { |
| | 207 | // In some cases (such as bitcast), an operand |
| | 208 | // may be the same MCValue as the result. If |
| | 209 | // that operand died and was a register, it |
| | 210 | // was freed by processDeath. We have to |
| | 211 | // "re-allocate" the register. |
| | 212 | if (bt.function.register_manager.isRegFree(reg)) { |
| | 213 | bt.function.register_manager.getRegAssumeFree(reg, bt.inst); |
| | 214 | } |
| | 215 | }, |
| | 216 | .register_with_overflow => |rwo| { |
| | 217 | if (bt.function.register_manager.isRegFree(rwo.reg)) { |
| | 218 | bt.function.register_manager.getRegAssumeFree(rwo.reg, bt.inst); |
| | 219 | } |
| | 220 | bt.function.compare_flags_inst = bt.inst; |
| | 221 | }, |
| | 222 | .compare_flags => |_| { |
| | 223 | bt.function.compare_flags_inst = bt.inst; |
| | 224 | }, |
| | 225 | else => {}, |
| | 226 | } |
| 204 | } | 227 | } |
| 205 | bt.function.finishAirBookkeeping(); | 228 | bt.function.finishAirBookkeeping(); |
| 206 | } | 229 | } |
| ... | @@ -539,8 +562,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -539,8 +562,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 539 | .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), | 562 | .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), |
| 540 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), | 563 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), |
| 541 | | 564 | |
| 542 | .min => try self.airMin(inst), | 565 | .min => try self.airMinMax(inst), |
| 543 | .max => try self.airMax(inst), | 566 | .max => try self.airMinMax(inst), |
| 544 | | 567 | |
| 545 | .add_sat => try self.airAddSat(inst), | 568 | .add_sat => try self.airAddSat(inst), |
| 546 | .sub_sat => try self.airSubSat(inst), | 569 | .sub_sat => try self.airSubSat(inst), |
| ... | @@ -764,10 +787,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { | ... | @@ -764,10 +787,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 764 | }, | 787 | }, |
| 765 | .register_with_overflow => |rwo| { | 788 | .register_with_overflow => |rwo| { |
| 766 | self.register_manager.freeReg(rwo.reg); | 789 | self.register_manager.freeReg(rwo.reg); |
| 767 | self.condition_flags_inst = null; | 790 | self.compare_flags_inst = null; |
| 768 | }, | 791 | }, |
| 769 | .condition_flags => { | 792 | .compare_flags => { |
| 770 | self.condition_flags_inst = null; | 793 | self.compare_flags_inst = null; |
| 771 | }, | 794 | }, |
| 772 | else => {}, // TODO process stack allocation death | 795 | else => {}, // TODO process stack allocation death |
| 773 | } | 796 | } |
| ... | @@ -808,6 +831,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -808,6 +831,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 808 | self.register_manager.getRegAssumeFree(reg, inst); | 831 | self.register_manager.getRegAssumeFree(reg, inst); |
| 809 | } | 832 | } |
| 810 | }, | 833 | }, |
| | 834 | .register_with_overflow => |rwo| { |
| | 835 | if (self.register_manager.isRegFree(rwo.reg)) { |
| | 836 | self.register_manager.getRegAssumeFree(rwo.reg, inst); |
| | 837 | } |
| | 838 | self.compare_flags_inst = inst; |
| | 839 | }, |
| | 840 | .compare_flags => |_| { |
| | 841 | self.compare_flags_inst = inst; |
| | 842 | }, |
| 811 | else => {}, | 843 | else => {}, |
| 812 | } | 844 | } |
| 813 | } | 845 | } |
| ... | @@ -931,11 +963,11 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -931,11 +963,11 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 931 | /// Save the current instruction stored in the compare flags if | 963 | /// Save the current instruction stored in the compare flags if |
| 932 | /// occupied | 964 | /// occupied |
| 933 | fn spillCompareFlagsIfOccupied(self: *Self) !void { | 965 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 934 | if (self.condition_flags_inst) |inst_to_save| { | 966 | if (self.compare_flags_inst) |inst_to_save| { |
| 935 | const ty = self.air.typeOfIndex(inst_to_save); | 967 | const ty = self.air.typeOfIndex(inst_to_save); |
| 936 | const mcv = self.getResolvedInstValue(inst_to_save); | 968 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 937 | const new_mcv = switch (mcv) { | 969 | const new_mcv = switch (mcv) { |
| 938 | .condition_flags => try self.allocRegOrMem(ty, true, inst_to_save), | 970 | .compare_flags => try self.allocRegOrMem(ty, true, inst_to_save), |
| 939 | .register_with_overflow => try self.allocRegOrMem(ty, false, inst_to_save), | 971 | .register_with_overflow => try self.allocRegOrMem(ty, false, inst_to_save), |
| 940 | else => unreachable, // mcv doesn't occupy the compare flags | 972 | else => unreachable, // mcv doesn't occupy the compare flags |
| 941 | }; | 973 | }; |
| ... | @@ -946,7 +978,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -946,7 +978,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 946 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 978 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 947 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); | 979 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); |
| 948 | | 980 | |
| 949 | self.condition_flags_inst = null; | 981 | self.compare_flags_inst = null; |
| 950 | | 982 | |
| 951 | // TODO consolidate with register manager and spillInstruction | 983 | // TODO consolidate with register manager and spillInstruction |
| 952 | // this call should really belong in the register manager! | 984 | // this call should really belong in the register manager! |
| ... | @@ -984,8 +1016,27 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -984,8 +1016,27 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 984 | } | 1016 | } |
| 985 | | 1017 | |
| 986 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { | 1018 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 987 | const stack_offset = try self.allocMemPtr(inst); | 1019 | const result: MCValue = switch (self.ret_mcv) { |
| 988 | return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); | 1020 | .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, |
| | 1021 | .stack_offset => blk: { |
| | 1022 | // self.ret_mcv is an address to where this function |
| | 1023 | // should store its result into |
| | 1024 | const ret_ty = self.fn_type.fnReturnType(); |
| | 1025 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| | 1026 | .base = .{ .tag = .single_mut_pointer }, |
| | 1027 | .data = ret_ty, |
| | 1028 | }; |
| | 1029 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); |
| | 1030 | |
| | 1031 | // addr_reg will contain the address of where to store the |
| | 1032 | // result into |
| | 1033 | const addr_reg = try self.copyToTmpRegister(ptr_ty, self.ret_mcv); |
| | 1034 | break :blk .{ .register = addr_reg }; |
| | 1035 | }, |
| | 1036 | else => unreachable, // invalid return result |
| | 1037 | }; |
| | 1038 | |
| | 1039 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 989 | } | 1040 | } |
| 990 | | 1041 | |
| 991 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { | 1042 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1155,7 +1206,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1155,7 +1206,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1155 | switch (operand) { | 1206 | switch (operand) { |
| 1156 | .dead => unreachable, | 1207 | .dead => unreachable, |
| 1157 | .unreach => unreachable, | 1208 | .unreach => unreachable, |
| 1158 | .condition_flags => |cond| break :result MCValue{ .condition_flags = cond.negate() }, | 1209 | .compare_flags => |cond| break :result MCValue{ .compare_flags = cond.negate() }, |
| 1159 | else => { | 1210 | else => { |
| 1160 | switch (operand_ty.zigTypeTag()) { | 1211 | switch (operand_ty.zigTypeTag()) { |
| 1161 | .Bool => { | 1212 | .Bool => { |
| ... | @@ -1234,15 +1285,102 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1234,15 +1285,102 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1234 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1285 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1235 | } | 1286 | } |
| 1236 | | 1287 | |
| 1237 | fn airMin(self: *Self, inst: Air.Inst.Index) !void { | 1288 | fn minMax( |
| 1238 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1289 | self: *Self, |
| 1239 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement min for {}", .{self.target.cpu.arch}); | 1290 | tag: Air.Inst.Tag, |
| 1240 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1291 | lhs_bind: ReadArg.Bind, |
| | 1292 | rhs_bind: ReadArg.Bind, |
| | 1293 | lhs_ty: Type, |
| | 1294 | rhs_ty: Type, |
| | 1295 | maybe_inst: ?Air.Inst.Index, |
| | 1296 | ) !MCValue { |
| | 1297 | switch (lhs_ty.zigTypeTag()) { |
| | 1298 | .Float => return self.fail("TODO ARM min/max on floats", .{}), |
| | 1299 | .Vector => return self.fail("TODO ARM min/max on vectors", .{}), |
| | 1300 | .Int => { |
| | 1301 | const mod = self.bin_file.options.module.?; |
| | 1302 | assert(lhs_ty.eql(rhs_ty, mod)); |
| | 1303 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 1304 | if (int_info.bits <= 64) { |
| | 1305 | var lhs_reg: Register = undefined; |
| | 1306 | var rhs_reg: Register = undefined; |
| | 1307 | var dest_reg: Register = undefined; |
| | 1308 | |
| | 1309 | const read_args = [_]ReadArg{ |
| | 1310 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| | 1311 | .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg }, |
| | 1312 | }; |
| | 1313 | const write_args = [_]WriteArg{ |
| | 1314 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| | 1315 | }; |
| | 1316 | try self.allocRegs( |
| | 1317 | &read_args, |
| | 1318 | &write_args, |
| | 1319 | if (maybe_inst) |inst| .{ |
| | 1320 | .corresponding_inst = inst, |
| | 1321 | .operand_mapping = &.{ 0, 1 }, |
| | 1322 | } else null, |
| | 1323 | ); |
| | 1324 | |
| | 1325 | // lhs == reg should have been checked by airMinMax |
| | 1326 | assert(lhs_reg != rhs_reg); // see note above |
| | 1327 | |
| | 1328 | _ = try self.addInst(.{ |
| | 1329 | .tag = .cmp_shifted_register, |
| | 1330 | .data = .{ .rr_imm6_shift = .{ |
| | 1331 | .rn = lhs_reg, |
| | 1332 | .rm = rhs_reg, |
| | 1333 | .imm6 = 0, |
| | 1334 | .shift = .lsl, |
| | 1335 | } }, |
| | 1336 | }); |
| | 1337 | |
| | 1338 | const cond_choose_lhs: Condition = switch (tag) { |
| | 1339 | .max => switch (int_info.signedness) { |
| | 1340 | .signed => Condition.gt, |
| | 1341 | .unsigned => Condition.hi, |
| | 1342 | }, |
| | 1343 | .min => switch (int_info.signedness) { |
| | 1344 | .signed => Condition.lt, |
| | 1345 | .unsigned => Condition.cc, |
| | 1346 | }, |
| | 1347 | else => unreachable, |
| | 1348 | }; |
| | 1349 | |
| | 1350 | _ = try self.addInst(.{ |
| | 1351 | .tag = .csel, |
| | 1352 | .data = .{ .rrr_cond = .{ |
| | 1353 | .rd = dest_reg, |
| | 1354 | .rn = lhs_reg, |
| | 1355 | .rm = rhs_reg, |
| | 1356 | .cond = cond_choose_lhs, |
| | 1357 | } }, |
| | 1358 | }); |
| | 1359 | |
| | 1360 | return MCValue{ .register = dest_reg }; |
| | 1361 | } else { |
| | 1362 | return self.fail("TODO ARM min/max on integers > u32/i32", .{}); |
| | 1363 | } |
| | 1364 | }, |
| | 1365 | else => unreachable, |
| | 1366 | } |
| 1241 | } | 1367 | } |
| 1242 | | 1368 | |
| 1243 | fn airMax(self: *Self, inst: Air.Inst.Index) !void { | 1369 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { |
| | 1370 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1244 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1371 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1245 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement max for {}", .{self.target.cpu.arch}); | 1372 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| | 1373 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| | 1374 | |
| | 1375 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1376 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| | 1377 | const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| | 1378 | |
| | 1379 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1380 | if (bin_op.lhs == bin_op.rhs) break :result lhs; |
| | 1381 | |
| | 1382 | break :result try self.minMax(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst); |
| | 1383 | }; |
| 1246 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1384 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1247 | } | 1385 | } |
| 1248 | | 1386 | |
| ... | @@ -1477,9 +1615,9 @@ fn allocRegs( | ... | @@ -1477,9 +1615,9 @@ fn allocRegs( |
| 1477 | // If the previous MCValue occupied some space we track, we | 1615 | // If the previous MCValue occupied some space we track, we |
| 1478 | // need to make sure it is marked as free now. | 1616 | // need to make sure it is marked as free now. |
| 1479 | switch (mcv) { | 1617 | switch (mcv) { |
| 1480 | .condition_flags => { | 1618 | .compare_flags => { |
| 1481 | assert(self.condition_flags_inst.? == inst); | 1619 | assert(self.compare_flags_inst.? == inst); |
| 1482 | self.condition_flags_inst = null; | 1620 | self.compare_flags_inst = null; |
| 1483 | }, | 1621 | }, |
| 1484 | .register => |prev_reg| { | 1622 | .register => |prev_reg| { |
| 1485 | assert(!self.register_manager.isRegFree(prev_reg)); | 1623 | assert(!self.register_manager.isRegFree(prev_reg)); |
| ... | @@ -2276,7 +2414,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2276,7 +2414,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2276 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 2414 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 2277 | | 2415 | |
| 2278 | try self.spillCompareFlagsIfOccupied(); | 2416 | try self.spillCompareFlagsIfOccupied(); |
| 2279 | self.condition_flags_inst = null; | 2417 | self.compare_flags_inst = null; |
| 2280 | | 2418 | |
| 2281 | const base_tag: Air.Inst.Tag = switch (tag) { | 2419 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 2282 | .add_with_overflow => .add, | 2420 | .add_with_overflow => .add, |
| ... | @@ -2308,7 +2446,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2308,7 +2446,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2308 | }); | 2446 | }); |
| 2309 | | 2447 | |
| 2310 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2448 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2311 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); | 2449 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2312 | | 2450 | |
| 2313 | break :result MCValue{ .stack_offset = stack_offset }; | 2451 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2314 | }, | 2452 | }, |
| ... | @@ -2343,7 +2481,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2343,7 +2481,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2343 | }; | 2481 | }; |
| 2344 | | 2482 | |
| 2345 | try self.spillCompareFlagsIfOccupied(); | 2483 | try self.spillCompareFlagsIfOccupied(); |
| 2346 | self.condition_flags_inst = inst; | 2484 | self.compare_flags_inst = inst; |
| 2347 | | 2485 | |
| 2348 | const dest = blk: { | 2486 | const dest = blk: { |
| 2349 | if (rhs_immediate_ok) { | 2487 | if (rhs_immediate_ok) { |
| ... | @@ -2452,7 +2590,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2452,7 +2590,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2452 | } | 2590 | } |
| 2453 | | 2591 | |
| 2454 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2592 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2455 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); | 2593 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2456 | | 2594 | |
| 2457 | break :result MCValue{ .stack_offset = stack_offset }; | 2595 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2458 | } else if (int_info.bits <= 64) { | 2596 | } else if (int_info.bits <= 64) { |
| ... | @@ -2592,7 +2730,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2592,7 +2730,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2592 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); | 2730 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 2593 | | 2731 | |
| 2594 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2732 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2595 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); | 2733 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2596 | | 2734 | |
| 2597 | break :result MCValue{ .stack_offset = stack_offset }; | 2735 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2598 | } else return self.fail("TODO implement mul_with_overflow for integers > u64/i64", .{}); | 2736 | } else return self.fail("TODO implement mul_with_overflow for integers > u64/i64", .{}); |
| ... | @@ -2724,7 +2862,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2724,7 +2862,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2724 | }); | 2862 | }); |
| 2725 | | 2863 | |
| 2726 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg }); | 2864 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg }); |
| 2727 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); | 2865 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2728 | | 2866 | |
| 2729 | break :result MCValue{ .stack_offset = stack_offset }; | 2867 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2730 | } else { | 2868 | } else { |
| ... | @@ -2890,7 +3028,23 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2890,7 +3028,23 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2890 | /// T to E!T | 3028 | /// T to E!T |
| 2891 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | 3029 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2892 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3030 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2893 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement wrap errunion payload for {}", .{self.target.cpu.arch}); | 3031 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 3032 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| | 3033 | const error_ty = error_union_ty.errorUnionSet(); |
| | 3034 | const payload_ty = error_union_ty.errorUnionPayload(); |
| | 3035 | const operand = try self.resolveInst(ty_op.operand); |
| | 3036 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; |
| | 3037 | |
| | 3038 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| | 3039 | const abi_align = error_union_ty.abiAlignment(self.target.*); |
| | 3040 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| | 3041 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); |
| | 3042 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); |
| | 3043 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand); |
| | 3044 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 }); |
| | 3045 | |
| | 3046 | break :result MCValue{ .stack_offset = stack_offset }; |
| | 3047 | }; |
| 2894 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3048 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2895 | } | 3049 | } |
| 2896 | | 3050 | |
| ... | @@ -2899,11 +3053,20 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2899,11 +3053,20 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2899 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3053 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2900 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3054 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2901 | const error_union_ty = self.air.getRefType(ty_op.ty); | 3055 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| | 3056 | const error_ty = error_union_ty.errorUnionSet(); |
| 2902 | const payload_ty = error_union_ty.errorUnionPayload(); | 3057 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2903 | const mcv = try self.resolveInst(ty_op.operand); | 3058 | const operand = try self.resolveInst(ty_op.operand); |
| 2904 | if (!payload_ty.hasRuntimeBits()) break :result mcv; | 3059 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; |
| 2905 | | 3060 | |
| 2906 | return self.fail("TODO implement wrap errunion error for non-empty payloads", .{}); | 3061 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| | 3062 | const abi_align = error_union_ty.abiAlignment(self.target.*); |
| | 3063 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| | 3064 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); |
| | 3065 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); |
| | 3066 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand); |
| | 3067 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef); |
| | 3068 | |
| | 3069 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2907 | }; | 3070 | }; |
| 2908 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3071 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2909 | } | 3072 | } |
| ... | @@ -3175,7 +3338,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -3175,7 +3338,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 3175 | .undef => unreachable, | 3338 | .undef => unreachable, |
| 3176 | .unreach => unreachable, | 3339 | .unreach => unreachable, |
| 3177 | .dead => unreachable, | 3340 | .dead => unreachable, |
| 3178 | .condition_flags, | 3341 | .compare_flags, |
| 3179 | .register_with_overflow, | 3342 | .register_with_overflow, |
| 3180 | => unreachable, // cannot hold an address | 3343 | => unreachable, // cannot hold an address |
| 3181 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 3344 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| ... | @@ -3187,7 +3350,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -3187,7 +3350,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 3187 | switch (dst_mcv) { | 3350 | switch (dst_mcv) { |
| 3188 | .dead => unreachable, | 3351 | .dead => unreachable, |
| 3189 | .undef => unreachable, | 3352 | .undef => unreachable, |
| 3190 | .condition_flags => unreachable, | 3353 | .compare_flags => unreachable, |
| 3191 | .register => |dst_reg| { | 3354 | .register => |dst_reg| { |
| 3192 | try self.genLdrRegister(dst_reg, addr_reg, elem_ty); | 3355 | try self.genLdrRegister(dst_reg, addr_reg, elem_ty); |
| 3193 | }, | 3356 | }, |
| ... | @@ -3315,6 +3478,104 @@ fn genInlineMemcpy( | ... | @@ -3315,6 +3478,104 @@ fn genInlineMemcpy( |
| 3315 | // end: | 3478 | // end: |
| 3316 | } | 3479 | } |
| 3317 | | 3480 | |
| | 3481 | fn genInlineMemset( |
| | 3482 | self: *Self, |
| | 3483 | dst: MCValue, |
| | 3484 | val: MCValue, |
| | 3485 | len: MCValue, |
| | 3486 | ) !void { |
| | 3487 | const dst_reg = switch (dst) { |
| | 3488 | .register => |r| r, |
| | 3489 | else => try self.copyToTmpRegister(Type.initTag(.manyptr_u8), dst), |
| | 3490 | }; |
| | 3491 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| | 3492 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3493 | |
| | 3494 | const val_reg = switch (val) { |
| | 3495 | .register => |r| r, |
| | 3496 | else => try self.copyToTmpRegister(Type.initTag(.u8), val), |
| | 3497 | }; |
| | 3498 | const val_reg_lock = self.register_manager.lockReg(val_reg); |
| | 3499 | defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3500 | |
| | 3501 | const len_reg = switch (len) { |
| | 3502 | .register => |r| r, |
| | 3503 | else => try self.copyToTmpRegister(Type.usize, len), |
| | 3504 | }; |
| | 3505 | const len_reg_lock = self.register_manager.lockReg(len_reg); |
| | 3506 | defer if (len_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3507 | |
| | 3508 | const count_reg = try self.register_manager.allocReg(null, gp); |
| | 3509 | |
| | 3510 | try self.genInlineMemsetCode(dst_reg, val_reg, len_reg, count_reg); |
| | 3511 | } |
| | 3512 | |
| | 3513 | fn genInlineMemsetCode( |
| | 3514 | self: *Self, |
| | 3515 | dst: Register, |
| | 3516 | val: Register, |
| | 3517 | len: Register, |
| | 3518 | count: Register, |
| | 3519 | ) !void { |
| | 3520 | // mov count, #0 |
| | 3521 | _ = try self.addInst(.{ |
| | 3522 | .tag = .movz, |
| | 3523 | .data = .{ .r_imm16_sh = .{ |
| | 3524 | .rd = count, |
| | 3525 | .imm16 = 0, |
| | 3526 | } }, |
| | 3527 | }); |
| | 3528 | |
| | 3529 | // loop: |
| | 3530 | // cmp count, len |
| | 3531 | _ = try self.addInst(.{ |
| | 3532 | .tag = .cmp_shifted_register, |
| | 3533 | .data = .{ .rr_imm6_shift = .{ |
| | 3534 | .rn = count, |
| | 3535 | .rm = len, |
| | 3536 | .imm6 = 0, |
| | 3537 | .shift = .lsl, |
| | 3538 | } }, |
| | 3539 | }); |
| | 3540 | |
| | 3541 | // bge end |
| | 3542 | _ = try self.addInst(.{ |
| | 3543 | .tag = .b_cond, |
| | 3544 | .data = .{ .inst_cond = .{ |
| | 3545 | .inst = @intCast(u32, self.mir_instructions.len + 4), |
| | 3546 | .cond = .ge, |
| | 3547 | } }, |
| | 3548 | }); |
| | 3549 | |
| | 3550 | // strb val, [src, count] |
| | 3551 | _ = try self.addInst(.{ |
| | 3552 | .tag = .strb_register, |
| | 3553 | .data = .{ .load_store_register_register = .{ |
| | 3554 | .rt = val, |
| | 3555 | .rn = dst, |
| | 3556 | .offset = Instruction.LoadStoreOffset.reg(count).register, |
| | 3557 | } }, |
| | 3558 | }); |
| | 3559 | |
| | 3560 | // add count, count, #1 |
| | 3561 | _ = try self.addInst(.{ |
| | 3562 | .tag = .add_immediate, |
| | 3563 | .data = .{ .rr_imm12_sh = .{ |
| | 3564 | .rd = count, |
| | 3565 | .rn = count, |
| | 3566 | .imm12 = 1, |
| | 3567 | } }, |
| | 3568 | }); |
| | 3569 | |
| | 3570 | // b loop |
| | 3571 | _ = try self.addInst(.{ |
| | 3572 | .tag = .b, |
| | 3573 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len - 4) }, |
| | 3574 | }); |
| | 3575 | |
| | 3576 | // end: |
| | 3577 | } |
| | 3578 | |
| 3318 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | 3579 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3319 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3580 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3320 | const elem_ty = self.air.typeOfIndex(inst); | 3581 | const elem_ty = self.air.typeOfIndex(inst); |
| ... | @@ -3389,6 +3650,7 @@ fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type | ... | @@ -3389,6 +3650,7 @@ fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type |
| 3389 | } | 3650 | } |
| 3390 | | 3651 | |
| 3391 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { | 3652 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| | 3653 | log.debug("store: storing {} to {}", .{ value, ptr }); |
| 3392 | const abi_size = value_ty.abiSize(self.target.*); | 3654 | const abi_size = value_ty.abiSize(self.target.*); |
| 3393 | | 3655 | |
| 3394 | switch (ptr) { | 3656 | switch (ptr) { |
| ... | @@ -3396,7 +3658,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3396,7 +3658,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3396 | .undef => unreachable, | 3658 | .undef => unreachable, |
| 3397 | .unreach => unreachable, | 3659 | .unreach => unreachable, |
| 3398 | .dead => unreachable, | 3660 | .dead => unreachable, |
| 3399 | .condition_flags, | 3661 | .compare_flags, |
| 3400 | .register_with_overflow, | 3662 | .register_with_overflow, |
| 3401 | => unreachable, // cannot hold an address | 3663 | => unreachable, // cannot hold an address |
| 3402 | .immediate => |imm| { | 3664 | .immediate => |imm| { |
| ... | @@ -3413,6 +3675,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3413,6 +3675,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3413 | .dead => unreachable, | 3675 | .dead => unreachable, |
| 3414 | .undef => unreachable, | 3676 | .undef => unreachable, |
| 3415 | .register => |value_reg| { | 3677 | .register => |value_reg| { |
| | 3678 | log.debug("store: register {} to {}", .{ value_reg, addr_reg }); |
| 3416 | try self.genStrRegister(value_reg, addr_reg, value_ty); | 3679 | try self.genStrRegister(value_reg, addr_reg, value_ty); |
| 3417 | }, | 3680 | }, |
| 3418 | else => { | 3681 | else => { |
| ... | @@ -3431,8 +3694,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3431,8 +3694,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3431 | self.register_manager.unlockReg(reg); | 3694 | self.register_manager.unlockReg(reg); |
| 3432 | }; | 3695 | }; |
| 3433 | | 3696 | |
| 3434 | const src_reg = addr_reg; | 3697 | const src_reg = regs[0]; |
| 3435 | const dst_reg = regs[0]; | 3698 | const dst_reg = addr_reg; |
| 3436 | const len_reg = regs[1]; | 3699 | const len_reg = regs[1]; |
| 3437 | const count_reg = regs[2]; | 3700 | const count_reg = regs[2]; |
| 3438 | const tmp_reg = regs[3]; | 3701 | const tmp_reg = regs[3]; |
| ... | @@ -3442,7 +3705,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3442,7 +3705,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3442 | // sub src_reg, fp, #off | 3705 | // sub src_reg, fp, #off |
| 3443 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); | 3706 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| 3444 | }, | 3707 | }, |
| 3445 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }), | | |
| 3446 | .stack_argument_offset => |off| { | 3708 | .stack_argument_offset => |off| { |
| 3447 | _ = try self.addInst(.{ | 3709 | _ = try self.addInst(.{ |
| 3448 | .tag = .ldr_ptr_stack_argument, | 3710 | .tag = .ldr_ptr_stack_argument, |
| ... | @@ -3452,6 +3714,24 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3452,6 +3714,24 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3452 | } }, | 3714 | } }, |
| 3453 | }); | 3715 | }); |
| 3454 | }, | 3716 | }, |
| | 3717 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }), |
| | 3718 | .linker_load => |load_struct| { |
| | 3719 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { |
| | 3720 | .got => .load_memory_ptr_got, |
| | 3721 | .direct => .load_memory_ptr_direct, |
| | 3722 | }; |
| | 3723 | const mod = self.bin_file.options.module.?; |
| | 3724 | _ = try self.addInst(.{ |
| | 3725 | .tag = tag, |
| | 3726 | .data = .{ |
| | 3727 | .payload = try self.addExtra(Mir.LoadMemoryPie{ |
| | 3728 | .register = @enumToInt(src_reg), |
| | 3729 | .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index, |
| | 3730 | .sym_index = load_struct.sym_index, |
| | 3731 | }), |
| | 3732 | }, |
| | 3733 | }); |
| | 3734 | }, |
| 3455 | else => return self.fail("TODO store {} to register", .{value}), | 3735 | else => return self.fail("TODO store {} to register", .{value}), |
| 3456 | } | 3736 | } |
| 3457 | | 3737 | |
| ... | @@ -3551,7 +3831,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3551,7 +3831,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3551 | 0 => MCValue{ .register = rwo.reg }, | 3831 | 0 => MCValue{ .register = rwo.reg }, |
| 3552 | | 3832 | |
| 3553 | // get overflow bit: return C or V flag | 3833 | // get overflow bit: return C or V flag |
| 3554 | 1 => MCValue{ .condition_flags = rwo.flag }, | 3834 | 1 => MCValue{ .compare_flags = rwo.flag }, |
| 3555 | | 3835 | |
| 3556 | else => unreachable, | 3836 | else => unreachable, |
| 3557 | }; | 3837 | }; |
| ... | @@ -4005,8 +4285,8 @@ fn cmp( | ... | @@ -4005,8 +4285,8 @@ fn cmp( |
| 4005 | } | 4285 | } |
| 4006 | | 4286 | |
| 4007 | return switch (int_info.signedness) { | 4287 | return switch (int_info.signedness) { |
| 4008 | .signed => MCValue{ .condition_flags = Condition.fromCompareOperatorSigned(op) }, | 4288 | .signed => MCValue{ .compare_flags = Condition.fromCompareOperatorSigned(op) }, |
| 4009 | .unsigned => MCValue{ .condition_flags = Condition.fromCompareOperatorUnsigned(op) }, | 4289 | .unsigned => MCValue{ .compare_flags = Condition.fromCompareOperatorUnsigned(op) }, |
| 4010 | }; | 4290 | }; |
| 4011 | } else { | 4291 | } else { |
| 4012 | return self.fail("TODO AArch64 cmp for ints > 64 bits", .{}); | 4292 | return self.fail("TODO AArch64 cmp for ints > 64 bits", .{}); |
| ... | @@ -4064,7 +4344,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4064,7 +4344,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4064 | | 4344 | |
| 4065 | fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { | 4345 | fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { |
| 4066 | switch (condition) { | 4346 | switch (condition) { |
| 4067 | .condition_flags => |cond| return try self.addInst(.{ | 4347 | .compare_flags => |cond| return try self.addInst(.{ |
| 4068 | .tag = .b_cond, | 4348 | .tag = .b_cond, |
| 4069 | .data = .{ | 4349 | .data = .{ |
| 4070 | .inst_cond = .{ | 4350 | .inst_cond = .{ |
| ... | @@ -4120,7 +4400,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4120,7 +4400,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4120 | var parent_stack = try self.stack.clone(self.gpa); | 4400 | var parent_stack = try self.stack.clone(self.gpa); |
| 4121 | defer parent_stack.deinit(self.gpa); | 4401 | defer parent_stack.deinit(self.gpa); |
| 4122 | const parent_registers = self.register_manager.registers; | 4402 | const parent_registers = self.register_manager.registers; |
| 4123 | const parent_condition_flags_inst = self.condition_flags_inst; | 4403 | const parent_compare_flags_inst = self.compare_flags_inst; |
| 4124 | | 4404 | |
| 4125 | try self.branch_stack.append(.{}); | 4405 | try self.branch_stack.append(.{}); |
| 4126 | errdefer { | 4406 | errdefer { |
| ... | @@ -4139,7 +4419,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4139,7 +4419,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4139 | defer saved_then_branch.deinit(self.gpa); | 4419 | defer saved_then_branch.deinit(self.gpa); |
| 4140 | | 4420 | |
| 4141 | self.register_manager.registers = parent_registers; | 4421 | self.register_manager.registers = parent_registers; |
| 4142 | self.condition_flags_inst = parent_condition_flags_inst; | 4422 | self.compare_flags_inst = parent_compare_flags_inst; |
| 4143 | | 4423 | |
| 4144 | self.stack.deinit(self.gpa); | 4424 | self.stack.deinit(self.gpa); |
| 4145 | self.stack = parent_stack; | 4425 | self.stack = parent_stack; |
| ... | @@ -4186,7 +4466,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4186,7 +4466,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4186 | if (else_value == .dead) | 4466 | if (else_value == .dead) |
| 4187 | continue; | 4467 | continue; |
| 4188 | // The instruction is only overridden in the else branch. | 4468 | // The instruction is only overridden in the else branch. |
| 4189 | var i: usize = self.branch_stack.items.len - 2; | 4469 | var i: usize = self.branch_stack.items.len - 1; |
| 4190 | while (true) { | 4470 | while (true) { |
| 4191 | i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead? | 4471 | i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead? |
| 4192 | if (self.branch_stack.items[i].inst_table.get(else_key)) |mcv| { | 4472 | if (self.branch_stack.items[i].inst_table.get(else_key)) |mcv| { |
| ... | @@ -4213,7 +4493,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4213,7 +4493,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4213 | if (then_value == .dead) | 4493 | if (then_value == .dead) |
| 4214 | continue; | 4494 | continue; |
| 4215 | const parent_mcv = blk: { | 4495 | const parent_mcv = blk: { |
| 4216 | var i: usize = self.branch_stack.items.len - 2; | 4496 | var i: usize = self.branch_stack.items.len - 1; |
| 4217 | while (true) { | 4497 | while (true) { |
| 4218 | i -= 1; | 4498 | i -= 1; |
| 4219 | if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| { | 4499 | if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| { |
| ... | @@ -4267,9 +4547,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -4267,9 +4547,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4267 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 4547 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4268 | const is_err_result = try self.isErr(ty, operand); | 4548 | const is_err_result = try self.isErr(ty, operand); |
| 4269 | switch (is_err_result) { | 4549 | switch (is_err_result) { |
| 4270 | .condition_flags => |cond| { | 4550 | .compare_flags => |cond| { |
| 4271 | assert(cond == .hi); | 4551 | assert(cond == .hi); |
| 4272 | return MCValue{ .condition_flags = cond.negate() }; | 4552 | return MCValue{ .compare_flags = cond.negate() }; |
| 4273 | }, | 4553 | }, |
| 4274 | .immediate => |imm| { | 4554 | .immediate => |imm| { |
| 4275 | assert(imm == 0); | 4555 | assert(imm == 0); |
| ... | @@ -4432,10 +4712,132 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4432,10 +4712,132 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 4432 | | 4712 | |
| 4433 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | 4713 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4434 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 4714 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4435 | const condition = pl_op.operand; | 4715 | const condition_ty = self.air.typeOf(pl_op.operand); |
| 4436 | _ = condition; | 4716 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| | 4717 | const liveness = try self.liveness.getSwitchBr( |
| | 4718 | self.gpa, |
| | 4719 | inst, |
| | 4720 | switch_br.data.cases_len + 1, |
| | 4721 | ); |
| | 4722 | defer self.gpa.free(liveness.deaths); |
| | 4723 | |
| | 4724 | var extra_index: usize = switch_br.end; |
| | 4725 | var case_i: u32 = 0; |
| | 4726 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| | 4727 | const case = self.air.extraData(Air.SwitchBr.Case, extra_index); |
| | 4728 | const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); |
| | 4729 | assert(items.len > 0); |
| | 4730 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; |
| | 4731 | extra_index = case.end + items.len + case_body.len; |
| | 4732 | |
| | 4733 | // For every item, we compare it to condition and branch into |
| | 4734 | // the prong if they are equal. After we compared to all |
| | 4735 | // items, we branch into the next prong (or if no other prongs |
| | 4736 | // exist out of the switch statement). |
| | 4737 | // |
| | 4738 | // cmp condition, item1 |
| | 4739 | // beq prong |
| | 4740 | // cmp condition, item2 |
| | 4741 | // beq prong |
| | 4742 | // cmp condition, item3 |
| | 4743 | // beq prong |
| | 4744 | // b out |
| | 4745 | // prong: ... |
| | 4746 | // ... |
| | 4747 | // out: ... |
| | 4748 | const branch_into_prong_relocs = try self.gpa.alloc(u32, items.len); |
| | 4749 | defer self.gpa.free(branch_into_prong_relocs); |
| | 4750 | |
| | 4751 | for (items) |item, idx| { |
| | 4752 | const cmp_result = try self.cmp(.{ .inst = pl_op.operand }, .{ .inst = item }, condition_ty, .neq); |
| | 4753 | branch_into_prong_relocs[idx] = try self.condBr(cmp_result); |
| | 4754 | } |
| 4437 | | 4755 | |
| 4438 | return self.fail("TODO airSwitch for {}", .{self.target.cpu.arch}); | 4756 | const branch_away_from_prong_reloc = try self.addInst(.{ |
| | 4757 | .tag = .b, |
| | 4758 | .data = .{ .inst = undefined }, // populated later through performReloc |
| | 4759 | }); |
| | 4760 | |
| | 4761 | for (branch_into_prong_relocs) |reloc| { |
| | 4762 | try self.performReloc(reloc); |
| | 4763 | } |
| | 4764 | |
| | 4765 | // Capture the state of register and stack allocation state so that we can revert to it. |
| | 4766 | const parent_next_stack_offset = self.next_stack_offset; |
| | 4767 | const parent_free_registers = self.register_manager.free_registers; |
| | 4768 | const parent_compare_flags_inst = self.compare_flags_inst; |
| | 4769 | var parent_stack = try self.stack.clone(self.gpa); |
| | 4770 | defer parent_stack.deinit(self.gpa); |
| | 4771 | const parent_registers = self.register_manager.registers; |
| | 4772 | |
| | 4773 | try self.branch_stack.append(.{}); |
| | 4774 | errdefer { |
| | 4775 | _ = self.branch_stack.pop(); |
| | 4776 | } |
| | 4777 | |
| | 4778 | try self.ensureProcessDeathCapacity(liveness.deaths[case_i].len); |
| | 4779 | for (liveness.deaths[case_i]) |operand| { |
| | 4780 | self.processDeath(operand); |
| | 4781 | } |
| | 4782 | try self.genBody(case_body); |
| | 4783 | |
| | 4784 | // Revert to the previous register and stack allocation state. |
| | 4785 | var saved_case_branch = self.branch_stack.pop(); |
| | 4786 | defer saved_case_branch.deinit(self.gpa); |
| | 4787 | |
| | 4788 | self.register_manager.registers = parent_registers; |
| | 4789 | self.compare_flags_inst = parent_compare_flags_inst; |
| | 4790 | self.stack.deinit(self.gpa); |
| | 4791 | self.stack = parent_stack; |
| | 4792 | parent_stack = .{}; |
| | 4793 | |
| | 4794 | self.next_stack_offset = parent_next_stack_offset; |
| | 4795 | self.register_manager.free_registers = parent_free_registers; |
| | 4796 | |
| | 4797 | try self.performReloc(branch_away_from_prong_reloc); |
| | 4798 | } |
| | 4799 | |
| | 4800 | if (switch_br.data.else_body_len > 0) { |
| | 4801 | const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| | 4802 | |
| | 4803 | // Capture the state of register and stack allocation state so that we can revert to it. |
| | 4804 | const parent_next_stack_offset = self.next_stack_offset; |
| | 4805 | const parent_free_registers = self.register_manager.free_registers; |
| | 4806 | const parent_compare_flags_inst = self.compare_flags_inst; |
| | 4807 | var parent_stack = try self.stack.clone(self.gpa); |
| | 4808 | defer parent_stack.deinit(self.gpa); |
| | 4809 | const parent_registers = self.register_manager.registers; |
| | 4810 | |
| | 4811 | try self.branch_stack.append(.{}); |
| | 4812 | errdefer { |
| | 4813 | _ = self.branch_stack.pop(); |
| | 4814 | } |
| | 4815 | |
| | 4816 | const else_deaths = liveness.deaths.len - 1; |
| | 4817 | try self.ensureProcessDeathCapacity(liveness.deaths[else_deaths].len); |
| | 4818 | for (liveness.deaths[else_deaths]) |operand| { |
| | 4819 | self.processDeath(operand); |
| | 4820 | } |
| | 4821 | try self.genBody(else_body); |
| | 4822 | |
| | 4823 | // Revert to the previous register and stack allocation state. |
| | 4824 | var saved_case_branch = self.branch_stack.pop(); |
| | 4825 | defer saved_case_branch.deinit(self.gpa); |
| | 4826 | |
| | 4827 | self.register_manager.registers = parent_registers; |
| | 4828 | self.compare_flags_inst = parent_compare_flags_inst; |
| | 4829 | self.stack.deinit(self.gpa); |
| | 4830 | self.stack = parent_stack; |
| | 4831 | parent_stack = .{}; |
| | 4832 | |
| | 4833 | self.next_stack_offset = parent_next_stack_offset; |
| | 4834 | self.register_manager.free_registers = parent_free_registers; |
| | 4835 | |
| | 4836 | // TODO consolidate returned MCValues between prongs and else branch like we do |
| | 4837 | // in airCondBr. |
| | 4838 | } |
| | 4839 | |
| | 4840 | return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); |
| 4439 | } | 4841 | } |
| 4440 | | 4842 | |
| 4441 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { | 4843 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| ... | @@ -4464,7 +4866,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | ... | @@ -4464,7 +4866,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 4464 | block_data.mcv = switch (operand_mcv) { | 4866 | block_data.mcv = switch (operand_mcv) { |
| 4465 | .none, .dead, .unreach => unreachable, | 4867 | .none, .dead, .unreach => unreachable, |
| 4466 | .register, .stack_offset, .memory => operand_mcv, | 4868 | .register, .stack_offset, .memory => operand_mcv, |
| 4467 | .immediate, .stack_argument_offset, .condition_flags => blk: { | 4869 | .immediate, .stack_argument_offset, .compare_flags => blk: { |
| 4468 | const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block); | 4870 | const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block); |
| 4469 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | 4871 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); |
| 4470 | break :blk new_mcv; | 4872 | break :blk new_mcv; |
| ... | @@ -4644,10 +5046,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -4644,10 +5046,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4644 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), | 5046 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 4645 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 5047 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 4646 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), | 5048 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 4647 | else => return self.fail("TODO implement memset", .{}), | 5049 | else => try self.genInlineMemset( |
| | 5050 | .{ .ptr_stack_offset = stack_offset }, |
| | 5051 | .{ .immediate = 0xaa }, |
| | 5052 | .{ .immediate = abi_size }, |
| | 5053 | ), |
| 4648 | } | 5054 | } |
| 4649 | }, | 5055 | }, |
| 4650 | .condition_flags, | 5056 | .compare_flags, |
| 4651 | .immediate, | 5057 | .immediate, |
| 4652 | .ptr_stack_offset, | 5058 | .ptr_stack_offset, |
| 4653 | => { | 5059 | => { |
| ... | @@ -4807,7 +5213,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -4807,7 +5213,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4807 | } }, | 5213 | } }, |
| 4808 | }); | 5214 | }); |
| 4809 | }, | 5215 | }, |
| 4810 | .condition_flags => |condition| { | 5216 | .compare_flags => |condition| { |
| 4811 | _ = try self.addInst(.{ | 5217 | _ = try self.addInst(.{ |
| 4812 | .tag = .cset, | 5218 | .tag = .cset, |
| 4813 | .data = .{ .r_cond = .{ | 5219 | .data = .{ .r_cond = .{ |
| ... | @@ -5084,7 +5490,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5084,7 +5490,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5084 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); | 5490 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 5085 | } | 5491 | } |
| 5086 | }, | 5492 | }, |
| 5087 | .condition_flags, | 5493 | .compare_flags, |
| 5088 | .immediate, | 5494 | .immediate, |
| 5089 | .ptr_stack_offset, | 5495 | .ptr_stack_offset, |
| 5090 | => { | 5496 | => { |