Path: blob/main/cranelift/assembler-x64/meta/src/instructions.rs
1692 views
//! Defines x64 instructions using the DSL.12mod abs;3mod add;4mod align;5mod and;6mod atomic;7mod avg;8mod bitmanip;9mod cmov;10mod cmp;11mod cvt;12mod div;13mod fma;14mod jmp;15mod lanes;16mod max;17mod min;18mod misc;19mod mov;20mod mul;21mod neg;22mod nop;23mod or;24mod pack;25mod pma;26mod recip;27mod round;28mod setcc;29mod shift;30mod sqrt;31mod stack;32mod sub;33mod unpack;34mod xor;3536use crate::dsl::{Feature, Inst, Mutability, OperandKind};37use std::collections::HashMap;3839#[must_use]40pub fn list() -> Vec<Inst> {41let mut all = vec![];42all.extend(abs::list());43all.extend(add::list());44all.extend(align::list());45all.extend(and::list());46all.extend(atomic::list());47all.extend(avg::list());48all.extend(bitmanip::list());49all.extend(cmov::list());50all.extend(cmp::list());51all.extend(cvt::list());52all.extend(div::list());53all.extend(fma::list());54all.extend(jmp::list());55all.extend(lanes::list());56all.extend(max::list());57all.extend(min::list());58all.extend(misc::list());59all.extend(mov::list());60all.extend(mul::list());61all.extend(neg::list());62all.extend(nop::list());63all.extend(or::list());64all.extend(pack::list());65all.extend(pma::list());66all.extend(recip::list());67all.extend(round::list());68all.extend(setcc::list());69all.extend(shift::list());70all.extend(sqrt::list());71all.extend(stack::list());72all.extend(sub::list());73all.extend(unpack::list());74all.extend(xor::list());7576check_avx_alternates(&mut all);7778all79}8081/// Checks that assigned AVX alternates are correctly applied to SSE82/// instructions.83///84/// # Panics85///86/// Expects that each AVX alternate to be of an SSE instruction (currently).87fn check_avx_alternates(all: &mut [Inst]) {88let name_to_index: HashMap<String, usize> = all89.iter()90.enumerate()91.map(|(index, inst)| (inst.name().clone(), index))92.collect();93for inst in all.iter().filter(|inst| inst.alternate.is_some()) {94assert!(95inst.features.is_sse(),96"expected an SSE instruction: {inst}"97);98let alternate = inst.alternate.as_ref().unwrap();99assert_eq!(alternate.feature, Feature::avx);100let avx_index = name_to_index.get(&alternate.name).expect(&format!(101"invalid alternate name: {} (did you use the full `<mnemonic>_<format>` form?)",102alternate.name103));104check_sse_matches_avx(inst, &all[*avx_index]);105}106}107108/// Checks if the SSE instruction `sse_inst` matches the AVX instruction109/// `avx_inst` in terms of operands and opcode.110///111/// # Panics112///113/// Panics for any condition indicating that the SSE and AVX instructions do not114/// match:115/// - the AVX instruction does not have a 'v' prefix116/// - the SSE and AVX instructions do not have the same opcode117/// - the operand formats do not match the expected patterns118fn check_sse_matches_avx(sse_inst: &Inst, avx_inst: &Inst) {119use crate::dsl::{Mutability::*, OperandKind::*};120121debug_assert_eq!(122&format!("v{}", sse_inst.mnemonic),123&avx_inst.mnemonic,124"an alternate AVX instruction should have a 'v' prefix: {avx_inst}"125);126127if sse_inst.encoding.opcode() != avx_inst.encoding.opcode() {128panic!("alternate instructions should have the same opcode:\n{sse_inst}\n{avx_inst}");129}130131match (list_ops(sse_inst).as_slice(), list_ops(avx_inst).as_slice()) {132// For now, we only really want to tie together SSE instructions that133// look like `rw(xmm), r(xmm_m*)` with their AVX counterpart that looks134// like `w(xmm), r(xmm), r(xmm_m*)`. This is because the relationship135// between these kinds of instructions is quite regular. Other formats136// may have slightly different operand semantics (e.g., `roundss` ->137// `vroundss`) and we want to be careful about matching too freely.138(139[140(ReadWrite | Write, Reg(_)),141(Read, Reg(_) | RegMem(_) | Mem(_)),142],143[144(Write, Reg(_)),145(Read, Reg(_)),146(Read, Reg(_) | RegMem(_) | Mem(_)),147],148) => {}149(150[(ReadWrite, Reg(_)), (Read, RegMem(_)), (Read, Imm(_))],151[152(Write, Reg(_)),153(Read, Reg(_)),154(Read, RegMem(_)),155(Read, Imm(_)),156],157) => {}158(159[(ReadWrite, Reg(_)), (Read, Imm(_))],160[(Write, Reg(_)), (Read, Reg(_)), (Read, Imm(_))],161) => {}162// The following formats are identical.163(164[165(Write, Reg(_) | RegMem(_) | Mem(_)),166(Read, Reg(_) | RegMem(_) | Mem(_)),167],168[169(Write, Reg(_) | RegMem(_) | Mem(_)),170(Read, Reg(_) | RegMem(_) | Mem(_)),171],172) => {}173(174[175(Write, Reg(_) | RegMem(_)),176(Read, Reg(_) | RegMem(_)),177(Read, Imm(_)),178],179[180(Write, Reg(_) | RegMem(_)),181(Read, Reg(_) | RegMem(_)),182(Read, Imm(_)),183],184) => {}185([(Read, Reg(_)), (Read, RegMem(_))], [(Read, Reg(_)), (Read, RegMem(_))]) => {}186// We panic on other formats for now; feel free to add more patterns to187// avoid this.188_ => panic!(189"unmatched formats for SSE-to-AVX alternate:\n{sse_inst}\n{avx_inst}. {:?}, {:?}",190list_ops(sse_inst),191list_ops(avx_inst)192),193}194}195196/// Collect the mutability and kind of each operand in an instruction.197fn list_ops(inst: &Inst) -> Vec<(Mutability, OperandKind)> {198inst.format199.operands200.iter()201.map(|o| (o.mutability, o.location.kind()))202.collect()203}204205206