| ... | ... | @@ -9,19 +9,33 @@ result_insts_len: u8 = undefined, |
| 9 | 9 | result_relocs_len: u8 = undefined, |
| 10 | 10 | result_insts: [ |
| 11 | 11 | std.mem.max(usize, &.{ |
| 12 | 1, // non-pseudo instructions |
| 12 | 13 | 2, // cmovcc: cmovcc \ cmovcc |
| 13 | 14 | 3, // setcc: setcc \ setcc \ logicop |
| 14 | 15 | 2, // jcc: jcc \ jcc |
| 16 | pseudo_probe_align_insts, |
| 17 | pseudo_probe_adjust_unrolled_max_insts, |
| 18 | pseudo_probe_adjust_setup_insts, |
| 19 | pseudo_probe_adjust_loop_insts, |
| 15 | 20 | abi.Win64.callee_preserved_regs.len, // push_regs/pop_regs |
| 16 | 21 | abi.SysV.callee_preserved_regs.len, // push_regs/pop_regs |
| 17 | 22 | }) |
| 18 | 23 | ]Instruction = undefined, |
| 19 | 24 | result_relocs: [ |
| 20 | 25 | std.mem.max(usize, &.{ |
| 26 | 1, // jmp/jcc/call/mov/lea: jmp/jcc/call/mov/lea |
| 21 | 27 | 2, // jcc: jcc \ jcc |
| 28 | 2, // test \ jcc \ probe \ sub \ jmp |
| 29 | 1, // probe \ sub \ jcc |
| 22 | 30 | }) |
| 23 | 31 | ]Reloc = undefined, |
| 24 | 32 | |
| 33 | pub const pseudo_probe_align_insts = 5; // test \ jcc \ probe \ sub \ jmp |
| 34 | pub const pseudo_probe_adjust_unrolled_max_insts = |
| 35 | pseudo_probe_adjust_setup_insts + pseudo_probe_adjust_loop_insts; |
| 36 | pub const pseudo_probe_adjust_setup_insts = 2; // mov \ sub |
| 37 | pub const pseudo_probe_adjust_loop_insts = 3; // probe \ sub \ jcc |
| 38 | |
| 25 | 39 | pub const Error = error{ |
| 26 | 40 | OutOfMemory, |
| 27 | 41 | LowerFail, |
| ... | ... | @@ -62,6 +76,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 62 | 76 | else => try lower.generic(inst), |
| 63 | 77 | .pseudo => switch (inst.ops) { |
| 64 | 78 | .pseudo_cmov_z_and_np_rr => { |
| 79 | assert(inst.data.rr.fixes == ._); |
| 65 | 80 | try lower.emit(.none, .cmovnz, &.{ |
| 66 | 81 | .{ .reg = inst.data.rr.r2 }, |
| 67 | 82 | .{ .reg = inst.data.rr.r1 }, |
| ... | ... | @@ -72,6 +87,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 72 | 87 | }); |
| 73 | 88 | }, |
| 74 | 89 | .pseudo_cmov_nz_or_p_rr => { |
| 90 | assert(inst.data.rr.fixes == ._); |
| 75 | 91 | try lower.emit(.none, .cmovnz, &.{ |
| 76 | 92 | .{ .reg = inst.data.rr.r1 }, |
| 77 | 93 | .{ .reg = inst.data.rr.r2 }, |
| ... | ... | @@ -84,6 +100,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 84 | 100 | .pseudo_cmov_nz_or_p_rm_sib, |
| 85 | 101 | .pseudo_cmov_nz_or_p_rm_rip, |
| 86 | 102 | => { |
| 103 | assert(inst.data.rx.fixes == ._); |
| 87 | 104 | try lower.emit(.none, .cmovnz, &.{ |
| 88 | 105 | .{ .reg = inst.data.rx.r1 }, |
| 89 | 106 | .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) }, |
| ... | ... | @@ -94,6 +111,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 94 | 111 | }); |
| 95 | 112 | }, |
| 96 | 113 | .pseudo_set_z_and_np_r => { |
| 114 | assert(inst.data.rr.fixes == ._); |
| 97 | 115 | try lower.emit(.none, .setz, &.{ |
| 98 | 116 | .{ .reg = inst.data.rr.r1 }, |
| 99 | 117 | }); |
| ... | ... | @@ -108,6 +126,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 108 | 126 | .pseudo_set_z_and_np_m_sib, |
| 109 | 127 | .pseudo_set_z_and_np_m_rip, |
| 110 | 128 | => { |
| 129 | assert(inst.data.rx.fixes == ._); |
| 111 | 130 | try lower.emit(.none, .setz, &.{ |
| 112 | 131 | .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) }, |
| 113 | 132 | }); |
| ... | ... | @@ -120,6 +139,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 120 | 139 | }); |
| 121 | 140 | }, |
| 122 | 141 | .pseudo_set_nz_or_p_r => { |
| 142 | assert(inst.data.rr.fixes == ._); |
| 123 | 143 | try lower.emit(.none, .setnz, &.{ |
| 124 | 144 | .{ .reg = inst.data.rr.r1 }, |
| 125 | 145 | }); |
| ... | ... | @@ -134,6 +154,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 134 | 154 | .pseudo_set_nz_or_p_m_sib, |
| 135 | 155 | .pseudo_set_nz_or_p_m_rip, |
| 136 | 156 | => { |
| 157 | assert(inst.data.rx.fixes == ._); |
| 137 | 158 | try lower.emit(.none, .setnz, &.{ |
| 138 | 159 | .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) }, |
| 139 | 160 | }); |
| ... | ... | @@ -146,6 +167,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 146 | 167 | }); |
| 147 | 168 | }, |
| 148 | 169 | .pseudo_j_z_and_np_inst => { |
| 170 | assert(inst.data.inst.fixes == ._); |
| 149 | 171 | try lower.emit(.none, .jnz, &.{ |
| 150 | 172 | .{ .imm = lower.reloc(.{ .inst = index + 1 }) }, |
| 151 | 173 | }); |
| ... | ... | @@ -154,6 +176,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 154 | 176 | }); |
| 155 | 177 | }, |
| 156 | 178 | .pseudo_j_nz_or_p_inst => { |
| 179 | assert(inst.data.inst.fixes == ._); |
| 157 | 180 | try lower.emit(.none, .jnz, &.{ |
| 158 | 181 | .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, |
| 159 | 182 | }); |
| ... | ... | @@ -162,6 +185,78 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 162 | 185 | }); |
| 163 | 186 | }, |
| 164 | 187 | |
| 188 | .pseudo_probe_align_ri_s => { |
| 189 | try lower.emit(.none, .@"test", &.{ |
| 190 | .{ .reg = inst.data.ri.r1 }, |
| 191 | .{ .imm = Immediate.s(@bitCast(i32, inst.data.ri.i)) }, |
| 192 | }); |
| 193 | try lower.emit(.none, .jz, &.{ |
| 194 | .{ .imm = lower.reloc(.{ .inst = index + 1 }) }, |
| 195 | }); |
| 196 | try lower.emit(.none, .lea, &.{ |
| 197 | .{ .reg = inst.data.ri.r1 }, |
| 198 | .{ .mem = Memory.sib(.qword, .{ |
| 199 | .base = .{ .reg = inst.data.ri.r1 }, |
| 200 | .disp = -page_size, |
| 201 | }) }, |
| 202 | }); |
| 203 | try lower.emit(.none, .@"test", &.{ |
| 204 | .{ .mem = Memory.sib(.dword, .{ |
| 205 | .base = .{ .reg = inst.data.ri.r1 }, |
| 206 | }) }, |
| 207 | .{ .reg = inst.data.ri.r1.to32() }, |
| 208 | }); |
| 209 | try lower.emit(.none, .jmp, &.{ |
| 210 | .{ .imm = lower.reloc(.{ .inst = index }) }, |
| 211 | }); |
| 212 | assert(lower.result_insts_len == pseudo_probe_align_insts); |
| 213 | }, |
| 214 | .pseudo_probe_adjust_unrolled_ri_s => { |
| 215 | var offset = page_size; |
| 216 | while (offset < @bitCast(i32, inst.data.ri.i)) : (offset += page_size) { |
| 217 | try lower.emit(.none, .@"test", &.{ |
| 218 | .{ .mem = Memory.sib(.dword, .{ |
| 219 | .base = .{ .reg = inst.data.ri.r1 }, |
| 220 | .disp = -offset, |
| 221 | }) }, |
| 222 | .{ .reg = inst.data.ri.r1.to32() }, |
| 223 | }); |
| 224 | } |
| 225 | try lower.emit(.none, .sub, &.{ |
| 226 | .{ .reg = inst.data.ri.r1 }, |
| 227 | .{ .imm = Immediate.s(@bitCast(i32, inst.data.ri.i)) }, |
| 228 | }); |
| 229 | assert(lower.result_insts_len <= pseudo_probe_adjust_unrolled_max_insts); |
| 230 | }, |
| 231 | .pseudo_probe_adjust_setup_rri_s => { |
| 232 | try lower.emit(.none, .mov, &.{ |
| 233 | .{ .reg = inst.data.rri.r2.to32() }, |
| 234 | .{ .imm = Immediate.s(@bitCast(i32, inst.data.rri.i)) }, |
| 235 | }); |
| 236 | try lower.emit(.none, .sub, &.{ |
| 237 | .{ .reg = inst.data.rri.r1 }, |
| 238 | .{ .reg = inst.data.rri.r2 }, |
| 239 | }); |
| 240 | assert(lower.result_insts_len == pseudo_probe_adjust_setup_insts); |
| 241 | }, |
| 242 | .pseudo_probe_adjust_loop_rr => { |
| 243 | try lower.emit(.none, .@"test", &.{ |
| 244 | .{ .mem = Memory.sib(.dword, .{ |
| 245 | .base = .{ .reg = inst.data.rr.r1 }, |
| 246 | .scale_index = .{ .scale = 1, .index = inst.data.rr.r2 }, |
| 247 | .disp = -page_size, |
| 248 | }) }, |
| 249 | .{ .reg = inst.data.rr.r1.to32() }, |
| 250 | }); |
| 251 | try lower.emit(.none, .sub, &.{ |
| 252 | .{ .reg = inst.data.rr.r2 }, |
| 253 | .{ .imm = Immediate.s(page_size) }, |
| 254 | }); |
| 255 | try lower.emit(.none, .jae, &.{ |
| 256 | .{ .imm = lower.reloc(.{ .inst = index }) }, |
| 257 | }); |
| 258 | assert(lower.result_insts_len == pseudo_probe_adjust_loop_insts); |
| 259 | }, |
| 165 | 260 | .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst), |
| 166 | 261 | .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst), |
| 167 | 262 | |
| ... | ... | @@ -440,6 +535,8 @@ fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Er |
| 440 | 535 | }}); |
| 441 | 536 | } |
| 442 | 537 | |
| 538 | const page_size: i32 = 1 << 12; |
| 539 | |
| 443 | 540 | const abi = @import("abi.zig"); |
| 444 | 541 | const assert = std.debug.assert; |
| 445 | 542 | const bits = @import("bits.zig"); |