| ... | ... | @@ -193,6 +193,43 @@ const CallMCValues = struct { |
| 193 | 193 | } |
| 194 | 194 | }; |
| 195 | 195 | |
| 196 | const BigTomb = struct { |
| 197 | function: *Self, |
| 198 | inst: Air.Inst.Index, |
| 199 | tomb_bits: Liveness.Bpi, |
| 200 | big_tomb_bits: u32, |
| 201 | bit_index: usize, |
| 202 | |
| 203 | fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void { |
| 204 | const this_bit_index = bt.bit_index; |
| 205 | bt.bit_index += 1; |
| 206 | |
| 207 | const op_int = @enumToInt(op_ref); |
| 208 | if (op_int < Air.Inst.Ref.typed_value_map.len) return; |
| 209 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); |
| 210 | |
| 211 | if (this_bit_index < Liveness.bpi - 1) { |
| 212 | const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0; |
| 213 | if (!dies) return; |
| 214 | } else { |
| 215 | const big_bit_index = @intCast(u5, this_bit_index - (Liveness.bpi - 1)); |
| 216 | const dies = @truncate(u1, bt.big_tomb_bits >> big_bit_index) != 0; |
| 217 | if (!dies) return; |
| 218 | } |
| 219 | bt.function.processDeath(op_index); |
| 220 | } |
| 221 | |
| 222 | fn finishAir(bt: *BigTomb, result: MCValue) void { |
| 223 | const is_used = !bt.function.liveness.isUnused(bt.inst); |
| 224 | if (is_used) { |
| 225 | log.debug("%{d} => {}", .{ bt.inst, result }); |
| 226 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; |
| 227 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); |
| 228 | } |
| 229 | bt.function.finishAirBookkeeping(); |
| 230 | } |
| 231 | }; |
| 232 | |
| 196 | 233 | pub fn generate( |
| 197 | 234 | bin_file: *link.File, |
| 198 | 235 | src_loc: Module.SrcLoc, |
| ... | ... | @@ -684,8 +721,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 684 | 721 | return self.finishAir(inst, result, buf); |
| 685 | 722 | } |
| 686 | 723 | |
| 687 | | @panic("TODO implement asm return"); |
| 688 | | //return self.fail("TODO implement asm return for {}", .{self.target.cpu.arch}); |
| 724 | var bt = try self.iterateBigTomb(inst, outputs.len + inputs.len); |
| 725 | for (outputs) |output| { |
| 726 | if (output == .none) continue; |
| 727 | |
| 728 | bt.feed(output); |
| 729 | } |
| 730 | for (inputs) |input| { |
| 731 | bt.feed(input); |
| 732 | } |
| 733 | return bt.finishAir(result); |
| 689 | 734 | } |
| 690 | 735 | |
| 691 | 736 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -1071,13 +1116,65 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 1071 | 1116 | self.finishAirBookkeeping(); |
| 1072 | 1117 | } |
| 1073 | 1118 | |
| 1074 | | fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, off: i13, abi_size: u64) !void { |
| 1075 | | _ = value_reg; |
| 1076 | | _ = addr_reg; |
| 1077 | | _ = off; |
| 1119 | fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void { |
| 1120 | assert(off_type == Register or off_type == i13); |
| 1121 | |
| 1122 | const is_imm = (off_type == i13); |
| 1123 | const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off }; |
| 1078 | 1124 | |
| 1079 | 1125 | switch (abi_size) { |
| 1080 | | 1, 2, 4, 8 => return self.fail("TODO: A.27 Load Integer", .{}), |
| 1126 | 1 => { |
| 1127 | _ = try self.addInst(.{ |
| 1128 | .tag = .ldub, |
| 1129 | .data = .{ |
| 1130 | .arithmetic_3op = .{ |
| 1131 | .is_imm = is_imm, |
| 1132 | .rd = value_reg, |
| 1133 | .rs1 = addr_reg, |
| 1134 | .rs2_or_imm = rs2_or_imm, |
| 1135 | }, |
| 1136 | }, |
| 1137 | }); |
| 1138 | }, |
| 1139 | 2 => { |
| 1140 | _ = try self.addInst(.{ |
| 1141 | .tag = .lduh, |
| 1142 | .data = .{ |
| 1143 | .arithmetic_3op = .{ |
| 1144 | .is_imm = is_imm, |
| 1145 | .rd = value_reg, |
| 1146 | .rs1 = addr_reg, |
| 1147 | .rs2_or_imm = rs2_or_imm, |
| 1148 | }, |
| 1149 | }, |
| 1150 | }); |
| 1151 | }, |
| 1152 | 4 => { |
| 1153 | _ = try self.addInst(.{ |
| 1154 | .tag = .lduw, |
| 1155 | .data = .{ |
| 1156 | .arithmetic_3op = .{ |
| 1157 | .is_imm = is_imm, |
| 1158 | .rd = value_reg, |
| 1159 | .rs1 = addr_reg, |
| 1160 | .rs2_or_imm = rs2_or_imm, |
| 1161 | }, |
| 1162 | }, |
| 1163 | }); |
| 1164 | }, |
| 1165 | 8 => { |
| 1166 | _ = try self.addInst(.{ |
| 1167 | .tag = .ldx, |
| 1168 | .data = .{ |
| 1169 | .arithmetic_3op = .{ |
| 1170 | .is_imm = is_imm, |
| 1171 | .rd = value_reg, |
| 1172 | .rs1 = addr_reg, |
| 1173 | .rs2_or_imm = rs2_or_imm, |
| 1174 | }, |
| 1175 | }, |
| 1176 | }); |
| 1177 | }, |
| 1081 | 1178 | 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}), |
| 1082 | 1179 | else => unreachable, |
| 1083 | 1180 | } |
| ... | ... | @@ -1226,12 +1323,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 1226 | 1323 | // The value is in memory at a hard-coded address. |
| 1227 | 1324 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 1228 | 1325 | try self.genSetReg(ty, reg, .{ .immediate = addr }); |
| 1229 | | try self.genLoad(reg, reg, 0, ty.abiSize(self.target.*)); |
| 1326 | try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*)); |
| 1230 | 1327 | }, |
| 1231 | 1328 | .stack_offset => |off| { |
| 1232 | 1329 | const simm13 = math.cast(u12, off) catch |
| 1233 | 1330 | return self.fail("TODO larger stack offsets", .{}); |
| 1234 | | try self.genLoad(reg, .sp, simm13, ty.abiSize(self.target.*)); |
| 1331 | try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*)); |
| 1235 | 1332 | }, |
| 1236 | 1333 | } |
| 1237 | 1334 | } |
| ... | ... | @@ -1269,14 +1366,10 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 1269 | 1366 | return MCValue{ .undef = {} }; |
| 1270 | 1367 | |
| 1271 | 1368 | if (typed_value.val.castTag(.decl_ref)) |payload| { |
| 1272 | | _ = payload; |
| 1273 | | return self.fail("TODO implement lowerDeclRef non-mut", .{}); |
| 1274 | | // return self.lowerDeclRef(typed_value, payload.data); |
| 1369 | return self.lowerDeclRef(typed_value, payload.data); |
| 1275 | 1370 | } |
| 1276 | 1371 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { |
| 1277 | | _ = payload; |
| 1278 | | return self.fail("TODO implement lowerDeclRef mut", .{}); |
| 1279 | | // return self.lowerDeclRef(typed_value, payload.data.decl); |
| 1372 | return self.lowerDeclRef(typed_value, payload.data.decl); |
| 1280 | 1373 | } |
| 1281 | 1374 | const target = self.target.*; |
| 1282 | 1375 | |
| ... | ... | @@ -1315,6 +1408,39 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 1315 | 1408 | } |
| 1316 | 1409 | } |
| 1317 | 1410 | |
| 1411 | fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigTomb { |
| 1412 | try self.ensureProcessDeathCapacity(operand_count + 1); |
| 1413 | return BigTomb{ |
| 1414 | .function = self, |
| 1415 | .inst = inst, |
| 1416 | .tomb_bits = self.liveness.getTombBits(inst), |
| 1417 | .big_tomb_bits = self.liveness.special.get(inst) orelse 0, |
| 1418 | .bit_index = 0, |
| 1419 | }; |
| 1420 | } |
| 1421 | |
| 1422 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue { |
| 1423 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 1424 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 1425 | |
| 1426 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? |
| 1427 | if (tv.ty.zigTypeTag() == .Pointer) blk: { |
| 1428 | if (tv.ty.castPtrToFn()) |_| break :blk; |
| 1429 | if (!tv.ty.elemType2().hasRuntimeBits()) { |
| 1430 | return MCValue.none; |
| 1431 | } |
| 1432 | } |
| 1433 | |
| 1434 | decl.alive = true; |
| 1435 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 1436 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; |
| 1437 | const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; |
| 1438 | return MCValue{ .memory = got_addr }; |
| 1439 | } else { |
| 1440 | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); |
| 1441 | } |
| 1442 | } |
| 1443 | |
| 1318 | 1444 | fn parseRegName(name: []const u8) ?Register { |
| 1319 | 1445 | if (@hasDecl(Register, "parseRegName")) { |
| 1320 | 1446 | return Register.parseRegName(name); |