RISC-V: Do not inline when callee is versioned but caller is not
[official-gcc.git] / gcc / testsuite / jit.dg / test-asm.cc
blobd436f582351e4cff34998473ca0965e3fa0df499
1 /* { dg-do compile { target x86_64-*-* } } */
3 #include <stdint.h>
4 #include "libgccjit++.h"
6 #include "harness.h"
8 /**********************************************************************
9 Support fns for creating code.
10 **********************************************************************/
12 /* Make a "void FUNC_NAME (void)" function with a single block, returning
13 that block. */
15 static gccjit::block
16 make_single_block_func (gccjit::context ctxt, const char *func_name)
18 gccjit::type void_type = ctxt.get_type (GCC_JIT_TYPE_VOID);
19 std::vector<gccjit::param> params;
20 gccjit::function func
21 = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
22 void_type,
23 func_name, params, 0);
24 return func.new_block ("initial");
27 /**********************************************************************
28 Support fns for verifying code.
29 **********************************************************************/
31 typedef void (*void_void_fn) (void);
33 static void_void_fn
34 get_test_fn (gcc_jit_result *result, const char *func_name)
36 return (void_void_fn)gcc_jit_result_get_code (result, func_name);
39 /**********************************************************************
40 test_i386_basic_asm_1: simple example of asm
41 **********************************************************************/
43 /* Create the equivalent of:
45 int src;
46 int dst;
48 void test_i386_basic_asm_1 (void)
50 // Quote from here in docs/cp/topics/asm.rst: example 1: C
51 asm ("mov %1, %0\n\t"
52 "add $1, %0"
53 : "=r" (dst)
54 : "r" (src));
55 // Quote up to here in docs/cp/topics/asm.rst: example 1: C
58 i.e. copy src to dst and add 1 to dst. */
60 static void
61 create_test_i386_basic_asm_1 (gcc_jit_context *c_ctxt)
63 gccjit::context ctxt (c_ctxt);
64 gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
65 gccjit::lvalue dst
66 = ctxt.new_global (GCC_JIT_GLOBAL_EXPORTED, int_type, "dst");
67 gccjit::lvalue src
68 = ctxt.new_global (GCC_JIT_GLOBAL_EXPORTED, int_type, "src");
70 gccjit::block block
71 = make_single_block_func (ctxt, "test_i386_basic_asm_1");
73 gccjit::extended_asm ext_asm =
74 /* Quote from here in docs/cp/topics/asm.rst: example 1: jit. */
75 block.add_extended_asm ("mov %1, %0\n\t"
76 "add $1, %0")
77 .add_output_operand ("=r", dst)
78 .add_input_operand ("r", src);
79 /* Quote up to here in docs/cp/topics/asm.rst: example 1: jit. */
81 std::string desc = ext_asm.get_debug_string ();
82 CHECK_STRING_VALUE
83 (desc.c_str (),
84 "asm (\"mov %1, %0\\n\\tadd $1, %0\" : \"=r\" (dst) : \"r\" (src) : )");
86 block.end_with_return ();
89 static void
90 verify_code_1 (gcc_jit_context *ctxt, gcc_jit_result *result)
92 void_void_fn test_i386_basic_asm_1
93 = get_test_fn (result, "test_i386_basic_asm_1");
94 CHECK_NON_NULL (test_i386_basic_asm_1);
96 int *dst_ptr = (int *)gcc_jit_result_get_global (result, "dst");
97 CHECK_NON_NULL (dst_ptr);
98 int *src_ptr = (int *)gcc_jit_result_get_global (result, "src");
99 CHECK_NON_NULL (src_ptr);
101 *src_ptr = 42;
102 *dst_ptr = 0;
103 test_i386_basic_asm_1 ();
104 CHECK_VALUE (*src_ptr, 42);
105 CHECK_VALUE (*dst_ptr, 43);
108 /**********************************************************************
109 test_i386_basic_asm_2: test of symbolic names and clobbers
110 **********************************************************************/
112 /* Create the equivalent of:
113 uint32_t test_i386_basic_asm_2 (uint32_t Mask)
115 uint32_t Index;
116 // Quote from here in docs/cp/topics/asm.rst: example 2: C
117 asm ("bsfl %[aMask], %[aIndex]"
118 : [aIndex] "=r" (Index)
119 : [aMask] "r" (Mask)
120 : "cc");
121 // Quote up to here in docs/cp/topics/asm.rst: example 2: C
122 return Index;
124 i.e. return the first bit set in "Mask"
126 This exercises symbolic names and clobbers. */
128 static void
129 create_test_i386_basic_asm_2 (gcc_jit_context *c_ctxt)
131 gccjit::context ctxt (c_ctxt);
132 gccjit::type uint32_type = ctxt.get_int_type (4, 0);
133 gccjit::param mask = ctxt.new_param (uint32_type, "Mask");
134 std::vector<gccjit::param> params {mask};
135 gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
136 uint32_type,
137 "test_i386_basic_asm_2",
138 params, 0);
139 gccjit::lvalue index = func.new_local (uint32_type, "Index");
140 gccjit::block block = func.new_block ("initial");
141 gccjit::extended_asm ext_asm =
142 /* Quote from here in docs/cp/topics/asm.rst: example 2: jit. */
143 block.add_extended_asm ("bsfl %[aMask], %[aIndex]")
144 .add_output_operand ("aIndex", "=r", index)
145 .add_input_operand ("aMask", "r", mask)
146 .add_clobber ("cc");
147 /* Quote up to here in docs/cp/topics/asm.rst: example 2: jit. */
149 std::string desc = ext_asm.get_debug_string ();
150 CHECK_STRING_VALUE
151 (desc.c_str (),
152 "asm (\"bsfl %[aMask], %[aIndex]\""
153 " : [aIndex] \"=r\" (Index) : [aMask] \"r\" (Mask) : \"cc\")");
155 block.end_with_return (index);
158 static void
159 verify_code_2 (gcc_jit_context *ctxt, gcc_jit_result *result)
161 typedef uint32_t (*fntype) (uint32_t);
162 fntype test_i386_basic_asm_2
163 = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_2");
164 CHECK_NON_NULL (test_i386_basic_asm_2);
166 CHECK_VALUE (test_i386_basic_asm_2 (1), 0);
167 CHECK_VALUE (test_i386_basic_asm_2 (2), 1);
168 CHECK_VALUE (test_i386_basic_asm_2 (4), 2);
169 CHECK_VALUE (test_i386_basic_asm_2 (8), 3);
172 /**********************************************************************
173 test_i386_basic_asm_3a/b: test of control flow: "asm goto"
174 **********************************************************************/
176 /* Create the equivalent of:
178 int test_i386_basic_asm_3a (int p1, int p2)
180 asm goto ("btl %1, %0\n\t"
181 "jc %l2"
182 : // No outputs
183 : "r" (p1), "r" (p2)
184 : "cc"
185 : carry);
187 return 0;
189 carry:
190 return 1;
193 or (the "_3b" variant) using a name rather than a number for the goto
194 label:
196 // Quote from here in docs/cp/topics/asm.rst: example 3b: C
197 asm goto ("btl %1, %0\n\t"
198 "jc %l[carry]"
199 : // No outputs
200 : "r" (p1), "r" (p2)
201 : "cc"
202 : carry);
203 // Quote up to here in docs/cp/topics/asm.rst: example 3b: C
205 This exercises control flow with an asm. */
207 static void
208 create_test_i386_basic_asm_3 (gcc_jit_context *c_ctxt,
209 const char *funcname,
210 int use_name)
212 gccjit::context ctxt (c_ctxt);
213 gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
214 gccjit::param p1 = ctxt.new_param (int_type, "p1");
215 gccjit::param p2 = ctxt.new_param (int_type, "p2");
216 std::vector<gccjit::param> params ({p1, p2});
217 gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
218 int_type,
219 funcname,
220 params, 0);
221 gccjit::block b_start = func.new_block ("start");
222 gccjit::block b_fallthru = func.new_block ("fallthru");
223 gccjit::block b_carry = func.new_block ("carry");
225 gccjit::rvalue zero = ctxt.new_rvalue (int_type, 0);
226 gccjit::rvalue one = ctxt.new_rvalue (int_type, 1);
228 /* Quote from here in docs/cp/topics/asm.rst: example 3: jit. */
229 const char *asm_template =
230 (use_name
231 ? /* Label referred to by name: "%l[carry]". */
232 ("btl %1, %0\n\t"
233 "jc %l[carry]")
234 : /* Label referred to numerically: "%l2". */
235 ("btl %1, %0\n\t"
236 "jc %l2"));
238 std::vector<gccjit::block> goto_blocks ({b_carry});
239 gccjit::extended_asm ext_asm
240 = (b_start.end_with_extended_asm_goto (asm_template,
241 goto_blocks,
242 &b_fallthru)
243 .add_input_operand ("r", p1)
244 .add_input_operand ("r", p2)
245 .add_clobber ("cc"));
246 /* Quote up to here in docs/cp/topics/asm.rst: example 3: jit. */
248 std::string desc = ext_asm.get_debug_string ();
249 CHECK_STRING_VALUE
250 (desc.c_str (),
251 (use_name
252 ? ("asm goto (\"btl %1, %0\\n\\tjc %l[carry]\" "
253 ": : \"r\" (p1), \"r\" (p2) : \"cc\" "
254 ": carry [fallthrough: fallthru])")
255 : ("asm goto (\"btl %1, %0\\n\\tjc %l2\" "
256 ": : \"r\" (p1), \"r\" (p2) : \"cc\" "
257 ": carry [fallthrough: fallthru])")));
259 b_fallthru.end_with_return (zero);
260 b_carry.end_with_return (one);
263 static void
264 verify_code_3 (gcc_jit_context *ctxt, gcc_jit_result *result,
265 const char *funcname)
267 typedef int (*test_i386_basic_asm_3_type) (int, int);
269 test_i386_basic_asm_3_type test_i386_basic_asm_3
270 = (test_i386_basic_asm_3_type) gcc_jit_result_get_code (result, funcname);
271 CHECK_NON_NULL (test_i386_basic_asm_3);
273 /* The fn should test bits, returning 0 or 1. */
274 /* Bit 0. */
275 CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 0), 0);
276 CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 0), 1);
277 CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 0), 0);
278 CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 0), 1);
279 CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 0), 0);
280 /* Bit 1. */
281 CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 1), 0);
282 CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 1), 0);
283 CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 1), 1);
284 CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 1), 1);
285 CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 1), 0);
287 for (int i = 0; i < 15; i++)
289 CHECK_VALUE (test_i386_basic_asm_3 (0x0000, i), 0);
290 CHECK_VALUE (test_i386_basic_asm_3 (0xffff, i), 1);
294 /**********************************************************************
295 test_i386_basic_asm_4: test of "volatile"
296 **********************************************************************/
298 /* Create the equivalent of:
299 uint64_t test_i386_basic_asm_4 (void)
301 uint64_t start_time, end_time;
303 // Get start time
304 asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX.
305 "shl $32, %%rdx\n\t" // Shift the upper bits left.
306 "or %%rdx, %0" // 'Or' in the lower bits.
307 : "=a" (start_time)
309 : "rdx");
311 // could do other work here
313 // Get end time
314 asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX.
315 "shl $32, %%rdx\n\t" // Shift the upper bits left.
316 "or %%rdx, %0" // 'Or' in the lower bits.
317 : "=a" (start_time)
319 : "rdx");
321 // Get elapsed time
322 return end_time - start_time;
325 This exercises "volatile"; without it, the optimizer can assume that
326 both asm generate the same value and thus the time difference is zero. */
328 static void
329 add_rdtsc (gccjit::block block, gccjit::lvalue msr)
331 /* Quote from here in docs/cp/topics/asm.rst: example 4: jit. */
332 gccjit::extended_asm ext_asm
333 = block.add_extended_asm
334 ("rdtsc\n\t" /* Returns the time in EDX:EAX. */
335 "shl $32, %%rdx\n\t" /* Shift the upper bits left. */
336 "or %%rdx, %0") /* 'Or' in the lower bits. */
337 .set_volatile_flag (true)
338 .add_output_operand ("=a", msr)
339 .add_clobber ("rdx");
340 /* Quote up to here in docs/cp/topics/asm.rst: example 4: jit. */
342 std::string desc = ext_asm.get_debug_string ();
343 CHECK_STRING_STARTS_WITH (desc.c_str (), "asm volatile (");
346 static void
347 create_test_i386_basic_asm_4 (gcc_jit_context *c_ctxt)
349 gccjit::context ctxt (c_ctxt);
350 gccjit::type uint64_type = ctxt.get_int_type (8, 0);
351 std::vector<gccjit::param> params;
352 gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
353 uint64_type,
354 "test_i386_basic_asm_4",
355 params, 0);
356 gccjit::block block = func.new_block ();
358 gccjit::lvalue start_time = func.new_local (uint64_type, "start_time");
359 add_rdtsc (block, start_time);
361 block.add_comment ("other work here");
363 gccjit::lvalue end_time = func.new_local (uint64_type, "end_time");
364 add_rdtsc (block, end_time);
366 block.end_with_return (end_time - start_time);
369 static void
370 verify_code_4 (gcc_jit_context *ctxt, gcc_jit_result *result)
372 typedef uint64_t (*fntype) (void);
373 fntype test_i386_basic_asm_4
374 = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_4");
376 CHECK_NON_NULL (test_i386_basic_asm_4);
378 test_i386_basic_asm_4 ();
381 /**********************************************************************
382 test_i386_basic_asm_5: test of top-level asm
383 **********************************************************************/
385 /* Create the equivalent of:
387 // Quote from here in docs/cp/topics/asm.rst: example 5: C
388 asm ("\t.pushsection .text\n"
389 "\t.globl add_asm\n"
390 "\t.type add_asm, @function\n"
391 "add_asm:\n"
392 "\tmovq %rdi, %rax\n"
393 "\tadd %rsi, %rax\n"
394 "\tret\n"
395 "\t.popsection\n");
396 // Quote up to here in docs/cp/topics/asm.rst: example 5: C
398 to add a simple function ("add_asm") directly in assembly language. */
400 static void
401 create_test_i386_basic_asm_5 (gcc_jit_context *c_ctxt)
403 gccjit::context ctxt (c_ctxt);
404 #if __APPLE__
405 /* Darwin's assemblers do not support push/pop section, do not use .type
406 and external symbols should use __USER_LABEL_PREFIX__. */
407 ctxt.add_top_level_asm ("\t.text\n"
408 "\t.globl _add_asm\n"
409 "_add_asm:\n"
410 "\tmovq %rdi, %rax\n"
411 "\tadd %rsi, %rax\n"
412 "\tret\n"
413 "\t# some asm here\n");
414 #else
415 /* Quote from here in docs/cp/topics/asm.rst: example 5: jit. */
416 ctxt.add_top_level_asm ("\t.pushsection .text\n"
417 "\t.globl add_asm\n"
418 "\t.type add_asm, @function\n"
419 "add_asm:\n"
420 "\tmovq %rdi, %rax\n"
421 "\tadd %rsi, %rax\n"
422 "\tret\n"
423 "\t# some asm here\n"
424 "\t.popsection\n");
425 /* Quote up to here in docs/cp/topics/asm.rst: example 5: jit. */
426 #endif
429 static void
430 verify_code_5 (gcc_jit_context *ctxt, gcc_jit_result *result)
432 typedef int (*test_i386_basic_asm_5_type) (int, int);
433 test_i386_basic_asm_5_type test_i386_basic_asm_5
434 = (test_i386_basic_asm_5_type) gcc_jit_result_get_code (result, "add_asm");
435 CHECK_NON_NULL (test_i386_basic_asm_5);
437 CHECK_VALUE (test_i386_basic_asm_5 (2, 2), 4);
438 CHECK_VALUE (test_i386_basic_asm_5 (20, 7), 27);
441 /**********************************************************************
442 Code for harness
443 **********************************************************************/
445 void
446 create_code (gcc_jit_context *ctxt, void *user_data)
448 create_test_i386_basic_asm_1 (ctxt);
449 create_test_i386_basic_asm_2 (ctxt);
450 create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3a", 0);
451 create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3b", 1);
452 create_test_i386_basic_asm_4 (ctxt);
453 create_test_i386_basic_asm_5 (ctxt);
456 void
457 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
459 CHECK_NON_NULL (result);
460 verify_code_1 (ctxt, result);
461 verify_code_2 (ctxt, result);
462 verify_code_3 (ctxt, result, "test_i386_basic_asm_3a");
463 verify_code_3 (ctxt, result, "test_i386_basic_asm_3b");
464 verify_code_4 (ctxt, result);
465 verify_code_5 (ctxt, result);