| ... | @@ -9,19 +9,33 @@ result_insts_len: u8 = undefined, | ... | @@ -9,19 +9,33 @@ result_insts_len: u8 = undefined, |
| 9 | result_relocs_len: u8 = undefined, | 9 | result_relocs_len: u8 = undefined, |
| 10 | result_insts: [ | 10 | result_insts: [ |
| 11 | std.mem.max(usize, &.{ | 11 | std.mem.max(usize, &.{ |
| | 12 | 1, // non-pseudo instructions |
| 12 | 2, // cmovcc: cmovcc \ cmovcc | 13 | 2, // cmovcc: cmovcc \ cmovcc |
| 13 | 3, // setcc: setcc \ setcc \ logicop | 14 | 3, // setcc: setcc \ setcc \ logicop |
| 14 | 2, // jcc: jcc \ jcc | 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 | abi.Win64.callee_preserved_regs.len, // push_regs/pop_regs | 20 | abi.Win64.callee_preserved_regs.len, // push_regs/pop_regs |
| 16 | abi.SysV.callee_preserved_regs.len, // push_regs/pop_regs | 21 | abi.SysV.callee_preserved_regs.len, // push_regs/pop_regs |
| 17 | }) | 22 | }) |
| 18 | ]Instruction = undefined, | 23 | ]Instruction = undefined, |
| 19 | result_relocs: [ | 24 | result_relocs: [ |
| 20 | std.mem.max(usize, &.{ | 25 | std.mem.max(usize, &.{ |
| | 26 | 1, // jmp/jcc/call/mov/lea: jmp/jcc/call/mov/lea |
| 21 | 2, // jcc: jcc \ jcc | 27 | 2, // jcc: jcc \ jcc |
| | 28 | 2, // test \ jcc \ probe \ sub \ jmp |
| | 29 | 1, // probe \ sub \ jcc |
| 22 | }) | 30 | }) |
| 23 | ]Reloc = undefined, | 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 | pub const Error = error{ | 39 | pub const Error = error{ |
| 26 | OutOfMemory, | 40 | OutOfMemory, |
| 27 | LowerFail, | 41 | LowerFail, |
| ... | @@ -62,6 +76,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -62,6 +76,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 62 | else => try lower.generic(inst), | 76 | else => try lower.generic(inst), |
| 63 | .pseudo => switch (inst.ops) { | 77 | .pseudo => switch (inst.ops) { |
| 64 | .pseudo_cmov_z_and_np_rr => { | 78 | .pseudo_cmov_z_and_np_rr => { |
| | 79 | assert(inst.data.rr.fixes == ._); |
| 65 | try lower.emit(.none, .cmovnz, &.{ | 80 | try lower.emit(.none, .cmovnz, &.{ |
| 66 | .{ .reg = inst.data.rr.r2 }, | 81 | .{ .reg = inst.data.rr.r2 }, |
| 67 | .{ .reg = inst.data.rr.r1 }, | 82 | .{ .reg = inst.data.rr.r1 }, |
| ... | @@ -72,6 +87,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -72,6 +87,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 72 | }); | 87 | }); |
| 73 | }, | 88 | }, |
| 74 | .pseudo_cmov_nz_or_p_rr => { | 89 | .pseudo_cmov_nz_or_p_rr => { |
| | 90 | assert(inst.data.rr.fixes == ._); |
| 75 | try lower.emit(.none, .cmovnz, &.{ | 91 | try lower.emit(.none, .cmovnz, &.{ |
| 76 | .{ .reg = inst.data.rr.r1 }, | 92 | .{ .reg = inst.data.rr.r1 }, |
| 77 | .{ .reg = inst.data.rr.r2 }, | 93 | .{ .reg = inst.data.rr.r2 }, |
| ... | @@ -84,6 +100,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -84,6 +100,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 84 | .pseudo_cmov_nz_or_p_rm_sib, | 100 | .pseudo_cmov_nz_or_p_rm_sib, |
| 85 | .pseudo_cmov_nz_or_p_rm_rip, | 101 | .pseudo_cmov_nz_or_p_rm_rip, |
| 86 | => { | 102 | => { |
| | 103 | assert(inst.data.rx.fixes == ._); |
| 87 | try lower.emit(.none, .cmovnz, &.{ | 104 | try lower.emit(.none, .cmovnz, &.{ |
| 88 | .{ .reg = inst.data.rx.r1 }, | 105 | .{ .reg = inst.data.rx.r1 }, |
| 89 | .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) }, | 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,6 +111,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 94 | }); | 111 | }); |
| 95 | }, | 112 | }, |
| 96 | .pseudo_set_z_and_np_r => { | 113 | .pseudo_set_z_and_np_r => { |
| | 114 | assert(inst.data.rr.fixes == ._); |
| 97 | try lower.emit(.none, .setz, &.{ | 115 | try lower.emit(.none, .setz, &.{ |
| 98 | .{ .reg = inst.data.rr.r1 }, | 116 | .{ .reg = inst.data.rr.r1 }, |
| 99 | }); | 117 | }); |
| ... | @@ -108,6 +126,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -108,6 +126,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 108 | .pseudo_set_z_and_np_m_sib, | 126 | .pseudo_set_z_and_np_m_sib, |
| 109 | .pseudo_set_z_and_np_m_rip, | 127 | .pseudo_set_z_and_np_m_rip, |
| 110 | => { | 128 | => { |
| | 129 | assert(inst.data.rx.fixes == ._); |
| 111 | try lower.emit(.none, .setz, &.{ | 130 | try lower.emit(.none, .setz, &.{ |
| 112 | .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) }, | 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,6 +139,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 120 | }); | 139 | }); |
| 121 | }, | 140 | }, |
| 122 | .pseudo_set_nz_or_p_r => { | 141 | .pseudo_set_nz_or_p_r => { |
| | 142 | assert(inst.data.rr.fixes == ._); |
| 123 | try lower.emit(.none, .setnz, &.{ | 143 | try lower.emit(.none, .setnz, &.{ |
| 124 | .{ .reg = inst.data.rr.r1 }, | 144 | .{ .reg = inst.data.rr.r1 }, |
| 125 | }); | 145 | }); |
| ... | @@ -134,6 +154,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -134,6 +154,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 134 | .pseudo_set_nz_or_p_m_sib, | 154 | .pseudo_set_nz_or_p_m_sib, |
| 135 | .pseudo_set_nz_or_p_m_rip, | 155 | .pseudo_set_nz_or_p_m_rip, |
| 136 | => { | 156 | => { |
| | 157 | assert(inst.data.rx.fixes == ._); |
| 137 | try lower.emit(.none, .setnz, &.{ | 158 | try lower.emit(.none, .setnz, &.{ |
| 138 | .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) }, | 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,6 +167,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 146 | }); | 167 | }); |
| 147 | }, | 168 | }, |
| 148 | .pseudo_j_z_and_np_inst => { | 169 | .pseudo_j_z_and_np_inst => { |
| | 170 | assert(inst.data.inst.fixes == ._); |
| 149 | try lower.emit(.none, .jnz, &.{ | 171 | try lower.emit(.none, .jnz, &.{ |
| 150 | .{ .imm = lower.reloc(.{ .inst = index + 1 }) }, | 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,6 +176,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 154 | }); | 176 | }); |
| 155 | }, | 177 | }, |
| 156 | .pseudo_j_nz_or_p_inst => { | 178 | .pseudo_j_nz_or_p_inst => { |
| | 179 | assert(inst.data.inst.fixes == ._); |
| 157 | try lower.emit(.none, .jnz, &.{ | 180 | try lower.emit(.none, .jnz, &.{ |
| 158 | .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, | 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,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 | .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst), | 260 | .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst), |
| 166 | .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst), | 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,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 | const abi = @import("abi.zig"); | 540 | const abi = @import("abi.zig"); |
| 444 | const assert = std.debug.assert; | 541 | const assert = std.debug.assert; |
| 445 | const bits = @import("bits.zig"); | 542 | const bits = @import("bits.zig"); |