From 910d3f616ea809dddef12f02d0d0fd7d773d9952 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 17 Oct 2023 23:25:40 +0200 Subject: [PATCH] Add jit tests for `alias`, `always_inline`, `noinline`, `used`, `target` and `weak` attributes --- gcc/testsuite/jit.dg/test-alias-attribute.c | 50 ++++++ .../jit.dg/test-always_inline-attribute.c | 153 ++++++++++++++++++ .../jit.dg/test-noinline-attribute.c | 114 +++++++++++++ ...est-nonnull.c => test-nonnull-attribute.c} | 0 ...t-restrict.c => test-restrict-attribute.c} | 4 +- gcc/testsuite/jit.dg/test-target-attribute.c | 98 +++++++++++ gcc/testsuite/jit.dg/test-used-attribute.c | 112 +++++++++++++ gcc/testsuite/jit.dg/test-weak-attribute.c | 41 +++++ 8 files changed, 570 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-alias-attribute.c create mode 100644 gcc/testsuite/jit.dg/test-always_inline-attribute.c create mode 100644 gcc/testsuite/jit.dg/test-noinline-attribute.c rename gcc/testsuite/jit.dg/{test-nonnull.c => test-nonnull-attribute.c} (100%) rename gcc/testsuite/jit.dg/{test-restrict.c => test-restrict-attribute.c} (95%) create mode 100644 gcc/testsuite/jit.dg/test-target-attribute.c create mode 100644 gcc/testsuite/jit.dg/test-used-attribute.c create mode 100644 gcc/testsuite/jit.dg/test-weak-attribute.c diff --git a/gcc/testsuite/jit.dg/test-alias-attribute.c b/gcc/testsuite/jit.dg/test-alias-attribute.c new file mode 100644 index 0000000000000..eb29003dfc903 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-alias-attribute.c @@ -0,0 +1,50 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-alias-attribute.c.s" +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + +void xxx () {} +void f () __attribute__ ((alias ("xxx"))); + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + /* Creating the `xxx` function. */ + gcc_jit_function *xxx_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "xxx", + 0, NULL, + 0); + + /* Creating the `f` function. */ + gcc_jit_function *f_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + void_type, + "f", + 0, NULL, + 0); + gcc_jit_function_add_string_attribute(f_func, GCC_JIT_FN_ATTRIBUTE_ALIAS, "xxx"); + + /* void xxx () {} */ + gcc_jit_block *block = gcc_jit_function_new_block (xxx_func, NULL); + gcc_jit_block_end_with_void_return (block, NULL); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* Check that the attribute was applied correctly */ +/* { dg-final { jit-verify-assembler-output ".set\\s+f,xxx" } } */ diff --git a/gcc/testsuite/jit.dg/test-always_inline-attribute.c b/gcc/testsuite/jit.dg/test-always_inline-attribute.c new file mode 100644 index 0000000000000..5c3f386663f66 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-always_inline-attribute.c @@ -0,0 +1,153 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +#define TEST_ESCHEWS_SET_OPTIONS +static void set_options (gcc_jit_context *ctxt, const char *argv0) +{ + // Set "-O0". + gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 0); +} + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-always_inline-attribute.c.s" +#include "harness.h" + +gcc_jit_function* +create_function (gcc_jit_context *ctxt, + const char *func_name, + gcc_jit_type *int_type, + gcc_jit_type *pint_type) +{ + /* The `a` function argument */ + gcc_jit_param *a = gcc_jit_context_new_param (ctxt, NULL, pint_type, "a"); + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_INTERNAL, + int_type, + func_name, + 1, &a, + 0); + + gcc_jit_block *if_cond = + gcc_jit_function_new_block (func, "if_cond"); + gcc_jit_block *if_body = + gcc_jit_function_new_block (func, "if_body"); + gcc_jit_block *after_if = + gcc_jit_function_new_block (func, "after_if"); + + /* if (!a) */ + gcc_jit_block_end_with_conditional ( + if_cond, NULL, + gcc_jit_context_new_comparison ( + ctxt, NULL, + GCC_JIT_COMPARISON_EQ, + gcc_jit_param_as_rvalue (a), + gcc_jit_context_null (ctxt, pint_type)), + if_body, + after_if); + /* return -1; */ + gcc_jit_block_end_with_return ( + if_body, NULL, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, -1)); + + /* return *a; */ + gcc_jit_block_end_with_return ( + after_if, NULL, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference ( + gcc_jit_param_as_rvalue (a), NULL))); + + return func; +} + + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: +__attribute__ ((always_inline)) +static inline int removed (int *a) { + if (!a) { + return -1; + } + return *a; +} +static int not_removed (int *a) { + if (!a) { + return -1; + } + return *a; +} +int foo () { + int x = 0; + x += removed(NULL); + x += not_removed(NULL); + return x; +} + */ + 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); + + /* Creating the `removed` function. */ + gcc_jit_function *removed_func = + create_function (ctxt, "removed", int_type, pint_type); + /* This one is to declare the function as "inline" */ + gcc_jit_function_add_attribute(removed_func, GCC_JIT_FN_ATTRIBUTE_INLINE); + /* __attribute__ ((always_inline)) */ + gcc_jit_function_add_attribute(removed_func, GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE); + + /* Creating the `not_removed` function. */ + gcc_jit_function *not_removed_func = + create_function (ctxt, "not_removed", int_type, pint_type); + + /* Creating the `foo` function. */ + gcc_jit_function *foo_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "foo", + 0, NULL, + 0); + + gcc_jit_block *foo_block = gcc_jit_function_new_block (foo_func, NULL); + + /* Build locals: */ + gcc_jit_lvalue *x = + gcc_jit_function_new_local (foo_func, NULL, int_type, "x"); + + /* int x = 0; */ + gcc_jit_block_add_assignment ( + foo_block, NULL, + x, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)); + + /* x += removed(NULL); */ + gcc_jit_rvalue *null = gcc_jit_context_null (ctxt, pint_type); + gcc_jit_block_add_assignment_op ( + foo_block, NULL, + x, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_call (ctxt, NULL, removed_func, 1, &null)); + + /* x += not_removed(NULL); */ + gcc_jit_block_add_assignment_op ( + foo_block, NULL, + x, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_call (ctxt, NULL, not_removed_func, 1, &null)); + + /* return x; */ + gcc_jit_block_end_with_return (foo_block, NULL, gcc_jit_lvalue_as_rvalue(x)); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* Check that the "removed" function was inlined, but not the others */ +/* { dg-final { jit-verify-assembler-output-not ".type\\s+removed,\\s+@function" } } */ +/* { dg-final { jit-verify-assembler-output ".type\\s+not_removed,\\s+@function" } } */ +/* { dg-final { jit-verify-assembler-output ".type\\s+foo,\\s+@function" } } */ diff --git a/gcc/testsuite/jit.dg/test-noinline-attribute.c b/gcc/testsuite/jit.dg/test-noinline-attribute.c new file mode 100644 index 0000000000000..84933e600100f --- /dev/null +++ b/gcc/testsuite/jit.dg/test-noinline-attribute.c @@ -0,0 +1,114 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +/* We don't want set_options() in harness.h to set -O2 to see that the `noinline` + attribute affects the optimizations. */ +#define TEST_ESCHEWS_SET_OPTIONS +static void set_options (gcc_jit_context *ctxt, const char *argv0) +{ + // Set "-O2". + gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2); +} + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-noinline-attribute.c.s" +#include "harness.h" + +gcc_jit_function* +create_function (gcc_jit_context *ctxt, + const char *func_name, + gcc_jit_type *int_type, + int returned_value) +{ + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_INTERNAL, + int_type, + func_name, + 0, NULL, + 0); + + gcc_jit_block *foo_block = gcc_jit_function_new_block (func, NULL); + gcc_jit_block_end_with_return (foo_block, NULL, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, returned_value)); + + return func; +} + + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: +__attribute__ ((noinline)) +static int not_removed() { return 1; } +static int removed() { return 2; } +int foo () { + int x = 0; + x += removed(); + x += not_removed(); + return x; +} + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Creating the `not_removed` function. */ + gcc_jit_function *not_removed_func = + create_function (ctxt, "not_removed", int_type, 1); + /* __attribute__ ((no_inline)) */ + gcc_jit_function_add_attribute(not_removed_func, GCC_JIT_FN_ATTRIBUTE_NOINLINE); + + /* Creating the `removed` function. */ + gcc_jit_function *removed_func = + create_function (ctxt, "removed", int_type, 2); + + /* Creating the `foo` function. */ + gcc_jit_function *foo_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "foo", + 0, NULL, + 0); + + gcc_jit_block *foo_block = gcc_jit_function_new_block (foo_func, NULL); + + /* Build locals: */ + gcc_jit_lvalue *x = + gcc_jit_function_new_local (foo_func, NULL, int_type, "x"); + + /* int x = 0; */ + gcc_jit_block_add_assignment ( + foo_block, NULL, + x, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)); + + /* x += removed(); */ + gcc_jit_block_add_assignment_op ( + foo_block, NULL, + x, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_call (ctxt, NULL, removed_func, 0, NULL)); + + /* x += not_removed(); */ + gcc_jit_block_add_assignment_op ( + foo_block, NULL, + x, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_call (ctxt, NULL, not_removed_func, 0, NULL)); + + /* return x; */ + gcc_jit_block_end_with_return (foo_block, NULL, gcc_jit_lvalue_as_rvalue(x)); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* Check that the "removed" function was inlined, but not the others */ +/* { dg-final { jit-verify-assembler-output-not ".type\\s+removed,\\s+@function" } } */ +/* { dg-final { jit-verify-assembler-output ".type\\s+not_removed,\\s+@function" } } */ +/* { dg-final { jit-verify-assembler-output ".type\\s+foo,\\s+@function" } } */ diff --git a/gcc/testsuite/jit.dg/test-nonnull.c b/gcc/testsuite/jit.dg/test-nonnull-attribute.c similarity index 100% rename from gcc/testsuite/jit.dg/test-nonnull.c rename to gcc/testsuite/jit.dg/test-nonnull-attribute.c diff --git a/gcc/testsuite/jit.dg/test-restrict.c b/gcc/testsuite/jit.dg/test-restrict-attribute.c similarity index 95% rename from gcc/testsuite/jit.dg/test-restrict.c rename to gcc/testsuite/jit.dg/test-restrict-attribute.c index 4c8c4407f9152..f0272e83fee00 100644 --- a/gcc/testsuite/jit.dg/test-restrict.c +++ b/gcc/testsuite/jit.dg/test-restrict-attribute.c @@ -73,5 +73,5 @@ void t(int *__restrict__ a, int *__restrict__ b, char *__restrict__ c) { } /* { dg-final { jit-verify-output-file-was-created "" } } */ -/* { dg-final { jit-verify-assembler-output "addl %eax, (%rdi) - addl %eax, (%rsi)" } } */ +/* { dg-final { jit-verify-assembler-output "addl\\s+%eax,\\s+(%rdi) +\\s+addl\\s+%eax,\\s+(%rsi)" } } */ diff --git a/gcc/testsuite/jit.dg/test-target-attribute.c b/gcc/testsuite/jit.dg/test-target-attribute.c new file mode 100644 index 0000000000000..56fd93d097dd4 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-target-attribute.c @@ -0,0 +1,98 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +#define TEST_PROVIDES_MAIN +#include "harness.h" + +/* If the generated code compiles, it means that the `target` attribute was correctly set, + otherwise it would emit an error saying that it doesn't know the `__builtin_ia32_loadupd` + builtin. */ +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: +__attribute__((target("sse2"))) +void foo () { + __builtin_ia32_loadupd(NULL); +} + */ + gcc_jit_type *double_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); + gcc_jit_type *pdouble_type = gcc_jit_type_get_pointer (double_type); + gcc_jit_type *void_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + /* Creating the `foo` function. */ + gcc_jit_function *foo_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "foo", + 0, NULL, + 0); + + /* __attribute__((target("sse3"))) */ + gcc_jit_function_add_string_attribute ( + foo_func, + GCC_JIT_FN_ATTRIBUTE_TARGET, + "sse2"); + + gcc_jit_block *foo_block = gcc_jit_function_new_block (foo_func, NULL); + + gcc_jit_function *builtin = gcc_jit_context_get_target_builtin_function ( + ctxt, "__builtin_ia32_loadupd"); + CHECK_NON_NULL (builtin); + + gcc_jit_rvalue *arg = gcc_jit_context_null (ctxt, pdouble_type); + CHECK_NON_NULL (arg); + + gcc_jit_block_add_eval (foo_block, NULL, + gcc_jit_context_new_call (ctxt, NULL, builtin, 1, &arg)); + + gcc_jit_block_end_with_void_return (foo_block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); +} + +int +main (int argc, char **argv) +{ + /* This is the same as the main provided by harness.h, but it first create a dummy context and compile + in order to add the target builtins to libgccjit's internal state. */ + gcc_jit_context *ctxt; + ctxt = gcc_jit_context_acquire (); + if (!ctxt) + { + fail ("gcc_jit_context_acquire failed"); + return -1; + } + gcc_jit_result *result; + result = gcc_jit_context_compile (ctxt); + gcc_jit_result_release (result); + gcc_jit_context_release (ctxt); + + int i; + + for (i = 1; i <= 5; i++) + { + snprintf (test, sizeof (test), + "%s iteration %d of %d", + extract_progname (argv[0]), + i, 5); + + //printf ("ITERATION %d\n", i); + test_jit (argv[0], NULL); + //printf ("\n"); + } + + totals (); + + return 0; +} diff --git a/gcc/testsuite/jit.dg/test-used-attribute.c b/gcc/testsuite/jit.dg/test-used-attribute.c new file mode 100644 index 0000000000000..cb20952c687ff --- /dev/null +++ b/gcc/testsuite/jit.dg/test-used-attribute.c @@ -0,0 +1,112 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +#define TEST_ESCHEWS_SET_OPTIONS +static void set_options (gcc_jit_context *ctxt, const char *argv0) +{ + // Set "-O2". + gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2); +} + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-used-attribute.c.s" +#include "harness.h" + +gcc_jit_function* +create_function (gcc_jit_context *ctxt, + const char *func_name, + gcc_jit_type *int_type, + int returned_value) +{ + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_INTERNAL, + int_type, + func_name, + 0, NULL, + 0); + + gcc_jit_block *foo_block = gcc_jit_function_new_block (func, NULL); + gcc_jit_block_end_with_return (foo_block, NULL, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, returned_value)); + + return func; +} + + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: +__attribute__((used)) +static int not_removed() { return 1; } +static int removed() { return 2; } +int foo() { + int x = 0; + x += not_removed(); + x += removed(); + return x; +} + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Creating the `not_removed` function. */ + gcc_jit_function *not_removed_func = + create_function (ctxt, "not_removed", int_type, 1); + /* __attribute__ ((used)) */ + gcc_jit_function_add_attribute(not_removed_func, GCC_JIT_FN_ATTRIBUTE_USED); + + /* Creating the `removed` function. */ + gcc_jit_function *removed_func = + create_function (ctxt, "removed", int_type, 2); + + /* Creating the `foo` function. */ + gcc_jit_function *foo_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "foo", + 0, NULL, + 0); + + gcc_jit_block *foo_block = gcc_jit_function_new_block (foo_func, NULL); + + /* Build locals: */ + gcc_jit_lvalue *x = + gcc_jit_function_new_local (foo_func, NULL, int_type, "x"); + + /* int x = 0; */ + gcc_jit_block_add_assignment ( + foo_block, NULL, + x, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)); + + /* x += removed(); */ + gcc_jit_block_add_assignment_op ( + foo_block, NULL, + x, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_call (ctxt, NULL, removed_func, 0, NULL)); + + /* x += not_removed(); */ + gcc_jit_block_add_assignment_op ( + foo_block, NULL, + x, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_call (ctxt, NULL, not_removed_func, 0, NULL)); + + /* return x; */ + gcc_jit_block_end_with_return (foo_block, NULL, gcc_jit_lvalue_as_rvalue(x)); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* Check that the "removed" function was inlined, but not the others */ +/* { dg-final { jit-verify-assembler-output-not ".type\\s+removed,\\s+@function" } } */ +/* { dg-final { jit-verify-assembler-output ".type\\s+not_removed,\\s+@function" } } */ +/* { dg-final { jit-verify-assembler-output ".type\\s+foo,\\s+@function" } } */ diff --git a/gcc/testsuite/jit.dg/test-weak-attribute.c b/gcc/testsuite/jit.dg/test-weak-attribute.c new file mode 100644 index 0000000000000..546ade1c3c41e --- /dev/null +++ b/gcc/testsuite/jit.dg/test-weak-attribute.c @@ -0,0 +1,41 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-weak-attribute.c.s" +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + +__attribute__ ((weak)) +void f () {} + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + /* Creating the `f` function. */ + gcc_jit_function *f_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "f", + 0, NULL, + 0); + gcc_jit_function_add_attribute(f_func, GCC_JIT_FN_ATTRIBUTE_WEAK); + + /* void f () {} */ + gcc_jit_block *block = gcc_jit_function_new_block (f_func, NULL); + gcc_jit_block_end_with_void_return (block, NULL); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* Check that the attribute was applied correctly */ +/* { dg-final { jit-verify-assembler-output ".weak\\s+f" } } */