| author | |
| committer | |
| log | f47245865eea35fa0b08cb2a87e3620fa904dd88 |
| tree | 61995c5a806a91a2cc90cba8cd5eab40655d226b |
| parent | f598d2ae056e72bda1efb3bc7d77e8183e95e191 |
| signature |
3 files changed, 78 insertions(+), 98 deletions(-)
src/arch/aarch64/CodeGen.zig+30-49| ... | ... | @@ -2121,8 +2121,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2121 | 2121 | .immediate => |imm| { |
| 2122 | 2122 | _ = try self.addInst(.{ |
| 2123 | 2123 | .tag = .cmp_immediate, |
| 2124 | .data = .{ .rr_imm12_sh = .{ | |
| 2125 | .rd = .xzr, | |
| 2124 | .data = .{ .r_imm12_sh = .{ | |
| 2126 | 2125 | .rn = lhs_mcv.register, |
| 2127 | 2126 | .imm12 = @intCast(u12, imm), |
| 2128 | 2127 | } }, |
| ... | ... | @@ -2334,8 +2333,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2334 | 2333 | |
| 2335 | 2334 | _ = try self.addInst(.{ |
| 2336 | 2335 | .tag = .cmp_immediate, |
| 2337 | .data = .{ .rr_imm12_sh = .{ | |
| 2338 | .rd = .xzr, | |
| 2336 | .data = .{ .r_imm12_sh = .{ | |
| 2339 | 2337 | .rn = reg_mcv.register, |
| 2340 | 2338 | .imm12 = 0, |
| 2341 | 2339 | } }, |
| ... | ... | @@ -2559,7 +2557,16 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 2559 | 2557 | const operand_mcv = try self.resolveInst(operand); |
| 2560 | 2558 | const block_mcv = block_data.mcv; |
| 2561 | 2559 | if (block_mcv == .none) { |
| 2562 | block_data.mcv = operand_mcv; | |
| 2560 | block_data.mcv = switch (operand_mcv) { | |
| 2561 | .none, .dead, .unreach => unreachable, | |
| 2562 | .register, .stack_offset, .memory => operand_mcv, | |
| 2563 | .immediate => blk: { | |
| 2564 | const new_mcv = try self.allocRegOrMem(block, true); | |
| 2565 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | |
| 2566 | break :blk new_mcv; | |
| 2567 | }, | |
| 2568 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), | |
| 2569 | }; | |
| 2563 | 2570 | } else { |
| 2564 | 2571 | try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv); |
| 2565 | 2572 | } |
| ... | ... | @@ -2845,10 +2852,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2845 | 2852 | |
| 2846 | 2853 | _ = try self.addInst(.{ |
| 2847 | 2854 | .tag = .cset, |
| 2848 | .data = .{ .rrr_cond = .{ | |
| 2855 | .data = .{ .r_cond = .{ | |
| 2849 | 2856 | .rd = reg, |
| 2850 | .rn = .xzr, | |
| 2851 | .rm = .xzr, | |
| 2852 | 2857 | .cond = condition, |
| 2853 | 2858 | } }, |
| 2854 | 2859 | }); |
| ... | ... | @@ -2933,7 +2938,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2933 | 2938 | } }, |
| 2934 | 2939 | }); |
| 2935 | 2940 | }, |
| 2936 | 3 => return self.fail("TODO implement genSetReg types size 3", .{}), | |
| 2941 | 3, 5, 6, 7 => return self.fail("TODO implement genSetReg types size {}", .{abi_size}), | |
| 2937 | 2942 | else => unreachable, |
| 2938 | 2943 | } |
| 2939 | 2944 | }, |
| ... | ... | @@ -3114,27 +3119,6 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 3114 | 3119 | } |
| 3115 | 3120 | } |
| 3116 | 3121 | |
| 3117 | /// If the MCValue is an immediate, and it does not fit within this type, | |
| 3118 | /// we put it in a register. | |
| 3119 | /// A potential opportunity for future optimization here would be keeping track | |
| 3120 | /// of the fact that the instruction is available both as an immediate | |
| 3121 | /// and as a register. | |
| 3122 | fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCValue { | |
| 3123 | const mcv = try self.resolveInst(operand); | |
| 3124 | const ti = @typeInfo(T).Int; | |
| 3125 | switch (mcv) { | |
| 3126 | .immediate => |imm| { | |
| 3127 | // This immediate is unsigned. | |
| 3128 | const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed)); | |
| 3129 | if (imm >= math.maxInt(U)) { | |
| 3130 | return MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.usize), mcv) }; | |
| 3131 | } | |
| 3132 | }, | |
| 3133 | else => {}, | |
| 3134 | } | |
| 3135 | return mcv; | |
| 3136 | } | |
| 3137 | ||
| 3138 | 3122 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue { |
| 3139 | 3123 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 3140 | 3124 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| ... | ... | @@ -3248,19 +3232,11 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3248 | 3232 | } |
| 3249 | 3233 | }, |
| 3250 | 3234 | .ErrorSet => { |
| 3251 | switch (typed_value.val.tag()) { | |
| 3252 | .@"error" => { | |
| 3253 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | |
| 3254 | const module = self.bin_file.options.module.?; | |
| 3255 | const global_error_set = module.global_error_set; | |
| 3256 | const error_index = global_error_set.get(err_name).?; | |
| 3257 | return MCValue{ .immediate = error_index }; | |
| 3258 | }, | |
| 3259 | else => { | |
| 3260 | // In this case we are rendering an error union which has a 0 bits payload. | |
| 3261 | return MCValue{ .immediate = 0 }; | |
| 3262 | }, | |
| 3263 | } | |
| 3235 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | |
| 3236 | const module = self.bin_file.options.module.?; | |
| 3237 | const global_error_set = module.global_error_set; | |
| 3238 | const error_index = global_error_set.get(err_name).?; | |
| 3239 | return MCValue{ .immediate = error_index }; | |
| 3264 | 3240 | }, |
| 3265 | 3241 | .ErrorUnion => { |
| 3266 | 3242 | const error_type = typed_value.ty.errorUnionSet(); |
| ... | ... | @@ -3425,13 +3401,18 @@ fn parseRegName(name: []const u8) ?Register { |
| 3425 | 3401 | } |
| 3426 | 3402 | |
| 3427 | 3403 | fn registerAlias(reg: Register, size_bytes: u32) Register { |
| 3428 | _ = size_bytes; | |
| 3429 | ||
| 3430 | return reg; | |
| 3404 | if (size_bytes == 0) { | |
| 3405 | unreachable; // should be comptime known | |
| 3406 | } else if (size_bytes <= 4) { | |
| 3407 | return reg.to32(); | |
| 3408 | } else if (size_bytes <= 8) { | |
| 3409 | return reg.to64(); | |
| 3410 | } else { | |
| 3411 | unreachable; // TODO handle floating-point registers | |
| 3412 | } | |
| 3431 | 3413 | } |
| 3432 | 3414 | |
| 3433 | /// For most architectures this does nothing. For x86_64 it resolves any aliased registers | |
| 3434 | /// to the 64-bit wide ones. | |
| 3415 | /// Resolves any aliased registers to the 64-bit wide ones. | |
| 3435 | 3416 | fn toCanonicalReg(reg: Register) Register { |
| 3436 | return reg; | |
| 3417 | return reg.to64(); | |
| 3437 | 3418 | } |
src/arch/aarch64/Emit.zig+33-40| ... | ... | @@ -423,27 +423,30 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 423 | 423 | |
| 424 | 424 | fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 425 | 425 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 426 | const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh; | |
| 427 | ||
| 428 | 426 | switch (tag) { |
| 429 | .add_immediate => try emit.writeInstruction(Instruction.add( | |
| 430 | rr_imm12_sh.rd, | |
| 431 | rr_imm12_sh.rn, | |
| 432 | rr_imm12_sh.imm12, | |
| 433 | rr_imm12_sh.sh == 1, | |
| 434 | )), | |
| 435 | .cmp_immediate => try emit.writeInstruction(Instruction.subs( | |
| 436 | rr_imm12_sh.rd, | |
| 437 | rr_imm12_sh.rn, | |
| 438 | rr_imm12_sh.imm12, | |
| 439 | rr_imm12_sh.sh == 1, | |
| 440 | )), | |
| 441 | .sub_immediate => try emit.writeInstruction(Instruction.sub( | |
| 442 | rr_imm12_sh.rd, | |
| 443 | rr_imm12_sh.rn, | |
| 444 | rr_imm12_sh.imm12, | |
| 445 | rr_imm12_sh.sh == 1, | |
| 446 | )), | |
| 427 | .add_immediate, | |
| 428 | .sub_immediate, | |
| 429 | => { | |
| 430 | const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh; | |
| 431 | const rd = rr_imm12_sh.rd; | |
| 432 | const rn = rr_imm12_sh.rn; | |
| 433 | const imm12 = rr_imm12_sh.imm12; | |
| 434 | const sh = rr_imm12_sh.sh == 1; | |
| 435 | ||
| 436 | switch (tag) { | |
| 437 | .add_immediate => try emit.writeInstruction(Instruction.add(rd, rn, imm12, sh)), | |
| 438 | .sub_immediate => try emit.writeInstruction(Instruction.sub(rd, rn, imm12, sh)), | |
| 439 | else => unreachable, | |
| 440 | } | |
| 441 | }, | |
| 442 | .cmp_immediate => { | |
| 443 | const r_imm12_sh = emit.mir.instructions.items(.data)[inst].r_imm12_sh; | |
| 444 | const rn = r_imm12_sh.rn; | |
| 445 | const imm12 = r_imm12_sh.imm12; | |
| 446 | const sh = r_imm12_sh.sh == 1; | |
| 447 | ||
| 448 | try emit.writeInstruction(Instruction.subs(.xzr, rn, imm12, sh)); | |
| 449 | }, | |
| 447 | 450 | else => unreachable, |
| 448 | 451 | } |
| 449 | 452 | } |
| ... | ... | @@ -589,15 +592,11 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 589 | 592 | |
| 590 | 593 | fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 591 | 594 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 592 | const rrr_cond = emit.mir.instructions.items(.data)[inst].rrr_cond; | |
| 593 | ||
| 594 | 595 | switch (tag) { |
| 595 | .cset => try emit.writeInstruction(Instruction.csinc( | |
| 596 | rrr_cond.rd, | |
| 597 | rrr_cond.rn, | |
| 598 | rrr_cond.rm, | |
| 599 | rrr_cond.cond, | |
| 600 | )), | |
| 596 | .cset => { | |
| 597 | const r_cond = emit.mir.instructions.items(.data)[inst].r_cond; | |
| 598 | try emit.writeInstruction(Instruction.csinc(r_cond.rd, .xzr, .xzr, r_cond.cond)); | |
| 599 | }, | |
| 601 | 600 | else => unreachable, |
| 602 | 601 | } |
| 603 | 602 | } |
| ... | ... | @@ -662,20 +661,14 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 662 | 661 | fn mirLoadStoreRegisterPair(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 663 | 662 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 664 | 663 | const load_store_register_pair = emit.mir.instructions.items(.data)[inst].load_store_register_pair; |
| 664 | const rt = load_store_register_pair.rt; | |
| 665 | const rt2 = load_store_register_pair.rt2; | |
| 666 | const rn = load_store_register_pair.rn; | |
| 667 | const offset = load_store_register_pair.offset; | |
| 665 | 668 | |
| 666 | 669 | switch (tag) { |
| 667 | .stp => try emit.writeInstruction(Instruction.stp( | |
| 668 | load_store_register_pair.rt, | |
| 669 | load_store_register_pair.rt2, | |
| 670 | load_store_register_pair.rn, | |
| 671 | load_store_register_pair.offset, | |
| 672 | )), | |
| 673 | .ldp => try emit.writeInstruction(Instruction.ldp( | |
| 674 | load_store_register_pair.rt, | |
| 675 | load_store_register_pair.rt2, | |
| 676 | load_store_register_pair.rn, | |
| 677 | load_store_register_pair.offset, | |
| 678 | )), | |
| 670 | .stp => try emit.writeInstruction(Instruction.stp(rt, rt2, rn, offset)), | |
| 671 | .ldp => try emit.writeInstruction(Instruction.ldp(rt, rt2, rn, offset)), | |
| 679 | 672 | else => unreachable, |
| 680 | 673 | } |
| 681 | 674 | } |
src/arch/aarch64/Mir.zig+15-9| ... | ... | @@ -175,6 +175,13 @@ pub const Inst = struct { |
| 175 | 175 | imm16: u16, |
| 176 | 176 | hw: u2 = 0, |
| 177 | 177 | }, |
| 178 | /// A register and a condition | |
| 179 | /// | |
| 180 | /// Used by e.g. cset | |
| 181 | r_cond: struct { | |
| 182 | rd: Register, | |
| 183 | cond: bits.Instruction.Condition, | |
| 184 | }, | |
| 178 | 185 | /// Two registers |
| 179 | 186 | /// |
| 180 | 187 | /// Used by e.g. mov_register |
| ... | ... | @@ -182,6 +189,14 @@ pub const Inst = struct { |
| 182 | 189 | rd: Register, |
| 183 | 190 | rn: Register, |
| 184 | 191 | }, |
| 192 | /// A register, an unsigned 12-bit immediate, and an optional shift | |
| 193 | /// | |
| 194 | /// Used by e.g. cmp_immediate | |
| 195 | r_imm12_sh: struct { | |
| 196 | rn: Register, | |
| 197 | imm12: u12, | |
| 198 | sh: u1 = 0, | |
| 199 | }, | |
| 185 | 200 | /// Two registers, an unsigned 12-bit immediate, and an optional shift |
| 186 | 201 | /// |
| 187 | 202 | /// Used by e.g. sub_immediate |
| ... | ... | @@ -209,15 +224,6 @@ pub const Inst = struct { |
| 209 | 224 | imm6: u6, |
| 210 | 225 | shift: bits.Instruction.AddSubtractShiftedRegisterShift, |
| 211 | 226 | }, |
| 212 | /// Three registers and a condition | |
| 213 | /// | |
| 214 | /// Used by e.g. cset | |
| 215 | rrr_cond: struct { | |
| 216 | rd: Register, | |
| 217 | rn: Register, | |
| 218 | rm: Register, | |
| 219 | cond: bits.Instruction.Condition, | |
| 220 | }, | |
| 221 | 227 | /// Two registers and a LoadStoreOffsetImmediate |
| 222 | 228 | /// |
| 223 | 229 | /// Used by e.g. str_immediate |