//! 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");