| ... | ... | @@ -543,7 +543,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 543 | 543 | .assembly => try self.airAsm(inst), |
| 544 | 544 | .bitcast => @panic("TODO try self.airBitCast(inst)"), |
| 545 | 545 | .block => try self.airBlock(inst), |
| 546 | | .br => @panic("TODO try self.airBr(inst)"), |
| 546 | .br => try self.airBr(inst), |
| 547 | 547 | .breakpoint => try self.airBreakpoint(), |
| 548 | 548 | .ret_addr => @panic("TODO try self.airRetAddr(inst)"), |
| 549 | 549 | .frame_addr => @panic("TODO try self.airFrameAddress(inst)"), |
| ... | ... | @@ -852,6 +852,12 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 852 | 852 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 853 | 853 | } |
| 854 | 854 | |
| 855 | fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 856 | const branch = self.air.instructions.items(.data)[inst].br; |
| 857 | try self.br(branch.block_inst, branch.operand); |
| 858 | return self.finishAir(inst, .dead, .{ branch.operand, .none, .none }); |
| 859 | } |
| 860 | |
| 855 | 861 | fn airBreakpoint(self: *Self) !void { |
| 856 | 862 | // ta 0x01 |
| 857 | 863 | _ = try self.addInst(.{ |
| ... | ... | @@ -1365,6 +1371,56 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 1365 | 1371 | return MCValue{ .stack_offset = stack_offset }; |
| 1366 | 1372 | } |
| 1367 | 1373 | |
| 1374 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 1375 | const block_data = self.blocks.getPtr(block).?; |
| 1376 | |
| 1377 | if (self.air.typeOf(operand).hasRuntimeBits()) { |
| 1378 | const operand_mcv = try self.resolveInst(operand); |
| 1379 | const block_mcv = block_data.mcv; |
| 1380 | if (block_mcv == .none) { |
| 1381 | block_data.mcv = switch (operand_mcv) { |
| 1382 | .none, .dead, .unreach => unreachable, |
| 1383 | .register, .stack_offset, .memory => operand_mcv, |
| 1384 | .immediate => blk: { |
| 1385 | const new_mcv = try self.allocRegOrMem(block, true); |
| 1386 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); |
| 1387 | break :blk new_mcv; |
| 1388 | }, |
| 1389 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), |
| 1390 | }; |
| 1391 | } else { |
| 1392 | try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv); |
| 1393 | } |
| 1394 | } |
| 1395 | return self.brVoid(block); |
| 1396 | } |
| 1397 | |
| 1398 | fn brVoid(self: *Self, block: Air.Inst.Index) !void { |
| 1399 | const block_data = self.blocks.getPtr(block).?; |
| 1400 | |
| 1401 | // Emit a jump with a relocation. It will be patched up after the block ends. |
| 1402 | try block_data.relocs.ensureUnusedCapacity(self.gpa, 1); |
| 1403 | |
| 1404 | const br_index = try self.addInst(.{ |
| 1405 | .tag = .bpcc, |
| 1406 | .data = .{ |
| 1407 | .branch_predict_int = .{ |
| 1408 | .ccr = .xcc, |
| 1409 | .cond = .al, |
| 1410 | .inst = undefined, // Will be filled by performReloc |
| 1411 | }, |
| 1412 | }, |
| 1413 | }); |
| 1414 | |
| 1415 | // TODO Find a way to fill this delay slot |
| 1416 | _ = try self.addInst(.{ |
| 1417 | .tag = .nop, |
| 1418 | .data = .{ .nop = {} }, |
| 1419 | }); |
| 1420 | |
| 1421 | block_data.relocs.appendAssumeCapacity(br_index); |
| 1422 | } |
| 1423 | |
| 1368 | 1424 | /// Copies a value to a register without tracking the register. The register is not considered |
| 1369 | 1425 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 1370 | 1426 | /// This can have a side effect of spilling instructions to the stack to free up a register. |