Path: blob/main/cranelift/codegen/meta/src/shared/instructions.rs
1693 views
#![expect(non_snake_case, reason = "DSL style here")]12use crate::cdsl::instructions::{3AllInstructions, InstructionBuilder as Inst, InstructionGroupBuilder,4};5use crate::cdsl::operands::Operand;6use crate::cdsl::types::{LaneType, ValueType};7use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar};8use crate::shared::formats::Formats;9use crate::shared::types;10use crate::shared::{entities::EntityRefs, immediates::Immediates};1112#[inline(never)]13fn define_control_flow(14ig: &mut InstructionGroupBuilder,15formats: &Formats,16imm: &Immediates,17entities: &EntityRefs,18) {19ig.push(20Inst::new(21"jump",22r#"23Jump.2425Unconditionally jump to a basic block, passing the specified26block arguments. The number and types of arguments must match the27destination block.28"#,29&formats.jump,30)31.operands_in(vec![32Operand::new("block_call", &entities.block_call)33.with_doc("Destination basic block, with its arguments provided"),34])35.branches(),36);3738let ScalarTruthy = &TypeVar::new(39"ScalarTruthy",40"A scalar truthy type",41TypeSetBuilder::new().ints(Interval::All).build(),42);4344ig.push(45Inst::new(46"brif",47r#"48Conditional branch when cond is non-zero.4950Take the ``then`` branch when ``c != 0``, and the ``else`` branch otherwise.51"#,52&formats.brif,53)54.operands_in(vec![55Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"),56Operand::new("block_then", &entities.block_then).with_doc("Then block"),57Operand::new("block_else", &entities.block_else).with_doc("Else block"),58])59.branches(),60);6162{63let _i32 = &TypeVar::new(64"i32",65"A 32 bit scalar integer type",66TypeSetBuilder::new().ints(32..32).build(),67);6869ig.push(70Inst::new(71"br_table",72r#"73Indirect branch via jump table.7475Use ``x`` as an unsigned index into the jump table ``JT``. If a jump76table entry is found, branch to the corresponding block. If no entry was77found or the index is out-of-bounds, branch to the default block of the78table.7980Note that this branch instruction can't pass arguments to the targeted81blocks. Split critical edges as needed to work around this.8283Do not confuse this with "tables" in WebAssembly. ``br_table`` is for84jump tables with destinations within the current function only -- think85of a ``match`` in Rust or a ``switch`` in C. If you want to call a86function in a dynamic library, that will typically use87``call_indirect``.88"#,89&formats.branch_table,90)91.operands_in(vec![92Operand::new("x", _i32).with_doc("i32 index into jump table"),93Operand::new("JT", &entities.jump_table),94])95.branches(),96);97}9899let iAddr = &TypeVar::new(100"iAddr",101"An integer address type",102TypeSetBuilder::new().ints(32..64).build(),103);104105ig.push(106Inst::new(107"debugtrap",108r#"109Encodes an assembly debug trap.110"#,111&formats.nullary,112)113.other_side_effects()114.can_load()115.can_store(),116);117118ig.push(119Inst::new(120"trap",121r#"122Terminate execution unconditionally.123"#,124&formats.trap,125)126.operands_in(vec![Operand::new("code", &imm.trapcode)])127.can_trap()128.terminates_block(),129);130131ig.push(132Inst::new(133"trapz",134r#"135Trap when zero.136137if ``c`` is non-zero, execution continues at the following instruction.138"#,139&formats.cond_trap,140)141.operands_in(vec![142Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"),143Operand::new("code", &imm.trapcode),144])145.can_trap()146// When one `trapz` dominates another `trapz` and they have identical147// conditions and trap codes, it is safe to deduplicate them (like GVN,148// although there is not actually any value being numbered). Either the149// first `trapz` raised a trap and execution halted, or it didn't and150// therefore the dominated `trapz` will not raise a trap either.151.side_effects_idempotent(),152);153154ig.push(155Inst::new(156"trapnz",157r#"158Trap when non-zero.159160If ``c`` is zero, execution continues at the following instruction.161"#,162&formats.cond_trap,163)164.operands_in(vec![165Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"),166Operand::new("code", &imm.trapcode),167])168.can_trap()169// See the above comment for `trapz` and idempotent side effects.170.side_effects_idempotent(),171);172173ig.push(174Inst::new(175"return",176r#"177Return from the function.178179Unconditionally transfer control to the calling function, passing the180provided return values. The list of return values must match the181function signature's return types.182"#,183&formats.multiary,184)185.operands_in(vec![186Operand::new("rvals", &entities.varargs).with_doc("return values"),187])188.returns(),189);190191ig.push(192Inst::new(193"call",194r#"195Direct function call.196197Call a function which has been declared in the preamble. The argument198types must match the function's signature.199"#,200&formats.call,201)202.operands_in(vec![203Operand::new("FN", &entities.func_ref)204.with_doc("function to call, declared by `function`"),205Operand::new("args", &entities.varargs).with_doc("call arguments"),206])207.operands_out(vec![208Operand::new("rvals", &entities.varargs).with_doc("return values"),209])210.call(),211);212213ig.push(214Inst::new(215"call_indirect",216r#"217Indirect function call.218219Call the function pointed to by `callee` with the given arguments. The220called function must match the specified signature.221222Note that this is different from WebAssembly's ``call_indirect``; the223callee is a native address, rather than a table index. For WebAssembly,224`table_addr` and `load` are used to obtain a native address225from a table.226"#,227&formats.call_indirect,228)229.operands_in(vec![230Operand::new("SIG", &entities.sig_ref).with_doc("function signature"),231Operand::new("callee", iAddr).with_doc("address of function to call"),232Operand::new("args", &entities.varargs).with_doc("call arguments"),233])234.operands_out(vec![235Operand::new("rvals", &entities.varargs).with_doc("return values"),236])237.call(),238);239240ig.push(241Inst::new(242"return_call",243r#"244Direct tail call.245246Tail call a function which has been declared in the preamble. The247argument types must match the function's signature, the caller and248callee calling conventions must be the same, and must be a calling249convention that supports tail calls.250251This instruction is a block terminator.252"#,253&formats.call,254)255.operands_in(vec![256Operand::new("FN", &entities.func_ref)257.with_doc("function to call, declared by `function`"),258Operand::new("args", &entities.varargs).with_doc("call arguments"),259])260.returns()261.call(),262);263264ig.push(265Inst::new(266"return_call_indirect",267r#"268Indirect tail call.269270Call the function pointed to by `callee` with the given arguments. The271argument types must match the function's signature, the caller and272callee calling conventions must be the same, and must be a calling273convention that supports tail calls.274275This instruction is a block terminator.276277Note that this is different from WebAssembly's ``tail_call_indirect``;278the callee is a native address, rather than a table index. For279WebAssembly, `table_addr` and `load` are used to obtain a native address280from a table.281"#,282&formats.call_indirect,283)284.operands_in(vec![285Operand::new("SIG", &entities.sig_ref).with_doc("function signature"),286Operand::new("callee", iAddr).with_doc("address of function to call"),287Operand::new("args", &entities.varargs).with_doc("call arguments"),288])289.returns()290.call(),291);292293ig.push(294Inst::new(295"func_addr",296r#"297Get the address of a function.298299Compute the absolute address of a function declared in the preamble.300The returned address can be used as a ``callee`` argument to301`call_indirect`. This is also a method for calling functions that302are too far away to be addressable by a direct `call`303instruction.304"#,305&formats.func_addr,306)307.operands_in(vec![308Operand::new("FN", &entities.func_ref)309.with_doc("function to call, declared by `function`"),310])311.operands_out(vec![Operand::new("addr", iAddr)]),312);313314ig.push(315Inst::new(316"try_call",317r#"318Call a function, catching the specified exceptions.319320Call the function pointed to by `callee` with the given arguments. On321normal return, branch to the first target, with function returns322available as `retN` block arguments. On exceptional return,323look up the thrown exception tag in the provided exception table;324if the tag matches one of the targets, branch to the matching325target with the exception payloads available as `exnN` block arguments.326If no tag matches, then propagate the exception up the stack.327328It is the Cranelift embedder's responsibility to define the meaning329of tags: they are accepted by this instruction and passed through330to unwind metadata tables in Cranelift's output. Actual unwinding is331outside the purview of the core Cranelift compiler.332333Payload values on exception are passed in fixed register(s) that are334defined by the platform and ABI. See the documentation on `CallConv`335for details.336"#,337&formats.try_call,338)339.operands_in(vec![340Operand::new("callee", &entities.func_ref)341.with_doc("function to call, declared by `function`"),342Operand::new("args", &entities.varargs).with_doc("call arguments"),343Operand::new("ET", &entities.exception_table).with_doc("exception table"),344])345.call()346.branches(),347);348349ig.push(350Inst::new(351"try_call_indirect",352r#"353Call a function, catching the specified exceptions.354355Call the function pointed to by `callee` with the given arguments. On356normal return, branch to the first target, with function returns357available as `retN` block arguments. On exceptional return,358look up the thrown exception tag in the provided exception table;359if the tag matches one of the targets, branch to the matching360target with the exception payloads available as `exnN` block arguments.361If no tag matches, then propagate the exception up the stack.362363It is the Cranelift embedder's responsibility to define the meaning364of tags: they are accepted by this instruction and passed through365to unwind metadata tables in Cranelift's output. Actual unwinding is366outside the purview of the core Cranelift compiler.367368Payload values on exception are passed in fixed register(s) that are369defined by the platform and ABI. See the documentation on `CallConv`370for details.371"#,372&formats.try_call_indirect,373)374.operands_in(vec![375Operand::new("callee", iAddr).with_doc("address of function to call"),376Operand::new("args", &entities.varargs).with_doc("call arguments"),377Operand::new("ET", &entities.exception_table).with_doc("exception table"),378])379.call()380.branches(),381);382}383384#[inline(never)]385fn define_simd_lane_access(386ig: &mut InstructionGroupBuilder,387formats: &Formats,388imm: &Immediates,389_: &EntityRefs,390) {391let TxN = &TypeVar::new(392"TxN",393"A SIMD vector type",394TypeSetBuilder::new()395.ints(Interval::All)396.floats(Interval::All)397.simd_lanes(Interval::All)398.dynamic_simd_lanes(Interval::All)399.includes_scalars(false)400.build(),401);402403ig.push(404Inst::new(405"splat",406r#"407Vector splat.408409Return a vector whose lanes are all ``x``.410"#,411&formats.unary,412)413.operands_in(vec![414Operand::new("x", &TxN.lane_of()).with_doc("Value to splat to all lanes"),415])416.operands_out(vec![Operand::new("a", TxN)]),417);418419let I8x16 = &TypeVar::new(420"I8x16",421"A SIMD vector type consisting of 16 lanes of 8-bit integers",422TypeSetBuilder::new()423.ints(8..8)424.simd_lanes(16..16)425.includes_scalars(false)426.build(),427);428429ig.push(430Inst::new(431"swizzle",432r#"433Vector swizzle.434435Returns a new vector with byte-width lanes selected from the lanes of the first input436vector ``x`` specified in the second input vector ``s``. The indices ``i`` in range437``[0, 15]`` select the ``i``-th element of ``x``. For indices outside of the range the438resulting lane is 0. Note that this operates on byte-width lanes.439"#,440&formats.binary,441)442.operands_in(vec![443Operand::new("x", I8x16).with_doc("Vector to modify by re-arranging lanes"),444Operand::new("y", I8x16).with_doc("Mask for re-arranging lanes"),445])446.operands_out(vec![Operand::new("a", I8x16)]),447);448449ig.push(450Inst::new(451"x86_pshufb",452r#"453A vector swizzle lookalike which has the semantics of `pshufb` on x64.454455This instruction will permute the 8-bit lanes of `x` with the indices456specified in `y`. Each lane in the mask, `y`, uses the bottom four457bits for selecting the lane from `x` unless the most significant bit458is set, in which case the lane is zeroed. The output vector will have459the following contents when the element of `y` is in these ranges:460461* `[0, 127]` -> `x[y[i] % 16]`462* `[128, 255]` -> 0463"#,464&formats.binary,465)466.operands_in(vec![467Operand::new("x", I8x16).with_doc("Vector to modify by re-arranging lanes"),468Operand::new("y", I8x16).with_doc("Mask for re-arranging lanes"),469])470.operands_out(vec![Operand::new("a", I8x16)]),471);472473ig.push(474Inst::new(475"insertlane",476r#"477Insert ``y`` as lane ``Idx`` in x.478479The lane index, ``Idx``, is an immediate value, not an SSA value. It480must indicate a valid lane index for the type of ``x``.481"#,482&formats.ternary_imm8,483)484.operands_in(vec![485Operand::new("x", TxN).with_doc("The vector to modify"),486Operand::new("y", &TxN.lane_of()).with_doc("New lane value"),487Operand::new("Idx", &imm.uimm8).with_doc("Lane index"),488])489.operands_out(vec![Operand::new("a", TxN)]),490);491492ig.push(493Inst::new(494"extractlane",495r#"496Extract lane ``Idx`` from ``x``.497498The lane index, ``Idx``, is an immediate value, not an SSA value. It499must indicate a valid lane index for the type of ``x``. Note that the upper bits of ``a``500may or may not be zeroed depending on the ISA but the type system should prevent using501``a`` as anything other than the extracted value.502"#,503&formats.binary_imm8,504)505.operands_in(vec![506Operand::new("x", TxN),507Operand::new("Idx", &imm.uimm8).with_doc("Lane index"),508])509.operands_out(vec![Operand::new("a", &TxN.lane_of())]),510);511}512513#[inline(never)]514fn define_simd_arithmetic(515ig: &mut InstructionGroupBuilder,516formats: &Formats,517_: &Immediates,518_: &EntityRefs,519) {520let Int = &TypeVar::new(521"Int",522"A scalar or vector integer type",523TypeSetBuilder::new()524.ints(Interval::All)525.simd_lanes(Interval::All)526.build(),527);528529ig.push(530Inst::new(531"smin",532r#"533Signed integer minimum.534"#,535&formats.binary,536)537.operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)])538.operands_out(vec![Operand::new("a", Int)]),539);540541ig.push(542Inst::new(543"umin",544r#"545Unsigned integer minimum.546"#,547&formats.binary,548)549.operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)])550.operands_out(vec![Operand::new("a", Int)]),551);552553ig.push(554Inst::new(555"smax",556r#"557Signed integer maximum.558"#,559&formats.binary,560)561.operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)])562.operands_out(vec![Operand::new("a", Int)]),563);564565ig.push(566Inst::new(567"umax",568r#"569Unsigned integer maximum.570"#,571&formats.binary,572)573.operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)])574.operands_out(vec![Operand::new("a", Int)]),575);576577let IxN = &TypeVar::new(578"IxN",579"A SIMD vector type containing integers",580TypeSetBuilder::new()581.ints(Interval::All)582.simd_lanes(Interval::All)583.includes_scalars(false)584.build(),585);586587ig.push(588Inst::new(589"avg_round",590r#"591Unsigned average with rounding: `a := (x + y + 1) // 2`592593The addition does not lose any information (such as from overflow).594"#,595&formats.binary,596)597.operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)])598.operands_out(vec![Operand::new("a", IxN)]),599);600601ig.push(602Inst::new(603"uadd_sat",604r#"605Add with unsigned saturation.606607This is similar to `iadd` but the operands are interpreted as unsigned integers and their608summed result, instead of wrapping, will be saturated to the highest unsigned integer for609the controlling type (e.g. `0xFF` for i8).610"#,611&formats.binary,612)613.operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)])614.operands_out(vec![Operand::new("a", IxN)]),615);616617ig.push(618Inst::new(619"sadd_sat",620r#"621Add with signed saturation.622623This is similar to `iadd` but the operands are interpreted as signed integers and their624summed result, instead of wrapping, will be saturated to the lowest or highest625signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8). For example,626since an `sadd_sat.i8` of `0x70` and `0x70` is greater than `0x7F`, the result will be627clamped to `0x7F`.628"#,629&formats.binary,630)631.operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)])632.operands_out(vec![Operand::new("a", IxN)]),633);634635ig.push(636Inst::new(637"usub_sat",638r#"639Subtract with unsigned saturation.640641This is similar to `isub` but the operands are interpreted as unsigned integers and their642difference, instead of wrapping, will be saturated to the lowest unsigned integer for643the controlling type (e.g. `0x00` for i8).644"#,645&formats.binary,646)647.operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)])648.operands_out(vec![Operand::new("a", IxN)]),649);650651ig.push(652Inst::new(653"ssub_sat",654r#"655Subtract with signed saturation.656657This is similar to `isub` but the operands are interpreted as signed integers and their658difference, instead of wrapping, will be saturated to the lowest or highest659signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8).660"#,661&formats.binary,662)663.operands_in(vec![Operand::new("x", IxN), Operand::new("y", IxN)])664.operands_out(vec![Operand::new("a", IxN)]),665);666}667668pub(crate) fn define(669all_instructions: &mut AllInstructions,670formats: &Formats,671imm: &Immediates,672entities: &EntityRefs,673) {674let mut ig = InstructionGroupBuilder::new(all_instructions);675676define_control_flow(&mut ig, formats, imm, entities);677define_simd_lane_access(&mut ig, formats, imm, entities);678define_simd_arithmetic(&mut ig, formats, imm, entities);679680// Operand kind shorthands.681let i8: &TypeVar = &ValueType::from(LaneType::from(types::Int::I8)).into();682let f16_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F16)).into();683let f32_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F32)).into();684let f64_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F64)).into();685let f128_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F128)).into();686687// Starting definitions.688let Int = &TypeVar::new(689"Int",690"A scalar or vector integer type",691TypeSetBuilder::new()692.ints(Interval::All)693.simd_lanes(Interval::All)694.dynamic_simd_lanes(Interval::All)695.build(),696);697698let NarrowInt = &TypeVar::new(699"NarrowInt",700"An integer type of width up to `i64`",701TypeSetBuilder::new().ints(8..64).build(),702);703704let ScalarTruthy = &TypeVar::new(705"ScalarTruthy",706"A scalar truthy type",707TypeSetBuilder::new().ints(Interval::All).build(),708);709710let iB = &TypeVar::new(711"iB",712"A scalar integer type",713TypeSetBuilder::new().ints(Interval::All).build(),714);715716let iSwappable = &TypeVar::new(717"iSwappable",718"A multi byte scalar integer type",719TypeSetBuilder::new().ints(16..128).build(),720);721722let iAddr = &TypeVar::new(723"iAddr",724"An integer address type",725TypeSetBuilder::new().ints(32..64).build(),726);727728let TxN = &TypeVar::new(729"TxN",730"A SIMD vector type",731TypeSetBuilder::new()732.ints(Interval::All)733.floats(Interval::All)734.simd_lanes(Interval::All)735.includes_scalars(false)736.build(),737);738let Any = &TypeVar::new(739"Any",740"Any integer, float, or reference scalar or vector type",741TypeSetBuilder::new()742.ints(Interval::All)743.floats(Interval::All)744.simd_lanes(Interval::All)745.includes_scalars(true)746.build(),747);748749let Mem = &TypeVar::new(750"Mem",751"Any type that can be stored in memory",752TypeSetBuilder::new()753.ints(Interval::All)754.floats(Interval::All)755.simd_lanes(Interval::All)756.dynamic_simd_lanes(Interval::All)757.build(),758);759760let MemTo = &TypeVar::copy_from(Mem, "MemTo".to_string());761762ig.push(763Inst::new(764"load",765r#"766Load from memory at ``p + Offset``.767768This is a polymorphic instruction that can load any value type which769has a memory representation.770"#,771&formats.load,772)773.operands_in(vec![774Operand::new("MemFlags", &imm.memflags),775Operand::new("p", iAddr),776Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),777])778.operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")])779.can_load(),780);781782ig.push(783Inst::new(784"store",785r#"786Store ``x`` to memory at ``p + Offset``.787788This is a polymorphic instruction that can store any value type with a789memory representation.790"#,791&formats.store,792)793.operands_in(vec![794Operand::new("MemFlags", &imm.memflags),795Operand::new("x", Mem).with_doc("Value to be stored"),796Operand::new("p", iAddr),797Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),798])799.can_store(),800);801802let iExt8 = &TypeVar::new(803"iExt8",804"An integer type with more than 8 bits",805TypeSetBuilder::new().ints(16..64).build(),806);807808ig.push(809Inst::new(810"uload8",811r#"812Load 8 bits from memory at ``p + Offset`` and zero-extend.813814This is equivalent to ``load.i8`` followed by ``uextend``.815"#,816&formats.load,817)818.operands_in(vec![819Operand::new("MemFlags", &imm.memflags),820Operand::new("p", iAddr),821Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),822])823.operands_out(vec![Operand::new("a", iExt8)])824.can_load(),825);826827ig.push(828Inst::new(829"sload8",830r#"831Load 8 bits from memory at ``p + Offset`` and sign-extend.832833This is equivalent to ``load.i8`` followed by ``sextend``.834"#,835&formats.load,836)837.operands_in(vec![838Operand::new("MemFlags", &imm.memflags),839Operand::new("p", iAddr),840Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),841])842.operands_out(vec![Operand::new("a", iExt8)])843.can_load(),844);845846ig.push(847Inst::new(848"istore8",849r#"850Store the low 8 bits of ``x`` to memory at ``p + Offset``.851852This is equivalent to ``ireduce.i8`` followed by ``store.i8``.853"#,854&formats.store,855)856.operands_in(vec![857Operand::new("MemFlags", &imm.memflags),858Operand::new("x", iExt8),859Operand::new("p", iAddr),860Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),861])862.can_store(),863);864865let iExt16 = &TypeVar::new(866"iExt16",867"An integer type with more than 16 bits",868TypeSetBuilder::new().ints(32..64).build(),869);870871ig.push(872Inst::new(873"uload16",874r#"875Load 16 bits from memory at ``p + Offset`` and zero-extend.876877This is equivalent to ``load.i16`` followed by ``uextend``.878"#,879&formats.load,880)881.operands_in(vec![882Operand::new("MemFlags", &imm.memflags),883Operand::new("p", iAddr),884Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),885])886.operands_out(vec![Operand::new("a", iExt16)])887.can_load(),888);889890ig.push(891Inst::new(892"sload16",893r#"894Load 16 bits from memory at ``p + Offset`` and sign-extend.895896This is equivalent to ``load.i16`` followed by ``sextend``.897"#,898&formats.load,899)900.operands_in(vec![901Operand::new("MemFlags", &imm.memflags),902Operand::new("p", iAddr),903Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),904])905.operands_out(vec![Operand::new("a", iExt16)])906.can_load(),907);908909ig.push(910Inst::new(911"istore16",912r#"913Store the low 16 bits of ``x`` to memory at ``p + Offset``.914915This is equivalent to ``ireduce.i16`` followed by ``store.i16``.916"#,917&formats.store,918)919.operands_in(vec![920Operand::new("MemFlags", &imm.memflags),921Operand::new("x", iExt16),922Operand::new("p", iAddr),923Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),924])925.can_store(),926);927928let iExt32 = &TypeVar::new(929"iExt32",930"An integer type with more than 32 bits",931TypeSetBuilder::new().ints(64..64).build(),932);933934ig.push(935Inst::new(936"uload32",937r#"938Load 32 bits from memory at ``p + Offset`` and zero-extend.939940This is equivalent to ``load.i32`` followed by ``uextend``.941"#,942&formats.load,943)944.operands_in(vec![945Operand::new("MemFlags", &imm.memflags),946Operand::new("p", iAddr),947Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),948])949.operands_out(vec![Operand::new("a", iExt32)])950.can_load(),951);952953ig.push(954Inst::new(955"sload32",956r#"957Load 32 bits from memory at ``p + Offset`` and sign-extend.958959This is equivalent to ``load.i32`` followed by ``sextend``.960"#,961&formats.load,962)963.operands_in(vec![964Operand::new("MemFlags", &imm.memflags),965Operand::new("p", iAddr),966Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),967])968.operands_out(vec![Operand::new("a", iExt32)])969.can_load(),970);971972ig.push(973Inst::new(974"istore32",975r#"976Store the low 32 bits of ``x`` to memory at ``p + Offset``.977978This is equivalent to ``ireduce.i32`` followed by ``store.i32``.979"#,980&formats.store,981)982.operands_in(vec![983Operand::new("MemFlags", &imm.memflags),984Operand::new("x", iExt32),985Operand::new("p", iAddr),986Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),987])988.can_store(),989);990ig.push(991Inst::new(992"stack_switch",993r#"994Suspends execution of the current stack and resumes execution of another995one.996997The target stack to switch to is identified by the data stored at998``load_context_ptr``. Before switching, this instruction stores999analogous information about the1000current (i.e., original) stack at ``store_context_ptr``, to1001enabled switching back to the original stack at a later point.10021003The size, alignment and layout of the information stored at1004``load_context_ptr`` and ``store_context_ptr`` is platform-dependent.1005The instruction assumes that ``load_context_ptr`` and1006``store_context_ptr`` are valid pointers to memory with said layout and1007alignment, and does not perform any checks on these pointers or the data1008stored there.10091010The instruction is experimental and only supported on x64 Linux at the1011moment.10121013When switching from a stack A to a stack B, one of the following cases1014must apply:10151. Stack B was previously suspended using a ``stack_switch`` instruction.10162. Stack B is a newly initialized stack. The necessary initialization is1017platform-dependent and will generally involve running some kind of1018trampoline to start execution of a function on the new stack.10191020In both cases, the ``in_payload`` argument of the ``stack_switch``1021instruction executed on A is passed to stack B. In the first case above,1022it will be the result value of the earlier ``stack_switch`` instruction1023executed on stack B. In the second case, the value will be accessible to1024the trampoline in a platform-dependent register.10251026The pointers ``load_context_ptr`` and ``store_context_ptr`` are allowed1027to be equal; the instruction ensures that all data is loaded from the1028former before writing to the latter.10291030Stack switching is one-shot in the sense that each ``stack_switch``1031operation effectively consumes the context identified by1032``load_context_ptr``. In other words, performing two ``stack_switches``1033using the same ``load_context_ptr`` causes undefined behavior, unless1034the context at ``load_context_ptr`` is overwritten by another1035`stack_switch` in between.1036"#,1037&formats.ternary,1038)1039.operands_in(vec![1040Operand::new("store_context_ptr", iAddr),1041Operand::new("load_context_ptr", iAddr),1042Operand::new("in_payload0", iAddr),1043])1044.operands_out(vec![Operand::new("out_payload0", iAddr)])1045.other_side_effects()1046.can_load()1047.can_store()1048.call(),1049);10501051let I16x8 = &TypeVar::new(1052"I16x8",1053"A SIMD vector with exactly 8 lanes of 16-bit values",1054TypeSetBuilder::new()1055.ints(16..16)1056.simd_lanes(8..8)1057.includes_scalars(false)1058.build(),1059);10601061ig.push(1062Inst::new(1063"uload8x8",1064r#"1065Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i16x81066vector.1067"#,1068&formats.load,1069)1070.operands_in(vec![1071Operand::new("MemFlags", &imm.memflags),1072Operand::new("p", iAddr),1073Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),1074])1075.operands_out(vec![Operand::new("a", I16x8).with_doc("Value loaded")])1076.can_load(),1077);10781079ig.push(1080Inst::new(1081"sload8x8",1082r#"1083Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i16x81084vector.1085"#,1086&formats.load,1087)1088.operands_in(vec![1089Operand::new("MemFlags", &imm.memflags),1090Operand::new("p", iAddr),1091Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),1092])1093.operands_out(vec![Operand::new("a", I16x8).with_doc("Value loaded")])1094.can_load(),1095);10961097let I32x4 = &TypeVar::new(1098"I32x4",1099"A SIMD vector with exactly 4 lanes of 32-bit values",1100TypeSetBuilder::new()1101.ints(32..32)1102.simd_lanes(4..4)1103.includes_scalars(false)1104.build(),1105);11061107ig.push(1108Inst::new(1109"uload16x4",1110r#"1111Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i32x41112vector.1113"#,1114&formats.load,1115)1116.operands_in(vec![1117Operand::new("MemFlags", &imm.memflags),1118Operand::new("p", iAddr),1119Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),1120])1121.operands_out(vec![Operand::new("a", I32x4).with_doc("Value loaded")])1122.can_load(),1123);11241125ig.push(1126Inst::new(1127"sload16x4",1128r#"1129Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i32x41130vector.1131"#,1132&formats.load,1133)1134.operands_in(vec![1135Operand::new("MemFlags", &imm.memflags),1136Operand::new("p", iAddr),1137Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),1138])1139.operands_out(vec![Operand::new("a", I32x4).with_doc("Value loaded")])1140.can_load(),1141);11421143let I64x2 = &TypeVar::new(1144"I64x2",1145"A SIMD vector with exactly 2 lanes of 64-bit values",1146TypeSetBuilder::new()1147.ints(64..64)1148.simd_lanes(2..2)1149.includes_scalars(false)1150.build(),1151);11521153ig.push(1154Inst::new(1155"uload32x2",1156r#"1157Load an 32x2 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i64x21158vector.1159"#,1160&formats.load,1161)1162.operands_in(vec![1163Operand::new("MemFlags", &imm.memflags),1164Operand::new("p", iAddr),1165Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),1166])1167.operands_out(vec![Operand::new("a", I64x2).with_doc("Value loaded")])1168.can_load(),1169);11701171ig.push(1172Inst::new(1173"sload32x2",1174r#"1175Load a 32x2 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i64x21176vector.1177"#,1178&formats.load,1179)1180.operands_in(vec![1181Operand::new("MemFlags", &imm.memflags),1182Operand::new("p", iAddr),1183Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address"),1184])1185.operands_out(vec![Operand::new("a", I64x2).with_doc("Value loaded")])1186.can_load(),1187);11881189ig.push(1190Inst::new(1191"stack_load",1192r#"1193Load a value from a stack slot at the constant offset.11941195This is a polymorphic instruction that can load any value type which1196has a memory representation.11971198The offset is an immediate constant, not an SSA value. The memory1199access cannot go out of bounds, i.e.1200`sizeof(a) + Offset <= sizeof(SS)`.1201"#,1202&formats.stack_load,1203)1204.operands_in(vec![1205Operand::new("SS", &entities.stack_slot),1206Operand::new("Offset", &imm.offset32).with_doc("In-bounds offset into stack slot"),1207])1208.operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")])1209.can_load(),1210);12111212ig.push(1213Inst::new(1214"stack_store",1215r#"1216Store a value to a stack slot at a constant offset.12171218This is a polymorphic instruction that can store any value type with a1219memory representation.12201221The offset is an immediate constant, not an SSA value. The memory1222access cannot go out of bounds, i.e.1223`sizeof(a) + Offset <= sizeof(SS)`.1224"#,1225&formats.stack_store,1226)1227.operands_in(vec![1228Operand::new("x", Mem).with_doc("Value to be stored"),1229Operand::new("SS", &entities.stack_slot),1230Operand::new("Offset", &imm.offset32).with_doc("In-bounds offset into stack slot"),1231])1232.can_store(),1233);12341235ig.push(1236Inst::new(1237"stack_addr",1238r#"1239Get the address of a stack slot.12401241Compute the absolute address of a byte in a stack slot. The offset must1242refer to a byte inside the stack slot:1243`0 <= Offset < sizeof(SS)`.1244"#,1245&formats.stack_load,1246)1247.operands_in(vec![1248Operand::new("SS", &entities.stack_slot),1249Operand::new("Offset", &imm.offset32).with_doc("In-bounds offset into stack slot"),1250])1251.operands_out(vec![Operand::new("addr", iAddr)]),1252);12531254ig.push(1255Inst::new(1256"dynamic_stack_load",1257r#"1258Load a value from a dynamic stack slot.12591260This is a polymorphic instruction that can load any value type which1261has a memory representation.1262"#,1263&formats.dynamic_stack_load,1264)1265.operands_in(vec![Operand::new("DSS", &entities.dynamic_stack_slot)])1266.operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")])1267.can_load(),1268);12691270ig.push(1271Inst::new(1272"dynamic_stack_store",1273r#"1274Store a value to a dynamic stack slot.12751276This is a polymorphic instruction that can store any dynamic value type with a1277memory representation.1278"#,1279&formats.dynamic_stack_store,1280)1281.operands_in(vec![1282Operand::new("x", Mem).with_doc("Value to be stored"),1283Operand::new("DSS", &entities.dynamic_stack_slot),1284])1285.can_store(),1286);12871288ig.push(1289Inst::new(1290"dynamic_stack_addr",1291r#"1292Get the address of a dynamic stack slot.12931294Compute the absolute address of the first byte of a dynamic stack slot.1295"#,1296&formats.dynamic_stack_load,1297)1298.operands_in(vec![Operand::new("DSS", &entities.dynamic_stack_slot)])1299.operands_out(vec![Operand::new("addr", iAddr)]),1300);13011302ig.push(1303Inst::new(1304"global_value",1305r#"1306Compute the value of global GV.1307"#,1308&formats.unary_global_value,1309)1310.operands_in(vec![Operand::new("GV", &entities.global_value)])1311.operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")]),1312);13131314ig.push(1315Inst::new(1316"symbol_value",1317r#"1318Compute the value of global GV, which is a symbolic value.1319"#,1320&formats.unary_global_value,1321)1322.operands_in(vec![Operand::new("GV", &entities.global_value)])1323.operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")]),1324);13251326ig.push(1327Inst::new(1328"tls_value",1329r#"1330Compute the value of global GV, which is a TLS (thread local storage) value.1331"#,1332&formats.unary_global_value,1333)1334.operands_in(vec![Operand::new("GV", &entities.global_value)])1335.operands_out(vec![Operand::new("a", Mem).with_doc("Value loaded")]),1336);13371338// Note this instruction is marked as having other side-effects, so GVN won't try to hoist it,1339// which would result in it being subject to spilling. While not hoisting would generally hurt1340// performance, since a computed value used many times may need to be regenerated before each1341// use, it is not the case here: this instruction doesn't generate any code. That's because,1342// by definition the pinned register is never used by the register allocator, but is written to1343// and read explicitly and exclusively by set_pinned_reg and get_pinned_reg.1344ig.push(1345Inst::new(1346"get_pinned_reg",1347r#"1348Gets the content of the pinned register, when it's enabled.1349"#,1350&formats.nullary,1351)1352.operands_out(vec![Operand::new("addr", iAddr)])1353.other_side_effects(),1354);13551356ig.push(1357Inst::new(1358"set_pinned_reg",1359r#"1360Sets the content of the pinned register, when it's enabled.1361"#,1362&formats.unary,1363)1364.operands_in(vec![Operand::new("addr", iAddr)])1365.other_side_effects(),1366);13671368ig.push(1369Inst::new(1370"get_frame_pointer",1371r#"1372Get the address in the frame pointer register.13731374Usage of this instruction requires setting `preserve_frame_pointers` to `true`.1375"#,1376&formats.nullary,1377)1378.operands_out(vec![Operand::new("addr", iAddr)]),1379);13801381ig.push(1382Inst::new(1383"get_stack_pointer",1384r#"1385Get the address in the stack pointer register.1386"#,1387&formats.nullary,1388)1389.operands_out(vec![Operand::new("addr", iAddr)]),1390);13911392ig.push(1393Inst::new(1394"get_return_address",1395r#"1396Get the PC where this function will transfer control to when it returns.13971398Usage of this instruction requires setting `preserve_frame_pointers` to `true`.1399"#,1400&formats.nullary,1401)1402.operands_out(vec![Operand::new("addr", iAddr)]),1403);14041405ig.push(1406Inst::new(1407"get_exception_handler_address",1408r#"1409Get the handler PC for the given exceptional edge for an1410exception return from the given `try_call`-terminated block.14111412This instruction provides the PC for the handler resume point,1413as defined by the exception-handling aspect of the given1414callee ABI, for a return from the given calling block. It can1415be used when the exception unwind mechanism requires manual1416plumbing for this information which must be set up before the call1417itself: for example, if the resume address needs to be stored in1418some context structure for a runtime to resume to on error.14191420The given caller block must end in a `try_call` and the given1421exception-handling block must be one of its exceptional1422successors in the associated exception-handling table. The1423returned PC is *only* valid to resume to when the `try_call`1424is on the stack having called the callee; in other words, when1425a normal exception unwinder might otherwise resume to that1426handler.1427"#,1428&formats.exception_handler_address,1429)1430.operands_in(vec![1431Operand::new("block", &entities.raw_block),1432Operand::new("index", &imm.imm64),1433])1434.operands_out(vec![Operand::new("addr", iAddr)]),1435);14361437ig.push(1438Inst::new(1439"iconst",1440r#"1441Integer constant.14421443Create a scalar integer SSA value with an immediate constant value, or1444an integer vector where all the lanes have the same value.1445"#,1446&formats.unary_imm,1447)1448.operands_in(vec![Operand::new("N", &imm.imm64)])1449.operands_out(vec![1450Operand::new("a", NarrowInt).with_doc("A constant integer scalar or vector value"),1451]),1452);14531454ig.push(1455Inst::new(1456"f16const",1457r#"1458Floating point constant.14591460Create a `f16` SSA value with an immediate constant value.1461"#,1462&formats.unary_ieee16,1463)1464.operands_in(vec![Operand::new("N", &imm.ieee16)])1465.operands_out(vec![1466Operand::new("a", f16_).with_doc("A constant f16 scalar value"),1467]),1468);14691470ig.push(1471Inst::new(1472"f32const",1473r#"1474Floating point constant.14751476Create a `f32` SSA value with an immediate constant value.1477"#,1478&formats.unary_ieee32,1479)1480.operands_in(vec![Operand::new("N", &imm.ieee32)])1481.operands_out(vec![1482Operand::new("a", f32_).with_doc("A constant f32 scalar value"),1483]),1484);14851486ig.push(1487Inst::new(1488"f64const",1489r#"1490Floating point constant.14911492Create a `f64` SSA value with an immediate constant value.1493"#,1494&formats.unary_ieee64,1495)1496.operands_in(vec![Operand::new("N", &imm.ieee64)])1497.operands_out(vec![1498Operand::new("a", f64_).with_doc("A constant f64 scalar value"),1499]),1500);15011502ig.push(1503Inst::new(1504"f128const",1505r#"1506Floating point constant.15071508Create a `f128` SSA value with an immediate constant value.1509"#,1510&formats.unary_const,1511)1512.operands_in(vec![Operand::new("N", &entities.pool_constant)])1513.operands_out(vec![1514Operand::new("a", f128_).with_doc("A constant f128 scalar value"),1515]),1516);15171518ig.push(1519Inst::new(1520"vconst",1521r#"1522SIMD vector constant.15231524Construct a vector with the given immediate bytes.1525"#,1526&formats.unary_const,1527)1528.operands_in(vec![1529Operand::new("N", &entities.pool_constant)1530.with_doc("The 16 immediate bytes of a 128-bit vector"),1531])1532.operands_out(vec![1533Operand::new("a", TxN).with_doc("A constant vector value"),1534]),1535);15361537let Tx16 = &TypeVar::new(1538"Tx16",1539"A SIMD vector with exactly 16 lanes of 8-bit values; eventually this may support other \1540lane counts and widths",1541TypeSetBuilder::new()1542.ints(8..8)1543.simd_lanes(16..16)1544.includes_scalars(false)1545.build(),1546);15471548ig.push(1549Inst::new(1550"shuffle",1551r#"1552SIMD vector shuffle.15531554Shuffle two vectors using the given immediate bytes. For each of the 16 bytes of the1555immediate, a value i of 0-15 selects the i-th element of the first vector and a value i of155616-31 selects the (i-16)th element of the second vector. Immediate values outside of the15570-31 range are not valid.1558"#,1559&formats.shuffle,1560)1561.operands_in(vec![1562Operand::new("a", Tx16).with_doc("A vector value"),1563Operand::new("b", Tx16).with_doc("A vector value"),1564Operand::new("mask", &entities.uimm128)1565.with_doc("The 16 immediate bytes used for selecting the elements to shuffle"),1566])1567.operands_out(vec![Operand::new("a", Tx16).with_doc("A vector value")]),1568);15691570ig.push(Inst::new(1571"nop",1572r#"1573Just a dummy instruction.15741575Note: this doesn't compile to a machine code nop.1576"#,1577&formats.nullary,1578));15791580ig.push(1581Inst::new(1582"select",1583r#"1584Conditional select.15851586This instruction selects whole values. Use `bitselect` to choose each1587bit according to a mask.1588"#,1589&formats.ternary,1590)1591.operands_in(vec![1592Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"),1593Operand::new("x", Any).with_doc("Value to use when `c` is true"),1594Operand::new("y", Any).with_doc("Value to use when `c` is false"),1595])1596.operands_out(vec![Operand::new("a", Any)]),1597);15981599ig.push(1600Inst::new(1601"select_spectre_guard",1602r#"1603Conditional select intended for Spectre guards.16041605This operation is semantically equivalent to a select instruction.1606However, this instruction prohibits all speculation on the1607controlling value when determining which input to use as the result.1608As such, it is suitable for use in Spectre guards.16091610For example, on a target which may speculatively execute branches,1611the lowering of this instruction is guaranteed to not conditionally1612branch. Instead it will typically lower to a conditional move1613instruction. (No Spectre-vulnerable processors are known to perform1614value speculation on conditional move instructions.)16151616Ensure that the instruction you're trying to protect from Spectre1617attacks has a data dependency on the result of this instruction.1618That prevents an out-of-order CPU from evaluating that instruction1619until the result of this one is known, which in turn will be blocked1620until the controlling value is known.16211622Typical usage is to use a bounds-check as the controlling value,1623and select between either a null pointer if the bounds-check1624fails, or an in-bounds address otherwise, so that dereferencing1625the resulting address with a load or store instruction will trap if1626the bounds-check failed. When this instruction is used in this way,1627any microarchitectural side effects of the memory access will only1628occur after the bounds-check finishes, which ensures that no Spectre1629vulnerability will exist.16301631Optimization opportunities for this instruction are limited compared1632to a normal select instruction, but it is allowed to be replaced1633by other values which are functionally equivalent as long as doing1634so does not introduce any new opportunities to speculate on the1635controlling value.1636"#,1637&formats.ternary,1638)1639.operands_in(vec![1640Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"),1641Operand::new("x", Any).with_doc("Value to use when `c` is true"),1642Operand::new("y", Any).with_doc("Value to use when `c` is false"),1643])1644.operands_out(vec![Operand::new("a", Any)]),1645);16461647ig.push(1648Inst::new(1649"bitselect",1650r#"1651Conditional select of bits.16521653For each bit in `c`, this instruction selects the corresponding bit from `x` if the bit1654in `x` is 1 and the corresponding bit from `y` if the bit in `c` is 0. See also:1655`select`.1656"#,1657&formats.ternary,1658)1659.operands_in(vec![1660Operand::new("c", Any).with_doc("Controlling value to test"),1661Operand::new("x", Any).with_doc("Value to use when `c` is true"),1662Operand::new("y", Any).with_doc("Value to use when `c` is false"),1663])1664.operands_out(vec![Operand::new("a", Any)]),1665);16661667ig.push(1668Inst::new(1669"x86_blendv",1670r#"1671A bitselect-lookalike instruction except with the semantics of1672`blendv`-related instructions on x86.16731674This instruction will use the top bit of each lane in `c`, the condition1675mask. If the bit is 1 then the corresponding lane from `x` is chosen.1676Otherwise the corresponding lane from `y` is chosen.16771678"#,1679&formats.ternary,1680)1681.operands_in(vec![1682Operand::new("c", Any).with_doc("Controlling value to test"),1683Operand::new("x", Any).with_doc("Value to use when `c` is true"),1684Operand::new("y", Any).with_doc("Value to use when `c` is false"),1685])1686.operands_out(vec![Operand::new("a", Any)]),1687);16881689ig.push(1690Inst::new(1691"vany_true",1692r#"1693Reduce a vector to a scalar boolean.16941695Return a scalar boolean true if any lane in ``a`` is non-zero, false otherwise.1696"#,1697&formats.unary,1698)1699.operands_in(vec![Operand::new("a", TxN)])1700.operands_out(vec![Operand::new("s", i8)]),1701);17021703ig.push(1704Inst::new(1705"vall_true",1706r#"1707Reduce a vector to a scalar boolean.17081709Return a scalar boolean true if all lanes in ``i`` are non-zero, false otherwise.1710"#,1711&formats.unary,1712)1713.operands_in(vec![Operand::new("a", TxN)])1714.operands_out(vec![Operand::new("s", i8)]),1715);17161717ig.push(1718Inst::new(1719"vhigh_bits",1720r#"1721Reduce a vector to a scalar integer.17221723Return a scalar integer, consisting of the concatenation of the most significant bit1724of each lane of ``a``.1725"#,1726&formats.unary,1727)1728.operands_in(vec![Operand::new("a", TxN)])1729.operands_out(vec![Operand::new("x", NarrowInt)]),1730);17311732ig.push(1733Inst::new(1734"icmp",1735r#"1736Integer comparison.17371738The condition code determines if the operands are interpreted as signed1739or unsigned integers.17401741| Signed | Unsigned | Condition |1742|--------|----------|-----------------------|1743| eq | eq | Equal |1744| ne | ne | Not equal |1745| slt | ult | Less than |1746| sge | uge | Greater than or equal |1747| sgt | ugt | Greater than |1748| sle | ule | Less than or equal |17491750When this instruction compares integer vectors, it returns a vector of1751lane-wise comparisons.17521753When comparing scalars, the result is:1754- `1` if the condition holds.1755- `0` if the condition does not hold.17561757When comparing vectors, the result is:1758- `-1` (i.e. all ones) in each lane where the condition holds.1759- `0` in each lane where the condition does not hold.1760"#,1761&formats.int_compare,1762)1763.operands_in(vec![1764Operand::new("Cond", &imm.intcc),1765Operand::new("x", Int),1766Operand::new("y", Int),1767])1768.operands_out(vec![Operand::new("a", &Int.as_truthy())]),1769);17701771ig.push(1772Inst::new(1773"icmp_imm",1774r#"1775Compare scalar integer to a constant.17761777This is the same as the `icmp` instruction, except one operand is1778a sign extended 64 bit immediate constant.17791780This instruction can only compare scalars. Use `icmp` for1781lane-wise vector comparisons.1782"#,1783&formats.int_compare_imm,1784)1785.operands_in(vec![1786Operand::new("Cond", &imm.intcc),1787Operand::new("x", iB),1788Operand::new("Y", &imm.imm64),1789])1790.operands_out(vec![Operand::new("a", i8)]),1791);17921793ig.push(1794Inst::new(1795"iadd",1796r#"1797Wrapping integer addition: `a := x + y \pmod{2^B}`.17981799This instruction does not depend on the signed/unsigned interpretation1800of the operands.1801"#,1802&formats.binary,1803)1804.operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)])1805.operands_out(vec![Operand::new("a", Int)]),1806);18071808ig.push(1809Inst::new(1810"isub",1811r#"1812Wrapping integer subtraction: `a := x - y \pmod{2^B}`.18131814This instruction does not depend on the signed/unsigned interpretation1815of the operands.1816"#,1817&formats.binary,1818)1819.operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)])1820.operands_out(vec![Operand::new("a", Int)]),1821);18221823ig.push(1824Inst::new(1825"ineg",1826r#"1827Integer negation: `a := -x \pmod{2^B}`.1828"#,1829&formats.unary,1830)1831.operands_in(vec![Operand::new("x", Int)])1832.operands_out(vec![Operand::new("a", Int)]),1833);18341835ig.push(1836Inst::new(1837"iabs",1838r#"1839Integer absolute value with wrapping: `a := |x|`.1840"#,1841&formats.unary,1842)1843.operands_in(vec![Operand::new("x", Int)])1844.operands_out(vec![Operand::new("a", Int)]),1845);18461847ig.push(1848Inst::new(1849"imul",1850r#"1851Wrapping integer multiplication: `a := x y \pmod{2^B}`.18521853This instruction does not depend on the signed/unsigned interpretation1854of the operands.18551856Polymorphic over all integer types (vector and scalar).1857"#,1858&formats.binary,1859)1860.operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)])1861.operands_out(vec![Operand::new("a", Int)]),1862);18631864ig.push(1865Inst::new(1866"umulhi",1867r#"1868Unsigned integer multiplication, producing the high half of a1869double-length result.18701871Polymorphic over all integer types (vector and scalar).1872"#,1873&formats.binary,1874)1875.operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)])1876.operands_out(vec![Operand::new("a", Int)]),1877);18781879ig.push(1880Inst::new(1881"smulhi",1882r#"1883Signed integer multiplication, producing the high half of a1884double-length result.18851886Polymorphic over all integer types (vector and scalar).1887"#,1888&formats.binary,1889)1890.operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)])1891.operands_out(vec![Operand::new("a", Int)]),1892);18931894let I16or32 = &TypeVar::new(1895"I16or32",1896"A vector integer type with 16- or 32-bit numbers",1897TypeSetBuilder::new().ints(16..32).simd_lanes(4..8).build(),1898);18991900ig.push(1901Inst::new(1902"sqmul_round_sat",1903r#"1904Fixed-point multiplication of numbers in the QN format, where N + 11905is the number bitwidth:1906`a := signed_saturate((x * y + (1 << (Q - 1))) >> Q)`19071908Polymorphic over all integer vector types with 16- or 32-bit numbers.1909"#,1910&formats.binary,1911)1912.operands_in(vec![Operand::new("x", I16or32), Operand::new("y", I16or32)])1913.operands_out(vec![Operand::new("a", I16or32)]),1914);19151916ig.push(1917Inst::new(1918"x86_pmulhrsw",1919r#"1920A similar instruction to `sqmul_round_sat` except with the semantics1921of x86's `pmulhrsw` instruction.19221923This is the same as `sqmul_round_sat` except when both input lanes are1924`i16::MIN`.1925"#,1926&formats.binary,1927)1928.operands_in(vec![Operand::new("x", I16or32), Operand::new("y", I16or32)])1929.operands_out(vec![Operand::new("a", I16or32)]),1930);19311932// Integer division and remainder are scalar-only; most1933// hardware does not directly support vector integer division.19341935ig.push(1936Inst::new(1937"udiv",1938r#"1939Unsigned integer division: `a := \lfloor {x \over y} \rfloor`.19401941This operation traps if the divisor is zero.1942"#,1943&formats.binary,1944)1945.operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])1946.operands_out(vec![Operand::new("a", iB)])1947.can_trap()1948.side_effects_idempotent(),1949);19501951ig.push(1952Inst::new(1953"sdiv",1954r#"1955Signed integer division rounded toward zero: `a := sign(xy)1956\lfloor {|x| \over |y|}\rfloor`.19571958This operation traps if the divisor is zero, or if the result is not1959representable in `B` bits two's complement. This only happens1960when `x = -2^{B-1}, y = -1`.1961"#,1962&formats.binary,1963)1964.operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])1965.operands_out(vec![Operand::new("a", iB)])1966.can_trap()1967.side_effects_idempotent(),1968);19691970ig.push(1971Inst::new(1972"urem",1973r#"1974Unsigned integer remainder.19751976This operation traps if the divisor is zero.1977"#,1978&formats.binary,1979)1980.operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])1981.operands_out(vec![Operand::new("a", iB)])1982.can_trap()1983.side_effects_idempotent(),1984);19851986ig.push(1987Inst::new(1988"srem",1989r#"1990Signed integer remainder. The result has the sign of the dividend.19911992This operation traps if the divisor is zero.1993"#,1994&formats.binary,1995)1996.operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])1997.operands_out(vec![Operand::new("a", iB)])1998.can_trap()1999.side_effects_idempotent(),2000);20012002ig.push(2003Inst::new(2004"iadd_imm",2005r#"2006Add immediate integer.20072008Same as `iadd`, but one operand is a sign extended 64 bit immediate constant.20092010Polymorphic over all scalar integer types, but does not support vector2011types.2012"#,2013&formats.binary_imm64,2014)2015.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2016.operands_out(vec![Operand::new("a", iB)]),2017);20182019ig.push(2020Inst::new(2021"imul_imm",2022r#"2023Integer multiplication by immediate constant.20242025Same as `imul`, but one operand is a sign extended 64 bit immediate constant.20262027Polymorphic over all scalar integer types, but does not support vector2028types.2029"#,2030&formats.binary_imm64,2031)2032.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2033.operands_out(vec![Operand::new("a", iB)]),2034);20352036ig.push(2037Inst::new(2038"udiv_imm",2039r#"2040Unsigned integer division by an immediate constant.20412042Same as `udiv`, but one operand is a zero extended 64 bit immediate constant.20432044This operation traps if the divisor is zero.2045"#,2046&formats.binary_imm64,2047)2048.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2049.operands_out(vec![Operand::new("a", iB)]),2050);20512052ig.push(2053Inst::new(2054"sdiv_imm",2055r#"2056Signed integer division by an immediate constant.20572058Same as `sdiv`, but one operand is a sign extended 64 bit immediate constant.20592060This operation traps if the divisor is zero, or if the result is not2061representable in `B` bits two's complement. This only happens2062when `x = -2^{B-1}, Y = -1`.2063"#,2064&formats.binary_imm64,2065)2066.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2067.operands_out(vec![Operand::new("a", iB)]),2068);20692070ig.push(2071Inst::new(2072"urem_imm",2073r#"2074Unsigned integer remainder with immediate divisor.20752076Same as `urem`, but one operand is a zero extended 64 bit immediate constant.20772078This operation traps if the divisor is zero.2079"#,2080&formats.binary_imm64,2081)2082.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2083.operands_out(vec![Operand::new("a", iB)]),2084);20852086ig.push(2087Inst::new(2088"srem_imm",2089r#"2090Signed integer remainder with immediate divisor.20912092Same as `srem`, but one operand is a sign extended 64 bit immediate constant.20932094This operation traps if the divisor is zero.2095"#,2096&formats.binary_imm64,2097)2098.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2099.operands_out(vec![Operand::new("a", iB)]),2100);21012102ig.push(2103Inst::new(2104"irsub_imm",2105r#"2106Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`.21072108The immediate operand is a sign extended 64 bit constant.21092110Also works as integer negation when `Y = 0`. Use `iadd_imm`2111with a negative immediate operand for the reverse immediate2112subtraction.21132114Polymorphic over all scalar integer types, but does not support vector2115types.2116"#,2117&formats.binary_imm64,2118)2119.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2120.operands_out(vec![Operand::new("a", iB)]),2121);21222123ig.push(2124Inst::new(2125"sadd_overflow_cin",2126r#"2127Add signed integers with carry in and overflow out.21282129Same as `sadd_overflow` with an additional carry input. The `c_in` type2130is interpreted as 1 if it's nonzero or 0 if it's zero.2131"#,2132&formats.ternary,2133)2134.operands_in(vec![2135Operand::new("x", iB),2136Operand::new("y", iB),2137Operand::new("c_in", i8).with_doc("Input carry flag"),2138])2139.operands_out(vec![2140Operand::new("a", iB),2141Operand::new("c_out", i8).with_doc("Output carry flag"),2142]),2143);21442145ig.push(2146Inst::new(2147"uadd_overflow_cin",2148r#"2149Add unsigned integers with carry in and overflow out.21502151Same as `uadd_overflow` with an additional carry input. The `c_in` type2152is interpreted as 1 if it's nonzero or 0 if it's zero.2153"#,2154&formats.ternary,2155)2156.operands_in(vec![2157Operand::new("x", iB),2158Operand::new("y", iB),2159Operand::new("c_in", i8).with_doc("Input carry flag"),2160])2161.operands_out(vec![2162Operand::new("a", iB),2163Operand::new("c_out", i8).with_doc("Output carry flag"),2164]),2165);21662167{2168let of_out = Operand::new("of", i8).with_doc("Overflow flag");2169ig.push(2170Inst::new(2171"uadd_overflow",2172r#"2173Add integers unsigned with overflow out.2174``of`` is set when the addition overflowed.2175```text2176a &= x + y \pmod 2^B \\2177of &= x+y >= 2^B2178```2179Polymorphic over all scalar integer types, but does not support vector2180types.2181"#,2182&formats.binary,2183)2184.operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])2185.operands_out(vec![Operand::new("a", iB), of_out.clone()]),2186);21872188ig.push(2189Inst::new(2190"sadd_overflow",2191r#"2192Add integers signed with overflow out.2193``of`` is set when the addition over- or underflowed.2194Polymorphic over all scalar integer types, but does not support vector2195types.2196"#,2197&formats.binary,2198)2199.operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])2200.operands_out(vec![Operand::new("a", iB), of_out.clone()]),2201);22022203ig.push(2204Inst::new(2205"usub_overflow",2206r#"2207Subtract integers unsigned with overflow out.2208``of`` is set when the subtraction underflowed.2209```text2210a &= x - y \pmod 2^B \\2211of &= x - y < 02212```2213Polymorphic over all scalar integer types, but does not support vector2214types.2215"#,2216&formats.binary,2217)2218.operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])2219.operands_out(vec![Operand::new("a", iB), of_out.clone()]),2220);22212222ig.push(2223Inst::new(2224"ssub_overflow",2225r#"2226Subtract integers signed with overflow out.2227``of`` is set when the subtraction over- or underflowed.2228Polymorphic over all scalar integer types, but does not support vector2229types.2230"#,2231&formats.binary,2232)2233.operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])2234.operands_out(vec![Operand::new("a", iB), of_out.clone()]),2235);22362237{2238let NarrowScalar = &TypeVar::new(2239"NarrowScalar",2240"A scalar integer type up to 64 bits",2241TypeSetBuilder::new().ints(8..64).build(),2242);22432244ig.push(2245Inst::new(2246"umul_overflow",2247r#"2248Multiply integers unsigned with overflow out.2249``of`` is set when the multiplication overflowed.2250```text2251a &= x * y \pmod 2^B \\2252of &= x * y > 2^B2253```2254Polymorphic over all scalar integer types except i128, but does not support vector2255types.2256"#,2257&formats.binary,2258)2259.operands_in(vec![2260Operand::new("x", NarrowScalar),2261Operand::new("y", NarrowScalar),2262])2263.operands_out(vec![Operand::new("a", NarrowScalar), of_out.clone()]),2264);22652266ig.push(2267Inst::new(2268"smul_overflow",2269r#"2270Multiply integers signed with overflow out.2271``of`` is set when the multiplication over- or underflowed.2272Polymorphic over all scalar integer types except i128, but does not support vector2273types.2274"#,2275&formats.binary,2276)2277.operands_in(vec![2278Operand::new("x", NarrowScalar),2279Operand::new("y", NarrowScalar),2280])2281.operands_out(vec![Operand::new("a", NarrowScalar), of_out.clone()]),2282);2283}2284}22852286let i32_64 = &TypeVar::new(2287"i32_64",2288"A 32 or 64-bit scalar integer type",2289TypeSetBuilder::new().ints(32..64).build(),2290);22912292ig.push(2293Inst::new(2294"uadd_overflow_trap",2295r#"2296Unsigned addition of x and y, trapping if the result overflows.22972298Accepts 32 or 64-bit integers, and does not support vector types.2299"#,2300&formats.int_add_trap,2301)2302.operands_in(vec![2303Operand::new("x", i32_64),2304Operand::new("y", i32_64),2305Operand::new("code", &imm.trapcode),2306])2307.operands_out(vec![Operand::new("a", i32_64)])2308.can_trap()2309.side_effects_idempotent(),2310);23112312ig.push(2313Inst::new(2314"ssub_overflow_bin",2315r#"2316Subtract signed integers with borrow in and overflow out.23172318Same as `ssub_overflow` with an additional borrow input. The `b_in` type2319is interpreted as 1 if it's nonzero or 0 if it's zero. The computation2320performed here is `x - (y + (b_in != 0))`.2321"#,2322&formats.ternary,2323)2324.operands_in(vec![2325Operand::new("x", iB),2326Operand::new("y", iB),2327Operand::new("b_in", i8).with_doc("Input borrow flag"),2328])2329.operands_out(vec![2330Operand::new("a", iB),2331Operand::new("b_out", i8).with_doc("Output borrow flag"),2332]),2333);23342335ig.push(2336Inst::new(2337"usub_overflow_bin",2338r#"2339Subtract unsigned integers with borrow in and overflow out.23402341Same as `usub_overflow` with an additional borrow input. The `b_in` type2342is interpreted as 1 if it's nonzero or 0 if it's zero. The computation2343performed here is `x - (y + (b_in != 0))`.2344"#,2345&formats.ternary,2346)2347.operands_in(vec![2348Operand::new("x", iB),2349Operand::new("y", iB),2350Operand::new("b_in", i8).with_doc("Input borrow flag"),2351])2352.operands_out(vec![2353Operand::new("a", iB),2354Operand::new("b_out", i8).with_doc("Output borrow flag"),2355]),2356);23572358let bits = &TypeVar::new(2359"bits",2360"Any integer, float, or vector type",2361TypeSetBuilder::new()2362.ints(Interval::All)2363.floats(Interval::All)2364.simd_lanes(Interval::All)2365.includes_scalars(true)2366.build(),2367);23682369ig.push(2370Inst::new(2371"band",2372r#"2373Bitwise and.2374"#,2375&formats.binary,2376)2377.operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])2378.operands_out(vec![Operand::new("a", bits)]),2379);23802381ig.push(2382Inst::new(2383"bor",2384r#"2385Bitwise or.2386"#,2387&formats.binary,2388)2389.operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])2390.operands_out(vec![Operand::new("a", bits)]),2391);23922393ig.push(2394Inst::new(2395"bxor",2396r#"2397Bitwise xor.2398"#,2399&formats.binary,2400)2401.operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])2402.operands_out(vec![Operand::new("a", bits)]),2403);24042405ig.push(2406Inst::new(2407"bnot",2408r#"2409Bitwise not.2410"#,2411&formats.unary,2412)2413.operands_in(vec![Operand::new("x", bits)])2414.operands_out(vec![Operand::new("a", bits)]),2415);24162417ig.push(2418Inst::new(2419"band_not",2420r#"2421Bitwise and not.24222423Computes `x & ~y`.2424"#,2425&formats.binary,2426)2427.operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])2428.operands_out(vec![Operand::new("a", bits)]),2429);24302431ig.push(2432Inst::new(2433"bor_not",2434r#"2435Bitwise or not.24362437Computes `x | ~y`.2438"#,2439&formats.binary,2440)2441.operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])2442.operands_out(vec![Operand::new("a", bits)]),2443);24442445ig.push(2446Inst::new(2447"bxor_not",2448r#"2449Bitwise xor not.24502451Computes `x ^ ~y`.2452"#,2453&formats.binary,2454)2455.operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])2456.operands_out(vec![Operand::new("a", bits)]),2457);24582459ig.push(2460Inst::new(2461"band_imm",2462r#"2463Bitwise and with immediate.24642465Same as `band`, but one operand is a zero extended 64 bit immediate constant.24662467Polymorphic over all scalar integer types, but does not support vector2468types.2469"#,2470&formats.binary_imm64,2471)2472.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2473.operands_out(vec![Operand::new("a", iB)]),2474);24752476ig.push(2477Inst::new(2478"bor_imm",2479r#"2480Bitwise or with immediate.24812482Same as `bor`, but one operand is a zero extended 64 bit immediate constant.24832484Polymorphic over all scalar integer types, but does not support vector2485types.2486"#,2487&formats.binary_imm64,2488)2489.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2490.operands_out(vec![Operand::new("a", iB)]),2491);24922493ig.push(2494Inst::new(2495"bxor_imm",2496r#"2497Bitwise xor with immediate.24982499Same as `bxor`, but one operand is a zero extended 64 bit immediate constant.25002501Polymorphic over all scalar integer types, but does not support vector2502types.2503"#,2504&formats.binary_imm64,2505)2506.operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])2507.operands_out(vec![Operand::new("a", iB)]),2508);25092510ig.push(2511Inst::new(2512"rotl",2513r#"2514Rotate left.25152516Rotate the bits in ``x`` by ``y`` places.2517"#,2518&formats.binary,2519)2520.operands_in(vec![2521Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2522Operand::new("y", iB).with_doc("Number of bits to shift"),2523])2524.operands_out(vec![Operand::new("a", Int)]),2525);25262527ig.push(2528Inst::new(2529"rotr",2530r#"2531Rotate right.25322533Rotate the bits in ``x`` by ``y`` places.2534"#,2535&formats.binary,2536)2537.operands_in(vec![2538Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2539Operand::new("y", iB).with_doc("Number of bits to shift"),2540])2541.operands_out(vec![Operand::new("a", Int)]),2542);25432544ig.push(2545Inst::new(2546"rotl_imm",2547r#"2548Rotate left by immediate.25492550Same as `rotl`, but one operand is a zero extended 64 bit immediate constant.2551"#,2552&formats.binary_imm64,2553)2554.operands_in(vec![2555Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2556Operand::new("Y", &imm.imm64),2557])2558.operands_out(vec![Operand::new("a", Int)]),2559);25602561ig.push(2562Inst::new(2563"rotr_imm",2564r#"2565Rotate right by immediate.25662567Same as `rotr`, but one operand is a zero extended 64 bit immediate constant.2568"#,2569&formats.binary_imm64,2570)2571.operands_in(vec![2572Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2573Operand::new("Y", &imm.imm64),2574])2575.operands_out(vec![Operand::new("a", Int)]),2576);25772578ig.push(2579Inst::new(2580"ishl",2581r#"2582Integer shift left. Shift the bits in ``x`` towards the MSB by ``y``2583places. Shift in zero bits to the LSB.25842585The shift amount is masked to the size of ``x``.25862587When shifting a B-bits integer type, this instruction computes:25882589```text2590s &:= y \pmod B,2591a &:= x \cdot 2^s \pmod{2^B}.2592```2593"#,2594&formats.binary,2595)2596.operands_in(vec![2597Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2598Operand::new("y", iB).with_doc("Number of bits to shift"),2599])2600.operands_out(vec![Operand::new("a", Int)]),2601);26022603ig.push(2604Inst::new(2605"ushr",2606r#"2607Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y``2608places, shifting in zero bits to the MSB. Also called a *logical2609shift*.26102611The shift amount is masked to the size of ``x``.26122613When shifting a B-bits integer type, this instruction computes:26142615```text2616s &:= y \pmod B,2617a &:= \lfloor x \cdot 2^{-s} \rfloor.2618```2619"#,2620&formats.binary,2621)2622.operands_in(vec![2623Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2624Operand::new("y", iB).with_doc("Number of bits to shift"),2625])2626.operands_out(vec![Operand::new("a", Int)]),2627);26282629ig.push(2630Inst::new(2631"sshr",2632r#"2633Signed shift right. Shift bits in ``x`` towards the LSB by ``y``2634places, shifting in sign bits to the MSB. Also called an *arithmetic2635shift*.26362637The shift amount is masked to the size of ``x``.2638"#,2639&formats.binary,2640)2641.operands_in(vec![2642Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2643Operand::new("y", iB).with_doc("Number of bits to shift"),2644])2645.operands_out(vec![Operand::new("a", Int)]),2646);26472648ig.push(2649Inst::new(2650"ishl_imm",2651r#"2652Integer shift left by immediate.26532654The shift amount is masked to the size of ``x``.2655"#,2656&formats.binary_imm64,2657)2658.operands_in(vec![2659Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2660Operand::new("Y", &imm.imm64),2661])2662.operands_out(vec![Operand::new("a", Int)]),2663);26642665ig.push(2666Inst::new(2667"ushr_imm",2668r#"2669Unsigned shift right by immediate.26702671The shift amount is masked to the size of ``x``.2672"#,2673&formats.binary_imm64,2674)2675.operands_in(vec![2676Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2677Operand::new("Y", &imm.imm64),2678])2679.operands_out(vec![Operand::new("a", Int)]),2680);26812682ig.push(2683Inst::new(2684"sshr_imm",2685r#"2686Signed shift right by immediate.26872688The shift amount is masked to the size of ``x``.2689"#,2690&formats.binary_imm64,2691)2692.operands_in(vec![2693Operand::new("x", Int).with_doc("Scalar or vector value to shift"),2694Operand::new("Y", &imm.imm64),2695])2696.operands_out(vec![Operand::new("a", Int)]),2697);26982699ig.push(2700Inst::new(2701"bitrev",2702r#"2703Reverse the bits of a integer.27042705Reverses the bits in ``x``.2706"#,2707&formats.unary,2708)2709.operands_in(vec![Operand::new("x", iB)])2710.operands_out(vec![Operand::new("a", iB)]),2711);27122713ig.push(2714Inst::new(2715"clz",2716r#"2717Count leading zero bits.27182719Starting from the MSB in ``x``, count the number of zero bits before2720reaching the first one bit. When ``x`` is zero, returns the size of x2721in bits.2722"#,2723&formats.unary,2724)2725.operands_in(vec![Operand::new("x", iB)])2726.operands_out(vec![Operand::new("a", iB)]),2727);27282729ig.push(2730Inst::new(2731"cls",2732r#"2733Count leading sign bits.27342735Starting from the MSB after the sign bit in ``x``, count the number of2736consecutive bits identical to the sign bit. When ``x`` is 0 or -1,2737returns one less than the size of x in bits.2738"#,2739&formats.unary,2740)2741.operands_in(vec![Operand::new("x", iB)])2742.operands_out(vec![Operand::new("a", iB)]),2743);27442745ig.push(2746Inst::new(2747"ctz",2748r#"2749Count trailing zeros.27502751Starting from the LSB in ``x``, count the number of zero bits before2752reaching the first one bit. When ``x`` is zero, returns the size of x2753in bits.2754"#,2755&formats.unary,2756)2757.operands_in(vec![Operand::new("x", iB)])2758.operands_out(vec![Operand::new("a", iB)]),2759);27602761ig.push(2762Inst::new(2763"bswap",2764r#"2765Reverse the byte order of an integer.27662767Reverses the bytes in ``x``.2768"#,2769&formats.unary,2770)2771.operands_in(vec![Operand::new("x", iSwappable)])2772.operands_out(vec![Operand::new("a", iSwappable)]),2773);27742775ig.push(2776Inst::new(2777"popcnt",2778r#"2779Population count27802781Count the number of one bits in ``x``.2782"#,2783&formats.unary,2784)2785.operands_in(vec![Operand::new("x", Int)])2786.operands_out(vec![Operand::new("a", Int)]),2787);27882789let Float = &TypeVar::new(2790"Float",2791"A scalar or vector floating point number",2792TypeSetBuilder::new()2793.floats(Interval::All)2794.simd_lanes(Interval::All)2795.dynamic_simd_lanes(Interval::All)2796.build(),2797);27982799ig.push(2800Inst::new(2801"fcmp",2802r#"2803Floating point comparison.28042805Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each2806other in exactly one of four ways:28072808```text2809== ==========================================2810UN Unordered when one or both numbers is NaN.2811EQ When `x = y`. (And `0.0 = -0.0`).2812LT When `x < y`.2813GT When `x > y`.2814== ==========================================2815```28162817The 14 `floatcc` condition codes each correspond to a subset of2818the four relations, except for the empty set which would always be2819false, and the full set which would always be true.28202821The condition codes are divided into 7 'ordered' conditions which don't2822include UN, and 7 unordered conditions which all include UN.28232824```text2825+-------+------------+---------+------------+-------------------------+2826|Ordered |Unordered |Condition |2827+=======+============+=========+============+=========================+2828|ord |EQ | LT | GT|uno |UN |NaNs absent / present. |2829+-------+------------+---------+------------+-------------------------+2830|eq |EQ |ueq |UN | EQ |Equal |2831+-------+------------+---------+------------+-------------------------+2832|one |LT | GT |ne |UN | LT | GT|Not equal |2833+-------+------------+---------+------------+-------------------------+2834|lt |LT |ult |UN | LT |Less than |2835+-------+------------+---------+------------+-------------------------+2836|le |LT | EQ |ule |UN | LT | EQ|Less than or equal |2837+-------+------------+---------+------------+-------------------------+2838|gt |GT |ugt |UN | GT |Greater than |2839+-------+------------+---------+------------+-------------------------+2840|ge |GT | EQ |uge |UN | GT | EQ|Greater than or equal |2841+-------+------------+---------+------------+-------------------------+2842```28432844The standard C comparison operators, `<, <=, >, >=`, are all ordered,2845so they are false if either operand is NaN. The C equality operator,2846`==`, is ordered, and since inequality is defined as the logical2847inverse it is *unordered*. They map to the `floatcc` condition2848codes as follows:28492850```text2851==== ====== ============2852C `Cond` Subset2853==== ====== ============2854`==` eq EQ2855`!=` ne UN | LT | GT2856`<` lt LT2857`<=` le LT | EQ2858`>` gt GT2859`>=` ge GT | EQ2860==== ====== ============2861```28622863This subset of condition codes also corresponds to the WebAssembly2864floating point comparisons of the same name.28652866When this instruction compares floating point vectors, it returns a2867vector with the results of lane-wise comparisons.28682869When comparing scalars, the result is:2870- `1` if the condition holds.2871- `0` if the condition does not hold.28722873When comparing vectors, the result is:2874- `-1` (i.e. all ones) in each lane where the condition holds.2875- `0` in each lane where the condition does not hold.2876"#,2877&formats.float_compare,2878)2879.operands_in(vec![2880Operand::new("Cond", &imm.floatcc),2881Operand::new("x", Float),2882Operand::new("y", Float),2883])2884.operands_out(vec![Operand::new("a", &Float.as_truthy())]),2885);28862887ig.push(2888Inst::new(2889"fadd",2890r#"2891Floating point addition.2892"#,2893&formats.binary,2894)2895.operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])2896.operands_out(vec![2897Operand::new("a", Float).with_doc("Result of applying operator to each lane"),2898]),2899);29002901ig.push(2902Inst::new(2903"fsub",2904r#"2905Floating point subtraction.2906"#,2907&formats.binary,2908)2909.operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])2910.operands_out(vec![2911Operand::new("a", Float).with_doc("Result of applying operator to each lane"),2912]),2913);29142915ig.push(2916Inst::new(2917"fmul",2918r#"2919Floating point multiplication.2920"#,2921&formats.binary,2922)2923.operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])2924.operands_out(vec![2925Operand::new("a", Float).with_doc("Result of applying operator to each lane"),2926]),2927);29282929ig.push(2930Inst::new(2931"fdiv",2932r#"2933Floating point division.29342935Unlike the integer division instructions ` and2936`udiv`, this can't trap. Division by zero is infinity or2937NaN, depending on the dividend.2938"#,2939&formats.binary,2940)2941.operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])2942.operands_out(vec![2943Operand::new("a", Float).with_doc("Result of applying operator to each lane"),2944]),2945);29462947ig.push(2948Inst::new(2949"sqrt",2950r#"2951Floating point square root.2952"#,2953&formats.unary,2954)2955.operands_in(vec![Operand::new("x", Float)])2956.operands_out(vec![2957Operand::new("a", Float).with_doc("Result of applying operator to each lane"),2958]),2959);29602961ig.push(2962Inst::new(2963"fma",2964r#"2965Floating point fused multiply-and-add.29662967Computes `a := xy+z` without any intermediate rounding of the2968product.2969"#,2970&formats.ternary,2971)2972.operands_in(vec![2973Operand::new("x", Float),2974Operand::new("y", Float),2975Operand::new("z", Float),2976])2977.operands_out(vec![2978Operand::new("a", Float).with_doc("Result of applying operator to each lane"),2979]),2980);29812982ig.push(2983Inst::new(2984"fneg",2985r#"2986Floating point negation.29872988Note that this is a pure bitwise operation.2989"#,2990&formats.unary,2991)2992.operands_in(vec![Operand::new("x", Float)])2993.operands_out(vec![2994Operand::new("a", Float).with_doc("``x`` with its sign bit inverted"),2995]),2996);29972998ig.push(2999Inst::new(3000"fabs",3001r#"3002Floating point absolute value.30033004Note that this is a pure bitwise operation.3005"#,3006&formats.unary,3007)3008.operands_in(vec![Operand::new("x", Float)])3009.operands_out(vec![3010Operand::new("a", Float).with_doc("``x`` with its sign bit cleared"),3011]),3012);30133014ig.push(3015Inst::new(3016"fcopysign",3017r#"3018Floating point copy sign.30193020Note that this is a pure bitwise operation. The sign bit from ``y`` is3021copied to the sign bit of ``x``.3022"#,3023&formats.binary,3024)3025.operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])3026.operands_out(vec![3027Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``"),3028]),3029);30303031ig.push(3032Inst::new(3033"fmin",3034r#"3035Floating point minimum, propagating NaNs using the WebAssembly rules.30363037If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if3038each input NaN consists of a mantissa whose most significant bit is 1 and the rest is30390, then the output has the same form. Otherwise, the output mantissa's most significant3040bit is 1 and the rest is unspecified.3041"#,3042&formats.binary,3043)3044.operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])3045.operands_out(vec![3046Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``"),3047]),3048);30493050ig.push(3051Inst::new(3052"fmax",3053r#"3054Floating point maximum, propagating NaNs using the WebAssembly rules.30553056If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if3057each input NaN consists of a mantissa whose most significant bit is 1 and the rest is30580, then the output has the same form. Otherwise, the output mantissa's most significant3059bit is 1 and the rest is unspecified.3060"#,3061&formats.binary,3062)3063.operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])3064.operands_out(vec![3065Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``"),3066]),3067);30683069ig.push(3070Inst::new(3071"ceil",3072r#"3073Round floating point round to integral, towards positive infinity.3074"#,3075&formats.unary,3076)3077.operands_in(vec![Operand::new("x", Float)])3078.operands_out(vec![3079Operand::new("a", Float).with_doc("``x`` rounded to integral value"),3080]),3081);30823083ig.push(3084Inst::new(3085"floor",3086r#"3087Round floating point round to integral, towards negative infinity.3088"#,3089&formats.unary,3090)3091.operands_in(vec![Operand::new("x", Float)])3092.operands_out(vec![3093Operand::new("a", Float).with_doc("``x`` rounded to integral value"),3094]),3095);30963097ig.push(3098Inst::new(3099"trunc",3100r#"3101Round floating point round to integral, towards zero.3102"#,3103&formats.unary,3104)3105.operands_in(vec![Operand::new("x", Float)])3106.operands_out(vec![3107Operand::new("a", Float).with_doc("``x`` rounded to integral value"),3108]),3109);31103111ig.push(3112Inst::new(3113"nearest",3114r#"3115Round floating point round to integral, towards nearest with ties to3116even.3117"#,3118&formats.unary,3119)3120.operands_in(vec![Operand::new("x", Float)])3121.operands_out(vec![3122Operand::new("a", Float).with_doc("``x`` rounded to integral value"),3123]),3124);31253126ig.push(3127Inst::new(3128"bitcast",3129r#"3130Reinterpret the bits in `x` as a different type.31313132The input and output types must be storable to memory and of the same3133size. A bitcast is equivalent to storing one type and loading the other3134type from the same address, both using the specified MemFlags.31353136Note that this operation only supports the `big` or `little` MemFlags.3137The specified byte order only affects the result in the case where3138input and output types differ in lane count/size. In this case, the3139operation is only valid if a byte order specifier is provided.3140"#,3141&formats.load_no_offset,3142)3143.operands_in(vec![3144Operand::new("MemFlags", &imm.memflags),3145Operand::new("x", Mem),3146])3147.operands_out(vec![3148Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted"),3149]),3150);31513152ig.push(3153Inst::new(3154"scalar_to_vector",3155r#"3156Copies a scalar value to a vector value. The scalar is copied into the3157least significant lane of the vector, and all other lanes will be zero.3158"#,3159&formats.unary,3160)3161.operands_in(vec![3162Operand::new("s", &TxN.lane_of()).with_doc("A scalar value"),3163])3164.operands_out(vec![Operand::new("a", TxN).with_doc("A vector value")]),3165);31663167let Truthy = &TypeVar::new(3168"Truthy",3169"A scalar whose values are truthy",3170TypeSetBuilder::new().ints(Interval::All).build(),3171);3172let IntTo = &TypeVar::new(3173"IntTo",3174"An integer type",3175TypeSetBuilder::new().ints(Interval::All).build(),3176);31773178ig.push(3179Inst::new(3180"bmask",3181r#"3182Convert `x` to an integer mask.31833184Non-zero maps to all 1s and zero maps to all 0s.3185"#,3186&formats.unary,3187)3188.operands_in(vec![Operand::new("x", Truthy)])3189.operands_out(vec![Operand::new("a", IntTo)]),3190);31913192let Int = &TypeVar::new(3193"Int",3194"A scalar integer type",3195TypeSetBuilder::new().ints(Interval::All).build(),3196);31973198ig.push(3199Inst::new(3200"ireduce",3201r#"3202Convert `x` to a smaller integer type by discarding3203the most significant bits.32043205This is the same as reducing modulo `2^n`.3206"#,3207&formats.unary,3208)3209.operands_in(vec![3210Operand::new("x", &Int.wider())3211.with_doc("A scalar integer type, wider than the controlling type"),3212])3213.operands_out(vec![Operand::new("a", Int)]),3214);32153216let I16or32or64xN = &TypeVar::new(3217"I16or32or64xN",3218"A SIMD vector type containing integer lanes 16, 32, or 64 bits wide",3219TypeSetBuilder::new()3220.ints(16..64)3221.simd_lanes(2..8)3222.dynamic_simd_lanes(2..8)3223.includes_scalars(false)3224.build(),3225);32263227ig.push(3228Inst::new(3229"snarrow",3230r#"3231Combine `x` and `y` into a vector with twice the lanes but half the integer width while3232saturating overflowing values to the signed maximum and minimum.32333234The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`3235and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value3236returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.3237"#,3238&formats.binary,3239)3240.operands_in(vec![3241Operand::new("x", I16or32or64xN),3242Operand::new("y", I16or32or64xN),3243])3244.operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]),3245);32463247ig.push(3248Inst::new(3249"unarrow",3250r#"3251Combine `x` and `y` into a vector with twice the lanes but half the integer width while3252saturating overflowing values to the unsigned maximum and minimum.32533254Note that all input lanes are considered signed: any negative lanes will overflow and be3255replaced with the unsigned minimum, `0x00`.32563257The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`3258and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value3259returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.3260"#,3261&formats.binary,3262)3263.operands_in(vec![3264Operand::new("x", I16or32or64xN),3265Operand::new("y", I16or32or64xN),3266])3267.operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]),3268);32693270ig.push(3271Inst::new(3272"uunarrow",3273r#"3274Combine `x` and `y` into a vector with twice the lanes but half the integer width while3275saturating overflowing values to the unsigned maximum and minimum.32763277Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum.32783279The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`3280and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value3281returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.3282"#,3283&formats.binary,3284)3285.operands_in(vec![Operand::new("x", I16or32or64xN), Operand::new("y", I16or32or64xN)])3286.operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]),3287);32883289let I8or16or32xN = &TypeVar::new(3290"I8or16or32xN",3291"A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.",3292TypeSetBuilder::new()3293.ints(8..32)3294.simd_lanes(2..16)3295.dynamic_simd_lanes(2..16)3296.includes_scalars(false)3297.build(),3298);32993300ig.push(3301Inst::new(3302"swiden_low",3303r#"3304Widen the low lanes of `x` using signed extension.33053306This will double the lane width and halve the number of lanes.3307"#,3308&formats.unary,3309)3310.operands_in(vec![Operand::new("x", I8or16or32xN)])3311.operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]),3312);33133314ig.push(3315Inst::new(3316"swiden_high",3317r#"3318Widen the high lanes of `x` using signed extension.33193320This will double the lane width and halve the number of lanes.3321"#,3322&formats.unary,3323)3324.operands_in(vec![Operand::new("x", I8or16or32xN)])3325.operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]),3326);33273328ig.push(3329Inst::new(3330"uwiden_low",3331r#"3332Widen the low lanes of `x` using unsigned extension.33333334This will double the lane width and halve the number of lanes.3335"#,3336&formats.unary,3337)3338.operands_in(vec![Operand::new("x", I8or16or32xN)])3339.operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]),3340);33413342ig.push(3343Inst::new(3344"uwiden_high",3345r#"3346Widen the high lanes of `x` using unsigned extension.33473348This will double the lane width and halve the number of lanes.3349"#,3350&formats.unary,3351)3352.operands_in(vec![Operand::new("x", I8or16or32xN)])3353.operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]),3354);33553356ig.push(3357Inst::new(3358"iadd_pairwise",3359r#"3360Does lane-wise integer pairwise addition on two operands, putting the3361combined results into a single vector result. Here a pair refers to adjacent3362lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand3363pairwise add results will make up the low half of the resulting vector while3364the second operand pairwise add results will make up the upper half of the3365resulting vector.3366"#,3367&formats.binary,3368)3369.operands_in(vec![3370Operand::new("x", I8or16or32xN),3371Operand::new("y", I8or16or32xN),3372])3373.operands_out(vec![Operand::new("a", I8or16or32xN)]),3374);33753376let I8x16 = &TypeVar::new(3377"I8x16",3378"A SIMD vector type consisting of 16 lanes of 8-bit integers",3379TypeSetBuilder::new()3380.ints(8..8)3381.simd_lanes(16..16)3382.includes_scalars(false)3383.build(),3384);33853386ig.push(3387Inst::new(3388"x86_pmaddubsw",3389r#"3390An instruction with equivalent semantics to `pmaddubsw` on x86.33913392This instruction will take signed bytes from the first argument and3393multiply them against unsigned bytes in the second argument. Adjacent3394pairs are then added, with saturating, to a 16-bit value and are packed3395into the result.3396"#,3397&formats.binary,3398)3399.operands_in(vec![Operand::new("x", I8x16), Operand::new("y", I8x16)])3400.operands_out(vec![Operand::new("a", I16x8)]),3401);34023403ig.push(3404Inst::new(3405"uextend",3406r#"3407Convert `x` to a larger integer type by zero-extending.34083409Each lane in `x` is converted to a larger integer type by adding3410zeroes. The result has the same numerical value as `x` when both are3411interpreted as unsigned integers.34123413The result type must have the same number of vector lanes as the input,3414and each lane must not have fewer bits that the input lanes. If the3415input and output types are the same, this is a no-op.3416"#,3417&formats.unary,3418)3419.operands_in(vec![Operand::new("x", &Int.narrower()).with_doc(3420"A scalar integer type, narrower than the controlling type",3421)])3422.operands_out(vec![Operand::new("a", Int)]),3423);34243425ig.push(3426Inst::new(3427"sextend",3428r#"3429Convert `x` to a larger integer type by sign-extending.34303431Each lane in `x` is converted to a larger integer type by replicating3432the sign bit. The result has the same numerical value as `x` when both3433are interpreted as signed integers.34343435The result type must have the same number of vector lanes as the input,3436and each lane must not have fewer bits that the input lanes. If the3437input and output types are the same, this is a no-op.3438"#,3439&formats.unary,3440)3441.operands_in(vec![Operand::new("x", &Int.narrower()).with_doc(3442"A scalar integer type, narrower than the controlling type",3443)])3444.operands_out(vec![Operand::new("a", Int)]),3445);34463447let FloatScalar = &TypeVar::new(3448"FloatScalar",3449"A scalar only floating point number",3450TypeSetBuilder::new().floats(Interval::All).build(),3451);34523453ig.push(3454Inst::new(3455"fpromote",3456r#"3457Convert `x` to a larger floating point format.34583459Each lane in `x` is converted to the destination floating point format.3460This is an exact operation.34613462Cranelift currently only supports two floating point formats3463- `f32` and `f64`. This may change in the future.34643465The result type must have the same number of vector lanes as the input,3466and the result lanes must not have fewer bits than the input lanes.3467"#,3468&formats.unary,3469)3470.operands_in(vec![Operand::new("x", &FloatScalar.narrower()).with_doc(3471"A scalar only floating point number, narrower than the controlling type",3472)])3473.operands_out(vec![Operand::new("a", FloatScalar)]),3474);34753476ig.push(3477Inst::new(3478"fdemote",3479r#"3480Convert `x` to a smaller floating point format.34813482Each lane in `x` is converted to the destination floating point format3483by rounding to nearest, ties to even.34843485Cranelift currently only supports two floating point formats3486- `f32` and `f64`. This may change in the future.34873488The result type must have the same number of vector lanes as the input,3489and the result lanes must not have more bits than the input lanes.3490"#,3491&formats.unary,3492)3493.operands_in(vec![Operand::new("x", &FloatScalar.wider()).with_doc(3494"A scalar only floating point number, wider than the controlling type",3495)])3496.operands_out(vec![Operand::new("a", FloatScalar)]),3497);34983499let F64x2 = &TypeVar::new(3500"F64x2",3501"A SIMD vector type consisting of 2 lanes of 64-bit floats",3502TypeSetBuilder::new()3503.floats(64..64)3504.simd_lanes(2..2)3505.includes_scalars(false)3506.build(),3507);3508let F32x4 = &TypeVar::new(3509"F32x4",3510"A SIMD vector type consisting of 4 lanes of 32-bit floats",3511TypeSetBuilder::new()3512.floats(32..32)3513.simd_lanes(4..4)3514.includes_scalars(false)3515.build(),3516);35173518ig.push(3519Inst::new(3520"fvdemote",3521r#"3522Convert `x` to a smaller floating point format.35233524Each lane in `x` is converted to the destination floating point format3525by rounding to nearest, ties to even.35263527Cranelift currently only supports two floating point formats3528- `f32` and `f64`. This may change in the future.35293530Fvdemote differs from fdemote in that with fvdemote it targets vectors.3531Fvdemote is constrained to having the input type being F64x2 and the result3532type being F32x4. The result lane that was the upper half of the input lane3533is initialized to zero.3534"#,3535&formats.unary,3536)3537.operands_in(vec![Operand::new("x", F64x2)])3538.operands_out(vec![Operand::new("a", F32x4)]),3539);35403541ig.push(3542Inst::new(3543"fvpromote_low",3544r#"3545Converts packed single precision floating point to packed double precision floating point.35463547Considering only the lower half of the register, the low lanes in `x` are interpreted as3548single precision floats that are then converted to a double precision floats.35493550The result type will have half the number of vector lanes as the input. Fvpromote_low is3551constrained to input F32x4 with a result type of F64x2.3552"#,3553&formats.unary,3554)3555.operands_in(vec![Operand::new("a", F32x4)])3556.operands_out(vec![Operand::new("x", F64x2)]),3557);35583559let IntTo = &TypeVar::new(3560"IntTo",3561"An scalar only integer type",3562TypeSetBuilder::new().ints(Interval::All).build(),3563);35643565ig.push(3566Inst::new(3567"fcvt_to_uint",3568r#"3569Converts floating point scalars to unsigned integer.35703571Only operates on `x` if it is a scalar. If `x` is NaN or if3572the unsigned integral value cannot be represented in the result3573type, this instruction traps.35743575"#,3576&formats.unary,3577)3578.operands_in(vec![Operand::new("x", FloatScalar)])3579.operands_out(vec![Operand::new("a", IntTo)])3580.can_trap()3581.side_effects_idempotent(),3582);35833584ig.push(3585Inst::new(3586"fcvt_to_sint",3587r#"3588Converts floating point scalars to signed integer.35893590Only operates on `x` if it is a scalar. If `x` is NaN or if3591the unsigned integral value cannot be represented in the result3592type, this instruction traps.35933594"#,3595&formats.unary,3596)3597.operands_in(vec![Operand::new("x", FloatScalar)])3598.operands_out(vec![Operand::new("a", IntTo)])3599.can_trap()3600.side_effects_idempotent(),3601);36023603let IntTo = &TypeVar::new(3604"IntTo",3605"A larger integer type with the same number of lanes",3606TypeSetBuilder::new()3607.ints(Interval::All)3608.simd_lanes(Interval::All)3609.build(),3610);36113612ig.push(3613Inst::new(3614"fcvt_to_uint_sat",3615r#"3616Convert floating point to unsigned integer as fcvt_to_uint does, but3617saturates the input instead of trapping. NaN and negative values are3618converted to 0.3619"#,3620&formats.unary,3621)3622.operands_in(vec![Operand::new("x", Float)])3623.operands_out(vec![Operand::new("a", IntTo)]),3624);36253626ig.push(3627Inst::new(3628"fcvt_to_sint_sat",3629r#"3630Convert floating point to signed integer as fcvt_to_sint does, but3631saturates the input instead of trapping. NaN values are converted to 0.3632"#,3633&formats.unary,3634)3635.operands_in(vec![Operand::new("x", Float)])3636.operands_out(vec![Operand::new("a", IntTo)]),3637);36383639ig.push(3640Inst::new(3641"x86_cvtt2dq",3642r#"3643A float-to-integer conversion instruction for vectors-of-floats which3644has the same semantics as `cvttp{s,d}2dq` on x86. This specifically3645returns `INT_MIN` for NaN or out-of-bounds lanes.3646"#,3647&formats.unary,3648)3649.operands_in(vec![Operand::new("x", Float)])3650.operands_out(vec![Operand::new("a", IntTo)]),3651);36523653let Int = &TypeVar::new(3654"Int",3655"A scalar or vector integer type",3656TypeSetBuilder::new()3657.ints(Interval::All)3658.simd_lanes(Interval::All)3659.build(),3660);36613662let FloatTo = &TypeVar::new(3663"FloatTo",3664"A scalar or vector floating point number",3665TypeSetBuilder::new()3666.floats(Interval::All)3667.simd_lanes(Interval::All)3668.build(),3669);36703671ig.push(3672Inst::new(3673"fcvt_from_uint",3674r#"3675Convert unsigned integer to floating point.36763677Each lane in `x` is interpreted as an unsigned integer and converted to3678floating point using round to nearest, ties to even.36793680The result type must have the same number of vector lanes as the input.3681"#,3682&formats.unary,3683)3684.operands_in(vec![Operand::new("x", Int)])3685.operands_out(vec![Operand::new("a", FloatTo)]),3686);36873688ig.push(3689Inst::new(3690"fcvt_from_sint",3691r#"3692Convert signed integer to floating point.36933694Each lane in `x` is interpreted as a signed integer and converted to3695floating point using round to nearest, ties to even.36963697The result type must have the same number of vector lanes as the input.3698"#,3699&formats.unary,3700)3701.operands_in(vec![Operand::new("x", Int)])3702.operands_out(vec![Operand::new("a", FloatTo)]),3703);37043705let WideInt = &TypeVar::new(3706"WideInt",3707"An integer type of width `i16` upwards",3708TypeSetBuilder::new().ints(16..128).build(),3709);37103711ig.push(3712Inst::new(3713"isplit",3714r#"3715Split an integer into low and high parts.37163717Vectors of integers are split lane-wise, so the results have the same3718number of lanes as the input, but the lanes are half the size.37193720Returns the low half of `x` and the high half of `x` as two independent3721values.3722"#,3723&formats.unary,3724)3725.operands_in(vec![Operand::new("x", WideInt)])3726.operands_out(vec![3727Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`"),3728Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`"),3729]),3730);37313732ig.push(3733Inst::new(3734"iconcat",3735r#"3736Concatenate low and high bits to form a larger integer type.37373738Vectors of integers are concatenated lane-wise such that the result has3739the same number of lanes as the inputs, but the lanes are twice the3740size.3741"#,3742&formats.binary,3743)3744.operands_in(vec![3745Operand::new("lo", NarrowInt),3746Operand::new("hi", NarrowInt),3747])3748.operands_out(vec![3749Operand::new("a", &NarrowInt.double_width())3750.with_doc("The concatenation of `lo` and `hi`"),3751]),3752);37533754// Instructions relating to atomic memory accesses and fences3755let AtomicMem = &TypeVar::new(3756"AtomicMem",3757"Any type that can be stored in memory, which can be used in an atomic operation",3758TypeSetBuilder::new().ints(8..128).build(),3759);37603761ig.push(3762Inst::new(3763"atomic_rmw",3764r#"3765Atomically read-modify-write memory at `p`, with second operand `x`. The old value is3766returned. `p` has the type of the target word size, and `x` may be any integer type; note3767that some targets require specific target features to be enabled in order to support 128-bit3768integer atomics. The type of the returned value is the same as the type of `x`. This3769operation is sequentially consistent and creates happens-before edges that order normal3770(non-atomic) loads and stores.3771"#,3772&formats.atomic_rmw,3773)3774.operands_in(vec![3775Operand::new("MemFlags", &imm.memflags),3776Operand::new("AtomicRmwOp", &imm.atomic_rmw_op),3777Operand::new("p", iAddr),3778Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"),3779])3780.operands_out(vec![3781Operand::new("a", AtomicMem).with_doc("Value atomically loaded"),3782])3783.can_load()3784.can_store()3785.other_side_effects(),3786);37873788ig.push(3789Inst::new(3790"atomic_cas",3791r#"3792Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,3793storing `x` if the value at `p` equals `e`. The old value at `p` is returned,3794regardless of whether the operation succeeds or fails. `p` has the type of the target3795word size, and `x` and `e` must have the same type and the same size, which may be any3796integer type; note that some targets require specific target features to be enabled in order3797to support 128-bit integer atomics. The type of the returned value is the same as the type3798of `x` and `e`. This operation is sequentially consistent and creates happens-before edges3799that order normal (non-atomic) loads and stores.3800"#,3801&formats.atomic_cas,3802)3803.operands_in(vec![3804Operand::new("MemFlags", &imm.memflags),3805Operand::new("p", iAddr),3806Operand::new("e", AtomicMem).with_doc("Expected value in CAS"),3807Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"),3808])3809.operands_out(vec![3810Operand::new("a", AtomicMem).with_doc("Value atomically loaded"),3811])3812.can_load()3813.can_store()3814.other_side_effects(),3815);38163817ig.push(3818Inst::new(3819"atomic_load",3820r#"3821Atomically load from memory at `p`.38223823This is a polymorphic instruction that can load any value type which has a memory3824representation. It can only be used for integer types; note that some targets require3825specific target features to be enabled in order to support 128-bit integer atomics. This3826operation is sequentially consistent and creates happens-before edges that order normal3827(non-atomic) loads and stores.3828"#,3829&formats.load_no_offset,3830)3831.operands_in(vec![3832Operand::new("MemFlags", &imm.memflags),3833Operand::new("p", iAddr),3834])3835.operands_out(vec![3836Operand::new("a", AtomicMem).with_doc("Value atomically loaded"),3837])3838.can_load()3839.other_side_effects(),3840);38413842ig.push(3843Inst::new(3844"atomic_store",3845r#"3846Atomically store `x` to memory at `p`.38473848This is a polymorphic instruction that can store any value type with a memory3849representation. It can only be used for integer types; note that some targets require3850specific target features to be enabled in order to support 128-bit integer atomics This3851operation is sequentially consistent and creates happens-before edges that order normal3852(non-atomic) loads and stores.3853"#,3854&formats.store_no_offset,3855)3856.operands_in(vec![3857Operand::new("MemFlags", &imm.memflags),3858Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"),3859Operand::new("p", iAddr),3860])3861.can_store()3862.other_side_effects(),3863);38643865ig.push(3866Inst::new(3867"fence",3868r#"3869A memory fence. This must provide ordering to ensure that, at a minimum, neither loads3870nor stores of any kind may move forwards or backwards across the fence. This operation3871is sequentially consistent.3872"#,3873&formats.nullary,3874)3875.other_side_effects(),3876);38773878let TxN = &TypeVar::new(3879"TxN",3880"A dynamic vector type",3881TypeSetBuilder::new()3882.ints(Interval::All)3883.floats(Interval::All)3884.dynamic_simd_lanes(Interval::All)3885.build(),3886);38873888ig.push(3889Inst::new(3890"extract_vector",3891r#"3892Return a fixed length sub vector, extracted from a dynamic vector.3893"#,3894&formats.binary_imm8,3895)3896.operands_in(vec![3897Operand::new("x", TxN).with_doc("The dynamic vector to extract from"),3898Operand::new("y", &imm.uimm8).with_doc("128-bit vector index"),3899])3900.operands_out(vec![3901Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector"),3902]),3903);3904}390539063907