| ... | @@ -193,6 +193,43 @@ const CallMCValues = struct { | ... | @@ -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 | pub fn generate( | 233 | pub fn generate( |
| 197 | bin_file: *link.File, | 234 | bin_file: *link.File, |
| 198 | src_loc: Module.SrcLoc, | 235 | src_loc: Module.SrcLoc, |
| ... | @@ -684,8 +721,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -684,8 +721,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 684 | return self.finishAir(inst, result, buf); | 721 | return self.finishAir(inst, result, buf); |
| 685 | } | 722 | } |
| 686 | | 723 | |
| 687 | @panic("TODO implement asm return"); | 724 | var bt = try self.iterateBigTomb(inst, outputs.len + inputs.len); |
| 688 | //return self.fail("TODO implement asm return for {}", .{self.target.cpu.arch}); | 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 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { | 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,13 +1116,65 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 1071 | self.finishAirBookkeeping(); | 1116 | self.finishAirBookkeeping(); |
| 1072 | } | 1117 | } |
| 1073 | | 1118 | |
| 1074 | fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, off: i13, abi_size: u64) !void { | 1119 | fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void { |
| 1075 | _ = value_reg; | 1120 | assert(off_type == Register or off_type == i13); |
| 1076 | _ = addr_reg; | 1121 | |
| 1077 | _ = off; | 1122 | const is_imm = (off_type == i13); |
| | 1123 | const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off }; |
| 1078 | | 1124 | |
| 1079 | switch (abi_size) { | 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 | 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}), | 1178 | 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}), |
| 1082 | else => unreachable, | 1179 | else => unreachable, |
| 1083 | } | 1180 | } |
| ... | @@ -1226,12 +1323,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -1226,12 +1323,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 1226 | // The value is in memory at a hard-coded address. | 1323 | // The value is in memory at a hard-coded address. |
| 1227 | // If the type is a pointer, it means the pointer address is at this memory location. | 1324 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 1228 | try self.genSetReg(ty, reg, .{ .immediate = addr }); | 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 | .stack_offset => |off| { | 1328 | .stack_offset => |off| { |
| 1232 | const simm13 = math.cast(u12, off) catch | 1329 | const simm13 = math.cast(u12, off) catch |
| 1233 | return self.fail("TODO larger stack offsets", .{}); | 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,14 +1366,10 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 1269 | return MCValue{ .undef = {} }; | 1366 | return MCValue{ .undef = {} }; |
| 1270 | | 1367 | |
| 1271 | if (typed_value.val.castTag(.decl_ref)) |payload| { | 1368 | if (typed_value.val.castTag(.decl_ref)) |payload| { |
| 1272 | _ = payload; | 1369 | return self.lowerDeclRef(typed_value, payload.data); |
| 1273 | return self.fail("TODO implement lowerDeclRef non-mut", .{}); | | |
| 1274 | // return self.lowerDeclRef(typed_value, payload.data); | | |
| 1275 | } | 1370 | } |
| 1276 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | 1371 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { |
| 1277 | _ = payload; | 1372 | return self.lowerDeclRef(typed_value, payload.data.decl); |
| 1278 | return self.fail("TODO implement lowerDeclRef mut", .{}); | | |
| 1279 | // return self.lowerDeclRef(typed_value, payload.data.decl); | | |
| 1280 | } | 1373 | } |
| 1281 | const target = self.target.*; | 1374 | const target = self.target.*; |
| 1282 | | 1375 | |
| ... | @@ -1315,6 +1408,39 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | ... | @@ -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 | fn parseRegName(name: []const u8) ?Register { | 1444 | fn parseRegName(name: []const u8) ?Register { |
| 1319 | if (@hasDecl(Register, "parseRegName")) { | 1445 | if (@hasDecl(Register, "parseRegName")) { |
| 1320 | return Register.parseRegName(name); | 1446 | return Register.parseRegName(name); |