#include #include "libgccjit.h" #include "harness.h" /* This testcase checks that gcc_jit_context_new_constructor() works with locals. Tests that constructors can be used as return values or function call values. Test that constructors can have side effects and be assigned to locals. */ void create_code (gcc_jit_context *ctxt, void *user_data) { gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); gcc_jit_type *pint_type = gcc_jit_type_get_pointer (int_type); gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT); gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL); gcc_jit_type *char_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR); gcc_jit_type *size_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T); gcc_jit_type *voidptr_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); gcc_jit_type *void_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); /* Make a struct: struct fi { float f; int i;} */ gcc_jit_field *fi_f = gcc_jit_context_new_field (ctxt, 0, float_type, "f"); gcc_jit_field *fi_i = gcc_jit_context_new_field (ctxt, 0, int_type, "i"); gcc_jit_field *fields[] = {fi_f, fi_i}; gcc_jit_type *struct_fi_type = gcc_jit_struct_as_type ( gcc_jit_context_new_struct_type (ctxt, 0, "fi", 2, fields)); /* Make a struct: struct bar { int ii; int arr[50]; float ff; char cc; } */ gcc_jit_field *bar_ff = gcc_jit_context_new_field (ctxt, 0, float_type, "ff"); gcc_jit_field *bar_ii = gcc_jit_context_new_field (ctxt, 0, int_type, "ii"); gcc_jit_field *bar_cc = gcc_jit_context_new_field (ctxt, 0, char_type, "cc"); gcc_jit_type *int50arr_type = gcc_jit_context_new_array_type (ctxt, 0, int_type, 50); gcc_jit_field *bar_fi = gcc_jit_context_new_field (ctxt, 0, int50arr_type, "arr"); gcc_jit_field *fields2[] = {bar_ff, bar_fi, bar_ii, bar_cc}; gcc_jit_type *struct_bar_type = gcc_jit_struct_as_type ( gcc_jit_context_new_struct_type (ctxt, 0, "bar", 4, fields2)); /* Make an union: union ubar { float ff; int ii; }; */ gcc_jit_field *ubar_ff = gcc_jit_context_new_field (ctxt, 0, float_type, "ff"); gcc_jit_field *ubar_ii = gcc_jit_context_new_field (ctxt, 0, int_type, "ii"); gcc_jit_field *fields3[] = {ubar_ff, ubar_ii}; gcc_jit_type *ubar = gcc_jit_context_new_union_type (ctxt, 0, "ubar", 2, fields3); (void) ubar; (void) struct_bar_type; (void) struct_fi_type; (void) bool_type; (void) double_type; (void) pint_type; (void) voidptr_type; (void) size_type; gcc_jit_function *fn_int_3; { /* int foo () { int local = 3; return local;} */ fn_int_3 = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, int_type, "fn_int_3", 0, 0, 0); gcc_jit_block *block = gcc_jit_function_new_block (fn_int_3, "start"); gcc_jit_lvalue *local = gcc_jit_function_new_local (fn_int_3, 0, int_type, "local"); gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 3); gcc_jit_block_add_assignment (block, 0, local, rval); gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(local)); } { /* struct fi foo() { return (struct fi){1,2};} */ gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, struct_fi_type, "fn_fi_1_2", 0, 0, 0); gcc_jit_block *block = gcc_jit_function_new_block (fn, "start"); gcc_jit_rvalue *rval_f1 = gcc_jit_context_new_rvalue_from_int ( ctxt, float_type, 1); gcc_jit_rvalue *rval_i2 = gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 2); gcc_jit_rvalue *vals[] = { rval_f1, rval_i2}; gcc_jit_field *fields[] = {fi_f, fi_i}; gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor (ctxt, 0, struct_fi_type, 2, fields, vals); gcc_jit_block_end_with_return (block, 0, ctor); } { /* struct fi foo() { struct fi local = {1,2}; local = (struct fi){5,6}; return local; } */ gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, struct_fi_type, "fn_fi_5_6", 0, 0, 0); gcc_jit_lvalue *local = gcc_jit_function_new_local (fn, 0, struct_fi_type, "local"); gcc_jit_block *block = gcc_jit_function_new_block (fn, "start"); { gcc_jit_rvalue *rval_f1 = gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 1); gcc_jit_rvalue *rval_i2 = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2); gcc_jit_rvalue *vals[] = { rval_f1, rval_i2}; gcc_jit_field *fields[] = {fi_f, fi_i}; gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor (ctxt, 0, struct_fi_type, 2, fields, vals); gcc_jit_block_add_assignment (block, 0, local, ctor); } { gcc_jit_rvalue *rval_f1 = gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 5); gcc_jit_rvalue *rval_i2 = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 6); gcc_jit_rvalue *vals[] = { rval_f1, rval_i2}; gcc_jit_field *fields[] = {fi_f, fi_i}; gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor (ctxt, 0, struct_fi_type, 2, fields, vals); gcc_jit_block_add_assignment (block, 0, local, ctor); } gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(local)); } { /* struct fi foo() { struct fi local = {1, fn_int_3()}; return local;} The ctor has a side effect (funccall) */ gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, struct_fi_type, "fn_fi_1_3", 0, 0, 0); gcc_jit_lvalue *local = gcc_jit_function_new_local (fn, 0, struct_fi_type, "local"); gcc_jit_block *block = gcc_jit_function_new_block (fn, "start"); { gcc_jit_rvalue *rval_f1 = gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 1); gcc_jit_rvalue *rval_i2 = gcc_jit_context_new_call (ctxt, 0, fn_int_3, 0, 0); gcc_jit_rvalue *vals[] = { rval_f1, rval_i2}; gcc_jit_field *fields[] = {fi_f, fi_i}; gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor (ctxt, 0, struct_fi_type, 2, fields, vals); gcc_jit_block_add_assignment (block, 0, local, ctor); } gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(local)); } { /* struct fi foo(fi) { return fi;} struct fi bar() { return foo((struct fi){3, 4}); } */ gcc_jit_param *fi_param = gcc_jit_context_new_param (ctxt, 0, struct_fi_type, "fi"); gcc_jit_function *fn0 = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, struct_fi_type, "fn_fi_x_x", 1, &fi_param, 0); gcc_jit_block *block0 = gcc_jit_function_new_block (fn0, "start"); gcc_jit_block_end_with_return (block0, 0, gcc_jit_param_as_rvalue ( gcc_jit_function_get_param (fn0, 0))); gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, struct_fi_type, "fn_fi_3_4", 0, 0, 0); gcc_jit_block *block = gcc_jit_function_new_block (fn, "start"); gcc_jit_rvalue *rval_f1 = gcc_jit_context_new_rvalue_from_int ( ctxt, float_type, 3); gcc_jit_rvalue *rval_i2 = gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 4); gcc_jit_rvalue *vals[] = { rval_f1, rval_i2}; gcc_jit_field *fields[] = {fi_f, fi_i}; gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor (ctxt, 0, struct_fi_type, 2, fields, vals); gcc_jit_rvalue *call = gcc_jit_context_new_call (ctxt, 0, fn0, 1, &ctor); gcc_jit_block_end_with_return (block, 0, call); } { /* void foo(struct bar *b) { *b = (struct bar) {.arr = {1,2}; } */ gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, gcc_jit_type_get_pointer (struct_bar_type), "b"); gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, void_type, "fn_pbar_12", 1, ¶m, 0); gcc_jit_block *block = gcc_jit_function_new_block (fn, "start"); gcc_jit_rvalue *rval_i1 = gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 1); gcc_jit_rvalue *rval_i2 = gcc_jit_context_new_rvalue_from_int ( ctxt, int_type, 2); gcc_jit_rvalue *arr_vals[] = { rval_i1, rval_i2}; gcc_jit_rvalue *arr_ctor = gcc_jit_context_new_array_constructor (ctxt, 0, int50arr_type, 2, arr_vals); gcc_jit_rvalue *str_ctor = gcc_jit_context_new_struct_constructor (ctxt, 0, struct_bar_type, 1, &bar_fi, &arr_ctor); gcc_jit_param *p0 = gcc_jit_function_get_param (fn, 0); gcc_jit_lvalue *lv0 = gcc_jit_param_as_lvalue (p0); gcc_jit_lvalue *deref = gcc_jit_rvalue_dereference (gcc_jit_lvalue_as_rvalue (lv0), 0); gcc_jit_block_add_assignment (block, 0, deref, str_ctor); gcc_jit_block_end_with_void_return (block, 0); } { /* struct bar foo() { struct bar local = {}; return local;} */ gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, struct_bar_type, "fn_bar_0s", 0, 0, 0); gcc_jit_lvalue *local = gcc_jit_function_new_local (fn, 0, struct_bar_type, "local"); gcc_jit_block *block = gcc_jit_function_new_block (fn, "start"); gcc_jit_rvalue *ctor = gcc_jit_context_new_struct_constructor (ctxt, 0, struct_bar_type, 0, 0, 0); gcc_jit_block_add_assignment (block, 0, local, ctor); gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(local)); } { /* struct bar foo() { struct bar local; local.arr = (int [50]){1,2,3,4,5,6}; return local;} */ gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, struct_bar_type, "fn_bar_123s", 0, 0, 0); gcc_jit_lvalue *local = gcc_jit_function_new_local (fn, 0, struct_bar_type, "local"); gcc_jit_block *block = gcc_jit_function_new_block (fn, "start"); gcc_jit_rvalue *values[6]; for (int i = 0; i < 6; i++) values[i] = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, i + 1); gcc_jit_rvalue *ctor = gcc_jit_context_new_array_constructor (ctxt, 0, int50arr_type, 6, values); gcc_jit_lvalue *arr_lv = gcc_jit_lvalue_access_field (local, 0, bar_fi); gcc_jit_block_add_assignment (block, 0, arr_lv, ctor); gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(local)); } { /* int[50] foo() { int arr[50]; arr = (int [50]){1,2,3,4,5,6}; return arr;} N.B: Not a typo, returning an array. */ gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, int50arr_type, "fn_int50arr_123s", 0, 0, 0); gcc_jit_lvalue *local = gcc_jit_function_new_local (fn, 0, int50arr_type, "local"); gcc_jit_block *block = gcc_jit_function_new_block (fn, "start"); gcc_jit_rvalue *values[6]; for (int i = 0; i < 6; i++) values[i] = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, i + 1); gcc_jit_rvalue *ctor = gcc_jit_context_new_array_constructor ( ctxt, 0, int50arr_type, 6, values); gcc_jit_block_add_assignment (block, 0, local, ctor); gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(local)); } { /* Verify that circular linked lists compiles, .e.g. that visit_children does not run in circles or something. struct llist { struct llist *next; }; bool foo (void) { volatile struct llist a; volatile struct llist b; a = (struct llist) {.next = &b}; b = (struct llist) {.next = &a}; return a.next == &b; } */ gcc_jit_struct *llist = gcc_jit_context_new_opaque_struct(ctxt, 0, "llist_lcl"); gcc_jit_field *fields[] = { gcc_jit_context_new_field (ctxt, 0, gcc_jit_type_get_pointer ( gcc_jit_struct_as_type (llist)), "next") }; gcc_jit_struct_set_fields (llist, 0, 1, fields); gcc_jit_type *t_llist = gcc_jit_struct_as_type (llist); gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, 0, GCC_JIT_FUNCTION_EXPORTED, bool_type, "fn_llist", 0, 0, 0); gcc_jit_block *block = gcc_jit_function_new_block (fn, "start"); gcc_jit_lvalue *a = gcc_jit_function_new_local (fn, 0, gcc_jit_type_get_volatile (t_llist), "a"); gcc_jit_lvalue *b = gcc_jit_function_new_local (fn, 0, gcc_jit_type_get_volatile (t_llist), "b"); gcc_jit_rvalue *a_addr = gcc_jit_lvalue_get_address( a, 0); gcc_jit_rvalue *b_addr = gcc_jit_lvalue_get_address( b, 0); gcc_jit_rvalue *a_ctor = gcc_jit_context_new_struct_constructor ( ctxt, 0, t_llist, 1, 0, &b_addr); gcc_jit_rvalue *b_ctor = gcc_jit_context_new_struct_constructor ( ctxt, 0, t_llist, 1, 0, &a_addr); gcc_jit_block_add_assignment (block, 0, a, a_ctor); gcc_jit_block_add_assignment (block, 0, b, b_ctor); gcc_jit_rvalue *cmp = gcc_jit_context_new_comparison ( ctxt, 0, GCC_JIT_COMPARISON_EQ, gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (a), 0, fields[0]), gcc_jit_context_new_cast (ctxt, 0, gcc_jit_lvalue_get_address (b, 0), gcc_jit_type_get_pointer (t_llist))); gcc_jit_block_end_with_return (block, 0, cmp); } } struct fi2 { float f; int i; }; struct bar2 { float ff; int arr[50]; int ii; char c; }; union ubar2 { float ff; int ii; }; struct int50arr { int arr[50]; }; void __attribute__((optimize(0))) scramble_stack(void) { char *p = alloca(100); for (int i = 0; i < 100; i++) *p++ = 0xF0; asm(""); /* Mark for side-effect */ } void __attribute__((optimize(0))) scramble_arr (char *arr, int len) { for (int i = 0; i < len; i++) *arr++ = i; asm(""); /* Mark for side-effect */ } void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { CHECK_NON_NULL (result); { struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_1_2"); scramble_stack (); struct fi2 fi = fn (); CHECK_VALUE (fi.f, 1); CHECK_VALUE (fi.i, 2); } { struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_5_6"); struct fi2 fi = fn (); CHECK_VALUE (fi.f, 5); CHECK_VALUE (fi.i, 6); } { struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_1_3"); struct fi2 fi = fn (); CHECK_VALUE (fi.f, 1); CHECK_VALUE (fi.i, 3); } { struct fi2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_fi_3_4"); struct fi2 fi = fn (); CHECK_VALUE (fi.f, 3); CHECK_VALUE (fi.i, 4); } { scramble_stack(); struct bar2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_bar_0s"); struct bar2 bar = fn (); struct bar2 key = {}; CHECK_VALUE (bar.ff, 0); CHECK_VALUE (bar.ii, 0); CHECK_VALUE (memcmp (&bar.arr, &key.arr, sizeof (key.arr)), 0); } { void (*fn) (struct bar2 *) = gcc_jit_result_get_code (result, "fn_pbar_12"); struct bar2 bar = (struct bar2) {}; scramble_arr ((char*)&bar, sizeof bar); scramble_stack(); fn (&bar); struct bar2 key = {.arr = {1,2}}; __builtin_clear_padding (&key); CHECK_VALUE (memcmp (&bar, &key, sizeof (key)), 0); } { scramble_stack(); struct bar2 (*fn) (void) = gcc_jit_result_get_code (result, "fn_bar_123s"); struct bar2 bar = fn (); struct bar2 key = {.arr = {1,2,3,4,5,6} }; CHECK_VALUE (memcmp (&bar.arr, &key.arr, sizeof (key.arr)), 0); } { scramble_stack (); /* This is abit shady. Lets just pretend that array returns à la Fortran is the same thing as returning a struct with an array in it in C. */ struct int50arr (*fn) (void) = gcc_jit_result_get_code (result, "fn_int50arr_123s"); struct int50arr ans = fn (); int key[50] = {1,2,3,4,5,6}; CHECK_VALUE (memcmp (ans.arr, key, sizeof (key)), 0); } { _Bool (*fn) (void) = gcc_jit_result_get_code (result, "fn_llist"); CHECK_VALUE (fn (), 1); } }