1 /* { dg-do compile { target x86_64-*-* } } */
4 #include "libgccjit++.h"
8 /**********************************************************************
9 Support fns for creating code.
10 **********************************************************************/
12 /* Make a "void FUNC_NAME (void)" function with a single block, returning
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
;
21 = ctxt
.new_function (GCC_JIT_FUNCTION_EXPORTED
,
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);
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:
48 void test_i386_basic_asm_1 (void)
50 // Quote from here in docs/cp/topics/asm.rst: example 1: C
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. */
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
);
66 = ctxt
.new_global (GCC_JIT_GLOBAL_EXPORTED
, int_type
, "dst");
68 = ctxt
.new_global (GCC_JIT_GLOBAL_EXPORTED
, int_type
, "src");
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"
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 ();
84 "asm (\"mov %1, %0\\n\\tadd $1, %0\" : \"=r\" (dst) : \"r\" (src) : )");
86 block
.end_with_return ();
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
);
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)
116 // Quote from here in docs/cp/topics/asm.rst: example 2: C
117 asm ("bsfl %[aMask], %[aIndex]"
118 : [aIndex] "=r" (Index)
121 // Quote up to here in docs/cp/topics/asm.rst: example 2: C
124 i.e. return the first bit set in "Mask"
126 This exercises symbolic names and clobbers. */
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
,
137 "test_i386_basic_asm_2",
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
)
147 /* Quote up to here in docs/cp/topics/asm.rst: example 2: jit. */
149 std::string desc
= ext_asm
.get_debug_string ();
152 "asm (\"bsfl %[aMask], %[aIndex]\""
153 " : [aIndex] \"=r\" (Index) : [aMask] \"r\" (Mask) : \"cc\")");
155 block
.end_with_return (index
);
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"
193 or (the "_3b" variant) using a name rather than a number for the goto
196 // Quote from here in docs/cp/topics/asm.rst: example 3b: C
197 asm goto ("btl %1, %0\n\t"
203 // Quote up to here in docs/cp/topics/asm.rst: example 3b: C
205 This exercises control flow with an asm. */
208 create_test_i386_basic_asm_3 (gcc_jit_context
*c_ctxt
,
209 const char *funcname
,
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
,
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
=
231 ? /* Label referred to by name: "%l[carry]". */
234 : /* Label referred to numerically: "%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
,
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 ();
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
);
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. */
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);
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;
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.
311 // could do other work here
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.
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. */
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 (");
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
,
354 "test_i386_basic_asm_4",
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
);
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"
390 "\t.type add_asm, @function\n"
392 "\tmovq %rdi, %rax\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. */
401 create_test_i386_basic_asm_5 (gcc_jit_context
*c_ctxt
)
403 gccjit::context
ctxt (c_ctxt
);
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"
410 "\tmovq %rdi, %rax\n"
413 "\t# some asm here\n");
415 /* Quote from here in docs/cp/topics/asm.rst: example 5: jit. */
416 ctxt
.add_top_level_asm ("\t.pushsection .text\n"
418 "\t.type add_asm, @function\n"
420 "\tmovq %rdi, %rax\n"
423 "\t# some asm here\n"
425 /* Quote up to here in docs/cp/topics/asm.rst: example 5: jit. */
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 /**********************************************************************
443 **********************************************************************/
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
);
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
);