| ... | ... | @@ -5,6 +5,8 @@ const math = std.math; |
| 5 | 5 | const assert = std.debug.assert; |
| 6 | 6 | const Air = @import("../../Air.zig"); |
| 7 | 7 | const Zir = @import("../../Zir.zig"); |
| 8 | const Mir = @import("Mir.zig"); |
| 9 | const Emit = @import("Emit.zig"); |
| 8 | 10 | const Liveness = @import("../../Liveness.zig"); |
| 9 | 11 | const Type = @import("../../type.zig").Type; |
| 10 | 12 | const Value = @import("../../value.zig").Value; |
| ... | ... | @@ -31,14 +33,12 @@ const InnerError = error{ |
| 31 | 33 | CodegenFail, |
| 32 | 34 | }; |
| 33 | 35 | |
| 34 | | arch: std.Target.Cpu.Arch, |
| 35 | 36 | gpa: *Allocator, |
| 36 | 37 | air: Air, |
| 37 | 38 | liveness: Liveness, |
| 38 | 39 | bin_file: *link.File, |
| 39 | 40 | target: *const std.Target, |
| 40 | 41 | mod_fn: *const Module.Fn, |
| 41 | | code: *std.ArrayList(u8), |
| 42 | 42 | debug_output: DebugInfoOutput, |
| 43 | 43 | err_msg: ?*ErrorMsg, |
| 44 | 44 | args: []MCValue, |
| ... | ... | @@ -48,6 +48,11 @@ arg_index: usize, |
| 48 | 48 | src_loc: Module.SrcLoc, |
| 49 | 49 | stack_align: u32, |
| 50 | 50 | |
| 51 | /// MIR Instructions |
| 52 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| 53 | /// MIR extra data |
| 54 | mir_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 55 | |
| 51 | 56 | prev_di_line: u32, |
| 52 | 57 | prev_di_column: u32, |
| 53 | 58 | /// Byte offset within the source file of the ending curly. |
| ... | ... | @@ -237,7 +242,6 @@ const BigTomb = struct { |
| 237 | 242 | const Self = @This(); |
| 238 | 243 | |
| 239 | 244 | pub fn generate( |
| 240 | | arch: std.Target.Cpu.Arch, |
| 241 | 245 | bin_file: *link.File, |
| 242 | 246 | src_loc: Module.SrcLoc, |
| 243 | 247 | module_fn: *Module.Fn, |
| ... | ... | @@ -246,7 +250,7 @@ pub fn generate( |
| 246 | 250 | code: *std.ArrayList(u8), |
| 247 | 251 | debug_output: DebugInfoOutput, |
| 248 | 252 | ) GenerateSymbolError!FnResult { |
| 249 | | if (build_options.skip_non_native and builtin.cpu.arch != arch) { |
| 253 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { |
| 250 | 254 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 251 | 255 | } |
| 252 | 256 | |
| ... | ... | @@ -262,14 +266,12 @@ pub fn generate( |
| 262 | 266 | try branch_stack.append(.{}); |
| 263 | 267 | |
| 264 | 268 | var function = Self{ |
| 265 | | .arch = arch, |
| 266 | 269 | .gpa = bin_file.allocator, |
| 267 | 270 | .air = air, |
| 268 | 271 | .liveness = liveness, |
| 269 | 272 | .target = &bin_file.options.target, |
| 270 | 273 | .bin_file = bin_file, |
| 271 | 274 | .mod_fn = module_fn, |
| 272 | | .code = code, |
| 273 | 275 | .debug_output = debug_output, |
| 274 | 276 | .err_msg = null, |
| 275 | 277 | .args = undefined, // populated after `resolveCallingConventionValues` |
| ... | ... | @@ -305,6 +307,19 @@ pub fn generate( |
| 305 | 307 | else => |e| return e, |
| 306 | 308 | }; |
| 307 | 309 | |
| 310 | var mir = Mir{ |
| 311 | .instructions = function.mir_instructions.toOwnedSlice(), |
| 312 | .extra = function.mir_extra.toOwnedSlice(bin_file.allocator), |
| 313 | }; |
| 314 | defer mir.deinit(bin_file.allocator); |
| 315 | |
| 316 | var emit = Emit{ |
| 317 | .mir = mir, |
| 318 | .target = &bin_file.options.target, |
| 319 | .code = code, |
| 320 | }; |
| 321 | try emit.emitMir(); |
| 322 | |
| 308 | 323 | if (function.err_msg) |em| { |
| 309 | 324 | return FnResult{ .fail = em }; |
| 310 | 325 | } else { |
| ... | ... | @@ -312,6 +327,16 @@ pub fn generate( |
| 312 | 327 | } |
| 313 | 328 | } |
| 314 | 329 | |
| 330 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 331 | const gpa = self.gpa; |
| 332 | |
| 333 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); |
| 334 | |
| 335 | const result_index = @intCast(Air.Inst.Index, self.mir_instructions.len); |
| 336 | self.mir_instructions.appendAssumeCapacity(inst); |
| 337 | return result_index; |
| 338 | } |
| 339 | |
| 315 | 340 | fn gen(self: *Self) !void { |
| 316 | 341 | const cc = self.fn_type.fnCallingConvention(); |
| 317 | 342 | if (cc != .Naked) { |
| ... | ... | @@ -320,15 +345,26 @@ fn gen(self: *Self) !void { |
| 320 | 345 | // stp fp, lr, [sp, #-16]! |
| 321 | 346 | // mov fp, sp |
| 322 | 347 | // sub sp, sp, #reloc |
| 323 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.stp( |
| 324 | | .x29, |
| 325 | | .x30, |
| 326 | | Register.sp, |
| 327 | | Instruction.LoadStorePairOffset.pre_index(-16), |
| 328 | | ).toU32()); |
| 329 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.add(.x29, .xzr, 0, false).toU32()); |
| 330 | | const backpatch_reloc = self.code.items.len; |
| 331 | | try self.code.resize(backpatch_reloc + 4); |
| 348 | |
| 349 | _ = try self.addInst(.{ |
| 350 | .tag = .stp, |
| 351 | .data = .{ .load_store_register_pair = .{ |
| 352 | .rt = .x29, |
| 353 | .rt2 = .x30, |
| 354 | .rn = Register.sp, |
| 355 | .offset = Instruction.LoadStorePairOffset.pre_index(-16), |
| 356 | } }, |
| 357 | }); |
| 358 | |
| 359 | _ = try self.addInst(.{ |
| 360 | .tag = .mov_to_from_sp, |
| 361 | .data = .{ .rr = .{ .rd = .x29, .rn = .xzr } }, |
| 362 | }); |
| 363 | |
| 364 | const backpatch_reloc = try self.addInst(.{ |
| 365 | .tag = .nop, |
| 366 | .data = .{ .nop = {} }, |
| 367 | }); |
| 332 | 368 | |
| 333 | 369 | try self.dbgSetPrologueEnd(); |
| 334 | 370 | |
| ... | ... | @@ -338,7 +374,10 @@ fn gen(self: *Self) !void { |
| 338 | 374 | const stack_end = self.max_end_stack; |
| 339 | 375 | const aligned_stack_end = mem.alignForward(stack_end, self.stack_align); |
| 340 | 376 | if (math.cast(u12, aligned_stack_end)) |size| { |
| 341 | | mem.writeIntLittle(u32, self.code.items[backpatch_reloc..][0..4], Instruction.sub(.xzr, .xzr, size, false).toU32()); |
| 377 | self.mir_instructions.set(backpatch_reloc, .{ |
| 378 | .tag = .sub_immediate, |
| 379 | .data = .{ .rr_imm12_sh = .{ .rd = .xzr, .rn = .xzr, .imm12 = size } }, |
| 380 | }); |
| 342 | 381 | } else |_| { |
| 343 | 382 | return self.failSymbol("TODO AArch64: allow larger stacks", .{}); |
| 344 | 383 | } |
| ... | ... | @@ -352,36 +391,36 @@ fn gen(self: *Self) !void { |
| 352 | 391 | // the code. Therefore, we can just delete |
| 353 | 392 | // the space initially reserved for the |
| 354 | 393 | // jump |
| 355 | | self.code.items.len -= 4; |
| 394 | self.mir_instructions.len -= 1; |
| 356 | 395 | } else for (self.exitlude_jump_relocs.items) |jmp_reloc| { |
| 357 | | const amt = @intCast(i32, self.code.items.len) - @intCast(i32, jmp_reloc + 8); |
| 358 | | if (amt == -4) { |
| 359 | | // This return is at the end of the |
| 360 | | // code block. We can't just delete |
| 361 | | // the space because there may be |
| 362 | | // other jumps we already relocated to |
| 363 | | // the address. Instead, insert a nop |
| 364 | | mem.writeIntLittle(u32, self.code.items[jmp_reloc..][0..4], Instruction.nop().toU32()); |
| 365 | | } else { |
| 366 | | if (math.cast(i28, amt)) |offset| { |
| 367 | | mem.writeIntLittle(u32, self.code.items[jmp_reloc..][0..4], Instruction.b(offset).toU32()); |
| 368 | | } else |_| { |
| 369 | | return self.failSymbol("exitlude jump is too large", .{}); |
| 370 | | } |
| 371 | | } |
| 396 | self.mir_instructions.set(jmp_reloc, .{ |
| 397 | .tag = .b, |
| 398 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len) }, |
| 399 | }); |
| 372 | 400 | } |
| 373 | 401 | |
| 374 | 402 | // ldp fp, lr, [sp], #16 |
| 375 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldp( |
| 376 | | .x29, |
| 377 | | .x30, |
| 378 | | Register.sp, |
| 379 | | Instruction.LoadStorePairOffset.post_index(16), |
| 380 | | ).toU32()); |
| 403 | _ = try self.addInst(.{ |
| 404 | .tag = .ldp, |
| 405 | .data = .{ .load_store_register_pair = .{ |
| 406 | .rt = .x29, |
| 407 | .rt2 = .x30, |
| 408 | .rn = Register.sp, |
| 409 | .offset = Instruction.LoadStorePairOffset.post_index(16), |
| 410 | } }, |
| 411 | }); |
| 412 | |
| 381 | 413 | // add sp, sp, #stack_size |
| 382 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.add(.xzr, .xzr, @intCast(u12, aligned_stack_end), false).toU32()); |
| 414 | _ = try self.addInst(.{ |
| 415 | .tag = .add_immediate, |
| 416 | .data = .{ .rr_imm12_sh = .{ .rd = .xzr, .rn = .xzr, .imm12 = @intCast(u12, aligned_stack_end) } }, |
| 417 | }); |
| 418 | |
| 383 | 419 | // ret lr |
| 384 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ret(null).toU32()); |
| 420 | _ = try self.addInst(.{ |
| 421 | .tag = .ret, |
| 422 | .data = .{ .reg = .x30 }, |
| 423 | }); |
| 385 | 424 | } else { |
| 386 | 425 | try self.dbgSetPrologueEnd(); |
| 387 | 426 | try self.genBody(self.air.getMainBody()); |
| ... | ... | @@ -389,7 +428,7 @@ fn gen(self: *Self) !void { |
| 389 | 428 | } |
| 390 | 429 | |
| 391 | 430 | // Drop them off at the rbrace. |
| 392 | | try self.dbgAdvancePCAndLine(self.end_di_line, self.end_di_column); |
| 431 | // try self.dbgAdvancePCAndLine(self.end_di_line, self.end_di_column); |
| 393 | 432 | } |
| 394 | 433 | |
| 395 | 434 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| ... | ... | @@ -534,7 +573,7 @@ fn dbgSetPrologueEnd(self: *Self) InnerError!void { |
| 534 | 573 | switch (self.debug_output) { |
| 535 | 574 | .dwarf => |dbg_out| { |
| 536 | 575 | try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); |
| 537 | | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 576 | // try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 538 | 577 | }, |
| 539 | 578 | .plan9 => {}, |
| 540 | 579 | .none => {}, |
| ... | ... | @@ -545,7 +584,7 @@ fn dbgSetEpilogueBegin(self: *Self) InnerError!void { |
| 545 | 584 | switch (self.debug_output) { |
| 546 | 585 | .dwarf => |dbg_out| { |
| 547 | 586 | try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); |
| 548 | | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 587 | // try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 549 | 588 | }, |
| 550 | 589 | .plan9 => {}, |
| 551 | 590 | .none => {}, |
| ... | ... | @@ -1297,310 +1336,6 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1297 | 1336 | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); |
| 1298 | 1337 | } |
| 1299 | 1338 | |
| 1300 | | fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool { |
| 1301 | | return switch (mcv) { |
| 1302 | | .none => unreachable, |
| 1303 | | .undef => unreachable, |
| 1304 | | .dead, .unreach => unreachable, |
| 1305 | | .compare_flags_unsigned => unreachable, |
| 1306 | | .compare_flags_signed => unreachable, |
| 1307 | | .ptr_stack_offset => unreachable, |
| 1308 | | .ptr_embedded_in_code => unreachable, |
| 1309 | | .immediate => |imm| blk: { |
| 1310 | | if (imm > std.math.maxInt(u32)) return self.fail("TODO ARM binary arithmetic immediate larger than u32", .{}); |
| 1311 | | |
| 1312 | | // Load immediate into register if it doesn't fit |
| 1313 | | // in an operand |
| 1314 | | break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) == null; |
| 1315 | | }, |
| 1316 | | .register => true, |
| 1317 | | .stack_offset, |
| 1318 | | .embedded_in_code, |
| 1319 | | .memory, |
| 1320 | | => true, |
| 1321 | | }; |
| 1322 | | } |
| 1323 | | |
| 1324 | | fn genArmBinOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref, op: Air.Inst.Tag) !MCValue { |
| 1325 | | // In the case of bitshifts, the type of rhs is different |
| 1326 | | // from the resulting type |
| 1327 | | const ty = self.air.typeOf(op_lhs); |
| 1328 | | |
| 1329 | | switch (ty.zigTypeTag()) { |
| 1330 | | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 1331 | | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 1332 | | .Bool => { |
| 1333 | | return self.genArmBinIntOp(inst, op_lhs, op_rhs, op, 1, .unsigned); |
| 1334 | | }, |
| 1335 | | .Int => { |
| 1336 | | const int_info = ty.intInfo(self.target.*); |
| 1337 | | return self.genArmBinIntOp(inst, op_lhs, op_rhs, op, int_info.bits, int_info.signedness); |
| 1338 | | }, |
| 1339 | | else => unreachable, |
| 1340 | | } |
| 1341 | | } |
| 1342 | | |
| 1343 | | fn genArmBinIntOp( |
| 1344 | | self: *Self, |
| 1345 | | inst: Air.Inst.Index, |
| 1346 | | op_lhs: Air.Inst.Ref, |
| 1347 | | op_rhs: Air.Inst.Ref, |
| 1348 | | op: Air.Inst.Tag, |
| 1349 | | bits: u16, |
| 1350 | | signedness: std.builtin.Signedness, |
| 1351 | | ) !MCValue { |
| 1352 | | if (bits > 32) { |
| 1353 | | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 1354 | | } |
| 1355 | | |
| 1356 | | const lhs = try self.resolveInst(op_lhs); |
| 1357 | | const rhs = try self.resolveInst(op_rhs); |
| 1358 | | |
| 1359 | | const lhs_is_register = lhs == .register; |
| 1360 | | const rhs_is_register = rhs == .register; |
| 1361 | | const lhs_should_be_register = switch (op) { |
| 1362 | | .shr, .shl => true, |
| 1363 | | else => try self.armOperandShouldBeRegister(lhs), |
| 1364 | | }; |
| 1365 | | const rhs_should_be_register = try self.armOperandShouldBeRegister(rhs); |
| 1366 | | const reuse_lhs = lhs_is_register and self.reuseOperand(inst, op_lhs, 0, lhs); |
| 1367 | | const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, op_rhs, 1, rhs); |
| 1368 | | const can_swap_lhs_and_rhs = switch (op) { |
| 1369 | | .shr, .shl => false, |
| 1370 | | else => true, |
| 1371 | | }; |
| 1372 | | |
| 1373 | | // Destination must be a register |
| 1374 | | var dst_mcv: MCValue = undefined; |
| 1375 | | var lhs_mcv = lhs; |
| 1376 | | var rhs_mcv = rhs; |
| 1377 | | var swap_lhs_and_rhs = false; |
| 1378 | | |
| 1379 | | // Allocate registers for operands and/or destination |
| 1380 | | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1381 | | if (reuse_lhs) { |
| 1382 | | // Allocate 0 or 1 registers |
| 1383 | | if (!rhs_is_register and rhs_should_be_register) { |
| 1384 | | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?, &.{lhs.register}) }; |
| 1385 | | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); |
| 1386 | | } |
| 1387 | | dst_mcv = lhs; |
| 1388 | | } else if (reuse_rhs and can_swap_lhs_and_rhs) { |
| 1389 | | // Allocate 0 or 1 registers |
| 1390 | | if (!lhs_is_register and lhs_should_be_register) { |
| 1391 | | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{rhs.register}) }; |
| 1392 | | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv); |
| 1393 | | } |
| 1394 | | dst_mcv = rhs; |
| 1395 | | |
| 1396 | | swap_lhs_and_rhs = true; |
| 1397 | | } else { |
| 1398 | | // Allocate 1 or 2 registers |
| 1399 | | if (lhs_should_be_register and rhs_should_be_register) { |
| 1400 | | if (lhs_is_register and rhs_is_register) { |
| 1401 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{ lhs.register, rhs.register }) }; |
| 1402 | | } else if (lhs_is_register) { |
| 1403 | | // Move RHS to register |
| 1404 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{lhs.register}) }; |
| 1405 | | rhs_mcv = dst_mcv; |
| 1406 | | } else if (rhs_is_register) { |
| 1407 | | // Move LHS to register |
| 1408 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) }; |
| 1409 | | lhs_mcv = dst_mcv; |
| 1410 | | } else { |
| 1411 | | // Move LHS and RHS to register |
| 1412 | | const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }, &.{}); |
| 1413 | | lhs_mcv = MCValue{ .register = regs[0] }; |
| 1414 | | rhs_mcv = MCValue{ .register = regs[1] }; |
| 1415 | | dst_mcv = lhs_mcv; |
| 1416 | | |
| 1417 | | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); |
| 1418 | | } |
| 1419 | | } else if (lhs_should_be_register) { |
| 1420 | | // RHS is immediate |
| 1421 | | if (lhs_is_register) { |
| 1422 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{lhs.register}) }; |
| 1423 | | } else { |
| 1424 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; |
| 1425 | | lhs_mcv = dst_mcv; |
| 1426 | | } |
| 1427 | | } else if (rhs_should_be_register and can_swap_lhs_and_rhs) { |
| 1428 | | // LHS is immediate |
| 1429 | | if (rhs_is_register) { |
| 1430 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) }; |
| 1431 | | } else { |
| 1432 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; |
| 1433 | | rhs_mcv = dst_mcv; |
| 1434 | | } |
| 1435 | | |
| 1436 | | swap_lhs_and_rhs = true; |
| 1437 | | } else unreachable; // binary operation on two immediates |
| 1438 | | } |
| 1439 | | |
| 1440 | | // Move the operands to the newly allocated registers |
| 1441 | | if (lhs_mcv == .register and !lhs_is_register) { |
| 1442 | | try self.genSetReg(self.air.typeOf(op_lhs), lhs_mcv.register, lhs); |
| 1443 | | } |
| 1444 | | if (rhs_mcv == .register and !rhs_is_register) { |
| 1445 | | try self.genSetReg(self.air.typeOf(op_rhs), rhs_mcv.register, rhs); |
| 1446 | | } |
| 1447 | | |
| 1448 | | try self.genArmBinOpCode( |
| 1449 | | dst_mcv.register, |
| 1450 | | lhs_mcv, |
| 1451 | | rhs_mcv, |
| 1452 | | swap_lhs_and_rhs, |
| 1453 | | op, |
| 1454 | | signedness, |
| 1455 | | ); |
| 1456 | | return dst_mcv; |
| 1457 | | } |
| 1458 | | |
| 1459 | | fn genArmBinOpCode( |
| 1460 | | self: *Self, |
| 1461 | | dst_reg: Register, |
| 1462 | | lhs_mcv: MCValue, |
| 1463 | | rhs_mcv: MCValue, |
| 1464 | | swap_lhs_and_rhs: bool, |
| 1465 | | op: Air.Inst.Tag, |
| 1466 | | signedness: std.builtin.Signedness, |
| 1467 | | ) !void { |
| 1468 | | assert(lhs_mcv == .register or rhs_mcv == .register); |
| 1469 | | |
| 1470 | | const op1 = if (swap_lhs_and_rhs) rhs_mcv.register else lhs_mcv.register; |
| 1471 | | const op2 = if (swap_lhs_and_rhs) lhs_mcv else rhs_mcv; |
| 1472 | | |
| 1473 | | const operand = switch (op2) { |
| 1474 | | .none => unreachable, |
| 1475 | | .undef => unreachable, |
| 1476 | | .dead, .unreach => unreachable, |
| 1477 | | .compare_flags_unsigned => unreachable, |
| 1478 | | .compare_flags_signed => unreachable, |
| 1479 | | .ptr_stack_offset => unreachable, |
| 1480 | | .ptr_embedded_in_code => unreachable, |
| 1481 | | .immediate => |imm| Instruction.Operand.fromU32(@intCast(u32, imm)).?, |
| 1482 | | .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none), |
| 1483 | | .stack_offset, |
| 1484 | | .embedded_in_code, |
| 1485 | | .memory, |
| 1486 | | => unreachable, |
| 1487 | | }; |
| 1488 | | |
| 1489 | | switch (op) { |
| 1490 | | .add => { |
| 1491 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.add(.al, dst_reg, op1, operand).toU32()); |
| 1492 | | }, |
| 1493 | | .sub => { |
| 1494 | | if (swap_lhs_and_rhs) { |
| 1495 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, op1, operand).toU32()); |
| 1496 | | } else { |
| 1497 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.sub(.al, dst_reg, op1, operand).toU32()); |
| 1498 | | } |
| 1499 | | }, |
| 1500 | | .bool_and, .bit_and => { |
| 1501 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, op1, operand).toU32()); |
| 1502 | | }, |
| 1503 | | .bool_or, .bit_or => { |
| 1504 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, op1, operand).toU32()); |
| 1505 | | }, |
| 1506 | | .not, .xor => { |
| 1507 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, op1, operand).toU32()); |
| 1508 | | }, |
| 1509 | | .cmp_eq => { |
| 1510 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, op1, operand).toU32()); |
| 1511 | | }, |
| 1512 | | .shl => { |
| 1513 | | assert(!swap_lhs_and_rhs); |
| 1514 | | const shift_amount = switch (operand) { |
| 1515 | | .Register => |reg_op| Instruction.ShiftAmount.reg(@intToEnum(Register, reg_op.rm)), |
| 1516 | | .Immediate => |imm_op| Instruction.ShiftAmount.imm(@intCast(u5, imm_op.imm)), |
| 1517 | | }; |
| 1518 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.lsl(.al, dst_reg, op1, shift_amount).toU32()); |
| 1519 | | }, |
| 1520 | | .shr => { |
| 1521 | | assert(!swap_lhs_and_rhs); |
| 1522 | | const shift_amount = switch (operand) { |
| 1523 | | .Register => |reg_op| Instruction.ShiftAmount.reg(@intToEnum(Register, reg_op.rm)), |
| 1524 | | .Immediate => |imm_op| Instruction.ShiftAmount.imm(@intCast(u5, imm_op.imm)), |
| 1525 | | }; |
| 1526 | | |
| 1527 | | const shr = switch (signedness) { |
| 1528 | | .signed => Instruction.asr, |
| 1529 | | .unsigned => Instruction.lsr, |
| 1530 | | }; |
| 1531 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), shr(.al, dst_reg, op1, shift_amount).toU32()); |
| 1532 | | }, |
| 1533 | | else => unreachable, // not a binary instruction |
| 1534 | | } |
| 1535 | | } |
| 1536 | | |
| 1537 | | fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { |
| 1538 | | const lhs = try self.resolveInst(op_lhs); |
| 1539 | | const rhs = try self.resolveInst(op_rhs); |
| 1540 | | |
| 1541 | | const lhs_is_register = lhs == .register; |
| 1542 | | const rhs_is_register = rhs == .register; |
| 1543 | | const reuse_lhs = lhs_is_register and self.reuseOperand(inst, op_lhs, 0, lhs); |
| 1544 | | const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, op_rhs, 1, rhs); |
| 1545 | | |
| 1546 | | // Destination must be a register |
| 1547 | | // LHS must be a register |
| 1548 | | // RHS must be a register |
| 1549 | | var dst_mcv: MCValue = undefined; |
| 1550 | | var lhs_mcv: MCValue = lhs; |
| 1551 | | var rhs_mcv: MCValue = rhs; |
| 1552 | | |
| 1553 | | // Allocate registers for operands and/or destination |
| 1554 | | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1555 | | if (reuse_lhs) { |
| 1556 | | // Allocate 0 or 1 registers |
| 1557 | | if (!rhs_is_register) { |
| 1558 | | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?, &.{lhs.register}) }; |
| 1559 | | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); |
| 1560 | | } |
| 1561 | | dst_mcv = lhs; |
| 1562 | | } else if (reuse_rhs) { |
| 1563 | | // Allocate 0 or 1 registers |
| 1564 | | if (!lhs_is_register) { |
| 1565 | | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{rhs.register}) }; |
| 1566 | | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv); |
| 1567 | | } |
| 1568 | | dst_mcv = rhs; |
| 1569 | | } else { |
| 1570 | | // Allocate 1 or 2 registers |
| 1571 | | if (lhs_is_register and rhs_is_register) { |
| 1572 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{ lhs.register, rhs.register }) }; |
| 1573 | | } else if (lhs_is_register) { |
| 1574 | | // Move RHS to register |
| 1575 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{lhs.register}) }; |
| 1576 | | rhs_mcv = dst_mcv; |
| 1577 | | } else if (rhs_is_register) { |
| 1578 | | // Move LHS to register |
| 1579 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) }; |
| 1580 | | lhs_mcv = dst_mcv; |
| 1581 | | } else { |
| 1582 | | // Move LHS and RHS to register |
| 1583 | | const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }, &.{}); |
| 1584 | | lhs_mcv = MCValue{ .register = regs[0] }; |
| 1585 | | rhs_mcv = MCValue{ .register = regs[1] }; |
| 1586 | | dst_mcv = lhs_mcv; |
| 1587 | | |
| 1588 | | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); |
| 1589 | | } |
| 1590 | | } |
| 1591 | | |
| 1592 | | // Move the operands to the newly allocated registers |
| 1593 | | if (!lhs_is_register) { |
| 1594 | | try self.genSetReg(self.air.typeOf(op_lhs), lhs_mcv.register, lhs); |
| 1595 | | } |
| 1596 | | if (!rhs_is_register) { |
| 1597 | | try self.genSetReg(self.air.typeOf(op_rhs), rhs_mcv.register, rhs); |
| 1598 | | } |
| 1599 | | |
| 1600 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mul(.al, dst_mcv.register, lhs_mcv.register, rhs_mcv.register).toU32()); |
| 1601 | | return dst_mcv; |
| 1602 | | } |
| 1603 | | |
| 1604 | 1339 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void { |
| 1605 | 1340 | const ty_str = self.air.instructions.items(.data)[inst].ty_str; |
| 1606 | 1341 | const zir = &self.mod_fn.owner_decl.getFileScope().zir; |
| ... | ... | @@ -1668,7 +1403,10 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1668 | 1403 | } |
| 1669 | 1404 | |
| 1670 | 1405 | fn airBreakpoint(self: *Self) !void { |
| 1671 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.brk(1).toU32()); |
| 1406 | _ = try self.addInst(.{ |
| 1407 | .tag = .brk, |
| 1408 | .data = .{ .imm16 = 1 }, |
| 1409 | }); |
| 1672 | 1410 | return self.finishAirBookkeeping(); |
| 1673 | 1411 | } |
| 1674 | 1412 | |
| ... | ... | @@ -1736,7 +1474,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1736 | 1474 | |
| 1737 | 1475 | try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr }); |
| 1738 | 1476 | |
| 1739 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); |
| 1477 | _ = try self.addInst(.{ |
| 1478 | .tag = .blr, |
| 1479 | .data = .{ .reg = .x30 }, |
| 1480 | }); |
| 1740 | 1481 | } else if (func_value.castTag(.extern_fn)) |_| { |
| 1741 | 1482 | return self.fail("TODO implement calling extern functions", .{}); |
| 1742 | 1483 | } else { |
| ... | ... | @@ -1789,14 +1530,22 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1789 | 1530 | .memory = func.owner_decl.link.macho.local_sym_index, |
| 1790 | 1531 | }); |
| 1791 | 1532 | // blr x30 |
| 1792 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); |
| 1533 | _ = try self.addInst(.{ |
| 1534 | .tag = .blr, |
| 1535 | .data = .{ .reg = .x30 }, |
| 1536 | }); |
| 1793 | 1537 | } else if (func_value.castTag(.extern_fn)) |func_payload| { |
| 1794 | 1538 | const decl = func_payload.data; |
| 1795 | 1539 | const n_strx = try macho_file.addExternFn(mem.spanZ(decl.name)); |
| 1796 | 1540 | const offset = blk: { |
| 1797 | | const offset = @intCast(u32, self.code.items.len); |
| 1541 | // TODO add a pseudo-instruction |
| 1542 | const offset = @intCast(u32, self.mir_instructions.len); |
| 1798 | 1543 | // bl |
| 1799 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bl(0).toU32()); |
| 1544 | // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bl(0).toU32()); |
| 1545 | _ = try self.addInst(.{ |
| 1546 | .tag = .bl, |
| 1547 | .data = .{ .nop = {} }, |
| 1548 | }); |
| 1800 | 1549 | break :blk offset; |
| 1801 | 1550 | }; |
| 1802 | 1551 | // Add relocation to the decl. |
| ... | ... | @@ -1857,7 +1606,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1857 | 1606 | |
| 1858 | 1607 | try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr }); |
| 1859 | 1608 | |
| 1860 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); |
| 1609 | _ = try self.addInst(.{ |
| 1610 | .tag = .blr, |
| 1611 | .data = .{ .reg = .x30 }, |
| 1612 | }); |
| 1861 | 1613 | } else if (func_value.castTag(.extern_fn)) |_| { |
| 1862 | 1614 | return self.fail("TODO implement calling extern functions", .{}); |
| 1863 | 1615 | } else { |
| ... | ... | @@ -1899,8 +1651,11 @@ fn ret(self: *Self, mcv: MCValue) !void { |
| 1899 | 1651 | const ret_ty = self.fn_type.fnReturnType(); |
| 1900 | 1652 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 1901 | 1653 | // Just add space for an instruction, patch this later |
| 1902 | | try self.code.resize(self.code.items.len + 4); |
| 1903 | | try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4); |
| 1654 | const index = try self.addInst(.{ |
| 1655 | .tag = .nop, |
| 1656 | .data = .{ .nop = {} }, |
| 1657 | }); |
| 1658 | try self.exitlude_jump_relocs.append(self.gpa, index); |
| 1904 | 1659 | } |
| 1905 | 1660 | |
| 1906 | 1661 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -1939,7 +1694,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1939 | 1694 | |
| 1940 | 1695 | fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1941 | 1696 | const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; |
| 1942 | | try self.dbgAdvancePCAndLine(dbg_stmt.line, dbg_stmt.column); |
| 1697 | _ = dbg_stmt; |
| 1698 | // try self.dbgAdvancePCAndLine(dbg_stmt.line, dbg_stmt.column); |
| 1943 | 1699 | return self.finishAirBookkeeping(); |
| 1944 | 1700 | } |
| 1945 | 1701 | |
| ... | ... | @@ -2090,19 +1846,18 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { |
| 2090 | 1846 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2091 | 1847 | const loop = self.air.extraData(Air.Block, ty_pl.payload); |
| 2092 | 1848 | const body = self.air.extra[loop.end..][0..loop.data.body_len]; |
| 2093 | | const start_index = self.code.items.len; |
| 1849 | const start_index = @intCast(u32, self.mir_instructions.len); |
| 2094 | 1850 | try self.genBody(body); |
| 2095 | 1851 | try self.jump(start_index); |
| 2096 | 1852 | return self.finishAirBookkeeping(); |
| 2097 | 1853 | } |
| 2098 | 1854 | |
| 2099 | | /// Send control flow to the `index` of `self.code`. |
| 2100 | | fn jump(self: *Self, index: usize) !void { |
| 2101 | | if (math.cast(i28, @intCast(i32, index) - @intCast(i32, self.code.items.len + 8))) |delta| { |
| 2102 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.b(delta).toU32()); |
| 2103 | | } else |_| { |
| 2104 | | return self.fail("TODO: enable larger branch offset", .{}); |
| 2105 | | } |
| 1855 | /// Send control flow to `inst`. |
| 1856 | fn jump(self: *Self, inst: Mir.Inst.Index) !void { |
| 1857 | _ = try self.addInst(.{ |
| 1858 | .tag = .b, |
| 1859 | .data = .{ .inst = inst }, |
| 1860 | }); |
| 2106 | 1861 | } |
| 2107 | 1862 | |
| 2108 | 1863 | fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -2140,19 +1895,8 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 2140 | 1895 | |
| 2141 | 1896 | fn performReloc(self: *Self, reloc: Reloc) !void { |
| 2142 | 1897 | switch (reloc) { |
| 2143 | | .rel32 => |pos| { |
| 2144 | | const amt = self.code.items.len - (pos + 4); |
| 2145 | | // Here it would be tempting to implement testing for amt == 0 and then elide the |
| 2146 | | // jump. However, that will cause a problem because other jumps may assume that they |
| 2147 | | // can jump to this code. Or maybe I didn't understand something when I was debugging. |
| 2148 | | // It could be worth another look. Anyway, that's why that isn't done here. Probably the |
| 2149 | | // best place to elide jumps will be in semantic analysis, by inlining blocks that only |
| 2150 | | // only have 1 break instruction. |
| 2151 | | const s32_amt = math.cast(i32, amt) catch |
| 2152 | | return self.fail("unable to perform relocation: jump too far", .{}); |
| 2153 | | mem.writeIntLittle(i32, self.code.items[pos..][0..4], s32_amt); |
| 2154 | | }, |
| 2155 | | .arm_branch => unreachable, |
| 1898 | .rel32 => return self.fail("TODO reloc.rel32 for {}", .{self.target.cpu.arch}), |
| 1899 | .arm_branch => return self.fail("TODO reloc.arm_branch for {}", .{self.target.cpu.arch}), |
| 2156 | 1900 | } |
| 2157 | 1901 | } |
| 2158 | 1902 | |
| ... | ... | @@ -2244,9 +1988,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 2244 | 1988 | } |
| 2245 | 1989 | |
| 2246 | 1990 | if (mem.eql(u8, asm_source, "svc #0")) { |
| 2247 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(0x0).toU32()); |
| 1991 | _ = try self.addInst(.{ |
| 1992 | .tag = .svc, |
| 1993 | .data = .{ .imm16 = 0x0 }, |
| 1994 | }); |
| 2248 | 1995 | } else if (mem.eql(u8, asm_source, "svc #0x80")) { |
| 2249 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(0x80).toU32()); |
| 1996 | _ = try self.addInst(.{ |
| 1997 | .tag = .svc, |
| 1998 | .data = .{ .imm16 = 0x80 }, |
| 1999 | }); |
| 2250 | 2000 | } else { |
| 2251 | 2001 | return self.fail("TODO implement support for more aarch64 assembly instructions", .{}); |
| 2252 | 2002 | } |
| ... | ... | @@ -2333,6 +2083,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2333 | 2083 | return self.fail("TODO implement set stack variable from embedded_in_code", .{}); |
| 2334 | 2084 | }, |
| 2335 | 2085 | .register => |reg| { |
| 2086 | _ = reg; |
| 2087 | |
| 2336 | 2088 | const abi_size = ty.abiSize(self.target.*); |
| 2337 | 2089 | const adj_off = stack_offset + abi_size; |
| 2338 | 2090 | |
| ... | ... | @@ -2347,16 +2099,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2347 | 2099 | .aarch64_32 => .w29, |
| 2348 | 2100 | else => unreachable, |
| 2349 | 2101 | }; |
| 2350 | | const str = switch (abi_size) { |
| 2351 | | 1 => Instruction.strb, |
| 2352 | | 2 => Instruction.strh, |
| 2353 | | 4, 8 => Instruction.str, |
| 2102 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 2103 | 1 => .strb, |
| 2104 | 2 => .strh, |
| 2105 | 4, 8 => .str, |
| 2354 | 2106 | else => unreachable, // unexpected abi size |
| 2355 | 2107 | }; |
| 2356 | 2108 | |
| 2357 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), str(reg, rn, .{ |
| 2358 | | .offset = offset, |
| 2359 | | }).toU32()); |
| 2109 | _ = try self.addInst(.{ |
| 2110 | .tag = tag, |
| 2111 | .data = .{ .load_store_register = .{ |
| 2112 | .rt = reg, |
| 2113 | .rn = rn, |
| 2114 | .offset = offset, |
| 2115 | } }, |
| 2116 | }); |
| 2360 | 2117 | }, |
| 2361 | 2118 | else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}), |
| 2362 | 2119 | } |
| ... | ... | @@ -2392,20 +2149,28 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2392 | 2149 | } |
| 2393 | 2150 | }, |
| 2394 | 2151 | .immediate => |x| { |
| 2395 | | if (x <= math.maxInt(u16)) { |
| 2396 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movz(reg, @intCast(u16, x), 0).toU32()); |
| 2397 | | } else if (x <= math.maxInt(u32)) { |
| 2398 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movz(reg, @truncate(u16, x), 0).toU32()); |
| 2399 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movk(reg, @intCast(u16, x >> 16), 16).toU32()); |
| 2400 | | } else if (x <= math.maxInt(u32)) { |
| 2401 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movz(reg, @truncate(u16, x), 0).toU32()); |
| 2402 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movk(reg, @truncate(u16, x >> 16), 16).toU32()); |
| 2403 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movk(reg, @intCast(u16, x >> 32), 32).toU32()); |
| 2404 | | } else { |
| 2405 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movz(reg, @truncate(u16, x), 0).toU32()); |
| 2406 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movk(reg, @truncate(u16, x >> 16), 16).toU32()); |
| 2407 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movk(reg, @truncate(u16, x >> 32), 32).toU32()); |
| 2408 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.movk(reg, @intCast(u16, x >> 48), 48).toU32()); |
| 2152 | _ = try self.addInst(.{ |
| 2153 | .tag = .movz, |
| 2154 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x) } }, |
| 2155 | }); |
| 2156 | |
| 2157 | if (x > math.maxInt(u16)) { |
| 2158 | _ = try self.addInst(.{ |
| 2159 | .tag = .movk, |
| 2160 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 16), .hw = 1 } }, |
| 2161 | }); |
| 2162 | } |
| 2163 | if (x > math.maxInt(u32)) { |
| 2164 | _ = try self.addInst(.{ |
| 2165 | .tag = .movk, |
| 2166 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 32), .hw = 2 } }, |
| 2167 | }); |
| 2168 | } |
| 2169 | if (x > math.maxInt(u48)) { |
| 2170 | _ = try self.addInst(.{ |
| 2171 | .tag = .movk, |
| 2172 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 48), .hw = 3 } }, |
| 2173 | }); |
| 2409 | 2174 | } |
| 2410 | 2175 | }, |
| 2411 | 2176 | .register => |src_reg| { |
| ... | ... | @@ -2414,30 +2179,36 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2414 | 2179 | return; |
| 2415 | 2180 | |
| 2416 | 2181 | // mov reg, src_reg |
| 2417 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr( |
| 2418 | | reg, |
| 2419 | | .xzr, |
| 2420 | | src_reg, |
| 2421 | | Instruction.Shift.none, |
| 2422 | | ).toU32()); |
| 2182 | _ = try self.addInst(.{ |
| 2183 | .tag = .mov_register, |
| 2184 | .data = .{ .rr = .{ .rd = reg, .rn = src_reg } }, |
| 2185 | }); |
| 2423 | 2186 | }, |
| 2424 | 2187 | .memory => |addr| { |
| 2425 | 2188 | if (self.bin_file.options.pie) { |
| 2426 | 2189 | // PC-relative displacement to the entry in the GOT table. |
| 2427 | 2190 | // adrp |
| 2428 | | const offset = @intCast(u32, self.code.items.len); |
| 2429 | | mem.writeIntLittle( |
| 2430 | | u32, |
| 2431 | | try self.code.addManyAsArray(4), |
| 2432 | | Instruction.adrp(reg, 0).toU32(), |
| 2433 | | ); |
| 2191 | // TODO add a pseudo instruction |
| 2192 | const offset = @intCast(u32, self.mir_instructions.len); |
| 2193 | // mem.writeIntLittle( |
| 2194 | // u32, |
| 2195 | // try self.code.addManyAsArray(4), |
| 2196 | // Instruction.adrp(reg, 0).toU32(), |
| 2197 | // ); |
| 2198 | _ = try self.addInst(.{ |
| 2199 | .tag = .nop, |
| 2200 | .data = .{ .nop = {} }, |
| 2201 | }); |
| 2202 | |
| 2434 | 2203 | // ldr reg, reg, offset |
| 2435 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ |
| 2436 | | .register = .{ |
| 2204 | _ = try self.addInst(.{ |
| 2205 | .tag = .ldr, |
| 2206 | .data = .{ .load_store_register = .{ |
| 2207 | .rt = reg, |
| 2437 | 2208 | .rn = reg, |
| 2438 | 2209 | .offset = Instruction.LoadStoreOffset.imm(0), |
| 2439 | | }, |
| 2440 | | }).toU32()); |
| 2210 | } }, |
| 2211 | }); |
| 2441 | 2212 | |
| 2442 | 2213 | if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 2443 | 2214 | // TODO I think the reloc might be in the wrong place. |
| ... | ... | @@ -2469,7 +2240,14 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2469 | 2240 | // The value is in memory at a hard-coded address. |
| 2470 | 2241 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 2471 | 2242 | try self.genSetReg(Type.initTag(.usize), reg, .{ .immediate = addr }); |
| 2472 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32()); |
| 2243 | _ = try self.addInst(.{ |
| 2244 | .tag = .ldr, |
| 2245 | .data = .{ .load_store_register = .{ |
| 2246 | .rt = reg, |
| 2247 | .rn = reg, |
| 2248 | .offset = Instruction.LoadStoreOffset.none, |
| 2249 | } }, |
| 2250 | }); |
| 2473 | 2251 | } |
| 2474 | 2252 | }, |
| 2475 | 2253 | .stack_offset => |unadjusted_off| { |
| ... | ... | @@ -2489,22 +2267,22 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2489 | 2267 | Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u64), MCValue{ .immediate = adj_off })); |
| 2490 | 2268 | |
| 2491 | 2269 | switch (abi_size) { |
| 2492 | | 1, 2 => { |
| 2493 | | const ldr = switch (abi_size) { |
| 2494 | | 1 => Instruction.ldrb, |
| 2495 | | 2 => Instruction.ldrh, |
| 2270 | 1, 2, 4, 8 => { |
| 2271 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 2272 | 1 => .ldrb, |
| 2273 | 2 => .ldrh, |
| 2274 | 4, 8 => .ldr, |
| 2496 | 2275 | else => unreachable, // unexpected abi size |
| 2497 | 2276 | }; |
| 2498 | 2277 | |
| 2499 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), ldr(reg, rn, .{ |
| 2500 | | .offset = offset, |
| 2501 | | }).toU32()); |
| 2502 | | }, |
| 2503 | | 4, 8 => { |
| 2504 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ |
| 2505 | | .rn = rn, |
| 2506 | | .offset = offset, |
| 2507 | | } }).toU32()); |
| 2278 | _ = try self.addInst(.{ |
| 2279 | .tag = tag, |
| 2280 | .data = .{ .load_store_register = .{ |
| 2281 | .rt = reg, |
| 2282 | .rn = rn, |
| 2283 | .offset = offset, |
| 2284 | } }, |
| 2285 | }); |
| 2508 | 2286 | }, |
| 2509 | 2287 | else => return self.fail("TODO implement genSetReg other types abi_size={}", .{abi_size}), |
| 2510 | 2288 | } |