zig/src/codegen/x86_64/Mir.zig

2132 lines
68 KiB
Zig

//! Machine Intermediate Representation.
//! This data is produced by x86_64 Codegen and consumed by x86_64 Isel.
//! These instructions have a 1:1 correspondence with machine code instructions
//! for the target. MIR can be lowered to source-annotated textual assembly code
//! instructions, or it can be lowered to machine code.
//! The main purpose of MIR is to postpone the assignment of offsets until Isel,
//! so that, for example, the smaller encodings of jump instructions can be used.
instructions: std.MultiArrayList(Inst).Slice,
/// The meaning of this data is determined by `Inst.Tag` value.
extra: []const u32,
string_bytes: []const u8,
locals: []const Local,
table: []const Inst.Index,
/// Optional data which, when present, can be used to accelerate encoding speed.
memoized_encodings: []const u0 = &.{},
frame_locs: std.MultiArrayList(FrameLoc).Slice,
pub const Inst = struct {
tag: Tag,
ops: Ops,
data: Data,
pub const Index = u32;
pub const Fixes = enum(u8) {
/// ___
@"_",
/// ___ 0
_0,
/// ___ 1
_1,
/// ___ 2
_2,
/// ___ 3
_3,
/// ___ 4
_4,
/// ___ Demote
_demote,
/// ___ Flush
_flush,
/// ___ Flush Optimized
_flushopt,
/// ___ Instructions With T0 Hint
_it0,
/// ___ Instructions With T0 Hint
_it1,
/// ___ With NTA Hint
_nta,
/// System Call ___
sys_,
/// ___ With T0 Hint
_t0,
/// ___ With T1 Hint
_t1,
/// ___ With T2 Hint
_t2,
/// ___ Write Back
_wb,
/// ___ With Intent to Write and T1 Hint
_wt1,
/// ___ crement Shadow Stack Pointer Doubleword
_csspd,
/// ___ crement Shadow Stack Pointer Quadword
_csspq,
/// ___ FS Segment Base
_fsbase,
/// ___ GS
_gs,
/// ___ GS Segment Base
_gsbase,
/// ___ Model Specific Register
_msr,
/// ___ MXCSR
_mxcsr,
/// ___ Processor ID
_pid,
/// ___ Protection Key Rights For User Pages
_pkru,
/// ___ Performance-Monitoring Counters
_pmc,
/// ___ Random Number
_rand,
/// ___ r Busy Flag in a Supervisor Shadow Stack token
_rssbsy,
/// ___ Random Seed
_seed,
/// ___ Shadow Stack Doubleword
_ssd,
/// ___ Shadow Stack Quadword
_ssq,
/// ___ Shadow Stack Pointer Doubleword
_sspd,
/// ___ Shadow Stack Pointer Quadword
_sspq,
/// ___ Time-Stamp Counter
_tsc,
/// ___ Time-Stamp Counter And Processor ID
_tscp,
/// ___ User Shadow Stack Doubleword
_ussd,
/// ___ User Shadow Stack Quadword
_ussq,
/// VEX-Encoded ___ MXCSR
v_mxcsr,
/// Byte ___
b_,
/// Interrupt ___
/// Integer ___
i_,
/// Interrupt ___ Word
i_w,
/// Interrupt ___ Doubleword
i_d,
/// Interrupt ___ Quadword
i_q,
/// User-Interrupt ___
ui_,
/// ___ mp
_mp,
/// ___ if CX register is 0
_cxz,
/// ___ if ECX register is 0
_ecxz,
/// ___ if RCX register is 0
_rcxz,
/// ___ Addition
_a,
/// ___ Subtraction
_s,
/// ___ Multiply
_m,
/// ___ Division
_d,
/// ___ Without Affecting Flags
_x,
/// ___ Left
_l,
/// ___ Left Double
_ld,
/// ___ Left Without Affecting Flags
_lx,
/// ___ Mask
_msk,
/// ___ Right
/// ___ For Reading
/// ___ Register
_r,
/// ___ Right Double
_rd,
/// ___ Right Without Affecting Flags
_rx,
/// ___ Forward
_f,
/// ___ Reverse
//_r,
/// ___ Above
//_a,
/// ___ Above Or Equal
_ae,
/// ___ Below
_b,
/// ___ Below Or Equal
/// ___ Big Endian
_be,
/// ___ Carry
/// ___ Carry Flag
_c,
/// ___ Equal
_e,
/// ___ Greater
_g,
/// ___ Greater Or Equal
_ge,
/// ___ Less
//_l,
/// ___ Less Or Equal
_le,
/// ___ Not Above
_na,
/// ___ Not Above Or Equal
_nae,
/// ___ Not Below
_nb,
/// ___ Not Below Or Equal
_nbe,
/// ___ Not Carry
_nc,
/// ___ Not Equal
_ne,
/// ___ Not Greater
_ng,
/// ___ Not Greater Or Equal
_nge,
/// ___ Not Less
_nl,
/// ___ Not Less Or Equal
_nle,
/// ___ Not Overflow
_no,
/// ___ Not Parity
_np,
/// ___ Not Sign
_ns,
/// ___ Not Zero
_nz,
/// ___ Overflow
_o,
/// ___ Parity
_p,
/// ___ Parity Even
_pe,
/// ___ Parity Odd
_po,
/// ___ Sign
//_s,
/// ___ Zero
_z,
/// ___ Alignment Check Flag
_ac,
/// ___ Direction Flag
//_d,
/// ___ Interrupt Flag
_i,
/// ___ Task-Switched Flag In CR0
_ts,
/// ___ User Interrupt Flag
_ui,
/// ___ Byte
//_b,
/// ___ Word
/// ___ For Writing
/// ___ With Intent to Write
_w,
/// ___ Doubleword
//_d,
/// ___ Double Quadword to Quadword
_dq2q,
/// ___ QuadWord
_q,
/// ___ Quadword to Double Quadword
_q2dq,
/// ___ String
//_s,
/// ___ String Byte
_sb,
/// ___ String Word
_sw,
/// ___ String Doubleword
_sd,
/// ___ String Quadword
_sq,
/// Repeat ___ String
@"rep _s",
/// Repeat ___ String Byte
@"rep _sb",
/// Repeat ___ String Word
@"rep _sw",
/// Repeat ___ String Doubleword
@"rep _sd",
/// Repeat ___ String Quadword
@"rep _sq",
/// Repeat Equal ___ String
@"repe _s",
/// Repeat Equal ___ String Byte
@"repe _sb",
/// Repeat Equal ___ String Word
@"repe _sw",
/// Repeat Equal ___ String Doubleword
@"repe _sd",
/// Repeat Equal ___ String Quadword
@"repe _sq",
/// Repeat Not Equal ___ String
@"repne _s",
/// Repeat Not Equal ___ String Byte
@"repne _sb",
/// Repeat Not Equal ___ String Word
@"repne _sw",
/// Repeat Not Equal ___ String Doubleword
@"repne _sd",
/// Repeat Not Equal ___ String Quadword
@"repne _sq",
/// Repeat Not Zero ___ String
@"repnz _s",
/// Repeat Not Zero ___ String Byte
@"repnz _sb",
/// Repeat Not Zero ___ String Word
@"repnz _sw",
/// Repeat Not Zero ___ String Doubleword
@"repnz _sd",
/// Repeat Not Zero ___ String Quadword
@"repnz _sq",
/// Repeat Zero ___ String
@"repz _s",
/// Repeat Zero ___ String Byte
@"repz _sb",
/// Repeat Zero ___ String Word
@"repz _sw",
/// Repeat Zero ___ String Doubleword
@"repz _sd",
/// Repeat Zero ___ String Quadword
@"repz _sq",
/// Locked ___
@"lock _",
/// ___ And Complement
//_c,
/// Locked ___ And Complement
@"lock _c",
/// ___ And Reset
//_r,
/// Locked ___ And Reset
@"lock _r",
/// ___ And Set
//_s,
/// Locked ___ And Set
@"lock _s",
/// ___ 8 Bytes
_8b,
/// Locked ___ 8 Bytes
@"lock _8b",
/// ___ 16 Bytes
_16b,
/// Locked ___ 16 Bytes
@"lock _16b",
/// Float ___
f_,
/// Float ___ +1.0
/// Float ___ 1
f_1,
/// Float ___ Below
f_b,
/// Float ___ Below Or Equal
f_be,
/// Float ___ Control Word
f_cw,
/// Float ___ Equal
f_e,
/// Float ___ Environment
f_env,
/// Float ___ log_2(e)
f_l2e,
/// Float ___ log_2(10)
f_l2t,
/// Float ___ log_10(2)
f_lg2,
/// Float ___ log_e(2)
f_ln2,
/// Float ___ Not Below
f_nb,
/// Float ___ Not Below Or Equal
f_nbe,
/// Float ___ Not Equal
f_ne,
/// Float ___ Not Unordered
f_nu,
/// Float ___ Pop
f_p,
/// Float ___ +1
f_p1,
/// Float ___ π
f_pi,
/// Float ___ Pop Pop
f_pp,
/// Float ___ crement Stack-Top Pointer
f_cstp,
/// Float ___ Status Word
f_sw,
/// Float ___ Unordered
f_u,
/// Float ___ +0.0
f_z,
/// Float BCD ___
fb_,
/// Float BCD ___ Pop
fb_p,
/// Float And Integer ___
fi_,
/// Float And Integer ___ Pop
fi_p,
/// Float No Wait ___
fn_,
/// Float No Wait ___ Control Word
fn_cw,
/// Float No Wait ___ Environment
fn_env,
/// Float No Wait ___ status word
fn_sw,
/// Float Extended ___
fx_,
/// Float Extended ___ 64
fx_64,
/// ___ in 32-bit and Compatibility Mode
_32,
/// ___ in 64-bit Mode
_64,
/// Packed ___
p_,
/// Packed ___ Byte
p_b,
/// Packed ___ Word
p_w,
/// Packed ___ Doubleword
p_d,
/// Packed ___ Quadword
p_q,
/// Packed ___ Double Quadword
/// Packed ___ Doubleword to Quadword
p_dq,
/// Packed ___ Unsigned Doubleword to Quadword
p_udq,
/// Packed Carry-Less ___ Quadword to Double Quadword
pcl_qdq,
/// Packed Half ___ Doubleword
ph_d,
/// Packed Half ___ Saturate Word
ph_sw,
/// Packed Half ___ Word
ph_w,
/// ___ Aligned Packed Integer Values
_dqa,
/// ___ Unaligned Packed Integer Values
_dqu,
/// ___ Scalar Single-Precision Values
_ss,
/// ___ Packed Single-Precision Values
_ps,
/// ___ Scalar Double-Precision Values
//_sd,
/// ___ Packed Double-Precision Values
_pd,
/// Half ___ Packed Single-Precision Values
h_ps,
/// Half ___ Packed Double-Precision Values
h_pd,
/// ___ Internal Caches
//_d,
/// ___ TLB Entries
_lpg,
/// ___ Process-Context Identifier
_pcid,
/// Load ___
l_,
/// Memory ___
m_,
/// Store ___
s_,
/// Timed ___
t_,
/// User Level Monitor ___
um_,
/// VEX-Encoded ___
v_,
/// VEX-Encoded ___ Byte
v_b,
/// VEX-Encoded ___ Word
v_w,
/// VEX-Encoded ___ Doubleword
v_d,
/// VEX-Encoded ___ Quadword
v_q,
/// VEX-Encoded ___ Aligned Packed Integer Values
v_dqa,
/// VEX-Encoded ___ Unaligned Packed Integer Values
v_dqu,
/// VEX-Encoded ___ Integer Data
v_i128,
/// VEX-Encoded Packed ___
vp_,
/// VEX-Encoded Packed ___ Byte
vp_b,
/// VEX-Encoded Packed ___ Word
vp_w,
/// VEX-Encoded Packed ___ Doubleword
vp_d,
/// VEX-Encoded Packed ___ Quadword
vp_q,
/// VEX-Encoded Packed ___ Double Quadword
/// VEX-Encoded Packed ___ Doubleword to Quadword
vp_dq,
/// VEX-Encoded Packed ___ Unsigned Doubleword to Quadword
vp_udq,
/// VEx-Encoded Packed Carry-Less ___ Quadword to Double Quadword
vpcl_qdq,
/// VEX-Encoded Packed Half ___ Doubleword
vph_d,
/// VEX-Encoded Packed Half ___ Saturate Word
vph_sw,
/// VEX-Encoded Packed Half ___ Word
vph_w,
/// VEX-Encoded ___ Scalar Single-Precision Values
v_ss,
/// VEX-Encoded ___ Packed Single-Precision Values
v_ps,
/// VEX-Encoded ___ Scalar Double-Precision Values
v_sd,
/// VEX-Encoded ___ Packed Double-Precision Values
v_pd,
/// VEX-Encoded ___ 128-Bits Of Floating-Point Data
v_f128,
/// VEX-Encoded Half ___ Packed Single-Precision Values
vh_ps,
/// VEX-Encoded Half ___ Packed Double-Precision Values
vh_pd,
/// ___ 128-bit key with key locker
_128,
/// ___ 256-bit key with key locker
_256,
/// ___ with key locker using 128-bit key
_128kl,
/// ___ with key locker using 256-bit key
_256kl,
/// ___ with key locker on 8 blocks using 128-bit key
_wide128kl,
/// ___ with key locker on 8 blocks using 256-bit key
_wide256kl,
/// Mask ___ Byte
k_b,
/// Mask ___ Word
k_w,
/// Mask ___ Doubleword
k_d,
/// Mask ___ Quadword
k_q,
pub fn fromCond(cc: bits.Condition) Fixes {
return switch (cc) {
inline else => |cc_tag| @field(Fixes, "_" ++ @tagName(cc_tag)),
.z_and_np, .nz_or_p => unreachable,
};
}
};
pub const Tag = enum(u8) {
// General-purpose
/// ASCII adjust al after addition
/// ASCII adjust ax before division
/// ASCII adjust ax after multiply
/// ASCII adjust al after subtraction
aa,
/// Add with carry
/// Unsigned integer addition of two operands with carry flag
adc,
/// Add
/// Add packed integers
/// Add packed single-precision floating-point values
/// Add scalar single-precision floating-point values
/// Add packed double-precision floating-point values
/// Add scalar double-precision floating-point values
/// Packed single-precision floating-point horizontal add
/// Packed double-precision floating-point horizontal add
/// Packed horizontal add
/// Packed horizontal add and saturate
add,
/// Logical and
/// Bitwise logical and of packed single-precision floating-point values
/// Bitwise logical and of packed double-precision floating-point values
@"and",
/// Adjust RPL field of segment selector
arpl,
/// Bit scan forward
/// Bit scan reverse
bs,
/// Byte swap
/// Swap GS base register
swap,
/// Bit test
/// Bit test and complement
/// Bit test and reset
/// Bit test and set
bt,
/// Check array index against bounds
bound,
/// Call
/// Fast system call
call,
/// Convert byte to word
cbw,
/// Convert doubleword to quadword
cdq,
/// Convert doubleword to quadword
cdqe,
/// Clear AC flag in EFLAGS register
/// Clear carry flag
/// Clear direction flag
/// Clear interrupt flag
/// Clear task-switched flag in CR0
/// Clear user interrupt flag
/// Cache line demote
/// Flush cache line
/// Flush cache line optimized
/// Clear busy flag in a supervisor shadow stack token
/// Cache line write back
cl,
/// Complement carry flag
cmc,
/// Conditional move
cmov,
/// Logical compare
/// Compare string
/// Compare scalar single-precision floating-point values
/// Compare scalar double-precision floating-point values
cmp,
/// Compare and exchange
/// Compare and exchange bytes
cmpxchg,
/// CPU identification
cpuid,
/// Convert doubleword to quadword
cqo,
/// Convert word to doubleword
cwd,
/// Convert word to doubleword
cwde,
/// Decimal adjust AL after addition
/// Decimal adjust AL after subtraction
da,
/// Decrement by 1
/// Decrement stack-top pointer
/// Decrement shadow stack pointer
de,
/// Unsigned division
/// Signed division
/// Divide
/// Divide packed single-precision floating-point values
/// Divide scalar single-precision floating-point values
/// Divide packed double-precision floating-point values
/// Divide scalar double-precision floating-point values
div,
/// Terminate and indirect branch in 32-bit and compatibility mode
/// Terminate and indirect branch in 64-bit mode
endbr,
/// Enqueue command
/// Enqueue command supervisor
enqcmd,
/// Make stack frame for procedure parameters
/// Fast system call
enter,
/// Fast return from fast system call
exit,
/// Load fence
/// Memory fence
/// Store fence
fence,
/// Halt
hlt,
/// History reset
hreset,
/// Input from port
/// Input from port to string
/// Increment by 1
/// Increment stack-top pointer
/// Increment shadow stack pointer
in,
/// Call to interrupt procedure
int,
/// Invalidate internal caches
/// Invalidate TLB entries
/// Invalidate process-context identifier
inv,
/// Conditional jump
/// Jump
j,
/// Load status flags into AH register
lahf,
/// Load access right byte
lar,
/// Load effective address
lea,
/// High level procedure exit
leave,
/// Load global descriptor table register
lgdt,
/// Load interrupt descriptor table register
lidt,
/// Load local descriptor table register
lldt,
/// Load machine status word
lmsw,
/// Load string
lod,
/// Loop according to ECX counter
loop,
/// Load segment limit
lsl,
/// Load task register
ltr,
/// Count the number of leading zero bits
lzcnt,
/// Move
/// Move data from string to string
/// Move data after swapping bytes
/// Move scalar single-precision floating-point value
/// Move scalar double-precision floating-point value
/// Move doubleword
/// Move quadword
/// Move aligned packed integer values
/// Move unaligned packed integer values
/// Move quadword from XMM to MMX technology register
/// Move quadword from MMX technology to XMM register
mov,
/// Move with sign extension
movsx,
/// Move with zero extension
movzx,
/// Multiply
/// Signed multiplication
/// Multiply packed single-precision floating-point values
/// Multiply scalar single-precision floating-point values
/// Multiply packed double-precision floating-point values
/// Multiply scalar double-precision floating-point values
/// Multiply packed unsigned doubleword integers
/// Multiply packed doubleword integers
/// Carry-less multiplication quadword
mul,
/// Two's complement negation
neg,
/// No-op
/// No operation
nop,
/// One's complement negation
not,
/// Logical or
/// Bitwise logical or of packed single-precision floating-point values
/// Bitwise logical or of packed double-precision floating-point values
@"or",
/// Output to port
/// Output string to port
out,
/// Spin loop hint
/// Timed pause
pause,
/// Pop
pop,
/// Return the count of number of bits set to 1
popcnt,
/// Pop stack into EFLAGS register
popf,
/// Push
push,
/// Push EFLAGS register onto the stack
pushf,
/// Rotate left through carry
/// Rotate right through carry
rc,
/// Read FS segment base
/// Read GS segment base
/// Read from model specific register
/// Read processor ID
/// Read protection key rights for user pages
/// Read performance-monitoring counters
/// Read random number
/// Read random seed
/// Read shadow stack pointer
/// Read time-stamp counter
/// Read time-stamp counter and processor ID
rd,
/// Return
/// Return from fast system call
/// Interrupt return
/// User-interrupt return
ret,
/// Rotate left
/// Rotate right
/// Rotate right logical without affecting flags
ro,
/// Resume from system management mode
rsm,
/// Arithmetic shift left
/// Arithmetic shift right
/// Shift left arithmetic without affecting flags
sa,
/// Store AH into flags
sahf,
/// Integer subtraction with borrow
sbb,
/// Scan string
sca,
/// Send user interprocessor interrupt
senduipi,
/// Serialize instruction execution
serialize,
/// Set byte on condition
set,
/// Logical shift left
/// Double precision shift left
/// Logical shift right
/// Double precision shift right
/// Shift left logical without affecting flags
/// Shift right logical without affecting flags
sh,
/// Store interrupt descriptor table register
sidt,
/// Store local descriptor table register
sldt,
/// Store machine status word
smsw,
/// Subtract
/// Subtract packed integers
/// Subtract packed single-precision floating-point values
/// Subtract scalar single-precision floating-point values
/// Subtract packed double-precision floating-point values
/// Subtract scalar double-precision floating-point values
/// Packed single-precision floating-point horizontal subtract
/// Packed double-precision floating-point horizontal subtract
/// Packed horizontal subtract
/// Packed horizontal subtract and saturate
sub,
/// Set carry flag
/// Set direction flag
/// Set interrupt flag
/// Store binary coded decimal integer and pop
/// Store floating-point value
/// Store integer
/// Store x87 FPU control word
/// Store x87 FPU environment
/// Store x87 FPU status word
/// Store MXCSR register state
st,
/// Store string
sto,
/// Test condition
/// Logical compare
/// Packed bit test
@"test",
/// Undefined instruction
ud,
/// User level set up monitor address
umonitor,
/// Verify a segment for reading
/// Verify a segment for writing
ver,
/// Write to model specific register
/// Write to model specific register
/// Write to model specific register
/// Write to shadow stack
/// Write to user shadow stack
wr,
/// Exchange and add
xadd,
/// Exchange register/memory with register
/// Exchange register contents
xch,
/// Get value of extended control register
xgetbv,
/// Table look-up translation
xlat,
/// Logical exclusive-or
/// Bitwise logical xor of packed single-precision floating-point values
/// Bitwise logical xor of packed double-precision floating-point values
xor,
// X87
/// Compute 2^x-1
@"2xm1",
/// Absolute value
abs,
/// Change sign
chs,
/// Clear exceptions
clex,
/// Compare floating-point values
com,
/// Compare floating-point values and set EFLAGS
/// Compare scalar ordered single-precision floating-point values
/// Compare scalar ordered double-precision floating-point values
comi,
/// Cosine
cos,
/// Reverse divide
divr,
/// Free floating-point register
free,
/// Initialize floating-point unit
init,
/// Load binary coded decimal integer
/// Load floating-point value
/// Load integer
/// Load constant
/// Load x87 FPU control word
/// Load x87 FPU environment
/// Load MXCSR register state
ld,
/// Partial arctangent
patan,
/// Partial remainder
prem,
/// Partial tangent
ptan,
/// Round to integer
rndint,
/// Restore x87 FPU state
/// Restore x87 FPU, MMX, XMM, and MXCSR state
rstor,
/// Store x87 FPU state
/// Save x87 FPU, MMX technology, and MXCSR state
save,
/// Scale
scale,
/// Sine
sin,
/// Sine and cosine
sincos,
/// Square root
/// Square root of packed single-precision floating-point values
/// Square root of scalar single-precision floating-point value
/// Square root of packed double-precision floating-point values
/// Square root of scalar double-precision floating-point value
sqrt,
/// Store integer with truncation
stt,
/// Reverse subtract
subr,
/// Test
tst,
/// Unordered compare floating-point values
ucom,
/// Unordered compare floating-point values and set EFLAGS
/// Unordered compare scalar single-precision floating-point values
/// Unordered compare scalar double-precision floating-point values
ucomi,
/// Wait
/// User level monitor wait
wait,
/// Examine floating-point
xam,
/// Extract exponent and significand
xtract,
/// Compute y * log2x
/// Compute y * log2(x + 1)
yl2x,
// MMX
/// Pack with signed saturation
ackssw,
/// Pack with signed saturation
ackssd,
/// Pack with unsigned saturation
ackusw,
/// Add packed signed integers with signed saturation
adds,
/// Add packed unsigned integers with unsigned saturation
addus,
/// Logical and not
/// Bitwise logical and not of packed single-precision floating-point values
/// Bitwise logical and not of packed double-precision floating-point values
andn,
/// Compare packed data for equal
cmpeq,
/// Compare packed data for greater than
cmpgt,
/// Empty MMX technology state
emms,
/// Multiply and add packed signed and unsigned bytes
maddubs,
/// Multiply and add packed integers
maddw,
/// Multiply packed signed integers and store low result
mull,
/// Multiply packed signed integers and store high result
mulh,
/// Shift packed data left logical
sll,
/// Shift packed data right arithmetic
sra,
/// Shift packed data right logical
srl,
/// Subtract packed signed integers with signed saturation
subs,
/// Subtract packed unsigned integers with unsigned saturation
subus,
/// Unpack high data
unpckhbw,
/// Unpack high data
unpckhdq,
/// Unpack high data
unpckhwd,
/// Unpack low data
unpcklbw,
/// Unpack low data
unpckldq,
/// Unpack low data
unpcklwd,
// SSE
/// Average packed integers
avg,
/// Convert packed doubleword integers to packed single-precision floating-point values
/// Convert packed doubleword integers to packed double-precision floating-point values
cvtpi2,
/// Convert packed single-precision floating-point values to packed doubleword integers
cvtps2pi,
/// Convert doubleword integer to scalar single-precision floating-point value
/// Convert doubleword integer to scalar double-precision floating-point value
cvtsi2,
/// Convert scalar single-precision floating-point value to doubleword integer
cvtss2si,
/// Convert with truncation packed single-precision floating-point values to packed doubleword integers
cvttps2pi,
/// Convert with truncation scalar single-precision floating-point value to doubleword integer
cvttss2si,
/// Extract byte
/// Extract word
/// Extract doubleword
/// Extract quadword
extr,
/// Insert byte
/// Insert word
/// Insert doubleword
/// Insert quadword
insr,
/// Maximum of packed single-precision floating-point values
/// Maximum of scalar single-precision floating-point values
/// Maximum of packed double-precision floating-point values
/// Maximum of scalar double-precision floating-point values
max,
/// Maximum of packed signed integers
maxs,
/// Maximum of packed unsigned integers
maxu,
/// Minimum of packed single-precision floating-point values
/// Minimum of scalar single-precision floating-point values
/// Minimum of packed double-precision floating-point values
/// Minimum of scalar double-precision floating-point values
min,
/// Minimum of packed signed integers
mins,
/// Minimum of packed unsigned integers
minu,
/// Move aligned packed single-precision floating-point values
/// Move aligned packed double-precision floating-point values
mova,
/// Move high packed single-precision floating-point values
/// Move high packed double-precision floating-point values
movh,
/// Move packed single-precision floating-point values high to low
movhl,
/// Move low packed single-precision floating-point values
/// Move low packed double-precision floating-point values
movl,
/// Move packed single-precision floating-point values low to high
movlh,
/// Move byte mask
/// Extract packed single precision floating-point sign mask
/// Extract packed double precision floating-point sign mask
movmsk,
/// Move unaligned packed single-precision floating-point values
/// Move unaligned packed double-precision floating-point values
movu,
/// Multiply packed unsigned integers and store high result
mulhu,
/// Prefetch data into caches
/// Prefetch data into caches with intent to write
prefetch,
/// Compute sum of absolute differences
sadb,
/// Packed interleave shuffle of quadruplets of single-precision floating-point values
/// Packed interleave shuffle of pairs of double-precision floating-point values
/// Shuffle packed doublewords
/// Shuffle packed words
shuf,
/// Unpack and interleave high packed single-precision floating-point values
/// Unpack and interleave high packed double-precision floating-point values
unpckh,
/// Unpack and interleave low packed single-precision floating-point values
/// Unpack and interleave low packed double-precision floating-point values
unpckl,
// SSE2
/// Convert packed doubleword integers to packed single-precision floating-point values
/// Convert packed doubleword integers to packed double-precision floating-point values
cvtdq2,
/// Convert packed double-precision floating-point values to packed doubleword integers
cvtpd2dq,
/// Convert packed double-precision floating-point values to packed doubleword integers
cvtpd2pi,
/// Convert packed double-precision floating-point values to packed single-precision floating-point values
cvtpd2,
/// Convert packed single-precision floating-point values to packed doubleword integers
cvtps2dq,
/// Convert packed single-precision floating-point values to packed double-precision floating-point values
cvtps2,
/// Convert scalar double-precision floating-point value to doubleword integer
cvtsd2si,
/// Convert scalar double-precision floating-point value to scalar single-precision floating-point value
cvtsd2,
/// Convert scalar single-precision floating-point value to scalar double-precision floating-point value
cvtss2,
/// Convert with truncation packed double-precision floating-point values to packed doubleword integers
cvttpd2dq,
/// Convert with truncation packed double-precision floating-point values to packed doubleword integers
cvttpd2pi,
/// Convert with truncation packed single-precision floating-point values to packed doubleword integers
cvttps2dq,
/// Convert with truncation scalar double-precision floating-point value to doubleword integer
cvttsd2si,
/// Galois field affine transformation inverse
gf2p8affineinvq,
/// Galois field affine transformation
gf2p8affineq,
/// Galois field multiply bytes
gf2p8mul,
/// Shuffle packed high words
shufh,
/// Shuffle packed low words
shufl,
/// Unpack high data
unpckhqdq,
/// Unpack low data
unpcklqdq,
// SSE3
/// Packed single-precision floating-point add/subtract
/// Packed double-precision floating-point add/subtract
addsub,
/// Replicate double floating-point values
movddup,
/// Replicate single floating-point values
movshdup,
/// Replicate single floating-point values
movsldup,
// SSSE3
/// Packed align right
alignr,
/// Packed multiply high with round and scale
mulhrs,
/// Packed sign
sign,
// SSE4.1
/// Pack with unsigned saturation
ackusd,
/// Blend packed single-precision floating-point values
/// Blend scalar single-precision floating-point values
/// Blend packed double-precision floating-point values
/// Blend scalar double-precision floating-point values
/// Blend packed dwords
blend,
/// Variable blend packed single-precision floating-point values
/// Variable blend scalar single-precision floating-point values
/// Variable blend packed double-precision floating-point values
/// Variable blend scalar double-precision floating-point values
blendv,
/// Dot product of packed single-precision floating-point values
/// Dot product of packed double-precision floating-point values
dp,
/// Extract packed floating-point values
/// Extract packed integer values
extract,
/// Insert scalar single-precision floating-point value
/// Insert packed floating-point values
insert,
/// Packed horizontal word minimum
minposu,
/// Packed move with sign extend
movsxb,
movsxd,
movsxw,
/// Packed move with zero extend
movzxb,
movzxd,
movzxw,
/// Round packed single-precision floating-point values
/// Round scalar single-precision floating-point value
/// Round packed double-precision floating-point values
/// Round scalar double-precision floating-point value
round,
// SSE4.2
/// Accumulate CRC32 value
crc32,
// AES
/// Perform one round of an AES decryption flow
/// Perform ten rounds of AES decryption flow with key locker using 128-bit key
/// Perform ten rounds of AES decryption flow with key locker using 256-bit key
/// Perform ten rounds of AES decryption flow with key locker on 8 blocks using 128-bit key
/// Perform ten rounds of AES decryption flow with key locker on 8 blocks using 256-bit key
aesdec,
/// Perform last round of an AES decryption flow
aesdeclast,
/// Perform one round of an AES encryption flow
/// Perform ten rounds of AES encryption flow with key locker using 128-bit key
/// Perform ten rounds of AES encryption flow with key locker using 256-bit key
/// Perform ten rounds of AES encryption flow with key locker on 8 blocks using 128-bit key
/// Perform ten rounds of AES encryption flow with key locker on 8 blocks using 256-bit key
aesenc,
/// Perform last round of an AES encryption flow
aesenclast,
/// Perform the AES InvMixColumn transformation
aesimc,
/// AES round key generation assist
aeskeygenassist,
// SHA
/// Perform four rounds of SHA1 operation
sha1rnds,
/// Calculate SHA1 state variable E after four rounds
sha1nexte,
/// Perform an intermediate calculation for the next four SHA1 message dwords
/// Perform a final calculation for the next four SHA1 message dwords
sha1msg,
/// Perform an intermediate calculation for the next four SHA256 message dwords
/// Perform a final calculation for the next four SHA256 message dwords
sha256msg,
/// Perform two rounds of SHA256 operation
sha256rnds,
// AVX
/// Load with broadcast floating-point data
/// Load integer and broadcast
broadcast,
/// Conditional SIMD packed loads and stores
/// Condition SIMD integer packed loads and stores
maskmov,
/// Permute floating-point values
/// Permute integer values
perm2,
/// Permute in-lane pairs of double-precision floating-point values
/// Permute in-lane quadruples of single-precision floating-point values
permil,
// BMI
/// Bit field extract
bextr,
/// Extract lowest set isolated bit
/// Get mask up to lowest set bit
/// Reset lowest set bit
bls,
/// Count the number of trailing zero bits
tzcnt,
// BMI2
/// Zero high bits starting with specified bit position
bzhi,
/// Parallel bits deposit
pdep,
/// Parallel bits extract
pext,
// F16C
/// Convert 16-bit floating-point values to single-precision floating-point values
cvtph2,
/// Convert single-precision floating-point values to 16-bit floating-point values
cvtps2ph,
// FMA
/// Fused multiply-add of packed single-precision floating-point values
/// Fused multiply-add of scalar single-precision floating-point values
/// Fused multiply-add of packed double-precision floating-point values
/// Fused multiply-add of scalar double-precision floating-point values
fmadd132,
/// Fused multiply-add of packed single-precision floating-point values
/// Fused multiply-add of scalar single-precision floating-point values
/// Fused multiply-add of packed double-precision floating-point values
/// Fused multiply-add of scalar double-precision floating-point values
fmadd213,
/// Fused multiply-add of packed single-precision floating-point values
/// Fused multiply-add of scalar single-precision floating-point values
/// Fused multiply-add of packed double-precision floating-point values
/// Fused multiply-add of scalar double-precision floating-point values
fmadd231,
// AVX2
/// Permute packed doubleword elements
/// Permute packed qword elements
/// Permute double-precision floating-point elements
/// Permute single-precision floating-point elements
perm,
/// Variable bit shift left logical
sllv,
/// Variable bit shift right arithmetic
srav,
/// Variable bit shift right logical
srlv,
// ADX
/// Unsigned integer addition of two operands with overflow flag
ado,
// AESKLE
/// Encode 128-bit key with key locker
/// Encode 256-bit key with key locker
encodekey,
/// Load internal wrapping key with key locker
loadiwkey,
/// A pseudo instruction that requires special lowering.
/// This should be the only tag in this enum that doesn't
/// directly correspond to one or more instruction mnemonics.
pseudo,
};
pub const FixedTag = struct { Fixes, Tag };
pub const Ops = enum(u8) {
/// No data associated with this instruction (only mnemonic is used).
none,
/// Single register operand.
/// Uses `r` payload.
r,
/// Register, register operands.
/// Uses `rr` payload.
rr,
/// Register, register, register operands.
/// Uses `rrr` payload.
rrr,
/// Register, register, register, register operands.
/// Uses `rrrr` payload.
rrrr,
/// Register, register, register, immediate (byte) operands.
/// Uses `rrri` payload.
rrri,
/// Register, register, immediate (sign-extended) operands.
/// Uses `rri` payload.
rri_s,
/// Register, register, immediate (unsigned) operands.
/// Uses `rri` payload.
rri_u,
/// Register, immediate (sign-extended) operands.
/// Uses `ri` payload.
ri_s,
/// Register, immediate (unsigned) operands.
/// Uses `ri` payload.
ri_u,
/// Register, 64-bit unsigned immediate operands.
/// Uses `ri` payload with `i` index of extra data of type `Imm64`.
ri_64,
/// Immediate (sign-extended) operand.
/// Uses `i` payload.
i_s,
/// Immediate (unsigned) operand.
/// Uses `i` payload.
i_u,
/// Immediate (word), immediate (byte) operands.
/// Uses `ii` payload.
ii,
/// Immediate (byte), register operands.
/// Uses `ri` payload.
ir,
/// Register, memory operands.
/// Uses `rx` payload with extra data of type `Memory`.
rm,
/// Register, memory, register operands.
/// Uses `rrx` payload with extra data of type `Memory`.
rmr,
/// Register, memory, immediate (word) operands.
/// Uses `rix` payload with extra data of type `Memory`.
rmi,
/// Register, memory, immediate (signed) operands.
/// Uses `rx` payload with extra data of type `Imm32` followed by `Memory`.
rmi_s,
/// Register, memory, immediate (unsigned) operands.
/// Uses `rx` payload with extra data of type `Imm32` followed by `Memory`.
rmi_u,
/// Register, register, memory.
/// Uses `rrix` payload with extra data of type `Memory`.
rrm,
/// Register, register, memory, register.
/// Uses `rrrx` payload with extra data of type `Memory`.
rrmr,
/// Register, register, memory, immediate (byte) operands.
/// Uses `rrix` payload with extra data of type `Memory`.
rrmi,
/// Single memory operand.
/// Uses `x` payload with extra data of type `Memory`.
m,
/// Memory, immediate (sign-extend) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `Memory`.
mi_s,
/// Memory, immediate (unsigned) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `Memory`.
mi_u,
/// Memory, register operands.
/// Uses `rx` payload with extra data of type `Memory`.
mr,
/// Memory, register, register operands.
/// Uses `rrx` payload with extra data of type `Memory`.
mrr,
/// Memory, register, immediate (word) operands.
/// Uses `rix` payload with extra data of type `Memory`.
mri,
/// References another Mir instruction directly.
/// Uses `inst` payload.
inst,
/// References a nav.
/// Uses `nav` payload.
nav,
/// References an uav.
/// Uses `uav` payload.
uav,
/// References a lazy symbol.
/// Uses `lazy_sym` payload.
lazy_sym,
/// References an external symbol.
/// Uses `extern_func` payload.
extern_func,
// Pseudo instructions:
/// Conditional move if zero flag set and parity flag not set
/// Clobbers the source operand!
/// Uses `rr` payload.
pseudo_cmov_z_and_np_rr,
/// Conditional move if zero flag not set or parity flag set
/// Uses `rr` payload.
pseudo_cmov_nz_or_p_rr,
/// Conditional move if zero flag not set or parity flag set
/// Uses `rx` payload.
pseudo_cmov_nz_or_p_rm,
/// Set byte if zero flag set and parity flag not set
/// Requires a scratch register!
/// Uses `rr` payload.
pseudo_set_z_and_np_r,
/// Set byte if zero flag set and parity flag not set
/// Requires a scratch register!
/// Uses `rx` payload.
pseudo_set_z_and_np_m,
/// Set byte if zero flag not set or parity flag set
/// Requires a scratch register!
/// Uses `rr` payload.
pseudo_set_nz_or_p_r,
/// Set byte if zero flag not set or parity flag set
/// Requires a scratch register!
/// Uses `rx` payload.
pseudo_set_nz_or_p_m,
/// Jump if zero flag set and parity flag not set
/// Uses `inst` payload.
pseudo_j_z_and_np_inst,
/// Jump if zero flag not set or parity flag set
/// Uses `inst` payload.
pseudo_j_nz_or_p_inst,
/// Probe alignment
/// Uses `ri` payload.
pseudo_probe_align_ri_s,
/// Probe adjust unrolled
/// Uses `ri` payload.
pseudo_probe_adjust_unrolled_ri_s,
/// Probe adjust setup
/// Uses `rri` payload.
pseudo_probe_adjust_setup_rri_s,
/// Probe adjust loop
/// Uses `rr` payload.
pseudo_probe_adjust_loop_rr,
/// Push registers
/// Uses `reg_list` payload.
pseudo_push_reg_list,
/// Pop registers
/// Uses `reg_list` payload.
pseudo_pop_reg_list,
/// Define cfa rule as offset from register.
/// Uses `ri` payload.
pseudo_cfi_def_cfa_ri_s,
/// Modify cfa rule register.
/// Uses `r` payload.
pseudo_cfi_def_cfa_register_r,
/// Modify cfa rule offset.
/// Uses `i` payload.
pseudo_cfi_def_cfa_offset_i_s,
/// Offset cfa rule offset.
/// Uses `i` payload.
pseudo_cfi_adjust_cfa_offset_i_s,
/// Define register rule as stored at offset from cfa.
/// Uses `ri` payload.
pseudo_cfi_offset_ri_s,
/// Define register rule as offset from cfa.
/// Uses `ri` payload.
pseudo_cfi_val_offset_ri_s,
/// Define register rule as stored at offset from cfa rule register.
/// Uses `ri` payload.
pseudo_cfi_rel_offset_ri_s,
/// Define register rule as register.
/// Uses `rr` payload.
pseudo_cfi_register_rr,
/// Define register rule from initial.
/// Uses `r` payload.
pseudo_cfi_restore_r,
/// Define register rule as undefined.
/// Uses `r` payload.
pseudo_cfi_undefined_r,
/// Define register rule as itself.
/// Uses `r` payload.
pseudo_cfi_same_value_r,
/// Push cfi state.
pseudo_cfi_remember_state_none,
/// Pop cfi state.
pseudo_cfi_restore_state_none,
/// Raw cfi bytes.
/// Uses `bytes` payload.
pseudo_cfi_escape_bytes,
/// End of prologue
/// Uses `none` payload.
pseudo_dbg_prologue_end_none,
/// Update debug line with is_stmt register set
/// Uses `line_column` payload.
pseudo_dbg_line_stmt_line_column,
/// Update debug line with is_stmt register clear
/// Uses `line_column` payload.
pseudo_dbg_line_line_column,
/// Start of epilogue
/// Uses `none` payload.
pseudo_dbg_epilogue_begin_none,
/// Start of lexical block
/// Uses `none` payload.
pseudo_dbg_enter_block_none,
/// End of lexical block
/// Uses `none` payload.
pseudo_dbg_leave_block_none,
/// Start of inline function
/// Uses `ip_index` payload.
pseudo_dbg_enter_inline_func,
/// End of inline function
/// Uses `ip_index` payload.
pseudo_dbg_leave_inline_func,
/// Local argument.
/// Uses `none` payload.
pseudo_dbg_arg_none,
/// Local argument.
/// Uses `i` payload.
pseudo_dbg_arg_i_s,
/// Local argument.
/// Uses `i` payload.
pseudo_dbg_arg_i_u,
/// Local argument.
/// Uses `i64` payload.
pseudo_dbg_arg_i_64,
/// Local argument.
/// Uses `ro` payload.
pseudo_dbg_arg_ro,
/// Local argument.
/// Uses `fa` payload.
pseudo_dbg_arg_fa,
/// Local argument.
/// Uses `x` payload with extra data of type `Memory`.
pseudo_dbg_arg_m,
/// Local argument.
/// Uses `ip_index` payload.
pseudo_dbg_arg_val,
/// Remaining arguments are varargs.
pseudo_dbg_var_args_none,
/// Local variable.
/// Uses `none` payload.
pseudo_dbg_var_none,
/// Local variable.
/// Uses `i` payload.
pseudo_dbg_var_i_s,
/// Local variable.
/// Uses `i` payload.
pseudo_dbg_var_i_u,
/// Local variable.
/// Uses `i64` payload.
pseudo_dbg_var_i_64,
/// Local variable.
/// Uses `ro` payload.
pseudo_dbg_var_ro,
/// Local variable.
/// Uses `fa` payload.
pseudo_dbg_var_fa,
/// Local variable.
/// Uses `x` payload with extra data of type `Memory`.
pseudo_dbg_var_m,
/// Local variable.
/// Uses `ip_index` payload.
pseudo_dbg_var_val,
/// Tombstone
/// Emitter should skip this instruction.
pseudo_dead_none,
};
pub const Data = union {
none: struct {
fixes: Fixes = ._,
},
/// References another Mir instruction.
inst: struct {
fixes: Fixes = ._,
inst: Index,
},
/// A 32-bit immediate value.
i64: u64,
i: struct {
fixes: Fixes = ._,
i: u32,
},
ii: struct {
fixes: Fixes = ._,
i1: u16,
i2: u8,
},
r: struct {
fixes: Fixes = ._,
r1: Register,
},
rr: struct {
fixes: Fixes = ._,
r1: Register,
r2: Register,
},
rrr: struct {
fixes: Fixes = ._,
r1: Register,
r2: Register,
r3: Register,
},
rrrr: struct {
fixes: Fixes = ._,
r1: Register,
r2: Register,
r3: Register,
r4: Register,
},
rrri: struct {
fixes: Fixes = ._,
r1: Register,
r2: Register,
r3: Register,
i: u8,
},
rri: struct {
fixes: Fixes = ._,
r1: Register,
r2: Register,
i: u32,
},
/// Register, immediate.
ri: struct {
fixes: Fixes = ._,
r1: Register,
i: u32,
},
/// Register, followed by custom payload found in extra.
rx: struct {
fixes: Fixes = ._,
r1: Register,
payload: u32,
},
/// Register, register, followed by Custom payload found in extra.
rrx: struct {
fixes: Fixes = ._,
r1: Register,
r2: Register,
payload: u32,
},
/// Register, register, register, followed by Custom payload found in extra.
rrrx: struct {
fixes: Fixes = ._,
r1: Register,
r2: Register,
r3: Register,
payload: u32,
},
/// Register, byte immediate, followed by Custom payload found in extra.
rix: struct {
fixes: Fixes = ._,
r1: Register,
i: u16,
payload: u32,
},
/// Register, register, byte immediate, followed by Custom payload found in extra.
rrix: struct {
fixes: Fixes = ._,
r1: Register,
r2: Register,
i: u8,
payload: u32,
},
/// Custom payload found in extra.
x: struct {
fixes: Fixes = ._,
payload: u32,
},
bytes: struct {
payload: u32,
len: u32,
pub fn get(bytes: @This(), mir: Mir) []const u8 {
return std.mem.sliceAsBytes(mir.extra[bytes.payload..])[0..bytes.len];
}
},
fa: bits.FrameAddr,
ro: bits.RegisterOffset,
nav: bits.NavOffset,
uav: InternPool.Key.Ptr.BaseAddr.Uav,
lazy_sym: link.File.LazySymbol,
extern_func: Mir.NullTerminatedString,
/// Debug line and column position
line_column: struct {
line: u32,
column: u32,
},
ip_index: InternPool.Index,
/// Register list
reg_list: RegisterList,
};
comptime {
if (!std.debug.runtime_safety) {
// Make sure we don't accidentally make instructions bigger than expected.
// Note that in safety builds, Zig is allowed to insert a secret field for safety checks.
assert(@sizeOf(Data) == 8);
}
const Mnemonic = @import("Encoding.zig").Mnemonic;
if (@typeInfo(Mnemonic).@"enum".fields.len != 977 or
@typeInfo(Fixes).@"enum".fields.len != 231 or
@typeInfo(Tag).@"enum".fields.len != 251)
{
const cond_src = (struct {
fn src() std.builtin.SourceLocation {
return @src();
}
}).src();
@setEvalBranchQuota(1_750_000);
for (@typeInfo(Mnemonic).@"enum".fields) |mnemonic| {
if (mnemonic.name[0] == '.') continue;
for (@typeInfo(Fixes).@"enum".fields) |fixes| {
const pattern = fixes.name[if (std.mem.indexOfScalar(u8, fixes.name, ' ')) |index| index + " ".len else 0..];
const wildcard_index = std.mem.indexOfScalar(u8, pattern, '_').?;
const mnem_prefix = pattern[0..wildcard_index];
const mnem_suffix = pattern[wildcard_index + "_".len ..];
if (!std.mem.startsWith(u8, mnemonic.name, mnem_prefix)) continue;
if (!std.mem.endsWith(u8, mnemonic.name, mnem_suffix)) continue;
if (@hasField(
Tag,
mnemonic.name[mnem_prefix.len .. mnemonic.name.len - mnem_suffix.len],
)) break;
} else @compileError("'" ++ mnemonic.name ++ "' is not encodable in Mir");
}
@compileError(std.fmt.comptimePrint(
\\All mnemonics are encodable in Mir! You may now change the condition at {s}:{d} to:
\\if (@typeInfo(Mnemonic).@"enum".fields.len != {d} or
\\ @typeInfo(Fixes).@"enum".fields.len != {d} or
\\ @typeInfo(Tag).@"enum".fields.len != {d})
, .{
cond_src.file,
cond_src.line - 6,
@typeInfo(Mnemonic).@"enum".fields.len,
@typeInfo(Fixes).@"enum".fields.len,
@typeInfo(Tag).@"enum".fields.len,
}));
}
}
};
/// Used in conjunction with payload to transfer a list of used registers in a compact manner.
pub const RegisterList = struct {
bitset: BitSet,
const BitSet = std.bit_set.IntegerBitSet(32);
const Self = @This();
pub const empty: RegisterList = .{ .bitset = .initEmpty() };
fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt {
for (registers, 0..) |cpreg, i| {
if (reg.id() == cpreg.id()) return @intCast(i);
}
unreachable; // register not in input register list!
}
pub fn push(self: *Self, registers: []const Register, reg: Register) void {
const index = getIndexForReg(registers, reg);
self.bitset.set(index);
}
pub fn isSet(self: Self, registers: []const Register, reg: Register) bool {
const index = getIndexForReg(registers, reg);
return self.bitset.isSet(index);
}
pub fn iterator(self: Self, comptime options: std.bit_set.IteratorOptions) BitSet.Iterator(options) {
return self.bitset.iterator(options);
}
pub fn count(self: Self) i32 {
return @intCast(self.bitset.count());
}
pub fn size(self: Self, target: *const std.Target) i32 {
return @intCast(self.bitset.count() * @as(u4, switch (target.cpu.arch) {
else => unreachable,
.x86 => 4,
.x86_64 => 8,
}));
}
};
pub const NullTerminatedString = enum(u32) {
none = std.math.maxInt(u32),
_,
pub fn toSlice(nts: NullTerminatedString, mir: *const Mir) ?[:0]const u8 {
if (nts == .none) return null;
const string_bytes = mir.string_bytes[@intFromEnum(nts)..];
return string_bytes[0..std.mem.indexOfScalar(u8, string_bytes, 0).? :0];
}
};
pub const Local = struct {
name: NullTerminatedString,
type: InternPool.Index,
};
pub const Imm32 = struct {
imm: u32,
};
pub const Imm64 = struct {
msb: u32,
lsb: u32,
pub fn encode(v: u64) Imm64 {
return .{
.msb = @truncate(v >> 32),
.lsb = @truncate(v),
};
}
pub fn decode(imm: Imm64) u64 {
var res: u64 = 0;
res |= @as(u64, @intCast(imm.msb)) << 32;
res |= @as(u64, @intCast(imm.lsb));
return res;
}
};
pub const Memory = struct {
info: Info,
base: u32,
off: u32,
extra: u32,
pub const Info = packed struct(u32) {
base: @typeInfo(bits.Memory.Base).@"union".tag_type.?,
mod: @typeInfo(bits.Memory.Mod).@"union".tag_type.?,
size: bits.Memory.Size,
index: Register,
scale: bits.Memory.Scale,
_: u13 = undefined,
};
pub fn encode(mem: bits.Memory) Memory {
return .{
.info = .{
.base = mem.base,
.mod = mem.mod,
.size = switch (mem.mod) {
.rm => |rm| rm.size,
.off => undefined,
},
.index = switch (mem.mod) {
.rm => |rm| rm.index,
.off => undefined,
},
.scale = switch (mem.mod) {
.rm => |rm| rm.scale,
.off => undefined,
},
},
.base = switch (mem.base) {
.none, .table => undefined,
.reg => |reg| @intFromEnum(reg),
.frame => |frame_index| @intFromEnum(frame_index),
.rip_inst => |inst_index| inst_index,
.nav => |nav| @intFromEnum(nav),
.uav => |uav| @intFromEnum(uav.val),
.lazy_sym => |lazy_sym| @intFromEnum(lazy_sym.ty),
.extern_func => |extern_func| @intFromEnum(extern_func),
},
.off = switch (mem.mod) {
.rm => |rm| @bitCast(rm.disp),
.off => |off| @truncate(off),
},
.extra = switch (mem.mod) {
.rm => switch (mem.base) {
else => undefined,
.uav => |uav| @intFromEnum(uav.orig_ty),
.lazy_sym => |lazy_sym| @intFromEnum(lazy_sym.kind),
},
.off => switch (mem.base) {
.reg => @intCast(mem.mod.off >> 32),
else => unreachable,
},
},
};
}
pub fn decode(mem: Memory) encoder.Instruction.Memory {
switch (mem.info.mod) {
.rm => {
if (mem.info.base == .reg and @as(Register, @enumFromInt(mem.base)) == .rip) {
assert(mem.info.index == .none and mem.info.scale == .@"1");
return encoder.Instruction.Memory.initRip(mem.info.size, @bitCast(mem.off));
}
return encoder.Instruction.Memory.initSib(mem.info.size, .{
.disp = @bitCast(mem.off),
.base = switch (mem.info.base) {
.none => .none,
.reg => .{ .reg = @enumFromInt(mem.base) },
.frame => .{ .frame = @enumFromInt(mem.base) },
.table => .table,
.rip_inst => .{ .rip_inst = mem.base },
.nav => .{ .nav = @enumFromInt(mem.base) },
.uav => .{ .uav = .{ .val = @enumFromInt(mem.base), .orig_ty = @enumFromInt(mem.extra) } },
.lazy_sym => .{ .lazy_sym = .{ .kind = @enumFromInt(mem.extra), .ty = @enumFromInt(mem.base) } },
.extern_func => .{ .extern_func = @enumFromInt(mem.base) },
},
.scale_index = switch (mem.info.index) {
.none => null,
else => |index| .{ .scale = switch (mem.info.scale) {
inline else => |scale| comptime std.fmt.parseInt(
u4,
@tagName(scale),
10,
) catch unreachable,
}, .index = index },
},
});
},
.off => {
assert(mem.info.base == .reg);
return encoder.Instruction.Memory.initMoffs(
@enumFromInt(mem.base),
@as(u64, mem.extra) << 32 | mem.off,
);
},
}
}
};
pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
mir.instructions.deinit(gpa);
gpa.free(mir.extra);
gpa.free(mir.string_bytes);
gpa.free(mir.locals);
gpa.free(mir.table);
gpa.free(mir.memoized_encodings);
mir.frame_locs.deinit(gpa);
mir.* = undefined;
}
pub fn emit(
mir: Mir,
lf: *link.File,
pt: Zcu.PerThread,
src_loc: Zcu.LazySrcLoc,
func_index: InternPool.Index,
atom_index: u32,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) codegen.CodeGenError!void {
const zcu = pt.zcu;
const comp = zcu.comp;
const gpa = comp.gpa;
const func = zcu.funcInfo(func_index);
const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?;
const nav = func.owner_nav;
const mod = zcu.navFileScope(nav).mod.?;
var e: Emit = .{
.lower = .{
.target = &mod.resolved_target.result,
.allocator = gpa,
.mir = mir,
.cc = fn_info.cc,
.src_loc = src_loc,
},
.bin_file = lf,
.pt = pt,
.pic = mod.pic,
.atom_index = atom_index,
.debug_output = debug_output,
.w = w,
.prev_di_loc = .{
.line = func.lbrace_line,
.column = func.lbrace_column,
.is_stmt = switch (debug_output) {
.dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt,
.none => undefined,
},
},
.prev_di_pc = 0,
.code_offset_mapping = .empty,
.relocs = .empty,
.table_relocs = .empty,
};
defer e.deinit();
e.emitMir() catch |err| switch (err) {
error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?),
error.InvalidInstruction, error.CannotEncode => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
else => return zcu.codegenFail(nav, "emit MIR failed: {s}", .{@errorName(err)}),
};
}
pub fn emitLazy(
mir: Mir,
lf: *link.File,
pt: Zcu.PerThread,
src_loc: Zcu.LazySrcLoc,
lazy_sym: link.File.LazySymbol,
atom_index: u32,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) codegen.CodeGenError!void {
const zcu = pt.zcu;
const comp = zcu.comp;
const gpa = comp.gpa;
const mod = comp.root_mod;
var e: Emit = .{
.lower = .{
.target = &mod.resolved_target.result,
.allocator = gpa,
.mir = mir,
.cc = .auto,
.src_loc = src_loc,
},
.bin_file = lf,
.pt = pt,
.pic = mod.pic,
.atom_index = atom_index,
.debug_output = debug_output,
.w = w,
.prev_di_loc = undefined,
.prev_di_pc = undefined,
.code_offset_mapping = .empty,
.relocs = .empty,
.table_relocs = .empty,
};
defer e.deinit();
e.emitMir() catch |err| switch (err) {
error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, e.lower.err_msg.?),
error.InvalidInstruction, error.CannotEncode => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
else => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s}", .{@errorName(err)}),
};
}
pub fn extraData(mir: Mir, comptime T: type, index: u32) struct { data: T, end: u32 } {
const fields = std.meta.fields(T);
var i: u32 = index;
var result: T = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => mir.extra[i],
i32, Memory.Info => @bitCast(mir.extra[i]),
bits.FrameIndex => @enumFromInt(mir.extra[i]),
else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
};
i += 1;
}
return .{
.data = result,
.end = i,
};
}
pub const FrameLoc = struct {
base: Register,
disp: i32,
};
pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffset {
const frame_loc = mir.frame_locs.get(@intFromEnum(frame_addr.index));
return .{ .reg = frame_loc.base, .off = frame_loc.disp + frame_addr.off };
}
pub fn resolveMemoryExtra(mir: Mir, payload: u32) Memory {
const mem = mir.extraData(Mir.Memory, payload).data;
return switch (mem.info.base) {
.none, .reg, .table, .rip_inst, .nav, .uav, .lazy_sym, .extern_func => mem,
.frame => if (mir.frame_locs.len > 0) .{
.info = .{
.base = .reg,
.mod = mem.info.mod,
.size = mem.info.size,
.index = mem.info.index,
.scale = mem.info.scale,
},
.base = @intFromEnum(mir.frame_locs.items(.base)[mem.base]),
.off = @bitCast(mir.frame_locs.items(.disp)[mem.base] + @as(i32, @bitCast(mem.off))),
.extra = mem.extra,
} else mem,
};
}
const assert = std.debug.assert;
const bits = @import("bits.zig");
const builtin = @import("builtin");
const encoder = @import("encoder.zig");
const std = @import("std");
const InternPool = @import("../../InternPool.zig");
const Mir = @This();
const Register = bits.Register;
const Emit = @import("Emit.zig");
const codegen = @import("../../codegen.zig");
const link = @import("../../link.zig");
const Zcu = @import("../../Zcu.zig");