v2 / vlib / v / slow_tests / assembly / asm_test.amd64.v
217 lines · 196 sloc · 3.37 KB · 2332ecff4811b8c97dfda8e825170e9397962519
Raw
1// vtest build: !msvc
2import v.slow_tests.assembly.util
3
4fn test_inline_asm() {
5 a, mut b := i64(10), i64(0)
6 asm amd64 {
7 mov rax, a
8 mov b, rax
9 ; +r (b)
10 ; r (a)
11 ; rax
12 }
13 assert a == 10
14 assert b == 10
15
16 mut c := 0
17 asm amd64 {
18 mov c, 5
19 ; +r (c)
20 }
21 assert c == 5
22
23 d, e, mut f := 10, 2, 0
24 asm amd64 {
25 mov f, d
26 add f, e
27 add f, 5
28 ; +r (f) // output
29 ; r (d)
30 r (e) // input
31 }
32 assert d == 10
33 assert e == 2
34 assert f == 17
35
36 // g, h, i := 2.3, 4.8, -3.5
37 // asm rv64 {
38 // fadd.s ${i}, ${g}, ${h} // test `.` in instruction name
39 // : =r (i) as i
40 // : r (g) as g
41 // r (g) as h
42 // }
43 // assert g == 2.3
44 // assert h == 4.8
45 // assert i == 7.1
46
47 mut j := 0
48 // do 5*3
49 // adding three, five times
50 asm amd64 {
51 mov rcx, 5 // loop 5 times
52 loop_start:
53 add j, 3
54 loop loop_start
55 ; +r (j)
56 ; ; rcx
57 }
58 assert j == 5 * 3
59
60 // k := 0 // Wait for tcc to implement goto, and gcc has odd errors
61 // mut loops := 0
62 // outside_label:
63 // if k != 5 {
64 // loops++
65 // asm goto amd64 {
66 // mov k, 1
67 // mov k, 5
68 // jmp outside_label
69 // ; =r (k) as k
70 // ; r (k)
71 // ;
72 // ; outside_label
73 // }
74 // }
75 // assert loops == 1
76 // assert k == 5
77
78 // not marked as mut because we dereference m to change l
79 l := 5
80 m := &l
81 asm amd64 {
82 movq [m], 7 // have to specify size with q
83 ; ; r (m)
84 ; memory
85 }
86 assert l == 7
87
88 // same as above
89 n := [5, 9, 0, 4]
90 asm amd64 {
91 loop_start2:
92 addq [in_data + rcx * 4 + 0], 2
93 loop loop_start2
94 addq [in_data + rcx * 4 + 0], 2
95 ; ; c (n.len - 1) // c is counter (loop) register
96 r (n.data) as in_data
97 ; memory
98 }
99 assert n == [7, 11, 2, 6]
100
101 assert util.add(8, 9, 34, 7) == 58 // test .amd64.v imported files
102
103 mut o := &Manu{}
104 asm amd64 {
105 mov eax, 0
106 cpuid
107 ; =b (o.ebx) as ebx0
108 =d (o.edx) as edx0
109 =c (o.ecx) as ecx0
110 ; ; eax
111 }
112 assert o.str()[0].is_capital()
113}
114
115@[packed]
116struct Manu {
117mut:
118 ebx u32
119 edx u32
120 ecx u32
121 zero u8 // for string
122}
123
124fn (m &Manu) str() string {
125 return unsafe {
126 string{
127 str: &u8(m)
128 len: 12
129 is_lit: 1
130 }
131 }
132}
133
134// this test does not appear in i386 test since rip relative addressing was introduced in 64-bit mode
135// doesn't actually work
136@[if !macos]
137fn test_rip_relative_label() {
138 $if !macos {
139 mut a := i64(4)
140 asm amd64 {
141 mov a, [rip + one_two_three] // see below
142 ; =r (a)
143 }
144 assert a == 48321074923
145 }
146}
147
148$if !macos {
149 asm amd64 {
150 .global one_two_three
151 one_two_three:
152 .quad 48321074923
153 }
154}
155
156// this test does not appear in i386 test since rip relative addressing was introduced in 64-bit mode
157// doesn't actually work
158@[if !macos]
159fn test_rip_relative_label_u8() {
160 $if !macos {
161 mut a := int(4)
162 asm amd64 {
163 mov a, [rip + byte_sequence] // see below
164 ; =r (a)
165 }
166 assert a == 0x480f3527
167 }
168}
169
170$if !macos {
171 asm amd64 {
172 .global byte_sequence
173 byte_sequence:
174 .byte 0x27, 0x35, 0x0f, 0x48
175 }
176}
177
178fn test_asm_generic() {
179 u := u64(49)
180 assert generic_asm(u) == 14
181 assert u == 63
182
183 i := i32(123)
184 assert generic_asm(i) == 14
185 assert i == 137
186}
187
188fn generic_asm[T](var &T) T {
189 mut ret := T(14)
190 unsafe {
191 asm volatile amd64 {
192 add var, ret
193 ; +m (var[0]) as var
194 +r (ret)
195 ; ; memory
196 }
197 }
198 return ret
199}
200
201fn test_lock_prefix() {
202 mut rv := u64(123)
203 mut atom := u64(0)
204 cmp := u64(1)
205 xchg := u64(1)
206
207 asm amd64 {
208 lock cmpxchgq '%1', '%2'
209 ; =a (rv)
210 +m (atom)
211 ; q (xchg)
212 0 (cmp)
213 ; memory
214 }
215 assert rv == 0
216 assert atom == 0
217}
218