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