Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/x64/inst/emit_tests.rs
1693 views
1
//! Tests for the emitter
2
//!
3
//! See comments at the top of `fn x64_emit` for advice on how to create reliable test cases.
4
//!
5
//! to see stdout: cargo test -- --nocapture
6
//!
7
//! for this specific case, as of 24 Aug 2020:
8
//!
9
//! cd to the top of your wasmtime tree, then:
10
//!
11
//! RUST_BACKTRACE=1 cargo test --features test-programs/test_programs \
12
//! --all --exclude wasmtime-wasi-nn \
13
//! -- isa::x64::inst::emit_tests::test_x64_emit
14
15
use super::*;
16
use crate::ir::UserExternalNameRef;
17
use crate::isa::x64;
18
use crate::isa::x64::lower::isle::generated_code::{Atomic128RmwSeqOp, AtomicRmwSeqOp};
19
use alloc::vec::Vec;
20
use cranelift_entity::EntityRef as _;
21
22
#[test]
23
fn test_x64_emit() {
24
let rax = regs::rax();
25
let rbx = regs::rbx();
26
let rcx = regs::rcx();
27
let rdx = regs::rdx();
28
let rsi = regs::rsi();
29
let _rdi = regs::rdi();
30
let rsp = regs::rsp();
31
let rbp = regs::rbp();
32
let r8 = regs::r8();
33
let r9 = regs::r9();
34
let r10 = regs::r10();
35
let r11 = regs::r11();
36
let r14 = regs::r14();
37
let r15 = regs::r15();
38
39
let xmm0 = regs::xmm0();
40
let xmm1 = regs::xmm1();
41
let xmm2 = regs::xmm2();
42
let xmm3 = regs::xmm3();
43
let xmm4 = regs::xmm4();
44
let _xmm5 = regs::xmm5();
45
let xmm6 = regs::xmm6();
46
let xmm7 = regs::xmm7();
47
let xmm8 = regs::xmm8();
48
let xmm9 = regs::xmm9();
49
let xmm10 = regs::xmm10();
50
let xmm11 = regs::xmm11();
51
let xmm12 = regs::xmm12();
52
let _xmm13 = regs::xmm13();
53
let _xmm14 = regs::xmm14();
54
let _xmm15 = regs::xmm15();
55
56
// And Writable<> versions of the same:
57
let w_rax = Writable::<Reg>::from_reg(rax);
58
let w_rbx = Writable::<Reg>::from_reg(rbx);
59
let w_rcx = Writable::<Reg>::from_reg(rcx);
60
let w_rdx = Writable::<Reg>::from_reg(rdx);
61
let _w_rsi = Writable::<Reg>::from_reg(rsi);
62
let _w_rsp = Writable::<Reg>::from_reg(rsp);
63
let _w_rbp = Writable::<Reg>::from_reg(rbp);
64
let _w_r8 = Writable::<Reg>::from_reg(r8);
65
let _w_r9 = Writable::<Reg>::from_reg(r9);
66
let w_r11 = Writable::<Reg>::from_reg(r11);
67
let _w_r14 = Writable::<Reg>::from_reg(r14);
68
let _w_r15 = Writable::<Reg>::from_reg(r15);
69
70
let _w_xmm0 = Writable::<Reg>::from_reg(xmm0);
71
let _w_xmm1 = Writable::<Reg>::from_reg(xmm1);
72
let _w_xmm2 = Writable::<Reg>::from_reg(xmm2);
73
let _w_xmm3 = Writable::<Reg>::from_reg(xmm3);
74
let _w_xmm4 = Writable::<Reg>::from_reg(xmm4);
75
let _w_xmm6 = Writable::<Reg>::from_reg(xmm6);
76
let _w_xmm7 = Writable::<Reg>::from_reg(xmm7);
77
let _w_xmm8 = Writable::<Reg>::from_reg(xmm8);
78
let _w_xmm9 = Writable::<Reg>::from_reg(xmm9);
79
let _w_xmm10 = Writable::<Reg>::from_reg(xmm10);
80
let _w_xmm11 = Writable::<Reg>::from_reg(xmm11);
81
let _w_xmm12 = Writable::<Reg>::from_reg(xmm12);
82
83
let mut insns = Vec::<(Inst, &str, &str)>::new();
84
85
// End of test cases for Addr
86
// ========================================================
87
88
// ========================================================
89
// General tests for each insn. Don't forget to follow the
90
// guidelines commented just prior to `fn x64_emit`.
91
//
92
93
// ========================================================
94
// CallKnown
95
insns.push((
96
Inst::call_known(Box::new(CallInfo::empty(
97
ExternalName::User(UserExternalNameRef::new(0)),
98
CallConv::SystemV,
99
))),
100
"E800000000",
101
"call User(userextname0)",
102
));
103
104
// ========================================================
105
// CallUnknown
106
fn call_unknown(rm: RegMem) -> Inst {
107
Inst::call_unknown(Box::new(CallInfo::empty(rm, CallConv::SystemV)))
108
}
109
110
insns.push((call_unknown(RegMem::reg(rbp)), "FFD5", "call *%rbp"));
111
insns.push((call_unknown(RegMem::reg(r11)), "41FFD3", "call *%r11"));
112
insns.push((
113
call_unknown(RegMem::mem(Amode::imm_reg_reg_shift(
114
321,
115
Gpr::unwrap_new(rsi),
116
Gpr::unwrap_new(rcx),
117
3,
118
))),
119
"FF94CE41010000",
120
"call *321(%rsi,%rcx,8)",
121
));
122
insns.push((
123
call_unknown(RegMem::mem(Amode::imm_reg_reg_shift(
124
321,
125
Gpr::unwrap_new(r10),
126
Gpr::unwrap_new(rdx),
127
2,
128
))),
129
"41FF949241010000",
130
"call *321(%r10,%rdx,4)",
131
));
132
133
// ========================================================
134
// LoadExtName
135
// N.B.: test harness below sets is_pic.
136
insns.push((
137
Inst::LoadExtName {
138
dst: Writable::from_reg(Gpr::R11),
139
name: Box::new(ExternalName::User(UserExternalNameRef::new(0))),
140
offset: 0,
141
distance: RelocDistance::Far,
142
},
143
"4C8B1D00000000",
144
"load_ext_name userextname0+0, %r11",
145
));
146
insns.push((
147
Inst::LoadExtName {
148
dst: Writable::from_reg(Gpr::R11),
149
name: Box::new(ExternalName::User(UserExternalNameRef::new(0))),
150
offset: 0x12345678,
151
distance: RelocDistance::Far,
152
},
153
"4C8B1D000000004981C378563412",
154
"load_ext_name userextname0+305419896, %r11",
155
));
156
insns.push((
157
Inst::LoadExtName {
158
dst: Writable::from_reg(Gpr::R11),
159
name: Box::new(ExternalName::User(UserExternalNameRef::new(0))),
160
offset: -0x12345678,
161
distance: RelocDistance::Far,
162
},
163
"4C8B1D000000004981C388A9CBED",
164
"load_ext_name userextname0+-305419896, %r11",
165
));
166
167
// ========================================================
168
// JmpKnown skipped for now
169
170
// ========================================================
171
// JmpCondSymm isn't a real instruction
172
173
// ========================================================
174
// JmpCond skipped for now
175
176
// ========================================================
177
// JmpCondCompound isn't a real instruction
178
179
// ========================================================
180
// Pertaining to atomics.
181
// Use `r9` with a 0 offset.
182
let am3: SyntheticAmode = Amode::imm_reg(0, r9).into();
183
184
// AtomicRmwSeq
185
insns.push((
186
Inst::AtomicRmwSeq {
187
ty: types::I8,
188
op: AtomicRmwSeqOp::Or,
189
mem: am3.clone(),
190
operand: Gpr::unwrap_new(r10),
191
temp: w_r11.map(Gpr::unwrap_new),
192
dst_old: w_rax.map(Gpr::unwrap_new),
193
},
194
"490FB6014989C34D0BDAF0450FB0190F85EFFFFFFF",
195
"atomically { 8_bits_at_[%r9] Or= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }",
196
));
197
insns.push((
198
Inst::AtomicRmwSeq {
199
ty: types::I16,
200
op: AtomicRmwSeqOp::And,
201
mem: am3.clone(),
202
operand: Gpr::unwrap_new(r10),
203
temp: w_r11.map(Gpr::unwrap_new),
204
dst_old: w_rax.map(Gpr::unwrap_new)
205
},
206
"490FB7014989C34D23DAF066450FB1190F85EEFFFFFF",
207
"atomically { 16_bits_at_[%r9] And= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }"
208
));
209
insns.push((
210
Inst::AtomicRmwSeq {
211
ty: types::I32,
212
op: AtomicRmwSeqOp::Nand,
213
mem: am3.clone(),
214
operand: Gpr::unwrap_new(r10),
215
temp: w_r11.map(Gpr::unwrap_new),
216
dst_old: w_rax.map(Gpr::unwrap_new)
217
},
218
"418B014989C34D23DA49F7D3F0450FB1190F85ECFFFFFF",
219
"atomically { 32_bits_at_[%r9] Nand= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }"
220
));
221
insns.push((
222
Inst::AtomicRmwSeq {
223
ty: types::I32,
224
op: AtomicRmwSeqOp::Umin,
225
mem: am3.clone(),
226
operand: Gpr::unwrap_new(r10),
227
temp: w_r11.map(Gpr::unwrap_new),
228
dst_old: w_rax.map(Gpr::unwrap_new)
229
},
230
"418B014989C34539DA4D0F46DAF0450FB1190F85EBFFFFFF",
231
"atomically { 32_bits_at_[%r9] Umin= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }"
232
));
233
insns.push((
234
Inst::AtomicRmwSeq {
235
ty: types::I64,
236
op: AtomicRmwSeqOp::Smax,
237
mem: am3.clone(),
238
operand: Gpr::unwrap_new(r10),
239
temp: w_r11.map(Gpr::unwrap_new),
240
dst_old: w_rax.map(Gpr::unwrap_new)
241
},
242
"498B014989C34D39DA4D0F4DDAF04D0FB1190F85EBFFFFFF",
243
"atomically { 64_bits_at_[%r9] Smax= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }"
244
));
245
246
// Atomic128RmwSeq
247
insns.push((
248
Inst::Atomic128RmwSeq {
249
op: Atomic128RmwSeqOp::Or,
250
mem: Box::new(am3.clone()),
251
operand_low: Gpr::unwrap_new(r10),
252
operand_high: Gpr::unwrap_new(r11),
253
temp_low: w_rbx.map(Gpr::unwrap_new),
254
temp_high: w_rcx.map(Gpr::unwrap_new),
255
dst_old_low: w_rax.map(Gpr::unwrap_new),
256
dst_old_high: w_rdx.map(Gpr::unwrap_new),
257
},
258
"498B01498B51084889C34889D1490BDA490BCBF0490FC7090F85E9FFFFFF",
259
"atomically { %rdx:%rax = 0(%r9); %rcx:%rbx = %rdx:%rax Or %r11:%r10; 0(%r9) = %rcx:%rbx }",
260
));
261
insns.push((
262
Inst::Atomic128RmwSeq {
263
op: Atomic128RmwSeqOp::And,
264
mem: Box::new(am3.clone()),
265
operand_low: Gpr::unwrap_new(r10),
266
operand_high: Gpr::unwrap_new(r11),
267
temp_low: w_rbx.map(Gpr::unwrap_new),
268
temp_high: w_rcx.map(Gpr::unwrap_new),
269
dst_old_low: w_rax.map(Gpr::unwrap_new),
270
dst_old_high: w_rdx.map(Gpr::unwrap_new),
271
},
272
"498B01498B51084889C34889D14923DA4923CBF0490FC7090F85E9FFFFFF",
273
"atomically { %rdx:%rax = 0(%r9); %rcx:%rbx = %rdx:%rax And %r11:%r10; 0(%r9) = %rcx:%rbx }"
274
));
275
insns.push((
276
Inst::Atomic128RmwSeq {
277
op: Atomic128RmwSeqOp::Umin,
278
mem: Box::new(am3.clone()),
279
operand_low: Gpr::unwrap_new(r10),
280
operand_high: Gpr::unwrap_new(r11),
281
temp_low: w_rbx.map(Gpr::unwrap_new),
282
temp_high: w_rcx.map(Gpr::unwrap_new),
283
dst_old_low: w_rax.map(Gpr::unwrap_new),
284
dst_old_high: w_rdx.map(Gpr::unwrap_new),
285
},
286
"498B01498B51084889C34889D14C39D3491BCB4889D1490F43DA490F43CBF0490FC7090F85DEFFFFFF",
287
"atomically { %rdx:%rax = 0(%r9); %rcx:%rbx = %rdx:%rax Umin %r11:%r10; 0(%r9) = %rcx:%rbx }"
288
));
289
insns.push((
290
Inst::Atomic128RmwSeq {
291
op: Atomic128RmwSeqOp::Add,
292
mem: Box::new(am3.clone()),
293
operand_low: Gpr::unwrap_new(r10),
294
operand_high: Gpr::unwrap_new(r11),
295
temp_low: w_rbx.map(Gpr::unwrap_new),
296
temp_high: w_rcx.map(Gpr::unwrap_new),
297
dst_old_low: w_rax.map(Gpr::unwrap_new),
298
dst_old_high: w_rdx.map(Gpr::unwrap_new),
299
},
300
"498B01498B51084889C34889D14903DA4913CBF0490FC7090F85E9FFFFFF",
301
"atomically { %rdx:%rax = 0(%r9); %rcx:%rbx = %rdx:%rax Add %r11:%r10; 0(%r9) = %rcx:%rbx }"
302
));
303
insns.push((
304
Inst::Atomic128XchgSeq {
305
mem: am3.clone(),
306
operand_low: Gpr::unwrap_new(rbx),
307
operand_high: Gpr::unwrap_new(rcx),
308
dst_old_low: w_rax.map(Gpr::unwrap_new),
309
dst_old_high: w_rdx.map(Gpr::unwrap_new),
310
},
311
"498B01498B5108F0490FC7090F85F5FFFFFF",
312
"atomically { %rdx:%rax = 0(%r9); 0(%r9) = %rcx:%rbx }",
313
));
314
315
// ========================================================
316
// Misc instructions.
317
318
insns.push((
319
Inst::ElfTlsGetAddr {
320
symbol: ExternalName::User(UserExternalNameRef::new(0)),
321
dst: WritableGpr::from_writable_reg(w_rax).unwrap(),
322
},
323
"66488D3D00000000666648E800000000",
324
"%rax = elf_tls_get_addr User(userextname0)",
325
));
326
327
insns.push((
328
Inst::MachOTlsGetAddr {
329
symbol: ExternalName::User(UserExternalNameRef::new(0)),
330
dst: WritableGpr::from_writable_reg(w_rax).unwrap(),
331
},
332
"488B3D00000000FF17",
333
"%rax = macho_tls_get_addr User(userextname0)",
334
));
335
336
insns.push((
337
Inst::CoffTlsGetAddr {
338
symbol: ExternalName::User(UserExternalNameRef::new(0)),
339
dst: WritableGpr::from_writable_reg(w_rax).unwrap(),
340
tmp: WritableGpr::from_writable_reg(w_rcx).unwrap(),
341
},
342
"8B050000000065488B0C2558000000488B04C1488D8000000000",
343
"%rax = coff_tls_get_addr User(userextname0)",
344
));
345
346
// ========================================================
347
// Actually run the tests!
348
let ctrl_plane = &mut Default::default();
349
let constants = Default::default();
350
let mut flag_builder = settings::builder();
351
flag_builder.enable("is_pic").unwrap();
352
let flags = settings::Flags::new(flag_builder);
353
354
use crate::settings::Configurable;
355
let mut isa_flag_builder = x64::settings::builder();
356
isa_flag_builder.enable("has_cmpxchg16b").unwrap();
357
isa_flag_builder.enable("has_ssse3").unwrap();
358
isa_flag_builder.enable("has_sse41").unwrap();
359
isa_flag_builder.enable("has_fma").unwrap();
360
isa_flag_builder.enable("has_avx").unwrap();
361
isa_flag_builder.enable("has_avx512bitalg").unwrap();
362
isa_flag_builder.enable("has_avx512dq").unwrap();
363
isa_flag_builder.enable("has_avx512f").unwrap();
364
isa_flag_builder.enable("has_avx512vbmi").unwrap();
365
isa_flag_builder.enable("has_avx512vl").unwrap();
366
let isa_flags = x64::settings::Flags::new(&flags, &isa_flag_builder);
367
368
let emit_info = EmitInfo::new(flags, isa_flags);
369
for (insn, expected_encoding, expected_printing) in insns {
370
// Check the printed text is as expected.
371
let actual_printing = insn.pretty_print_inst(&mut Default::default());
372
assert_eq!(expected_printing, actual_printing.trim());
373
let mut buffer = MachBuffer::new();
374
375
insn.emit(&mut buffer, &emit_info, &mut Default::default());
376
377
// Allow one label just after the instruction (so the offset is 0).
378
let label = buffer.get_label();
379
buffer.bind_label(label, ctrl_plane);
380
381
let buffer = buffer.finish(&constants, ctrl_plane);
382
let actual_encoding = &buffer.stringify_code_bytes();
383
assert_eq!(expected_encoding, actual_encoding, "{expected_printing}");
384
}
385
}
386
387