From 70e98145a0e5e1305b40f81475d269c2c4789a20 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 31 May 2021 09:38:14 -0400 Subject: [PATCH 01/45] Build and upload artifact on GitHub Actions --- .github/workflows/main.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000000..5fab7cf772c06 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,32 @@ +name: CI + +on: + - push + - pull_request + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v2 + + - name: Install mpfr + run: sudo apt-get install gcc-10 libmpfr-dev libmpc-dev + + - name: Build libgccjit + run: | + cd .. + ls + mkdir build install + cd build + ../gcc/configure --enable-host-shared --enable-languages=jit,c++ --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install + make -j4 + + - uses: actions/upload-artifact@v2 + with: + name: libgccjit.so + path: /home/runner/work/gcc/build/gcc/libgccjit.so From 8ad5bc94e071bef1b6c11060e19cc4795ff98292 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 28 Mar 2022 09:58:36 -0400 Subject: [PATCH 02/45] Allow creating an array type even when the struct fields weren't set yet --- gcc/jit/jit-recording.cc | 4 ++-- gcc/jit/libgccjit.cc | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 2ce272267b817..359e7bc6b33f5 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -842,7 +842,7 @@ recording::context::new_array_type (recording::location *loc, recording::type *element_type, int num_elements) { - if (struct_ *s = element_type->dyn_cast_struct ()) + /*if (struct_ *s = element_type->dyn_cast_struct ()) if (!s->get_fields ()) { add_error (NULL, @@ -850,7 +850,7 @@ recording::context::new_array_type (recording::location *loc, " until the fields have been set", s->get_name ()->c_str ()); return NULL; - } + }*/ recording::type *result = new recording::array_type (this, loc, element_type, num_elements); record (result); diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 8884128e8d8ff..b6e16d66b60a6 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -995,6 +995,7 @@ size_t gcc_jit_struct_get_field_count (gcc_jit_struct *struct_type) { RETURN_VAL_IF_FAIL (struct_type, 0, NULL, NULL, "NULL struct type"); + RETURN_VAL_IF_FAIL (struct_type->get_fields (), 0, NULL, NULL, "NULL fields"); return struct_type->get_fields ()->length (); } From c8413caca98ec98e5cd7289090168864bf7d54f3 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 28 Mar 2022 12:17:18 -0400 Subject: [PATCH 03/45] Fix infinite recursion in gt_ggc_mx_lang_tree_node --- gcc/jit/dummy-frontend.cc | 12 ++++++------ gcc/jit/jit-common.h | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index 0687567bc883d..cc6da5a3b7d5f 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -507,12 +507,12 @@ struct GTY(()) lang_identifier /* The resulting tree type. */ union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), - chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL"))) -lang_tree_node -{ - union tree_node GTY((tag ("0"), - desc ("tree_node_structure (&%h)"))) generic; - struct lang_identifier GTY((tag ("1"))) identifier; + chain_next ("(union lang_tree_node *) jit_tree_chain_next (&%h.generic)"))) lang_tree_node + { + union tree_node GTY ((tag ("0"), + desc ("tree_node_structure (&%h)"))) + generic; + struct lang_identifier GTY ((tag ("1"))) identifier; }; /* We don't use language_function. */ diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h index 3ff7447fbf3f6..f9aead2f66c75 100644 --- a/gcc/jit/jit-common.h +++ b/gcc/jit/jit-common.h @@ -93,6 +93,20 @@ const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_INT128_T + 1; End of comment for inclusion in the docs. */ +static inline tree +jit_tree_chain_next (tree t) +{ + /* TREE_CHAIN of a type is TYPE_STUB_DECL, which is different + kind of object, never a long chain of nodes. Prefer + TYPE_NEXT_VARIANT for types. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPE_COMMON)) + return TYPE_NEXT_VARIANT (t); + /* Otherwise, if there is TREE_CHAIN, return it. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON)) + return TREE_CHAIN (t); + return NULL; +} + namespace gcc { namespace jit { From 13e6eac9f821c7ba15387108bc7e478706d0fa1a Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 28 Mar 2022 21:10:41 -0400 Subject: [PATCH 04/45] Add support for packed struct --- gcc/jit/jit-playback.cc | 12 ++++++++++-- gcc/jit/jit-playback.h | 5 +++-- gcc/jit/jit-recording.cc | 14 +++++++++++--- gcc/jit/jit-recording.h | 6 ++++++ gcc/jit/libgccjit.cc | 8 ++++++++ gcc/jit/libgccjit.h | 4 ++++ gcc/jit/libgccjit.map | 5 +++++ 7 files changed, 47 insertions(+), 7 deletions(-) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 96e9227af40fd..aea9295f9ae33 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -407,7 +407,8 @@ playback::compound_type * playback::context:: new_compound_type (location *loc, const char *name, - bool is_struct) /* else is union */ + bool is_struct, /* else is union */ + bool is_packed) { gcc_assert (name); @@ -417,6 +418,9 @@ new_compound_type (location *loc, TYPE_NAME (t) = get_identifier (name); TYPE_SIZE (t) = 0; + if (is_packed) + TYPE_PACKED (t) = 1; + if (loc) set_tree_location (t, loc); @@ -424,7 +428,7 @@ new_compound_type (location *loc, } void -playback::compound_type::set_fields (const auto_vec *fields) +playback::compound_type::set_fields (const auto_vec *fields, bool is_packed) { /* Compare with c/c-decl.cc: finish_struct. */ tree t = as_tree (); @@ -441,6 +445,10 @@ playback::compound_type::set_fields (const auto_vec *fields) DECL_SIZE (x) = bitsize_int (width); DECL_BIT_FIELD (x) = 1; } + + if (is_packed && (DECL_BIT_FIELD (x) + || TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)) + DECL_PACKED (x) = 1; fieldlist = chainon (x, fieldlist); } fieldlist = nreverse (fieldlist); diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 43e92d67d7426..4facbce3f49ec 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -85,7 +85,8 @@ class context : public log_user compound_type * new_compound_type (location *loc, const char *name, - bool is_struct); /* else is union */ + bool is_struct, /* else is union */ + bool is_packed); type * new_function_type (type *return_type, @@ -460,7 +461,7 @@ class compound_type : public type : type (inner) {} - void set_fields (const auto_vec *fields); + void set_fields (const auto_vec *fields, bool is_packed); }; class field : public wrapper diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 359e7bc6b33f5..cda15b4c30d74 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -2294,6 +2294,12 @@ recording::type::get_aligned (size_t alignment_in_bytes) return result; } +void +recording::type::set_packed () +{ + m_packed = true; +} + /* Given a type, get a vector version of the type. Implements the post-error-checking part of @@ -3484,7 +3490,8 @@ recording::struct_::replay_into (replayer *r) set_playback_obj ( r->new_compound_type (playback_location (r, get_loc ()), get_name ()->c_str (), - true /* is_struct */)); + true, /* is_struct */ + m_packed)); } const char * @@ -3538,7 +3545,8 @@ recording::union_::replay_into (replayer *r) set_playback_obj ( r->new_compound_type (playback_location (r, get_loc ()), get_name ()->c_str (), - false /* is_struct */)); + false, /* is_struct */ + m_packed)); } /* Implementation of recording::memento::make_debug_string for @@ -3609,7 +3617,7 @@ recording::fields::replay_into (replayer *) playback_fields.create (m_fields.length ()); for (unsigned i = 0; i < m_fields.length (); i++) playback_fields.safe_push (m_fields[i]->playback_field ()); - m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields); + m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields, m_struct_or_union->m_packed); } /* Override the default implementation of diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index e1236dec57545..6fe52eb5865ad 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -527,6 +527,8 @@ class type : public memento type *get_aligned (size_t alignment_in_bytes); type *get_vector (size_t num_units); + void set_packed (); + /* Get the type obtained when dereferencing this type. This will return NULL if it's not valid to dereference this type. @@ -593,9 +595,13 @@ class type : public memento protected: type (context *ctxt) : memento (ctxt), + m_packed (false), m_pointer_to_this_type (NULL) {} +public: + bool m_packed; + private: type *m_pointer_to_this_type; }; diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index b6e16d66b60a6..6dff3a6f32ef9 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -3951,6 +3951,14 @@ gcc_jit_type_get_aligned (gcc_jit_type *type, return (gcc_jit_type *)type->get_aligned (alignment_in_bytes); } +void +gcc_jit_type_set_packed (gcc_jit_type *type) +{ + RETURN_IF_FAIL (type, NULL, NULL, "NULL type"); + + type->set_packed (); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index b3c389e93f68f..a3bbc5ffaa949 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1990,6 +1990,10 @@ gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *vector_type); extern gcc_jit_type * gcc_jit_type_unqualified (gcc_jit_type *type); +/* Given type "T", get type "T __attribute__ ((packed))". */ +extern void +gcc_jit_type_set_packed (gcc_jit_type *type); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index cc22b2b414e55..f47d9bfbd9818 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -271,3 +271,8 @@ LIBGCCJIT_ABI_24 { gcc_jit_lvalue_set_alignment; gcc_jit_lvalue_get_alignment; } LIBGCCJIT_ABI_23; + +LIBGCCJIT_ABI_25 { + global: + gcc_jit_type_set_packed; +} LIBGCCJIT_ABI_24; From e0d8a39249f83c08e2f15879da0836f7140a44ef Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 29 Apr 2022 23:35:12 -0400 Subject: [PATCH 05/45] Add gcc_jit_type_is_const --- gcc/jit/libgccjit.cc | 14 ++++++++++++++ gcc/jit/libgccjit.h | 5 +++++ gcc/jit/libgccjit.map | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 6dff3a6f32ef9..7447025bc0a81 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -592,6 +592,20 @@ gcc_jit_type_is_pointer (gcc_jit_type *type) return (gcc_jit_type *)type->is_pointer (); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::is_const method, in + jit-recording.cc. */ + +gcc_jit_type * +gcc_jit_type_is_const (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + + return (gcc_jit_type *)type->is_const (); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index a3bbc5ffaa949..079cfc72e61e1 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1969,6 +1969,11 @@ gcc_jit_type_is_integral (gcc_jit_type *type); extern gcc_jit_type * gcc_jit_type_is_pointer (gcc_jit_type *type); +/* Return the type behind const type or NULL if it's not a + * const type. */ +extern gcc_jit_type * +gcc_jit_type_is_const (gcc_jit_type *type); + /* Given a type, return a dynamic cast to a vector type or NULL. */ extern gcc_jit_vector_type * gcc_jit_type_dyncast_vector (gcc_jit_type *type); diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index f47d9bfbd9818..84678896637c2 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -276,3 +276,8 @@ LIBGCCJIT_ABI_25 { global: gcc_jit_type_set_packed; } LIBGCCJIT_ABI_24; + +LIBGCCJIT_ABI_26 { + global: + gcc_jit_type_is_const; +} LIBGCCJIT_ABI_25; From b440824659709a68f942cfa45b660b37fc161ad2 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 14 May 2022 17:24:29 -0400 Subject: [PATCH 06/45] Add convert vector --- gcc/jit/jit-playback.cc | 26 +++++++++++++++ gcc/jit/jit-playback.h | 5 +++ gcc/jit/jit-recording.cc | 72 ++++++++++++++++++++++++++++++++++++++++ gcc/jit/jit-recording.h | 34 +++++++++++++++++++ gcc/jit/libgccjit.cc | 25 ++++++++++++++ gcc/jit/libgccjit.h | 6 ++++ gcc/jit/libgccjit.map | 5 +++ 7 files changed, 173 insertions(+) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index aea9295f9ae33..862c80be1097b 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -1535,6 +1535,32 @@ new_array_access (location *loc, } } +/* Construct a playback::rvalue instance (wrapping a tree) for a + vector conversion. */ + +playback::rvalue * +playback::context:: +convert_vector (location *loc, + rvalue *vector, + type *type) +{ + gcc_assert (vector); + gcc_assert (type); + + /* For comparison, see: + c/c-common.cc: c_build_vec_convert + */ + + tree t_vector = vector->as_tree (); + + tree t_result = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_VEC_CONVERT, type->as_tree (), 1, t_vector); + + if (loc) + set_tree_location (t_result, loc); + + return new rvalue (this, t_result); +} + /* Construct a tree for a field access. */ tree diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 4facbce3f49ec..491b6be0ca44f 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -192,6 +192,11 @@ class context : public log_user rvalue *ptr, rvalue *index); + rvalue * + convert_vector (location *loc, + rvalue *vector, + type *type); + void set_str_option (enum gcc_jit_str_option opt, const char *value); diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index cda15b4c30d74..1f785df6aaf87 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -1309,6 +1309,23 @@ recording::context::new_array_access (recording::location *loc, return result; } +/* Create a recording::convert_vector instance and add it to this context's list + of mementos. + + Implements the post-error-checking part of + gcc_jit_context_convert_vector. */ + +recording::rvalue * +recording::context::new_convert_vector (recording::location *loc, + recording::rvalue *vector, + recording::type *type) +{ + // TODO: instead have an "internal function" memento? + recording::rvalue *result = new convert_vector (this, loc, vector, type); + record (result); + return result; +} + /* Create a recording::case_ instance and add it to this context's list of mementos. @@ -6268,6 +6285,61 @@ recording::array_access::write_reproducer (reproducer &r) r.get_identifier_as_rvalue (m_index)); } +/* The implementation of class gcc::jit::recording::convert_vector. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::convert_vector. */ + +void +recording::convert_vector::replay_into (replayer *r) +{ + set_playback_obj ( + r->convert_vector (playback_location (r, m_loc), + m_vector->playback_rvalue (), + m_type->playback_type ())); +} + +/* Implementation of pure virtual hook recording::rvalue::visit_children + for recording::convert_vector. */ + +void +recording::convert_vector::visit_children (rvalue_visitor *v) +{ + v->visit (m_vector); +} + +/* Implementation of recording::memento::make_debug_string for + array accesses. */ + +recording::string * +recording::convert_vector::make_debug_string () +{ + enum precedence prec = get_precedence (); + return string::from_printf (m_ctxt, + "(%s)%s", + m_type->get_debug_string (), + m_vector->get_debug_string_parens (prec)); +} + +/* Implementation of recording::memento::write_reproducer for + convert_vector. */ + +void +recording::convert_vector::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "lvalue"); + r.write (" gcc_jit_lvalue *%s = \n" + " gcc_jit_context_convert_vector (%s, /* gcc_jit_context *ctxt */\n" + " %s, /*gcc_jit_location *loc */\n" + " %s, /* gcc_jit_rvalue *vector */\n" + " %s); /* gcc_jit_type *type */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_loc), + r.get_identifier_as_rvalue (m_vector), + r.get_identifier_as_type (m_type)); +} + /* The implementation of class gcc::jit::recording::access_field_of_lvalue. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 6fe52eb5865ad..1766a59d0b989 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -215,6 +215,11 @@ class context : public log_user rvalue *ptr, rvalue *index); + rvalue * + new_convert_vector (location *loc, + rvalue *vector, + type *type); + case_ * new_case (rvalue *min_value, rvalue *max_value, @@ -1885,6 +1890,35 @@ class array_access : public lvalue rvalue *m_index; }; +class convert_vector : public rvalue +{ +public: + convert_vector (context *ctxt, + location *loc, + rvalue *vector, + type *type) + : rvalue (ctxt, loc, type), + m_vector (vector), + m_type (type) + {} + + void replay_into (replayer *r) final override; + + void visit_children (rvalue_visitor *v) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + enum precedence get_precedence () const final override + { + return PRECEDENCE_POSTFIX; + } + +private: + rvalue *m_vector; + type *m_type; +}; + class access_field_of_lvalue : public lvalue { public: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 7447025bc0a81..7cc10a6a1df5e 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -2503,6 +2503,31 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt, return (gcc_jit_lvalue *)ctxt->new_array_access (loc, ptr, index); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::new_convert_vector method in + jit-recording.cc. */ + +gcc_jit_rvalue * +gcc_jit_context_convert_vector (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_NULL_IF_FAIL (vector, ctxt, loc, "NULL vector"); + RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); + + // TODO: check if the value is a vector. + // TODO: check if type is a vector type. + // TODO: check if the number of elements in vector and type matches. + + return (gcc_jit_rvalue *)ctxt->new_convert_vector (loc, vector, type); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 079cfc72e61e1..26b61920b1925 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1292,6 +1292,12 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt, gcc_jit_rvalue *ptr, gcc_jit_rvalue *index); +extern gcc_jit_rvalue * +gcc_jit_context_convert_vector (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_type *type); + /* Field access is provided separately for both lvalues and rvalues. */ /* Accessing a field of an lvalue of struct type, analogous to: diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 84678896637c2..59cd8a1bfa953 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -281,3 +281,8 @@ LIBGCCJIT_ABI_26 { global: gcc_jit_type_is_const; } LIBGCCJIT_ABI_25; + +LIBGCCJIT_ABI_27 { + global: + gcc_jit_context_convert_vector; +} LIBGCCJIT_ABI_26; From f1b57c789777b93ddb8bf79febdd66997d328d42 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 24 May 2022 17:44:53 -0400 Subject: [PATCH 07/45] Allow sending a const pointer as argument --- gcc/jit/jit-recording.h | 6 ------ gcc/jit/libgccjit.cc | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 1766a59d0b989..3bbe1f076da62 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -729,12 +729,6 @@ class memento_of_get_const : public decorated_type memento_of_get_const (type *other_type) : decorated_type (other_type) {} - bool accepts_writes_from (type */*rtype*/) final override - { - /* Can't write to a "const". */ - return false; - } - /* Strip off the "const", giving the underlying type. */ type *unqualified () final override { return m_other_type; } diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 7cc10a6a1df5e..2c79246a3b387 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -2861,7 +2861,7 @@ gcc_jit_block_add_assignment (gcc_jit_block *block, RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); RETURN_IF_FAIL_PRINTF4 ( compatible_types (lvalue->get_type (), - rvalue->get_type ()), + rvalue->get_type ()) || lvalue->get_type ()->is_const () != NULL, ctxt, loc, "mismatching types:" " assignment to %s (type: %s) from %s (type: %s)", @@ -2907,7 +2907,7 @@ gcc_jit_block_add_assignment_op (gcc_jit_block *block, RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); RETURN_IF_FAIL_PRINTF4 ( compatible_types (lvalue->get_type (), - rvalue->get_type ()), + rvalue->get_type ()) || lvalue->get_type ()->is_const () != NULL, ctxt, loc, "mismatching types:" " assignment to %s (type: %s) involving %s (type: %s)", From 0137524a4f0b8cbd93c93b58429804efb8a460f8 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 24 May 2022 17:45:01 -0400 Subject: [PATCH 08/45] Add gcc_jit_global_set_readonly --- gcc/jit/jit-playback.cc | 15 +++++++++------ gcc/jit/jit-playback.h | 9 ++++++--- gcc/jit/jit-recording.cc | 6 ++++-- gcc/jit/jit-recording.h | 7 +++++++ gcc/jit/libgccjit.cc | 17 +++++++++++++++++ gcc/jit/libgccjit.h | 3 +++ gcc/jit/libgccjit.map | 5 +++++ 7 files changed, 51 insertions(+), 11 deletions(-) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 862c80be1097b..761fbef471e9e 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -615,7 +615,8 @@ global_new_decl (location *loc, enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags) + enum global_var_flags flags, + bool readonly) { gcc_assert (type); gcc_assert (name); @@ -654,7 +655,7 @@ global_new_decl (location *loc, break; } - if (TYPE_READONLY (type_tree)) + if (TYPE_READONLY (type_tree) || readonly) TREE_READONLY (inner) = 1; if (loc) @@ -682,10 +683,11 @@ new_global (location *loc, enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags) + enum global_var_flags flags, + bool readonly) { tree inner = - global_new_decl (loc, kind, type, name, flags); + global_new_decl (loc, kind, type, name, flags, readonly); return global_finalize_lvalue (inner); } @@ -830,9 +832,10 @@ new_global_initialized (location *loc, size_t initializer_num_elem, const void *initializer, const char *name, - enum global_var_flags flags) + enum global_var_flags flags, + bool readonly) { - tree inner = global_new_decl (loc, kind, type, name, flags); + tree inner = global_new_decl (loc, kind, type, name, flags, readonly); vec *constructor_elements = NULL; diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 491b6be0ca44f..47260be5e7917 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -112,7 +112,8 @@ class context : public log_user enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags); + enum global_var_flags flags, + bool readonly); lvalue * new_global_initialized (location *loc, @@ -122,7 +123,8 @@ class context : public log_user size_t initializer_num_elem, const void *initializer, const char *name, - enum global_var_flags flags); + enum global_var_flags flags, + bool readonly); rvalue * new_ctor (location *log, @@ -312,7 +314,8 @@ class context : public log_user enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags); + enum global_var_flags flags, + bool readonly); lvalue * global_finalize_lvalue (tree inner); diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 1f785df6aaf87..a929649cb59d9 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -4857,12 +4857,14 @@ recording::global::replay_into (replayer *r) / m_type->dereference ()->get_size (), m_initializer, playback_string (m_name), - m_flags) + m_flags, + m_readonly) : r->new_global (playback_location (r, m_loc), m_kind, m_type->playback_type (), playback_string (m_name), - m_flags); + m_flags, + m_readonly); if (m_tls_model != GCC_JIT_TLS_MODEL_NONE) global->set_tls_model (recording::tls_models[m_tls_model]); diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 3bbe1f076da62..9512e44bf836a 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -1213,6 +1213,12 @@ class lvalue : public rvalue as_rvalue () { return this; } const char *access_as_rvalue (reproducer &r) override; + + void set_readonly () + { + m_readonly = true; + } + virtual const char *access_as_lvalue (reproducer &r); virtual bool is_global () const { return false; } void set_tls_model (enum gcc_jit_tls_model model); @@ -1226,6 +1232,7 @@ class lvalue : public rvalue string *m_reg_name; enum gcc_jit_tls_model m_tls_model; unsigned m_alignment; + bool m_readonly = false; }; class param : public lvalue diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 2c79246a3b387..03a4a04e861b6 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -1868,6 +1868,23 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global, return global; } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::global::set_readonly method, in + jit-recording.cc. */ + +extern void +gcc_jit_global_set_readonly (gcc_jit_lvalue *global) +{ + RETURN_IF_FAIL (global, NULL, NULL, "NULL global"); + RETURN_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL, + "lvalue \"%s\" not a global", + global->get_debug_string ()); + + global->set_readonly (); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, this calls the trivial diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 26b61920b1925..6736cf345a39f 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1036,6 +1036,9 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global, const void *blob, size_t num_bytes); +extern void +gcc_jit_global_set_readonly (gcc_jit_lvalue *global); + /* Upcasting. */ extern gcc_jit_object * gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue); diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 59cd8a1bfa953..7c8c0f326ec49 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -286,3 +286,8 @@ LIBGCCJIT_ABI_27 { global: gcc_jit_context_convert_vector; } LIBGCCJIT_ABI_26; + +LIBGCCJIT_ABI_28 { + global: + gcc_jit_global_set_readonly; +} LIBGCCJIT_ABI_27; From ab15c3baa0dacffb097ca53708a0d13fac3b6c91 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 19 Jun 2022 15:07:38 -0400 Subject: [PATCH 09/45] Fix 'unrecognizable instruction' error for convert_vector (IFN_VEC_CONVERT) --- gcc/jit/jit-playback.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 761fbef471e9e..013063d86be76 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -1556,6 +1556,9 @@ convert_vector (location *loc, tree t_vector = vector->as_tree (); + /* It seems IFN_VEC_CONVERT only work on registers, not on memory. */ + if (TREE_CODE (t_vector) == VAR_DECL) + DECL_REGISTER (t_vector) = 1; tree t_result = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_VEC_CONVERT, type->as_tree (), 1, t_vector); if (loc) From 71c488c2deb1309ed0caa3d94e6b896bb2da7c23 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 9 Jun 2022 20:57:41 -0400 Subject: [PATCH 10/45] Fix a RTL bug for libgccjit which fixes a 'unrecognizable insn' error when generating some code using target-specific builtins --- gcc/emit-rtl.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc index a11f72f606b33..61603c37230c0 100644 --- a/gcc/emit-rtl.cc +++ b/gcc/emit-rtl.cc @@ -6191,8 +6191,13 @@ init_emit_once (void) /* Don't use gen_rtx_CONST_INT here since gen_rtx_CONST_INT in this case tries to use these variables. */ for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++) - const_int_rtx[i + MAX_SAVED_CONST_INT] = - gen_rtx_raw_CONST_INT (VOIDmode, (HOST_WIDE_INT) i); + { + // Do not initialize twice the constants because there are used elsewhere + // and libgccjit execute this function twice. + if (const_int_rtx[i + MAX_SAVED_CONST_INT] == NULL) + const_int_rtx[i + MAX_SAVED_CONST_INT] = + gen_rtx_raw_CONST_INT (VOIDmode, (HOST_WIDE_INT) i); + } if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT && STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT) From 96eed4fe2949535c05473a9c11fcc267ba94bca5 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 20 Jun 2022 14:34:39 -0400 Subject: [PATCH 11/45] WIP: Add support for function attributes --- gcc/jit/jit-playback.cc | 51 +++++++++++++++++++++++++++++++++++++++- gcc/jit/jit-playback.h | 6 ++++- gcc/jit/jit-recording.cc | 20 ++++++++++++++-- gcc/jit/jit-recording.h | 9 +++++++ gcc/jit/libgccjit.cc | 16 +++++++++++++ gcc/jit/libgccjit.h | 16 +++++++++++++ gcc/jit/libgccjit.map | 6 +++++ 7 files changed, 120 insertions(+), 4 deletions(-) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 013063d86be76..63d40e1621f33 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #define INCLUDE_MUTEX +#include "libgccjit.h" #include "system.h" #include "coretypes.h" #include "target.h" @@ -507,6 +508,20 @@ new_param (location *loc, return new param (this, inner); } +const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) +{ + switch (attr) + { + case GCC_JIT_FN_ATTRIBUTE_TARGET: + return "target"; + case GCC_JIT_FN_ATTRIBUTE_USED: + return "used"; + case GCC_JIT_FN_ATTRIBUTE_VISIBILITY: + return "visibility"; + } + return NULL; +} + /* Construct a playback::function instance. */ playback::function * @@ -517,7 +532,9 @@ new_function (location *loc, const char *name, const auto_vec *params, int is_variadic, - enum built_in_function builtin_id) + enum built_in_function builtin_id, + const std::vector &attributes, + const std::vector> &string_attributes) { int i; param *param; @@ -602,6 +619,38 @@ new_function (location *loc, DECL_ATTRIBUTES (fndecl)); } + for (auto attr: attributes) + { + tree ident = get_identifier (fn_attribute_to_string (attr)); + + /* See handle_used_attribute in gcc/c-family/c-attribs.cc. */ + if (attr == GCC_JIT_FN_ATTRIBUTE_USED) + { + TREE_USED (fndecl) = 1; + DECL_PRESERVE_P (fndecl) = 1; + } + + DECL_ATTRIBUTES (fndecl) = + tree_cons (ident, NULL_TREE, DECL_ATTRIBUTES (fndecl)); + } + + for (auto attr: string_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + std::string& value = std::get<1>(attr); + tree attribute_value = build_tree_list (NULL_TREE, ::build_string (value.length () + 1, value.c_str ())); + tree ident = get_identifier (fn_attribute_to_string (name)); + + /* See handle_target_attribute in gcc/c-family/c-attribs.cc. */ + if (name == GCC_JIT_FN_ATTRIBUTE_TARGET) + /* We need to call valid_attribute_p so that the hook set-up some internal options. */ + if (!targetm.target_option.valid_attribute_p (fndecl, ident, attribute_value, 0)) + continue; + + DECL_ATTRIBUTES (fndecl) = + tree_cons (ident, attribute_value, DECL_ATTRIBUTES (fndecl)); + } + function *func = new function (this, fndecl, kind); m_functions.safe_push (func); return func; diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 47260be5e7917..ef38d1325d137 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -21,7 +21,9 @@ along with GCC; see the file COPYING3. If not see #ifndef JIT_PLAYBACK_H #define JIT_PLAYBACK_H +#include #include // for std::pair +#include #include "timevar.h" #include "varasm.h" @@ -105,7 +107,9 @@ class context : public log_user const char *name, const auto_vec *params, int is_variadic, - enum built_in_function builtin_id); + enum built_in_function builtin_id, + const std::vector &attributes, + const std::vector> &string_attributes); lvalue * new_global (location *loc, diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index a929649cb59d9..1500d074f890d 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -4080,7 +4080,9 @@ recording::function::function (context *ctxt, m_builtin_id (builtin_id), m_locals (), m_blocks (), - m_fn_ptr_type (NULL) + m_fn_ptr_type (NULL), + m_attributes(), + m_string_attributes() { for (int i = 0; i< num_params; i++) { @@ -4139,7 +4141,9 @@ recording::function::replay_into (replayer *r) m_name->c_str (), ¶ms, m_is_variadic, - m_builtin_id)); + m_builtin_id, + m_attributes, + m_string_attributes)); } /* Create a recording::local instance and add it to @@ -4382,6 +4386,18 @@ recording::function::get_address (recording::location *loc) return result; } +void +recording::function::add_attribute (gcc_jit_fn_attribute attribute) +{ + m_attributes.push_back (attribute); +} + +void +recording::function::add_string_attribute (gcc_jit_fn_attribute attribute, const char* value) +{ + m_string_attributes.push_back (std::make_pair (attribute, std::string (value))); +} + /* Implementation of recording::memento::make_debug_string for functions. */ diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 9512e44bf836a..add1b9b930a44 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -23,6 +23,10 @@ along with GCC; see the file COPYING3. If not see #include "jit-common.h" #include "jit-logging.h" +#include "libgccjit.h" + +#include +#include class timer; @@ -1326,6 +1330,9 @@ class function : public memento rvalue *get_address (location *loc); + void add_attribute (gcc_jit_fn_attribute attribute); + void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value); + private: string * make_debug_string () final override; void write_reproducer (reproducer &r) final override; @@ -1341,6 +1348,8 @@ class function : public memento auto_vec m_locals; auto_vec m_blocks; type *m_fn_ptr_type; + std::vector m_attributes; + std::vector> m_string_attributes; }; class block : public memento diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 03a4a04e861b6..5979ed08c5e7f 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -4015,6 +4015,22 @@ gcc_jit_type_set_packed (gcc_jit_type *type) type->set_packed (); } +void +gcc_jit_function_add_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute) +{ + RETURN_IF_FAIL (func, NULL, NULL, "NULL func"); + + func->add_attribute (attribute); +} + +void +gcc_jit_function_add_string_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute, const char* value) +{ + RETURN_IF_FAIL (func, NULL, NULL, "NULL func"); + + func->add_string_attribute (attribute, value); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 6736cf345a39f..360c04bec6927 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2008,6 +2008,22 @@ gcc_jit_type_unqualified (gcc_jit_type *type); extern void gcc_jit_type_set_packed (gcc_jit_type *type); +/* Function attributes. */ +enum gcc_jit_fn_attribute +{ + GCC_JIT_FN_ATTRIBUTE_TARGET, + GCC_JIT_FN_ATTRIBUTE_USED, + GCC_JIT_FN_ATTRIBUTE_VISIBILITY, +}; + +/* Add an attribute to a function. */ +// TODO: also support integer values. +extern void +gcc_jit_function_add_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute); + +extern void +gcc_jit_function_add_string_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const char* value); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 7c8c0f326ec49..c33c07d4da08f 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -291,3 +291,9 @@ LIBGCCJIT_ABI_28 { global: gcc_jit_global_set_readonly; } LIBGCCJIT_ABI_27; + +LIBGCCJIT_ABI_29 { + global: + gcc_jit_function_add_attribute; + gcc_jit_function_add_string_attribute; +} LIBGCCJIT_ABI_28; From a39aa4ac4fbe565467020a3c532b989a0c041feb Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 10 Jul 2022 19:53:13 -0400 Subject: [PATCH 12/45] Disable check for unknown sizes in gcc_jit_rvalue_dereference_field to allow recursive types --- gcc/jit/libgccjit.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 5979ed08c5e7f..169e0a4922952 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -797,12 +797,13 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt, /* LOC can be NULL. */ RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name"); - RETURN_NULL_IF_FAIL_PRINTF2 ( + // TODO: check at playback if the size is known. + /*RETURN_NULL_IF_FAIL_PRINTF2 ( type->has_known_size (), ctxt, loc, "unknown size for field \"%s\" (type: %s)", name, - type->get_debug_string ()); + type->get_debug_string ());*/ RETURN_NULL_IF_FAIL_PRINTF1 ( !type->is_void (), ctxt, loc, From 24cafc4c4576c94fdf40d939e74c55c08a446e5b Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 24 Jul 2022 17:06:48 -0400 Subject: [PATCH 13/45] WIP: Add support for variable attributes --- gcc/jit/jit-playback.cc | 46 ++++++++++++++++++++++++++++++++++------ gcc/jit/jit-playback.h | 15 +++++++++---- gcc/jit/jit-recording.cc | 14 +++++++++--- gcc/jit/jit-recording.h | 6 +++++- gcc/jit/libgccjit.cc | 8 +++++++ gcc/jit/libgccjit.h | 11 ++++++++++ gcc/jit/libgccjit.map | 5 +++++ 7 files changed, 91 insertions(+), 14 deletions(-) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 63d40e1621f33..278f000091e59 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -522,6 +522,16 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) return NULL; } +const char* variable_attribute_to_string(gcc_jit_variable_attribute attr) +{ + switch (attr) + { + case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY: + return "visibility"; + } + return NULL; +} + /* Construct a playback::function instance. */ playback::function * @@ -665,7 +675,8 @@ global_new_decl (location *loc, type *type, const char *name, enum global_var_flags flags, - bool readonly) + bool readonly, + const std::vector> &attributes) { gcc_assert (type); gcc_assert (name); @@ -710,9 +721,27 @@ global_new_decl (location *loc, if (loc) set_tree_location (inner, loc); + set_variable_attribute (attributes, inner); + return inner; } +void +playback:: +set_variable_attribute(const std::vector> &attributes, tree decl) +{ + for (auto attr: attributes) + { + gcc_jit_variable_attribute& name = std::get<0>(attr); + std::string& value = std::get<1>(attr); + tree attribute_value = build_tree_list (NULL_TREE, ::build_string (value.length () + 1, value.c_str ())); + tree ident = get_identifier (variable_attribute_to_string (name)); + + DECL_ATTRIBUTES (decl) = + tree_cons (ident, attribute_value, DECL_ATTRIBUTES (decl)); + } +} + /* In use by new_global and new_global_initialized. */ playback::lvalue * @@ -733,10 +762,11 @@ new_global (location *loc, type *type, const char *name, enum global_var_flags flags, - bool readonly) + bool readonly, + const std::vector> &attributes) { tree inner = - global_new_decl (loc, kind, type, name, flags, readonly); + global_new_decl (loc, kind, type, name, flags, readonly, attributes); return global_finalize_lvalue (inner); } @@ -882,9 +912,10 @@ new_global_initialized (location *loc, const void *initializer, const char *name, enum global_var_flags flags, - bool readonly) + bool readonly, + const std::vector> &attributes) { - tree inner = global_new_decl (loc, kind, type, name, flags, readonly); + tree inner = global_new_decl (loc, kind, type, name, flags, readonly, attributes); vec *constructor_elements = NULL; @@ -1901,7 +1932,8 @@ playback::lvalue * playback::function:: new_local (location *loc, type *type, - const char *name) + const char *name, + const std::vector> &attributes) { gcc_assert (type); gcc_assert (name); @@ -1914,6 +1946,8 @@ new_local (location *loc, DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr); BIND_EXPR_VARS (m_inner_bind_expr) = inner; + set_variable_attribute (attributes, inner); + if (loc) set_tree_location (inner, loc); return new lvalue (m_ctxt, inner); diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index ef38d1325d137..74b9d2393bf3e 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -43,6 +43,9 @@ namespace jit { namespace playback { +void +set_variable_attribute(const std::vector> &attributes, tree decl); + /* playback::context is an abstract base class. The two concrete subclasses are: @@ -117,7 +120,8 @@ class context : public log_user type *type, const char *name, enum global_var_flags flags, - bool readonly); + bool readonly, + const std::vector> &attributes); lvalue * new_global_initialized (location *loc, @@ -128,7 +132,8 @@ class context : public log_user const void *initializer, const char *name, enum global_var_flags flags, - bool readonly); + bool readonly, + const std::vector> &attributes); rvalue * new_ctor (location *log, @@ -319,7 +324,8 @@ class context : public log_user type *type, const char *name, enum global_var_flags flags, - bool readonly); + bool readonly, + const std::vector> &attributes); lvalue * global_finalize_lvalue (tree inner); @@ -508,7 +514,8 @@ class function : public wrapper lvalue * new_local (location *loc, type *type, - const char *name); + const char *name, + const std::vector> &attributes); block* new_block (const char *name); diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 1500d074f890d..905e156d30f7d 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -4004,6 +4004,11 @@ void recording::lvalue::set_alignment (unsigned bytes) m_alignment = bytes; } +void recording::lvalue::add_attribute (gcc_jit_variable_attribute attribute, const char* value) +{ + m_attributes.push_back (std::make_pair (attribute, std::string (value))); +} + /* The implementation of class gcc::jit::recording::param. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -4874,13 +4879,15 @@ recording::global::replay_into (replayer *r) m_initializer, playback_string (m_name), m_flags, - m_readonly) + m_readonly, + m_attributes) : r->new_global (playback_location (r, m_loc), m_kind, m_type->playback_type (), playback_string (m_name), m_flags, - m_readonly); + m_readonly, + m_attributes); if (m_tls_model != GCC_JIT_TLS_MODEL_NONE) global->set_tls_model (recording::tls_models[m_tls_model]); @@ -6673,7 +6680,8 @@ recording::local::replay_into (replayer *r) playback::lvalue *obj = m_func->playback_function () ->new_local (playback_location (r, m_loc), m_type->playback_type (), - playback_string (m_name)); + playback_string (m_name), + m_attributes); if (m_reg_name != NULL) obj->set_register_name (m_reg_name->c_str ()); diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index add1b9b930a44..3f779f558c596 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -1197,7 +1197,8 @@ class lvalue : public rvalue m_link_section (NULL), m_reg_name (NULL), m_tls_model (GCC_JIT_TLS_MODEL_NONE), - m_alignment (0) + m_alignment (0), + m_attributes () {} playback::lvalue * @@ -1223,6 +1224,8 @@ class lvalue : public rvalue m_readonly = true; } + void add_attribute (gcc_jit_variable_attribute attribute, const char* value); + virtual const char *access_as_lvalue (reproducer &r); virtual bool is_global () const { return false; } void set_tls_model (enum gcc_jit_tls_model model); @@ -1237,6 +1240,7 @@ class lvalue : public rvalue enum gcc_jit_tls_model m_tls_model; unsigned m_alignment; bool m_readonly = false; + std::vector> m_attributes; }; class param : public lvalue diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 169e0a4922952..52b7983d8a0db 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -4032,6 +4032,14 @@ gcc_jit_function_add_string_attribute (gcc_jit_function *func, gcc_jit_fn_attrib func->add_string_attribute (attribute, value); } +void +gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, gcc_jit_variable_attribute attribute, const char* value) +{ + RETURN_IF_FAIL (variable, NULL, NULL, "NULL variable"); + + variable->add_attribute (attribute, value); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 360c04bec6927..e568c69391229 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2024,6 +2024,17 @@ gcc_jit_function_add_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribut extern void gcc_jit_function_add_string_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const char* value); +/* Variable attributes. */ +enum gcc_jit_variable_attribute +{ + GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY, +}; + +/* Add an attribute to a variable. */ +// TODO: also support integer values. +extern void +gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, enum gcc_jit_variable_attribute attribute, const char* value); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index c33c07d4da08f..36f480f62037b 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -297,3 +297,8 @@ LIBGCCJIT_ABI_29 { gcc_jit_function_add_attribute; gcc_jit_function_add_string_attribute; } LIBGCCJIT_ABI_28; + +LIBGCCJIT_ABI_30 { + global: + gcc_jit_lvalue_add_attribute; +} LIBGCCJIT_ABI_29; From 38b8410304810f44bd9c3804e448c32f6cf8e673 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 3 Oct 2022 19:11:39 -0400 Subject: [PATCH 14/45] Support signed char flag --- gcc/jit/dummy-frontend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index cc6da5a3b7d5f..a0ce78cf37f89 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -592,7 +592,7 @@ jit_langhook_init (void) global_dc->begin_diagnostic = jit_begin_diagnostic; global_dc->end_diagnostic = jit_end_diagnostic; - build_common_tree_nodes (false); + build_common_tree_nodes (flag_signed_char); build_common_builtin_nodes (); From 5522d7576bad4d0d581bfb8b9eab6a366021f7ea Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 3 Jan 2023 15:04:41 -0500 Subject: [PATCH 15/45] Add missing builtins needed by optimizations --- gcc/jit/jit-builtins.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc index fb86c77d0fe1c..e03e2fd23ae04 100644 --- a/gcc/jit/jit-builtins.cc +++ b/gcc/jit/jit-builtins.cc @@ -609,6 +609,9 @@ builtins_manager::ensure_optimization_builtins_exist () We can't loop through all of the builtin_data array, we don't support all types yet. */ (void)get_builtin_function_by_id (BUILT_IN_TRAP); + (void)get_builtin_function_by_id (BUILT_IN_POPCOUNT); + (void)get_builtin_function_by_id (BUILT_IN_POPCOUNTL); + (void)get_builtin_function_by_id (BUILT_IN_POPCOUNTLL); } /* Playback support. */ From 29bf2fc2e288db838d40782ee662bb7b9b93d963 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 14 Oct 2022 20:38:48 -0400 Subject: [PATCH 16/45] Add support for try/catch --- gcc/dwarf2asm.cc | 10 ++++ gcc/dwarf2asm.h | 2 + gcc/dwarf2out.cc | 3 + gcc/jit/dummy-frontend.cc | 8 +++ gcc/jit/jit-playback.cc | 79 ++++++++++++++++++++++++ gcc/jit/jit-playback.h | 10 ++++ gcc/jit/jit-recording.cc | 123 ++++++++++++++++++++++++++++++++++++++ gcc/jit/jit-recording.h | 53 ++++++++++++++++ gcc/jit/libgccjit.cc | 72 ++++++++++++++++++++++ gcc/jit/libgccjit.h | 36 +++++++++++ gcc/jit/libgccjit.map | 8 +++ gcc/toplev.cc | 1 + gcc/tree-eh.cc | 5 +- gcc/tree.cc | 1 + 14 files changed, 409 insertions(+), 2 deletions(-) diff --git a/gcc/dwarf2asm.cc b/gcc/dwarf2asm.cc index 65b95fee243fb..e66cd30c1fe87 100644 --- a/gcc/dwarf2asm.cc +++ b/gcc/dwarf2asm.cc @@ -1159,4 +1159,14 @@ dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool is_public, va_end (ap); } +void dwarf2asm_cc_finalize (void) +{ + if (indirect_pool) + { + indirect_pool->empty(); + indirect_pool = NULL; + } + dw2_const_labelno = 0; +} + #include "gt-dwarf2asm.h" diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h index 37a0a05e5bb1c..80695b3c6c8b3 100644 --- a/gcc/dwarf2asm.h +++ b/gcc/dwarf2asm.h @@ -86,6 +86,8 @@ extern const char *eh_data_format_name (int); extern rtx dw2_force_const_mem (rtx, bool); extern void dw2_output_indirect_constants (void); +void dwarf2asm_cc_finalize (void); + /* These are currently unused. */ #if 0 diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 1f39df3b1e250..61b711d4a5269 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -1003,6 +1003,9 @@ dwarf2out_do_cfi_startproc (bool second) if (targetm.asm_out.make_eh_symbol_indirect != NULL) ref = targetm.asm_out.make_eh_symbol_indirect (ref, true); else + // TODO: HERE: should not insert multiple times the same personality function. + // If we don't, we segfault later, possibly because we don't generate the info for the duplicates. + // I'm not sure why it's attempting to insert multiple times the same personality function. ref = dw2_force_const_mem (ref, true); } diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index a0ce78cf37f89..b671b1e42f2c1 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -594,8 +594,16 @@ jit_langhook_init (void) build_common_tree_nodes (flag_signed_char); + /* I don't know why this has to be done explicitly. */ + void_list_node = build_tree_list (NULL_TREE, void_type_node); + + target_builtins.empty (); build_common_builtin_nodes (); + /* Initialize EH, if we've been told to do so. */ + if (flag_exceptions) + using_eh_for_cleanups (); + /* The default precision for floating point numbers. This is used for floating point constants with abstract type. This may eventually be controllable by a command line option. */ diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 278f000091e59..6551cabb6b08d 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -567,6 +567,7 @@ new_function (location *loc, /* FIXME: this uses input_location: */ tree fndecl = build_fn_decl (name, fn_type); + TREE_NOTHROW (fndecl) = 0; if (loc) set_tree_location (fndecl, loc); @@ -1980,6 +1981,15 @@ playback::function::get_address (location *loc) return new rvalue (m_ctxt, t_fnptr); } +/* Construct a new local within this playback::function. */ + +void +playback::function:: +set_personality_function (function *personality_function) +{ + DECL_FUNCTION_PERSONALITY (m_inner_fndecl) = personality_function->as_fndecl (); +} + /* Build a statement list for the function as a whole out of the lists of statements for the individual blocks, building labels for each block. */ @@ -1998,6 +2008,11 @@ build_stmt_list () int j; tree stmt; + // Do not add try/catch block to the function. + // TODO: explain why. + if (b->m_is_try_or_catch) + continue; + b->m_label_expr = build1 (LABEL_EXPR, void_type_node, b->as_label_decl ()); @@ -2096,6 +2111,70 @@ add_eval (location *loc, add_stmt (rvalue->as_tree ()); } + +void +playback::block:: +add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally) +{ + gcc_assert (try_block); + gcc_assert (catch_block); + + try_block->m_is_try_or_catch = true; + catch_block->m_is_try_or_catch = true; + + if (loc) + { + set_tree_location (try_block->as_label_decl (), loc); + set_tree_location (catch_block->as_label_decl (), loc); + } + + tree try_body = alloc_stmt_list (); + int i; + tree stmt; + FOR_EACH_VEC_ELT (try_block->m_stmts, i, stmt) { + append_to_statement_list (stmt, &try_body); + } + + tree catch_body = alloc_stmt_list (); + int j; + tree catch_stmt; + FOR_EACH_VEC_ELT (catch_block->m_stmts, j, catch_stmt) { + append_to_statement_list (catch_stmt, &catch_body); + } + + if (is_finally) + { + tree success_body = alloc_stmt_list (); + + // TODO: find a better way to keep the EH_ELSE_EXPR than creating an empty inline asm. + tree t_string = build_string (""); + tree asm_stmt + = build5 (ASM_EXPR, void_type_node, t_string, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + + // asm statements without outputs, including simple ones, are treated + // as volatile. + ASM_VOLATILE_P (asm_stmt) = 1; + ASM_INPUT_P (asm_stmt) = 0; + append_to_statement_list (asm_stmt, &success_body); + + // TODO: Don't automatically add the `EH_ELSE_EXPR`. Make an API to create such a node and let the user of libgccjit + // add it manually. + catch_body = build2 (EH_ELSE_EXPR, void_type_node, success_body, catch_body); + add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, + try_body, catch_body)); + } + else + { + catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body); + tree try_catch = build2 (TRY_CATCH_EXPR, void_type_node, + try_body, catch_body); + add_stmt (try_catch); + } +} + /* Add an assignment to the function's statement list. */ void diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 74b9d2393bf3e..e650489c738ee 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -523,6 +523,9 @@ class function : public wrapper rvalue * get_address (location *loc); + void + set_personality_function (function *personality_function); + void build_stmt_list (); @@ -593,6 +596,12 @@ class block : public wrapper add_eval (location *loc, rvalue *rvalue); + void + add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally); + void add_assignment (location *loc, lvalue *lvalue, @@ -656,6 +665,7 @@ class block : public wrapper public: // for now tree m_label_expr; + bool m_is_try_or_catch = false; friend class function; }; diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 905e156d30f7d..cf1af67a7aca5 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -4151,6 +4151,36 @@ recording::function::replay_into (replayer *r) m_string_attributes)); } +/* Implementation of recording::memento::make_debug_string for + setting a personality function. */ + +recording::string * +recording::memento_of_set_personality_function::make_debug_string () +{ + return string::from_printf (m_ctxt, + "%s", + m_personality_function->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for setting the personality function. */ + +void +recording::memento_of_set_personality_function::write_reproducer (reproducer &r) +{ + r.write (" gcc_jit_function_set_personality_function (%s,\n" + " %s);\n", + r.get_identifier (m_function), + r.get_identifier (m_personality_function)); +} + +void +recording::function::set_personality_function (function *function) +{ + recording::memento_of_set_personality_function *result = + new memento_of_set_personality_function (m_ctxt, this, function); + m_ctxt->record (result); +} + /* Create a recording::local instance and add it to the functions's context's list of mementos, and to the function's list of locals. @@ -4293,6 +4323,13 @@ recording::function::validate () /* Iteratively walk the graph of blocks, marking their "m_is_reachable" flag, starting at the initial block. */ auto_vec worklist (m_blocks.length ()); + int j; + block *func_block; + /* Push the blocks used in try/catch because they're not successors of + other blocks. */ + FOR_EACH_VEC_ELT (m_blocks, j, func_block) + if (func_block->m_is_reachable) + worklist.safe_push (func_block); worklist.safe_push (m_blocks[0]); while (worklist.length () > 0) { @@ -4487,6 +4524,28 @@ recording::block::add_eval (recording::location *loc, return result; } +/* The implementation of class gcc::jit::recording::block. */ + +/* Create a recording::try_catch instance and add it to + the block's context's list of mementos, and to the block's + list of statements. + Implements the heart of gcc_jit_block_add_try_catch. */ + +recording::statement * +recording::block::add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally) +{ + statement *result = new try_catch (this, loc, try_block, catch_block, is_finally); + // TODO: explain why we set the blocks reachable state. + try_block->m_is_reachable = true; + catch_block->m_is_reachable = true; + m_ctxt->record (result); + m_statements.safe_push (result); + return result; +} + /* Create a recording::assignment instance and add it to the block's context's list of mementos, and to the block's list of statements. @@ -6755,6 +6814,17 @@ recording::statement::write_to_dump (dump &d) m_loc = d.make_location (); } +/* The implementation of class gcc::jit::recording::memento_of_set_personality_function. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_set_personality_function. */ + +void +recording::memento_of_set_personality_function::replay_into (replayer *r) +{ + m_function->playback_function ()->set_personality_function (m_personality_function->playback_function ()); +} + /* The implementation of class gcc::jit::recording::eval. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -6793,6 +6863,59 @@ recording::eval::write_reproducer (reproducer &r) r.get_identifier_as_rvalue (m_rvalue)); } +/* The implementation of class gcc::jit::recording::try_catch. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::try_catch. */ + +void +recording::try_catch::replay_into (replayer *r) +{ + playback_block (get_block ()) + ->add_try_catch (playback_location (r), + m_try_block->playback_block (), + m_catch_block->playback_block (), + m_is_finally); +} + +/* Implementation of recording::memento::make_debug_string for + an eval statement. */ + +recording::string * +recording::try_catch::make_debug_string () +{ + if (m_is_finally) + return string::from_printf (m_ctxt, + "try { %s } finally { %s };", + m_try_block->get_debug_string (), + m_catch_block->get_debug_string ()); + else + return string::from_printf (m_ctxt, + "try { %s } catch { %s };", + m_try_block->get_debug_string (), + m_catch_block->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for + eval statements. */ + +void +recording::try_catch::write_reproducer (reproducer &r) +{ + const char *func_name = "gcc_jit_block_add_try_catch"; + if (m_is_finally) + func_name = "gcc_jit_block_add_try_finally"; + r.write (" %s (%s, /*gcc_jit_block *block */\n" + " %s, /* gcc_jit_location *loc */\n" + " %s, /* gcc_jit_block *try_block */\n" + " %s); /* gcc_jit_block *catch_block */\n", + func_name, + r.get_identifier (get_block ()), + r.get_identifier (get_loc ()), + r.get_identifier (m_try_block), + r.get_identifier (m_catch_block)); +} + /* The implementation of class gcc::jit::recording::assignment. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 3f779f558c596..87ce3247ba982 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -1333,6 +1333,7 @@ class function : public memento void dump_to_dot (const char *path); rvalue *get_address (location *loc); + void set_personality_function (function *function); void add_attribute (gcc_jit_fn_attribute attribute); void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value); @@ -1382,6 +1383,12 @@ class block : public memento add_eval (location *loc, rvalue *rvalue); + statement * + add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally = false); + statement * add_assignment (location *loc, lvalue *lvalue, @@ -1597,6 +1604,27 @@ class memento_of_new_string_literal : public rvalue string *m_value; }; +class memento_of_set_personality_function : public memento +{ +public: + memento_of_set_personality_function (context *ctx, + function *func, + function *personality_function) + : memento(ctx), + m_function (func), + m_personality_function (personality_function) {} + + void replay_into (replayer *r) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + +private: + function *m_function; + function *m_personality_function; +}; + class memento_of_new_rvalue_from_vector : public rvalue { public: @@ -2173,6 +2201,31 @@ class eval : public statement rvalue *m_rvalue; }; +class try_catch : public statement +{ +public: + try_catch (block *b, + location *loc, + block *try_block, + block *catch_block, + bool is_finally = false) + : statement (b, loc), + m_try_block (try_block), + m_catch_block (catch_block), + m_is_finally (is_finally) {} + + void replay_into (replayer *r) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + +private: + block *m_try_block; + block *m_catch_block; + bool m_is_finally; +}; + class assignment : public statement { public: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 52b7983d8a0db..dd5d6a739e172 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -2859,6 +2859,64 @@ gcc_jit_block_add_eval (gcc_jit_block *block, rvalue->verify_valid_within_stmt (__func__, stmt); } +/* Public entrypoint. See description in libgccjit.h. + After error-checking, the real work is done by the + gcc::jit::recording::block::add_try_catch method in jit-recording.c. */ + +void +gcc_jit_block_add_try_catch (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *catch_block) +{ + RETURN_IF_NOT_VALID_BLOCK (block, loc); + gcc::jit::recording::context *ctxt = block->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_IF_FAIL (try_block, ctxt, loc, "NULL rvalue"); + RETURN_IF_FAIL (catch_block, ctxt, loc, "NULL rvalue"); + + gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, catch_block); + + // TODO: remove this or use it. + /* "stmt" should be good enough to be usable in error-messages, + but might still not be compilable; perform some more + error-checking here. We do this here so that the error messages + can contain a stringified version of "stmt", whilst appearing + as close as possible to the point of failure. */ + /*try_block->verify_valid_within_stmt (__func__, stmt); + catch_block->verify_valid_within_stmt (__func__, stmt);*/ +} + +/* Public entrypoint. See description in libgccjit.h. + After error-checking, the real work is done by the + gcc::jit::recording::block::add_try_catch method in jit-recording.c. */ + +void +gcc_jit_block_add_try_finally (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *finally_block) +{ + RETURN_IF_NOT_VALID_BLOCK (block, loc); + gcc::jit::recording::context *ctxt = block->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_IF_FAIL (try_block, ctxt, loc, "NULL rvalue"); + RETURN_IF_FAIL (finally_block, ctxt, loc, "NULL rvalue"); + + gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, finally_block, true); + + // TODO: remove this or use it. + /* "stmt" should be good enough to be usable in error-messages, + but might still not be compilable; perform some more + error-checking here. We do this here so that the error messages + can contain a stringified version of "stmt", whilst appearing + as close as possible to the point of failure. */ + /*try_block->verify_valid_within_stmt (__func__, stmt); + catch_block->verify_valid_within_stmt (__func__, stmt);*/ +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the @@ -3633,6 +3691,20 @@ gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt, ctxt->add_command_line_option (optname); } +/* Public entrypoint. See description in libgccjit.h. + After error-checking, the real work is done by the + gcc::jit::recording::function::set_personality_function method, in + jit-recording.c. */ + +void +gcc_jit_function_set_personality_function (gcc_jit_function *fn, + gcc_jit_function *personality_func) +{ + RETURN_IF_FAIL (fn, NULL, NULL, "NULL function"); + + fn->set_personality_function (personality_func); +} + /* Public entrypoint. See description in libgccjit.h. The real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index e568c69391229..3938e154d80e9 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1400,6 +1400,38 @@ gcc_jit_block_add_eval (gcc_jit_block *block, gcc_jit_location *loc, gcc_jit_rvalue *rvalue); +/* Add a try/catch statement. + This is equivalent to this C++ code: + try { + try_block + } + catch (...) { + catch_block + } +*/ + +void +gcc_jit_block_add_try_catch (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *catch_block); + +/* Add a try/finally statement. + This is equivalent to this C++-like code: + try { + try_block + } + finally { + finally_block + } +*/ + +void +gcc_jit_block_add_try_finally (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *finally_block); + /* Add evaluation of an rvalue, assigning the result to the given lvalue. @@ -1797,6 +1829,10 @@ extern gcc_jit_rvalue * gcc_jit_function_get_address (gcc_jit_function *fn, gcc_jit_location *loc); +void +gcc_jit_function_set_personality_function (gcc_jit_function *fn, + gcc_jit_function *personality_func); + #define LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 36f480f62037b..8027444471e6a 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -301,4 +301,12 @@ LIBGCCJIT_ABI_29 { LIBGCCJIT_ABI_30 { global: gcc_jit_lvalue_add_attribute; +<<<<<<< HEAD } LIBGCCJIT_ABI_29; + +LIBGCCJIT_ABI_31 { + global: + gcc_jit_block_add_try_catch; + gcc_jit_block_add_try_finally; + gcc_jit_function_set_personality_function; +} LIBGCCJIT_ABI_30; diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 42937f0ba004f..4469e0f069dd2 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -2332,6 +2332,7 @@ toplev::finalize (void) cgraphunit_cc_finalize (); symtab_thunks_cc_finalize (); dwarf2out_cc_finalize (); + dwarf2asm_cc_finalize (); gcse_cc_finalize (); ipa_cp_cc_finalize (); ira_costs_cc_finalize (); diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc index 41cf57d2b305f..b734f6be4168e 100644 --- a/gcc/tree-eh.cc +++ b/gcc/tree-eh.cc @@ -4882,9 +4882,10 @@ pass_cleanup_eh::execute (function *fun) /* If the function no longer needs an EH personality routine clear it. This exposes cross-language inlining opportunities and avoids references to a never defined personality routine. */ - if (DECL_FUNCTION_PERSONALITY (current_function_decl) + // TODO: uncomment and find out why this doesn't work. + /*if (DECL_FUNCTION_PERSONALITY (current_function_decl) && function_needs_eh_personality (fun) != eh_personality_lang) - DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE; + DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE;*/ return ret; } diff --git a/gcc/tree.cc b/gcc/tree.cc index 78b64ee98b3e5..ea95e67bb7968 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -15006,6 +15006,7 @@ void tree_cc_finalize (void) { clear_nonstandard_integer_type_cache (); + gcc_eh_personality_decl = NULL; } #if CHECKING_P From 8281be457d9ee9be4c26d5a3a29c118e7c601988 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 23 Jan 2023 17:21:23 -0500 Subject: [PATCH 17/45] TODO: add comment to fix is_int --- gcc/jit/jit-recording.h | 1 + 1 file changed, 1 insertion(+) diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 87ce3247ba982..5ee368e6d2b4f 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -714,6 +714,7 @@ class decorated_type : public type size_t get_size () final override { return m_other_type->get_size (); }; + // FIXME: this is wrong. A vector is not an int. bool is_int () const final override { return m_other_type->is_int (); } bool is_float () const final override { return m_other_type->is_float (); } bool is_bool () const final override { return m_other_type->is_bool (); } From 561b4caa9411a641ca9650ad8d886d90e1bfd00a Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 3 Feb 2023 12:28:25 -0500 Subject: [PATCH 18/45] Allow not terminating finally blocks --- gcc/jit/jit-playback.cc | 4 ++-- gcc/jit/jit-recording.cc | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 6551cabb6b08d..8d5b9a72852ab 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -2132,14 +2132,14 @@ add_try_catch (location *loc, } tree try_body = alloc_stmt_list (); - int i; + unsigned int i; tree stmt; FOR_EACH_VEC_ELT (try_block->m_stmts, i, stmt) { append_to_statement_list (stmt, &try_body); } tree catch_body = alloc_stmt_list (); - int j; + unsigned int j; tree catch_stmt; FOR_EACH_VEC_ELT (catch_block->m_stmts, j, catch_stmt) { append_to_statement_list (catch_stmt, &catch_body); diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index cf1af67a7aca5..e23015bdd9215 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -4541,6 +4541,9 @@ recording::block::add_try_catch (location *loc, // TODO: explain why we set the blocks reachable state. try_block->m_is_reachable = true; catch_block->m_is_reachable = true; + /* The finally block can fallthrough, so we don't require the user to terminate it. */ + if (is_finally) + catch_block->m_has_been_terminated = true; m_ctxt->record (result); m_statements.safe_push (result); return result; From 5d25bd6182423f5f31550d32d8a7960bf22a48c6 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 11 Feb 2023 14:57:09 -0500 Subject: [PATCH 19/45] libgccjit: Add support for machine-dependent builtins gcc/config/i386: PR jit/TODO * i386-builtins.cc: New function (clear_builtin_types). gcc/jit: PR jit/TODO * dummy-frontend.cc: Include headers target.h, jit-recording.h, unordered_map and string, new variables (target_function_types, and target_builtins_ctxt), new function (tree_type_to_jit_type). * jit-builtins.cc: Specify that the function types are not from target builtins. * jit-playback.cc: New argument is_target_builtin to new_function. * jit-playback.h * jit-recording.cc * jit-recording.h * libgccjit.cc * libgccjit.h * libgccjit.map gcc/testsuite/jit.dg: PR jit/TODO * all-non-failing-tests.h * test-target-builtins.c --- gcc/config/i386/i386-builtins.cc | 18 ++ gcc/jit/dummy-frontend.cc | 220 +++++++++++++++- gcc/jit/jit-builtins.cc | 6 +- gcc/jit/jit-common.h | 2 +- gcc/jit/jit-playback.cc | 163 +++++++++++- gcc/jit/jit-playback.h | 16 +- gcc/jit/jit-recording.cc | 250 ++++++++++++++++++- gcc/jit/jit-recording.h | 171 ++++++++++++- gcc/jit/libgccjit.cc | 116 +++++++++ gcc/jit/libgccjit.h | 31 ++- gcc/jit/libgccjit.map | 8 +- gcc/testsuite/jit.dg/all-non-failing-tests.h | 3 + gcc/testsuite/jit.dg/test-target-builtins.c | 77 ++++++ 13 files changed, 1057 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-target-builtins.c diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc index 01192ef4259a2..37df854ba514b 100644 --- a/gcc/config/i386/i386-builtins.cc +++ b/gcc/config/i386/i386-builtins.cc @@ -226,6 +226,22 @@ static GTY(()) tree ix86_builtins[(int) IX86_BUILTIN_MAX]; struct builtin_isa ix86_builtins_isa[(int) IX86_BUILTIN_MAX]; +static void +clear_builtin_types (void) +{ + for (int i = 0 ; i < IX86_BT_LAST_CPTR + 1 ; i++) + ix86_builtin_type_tab[i] = NULL; + + for (int i = 0 ; i < IX86_BUILTIN_MAX ; i++) + { + ix86_builtins[i] = NULL; + ix86_builtins_isa[i].set_and_not_built_p = true; + } + + for (int i = 0 ; i < IX86_BT_LAST_ALIAS + 1 ; i++) + ix86_builtin_func_type_tab[i] = NULL; +} + tree get_ix86_builtin (enum ix86_builtins c) { return ix86_builtins[c]; @@ -1443,6 +1459,8 @@ ix86_init_builtins (void) { tree ftype, decl; + clear_builtin_types (); + ix86_init_builtin_types (); /* Builtins to get CPU type and features. */ diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index b671b1e42f2c1..897511be8da88 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" +#include "target.h" #include "jit-playback.h" #include "stor-layout.h" #include "debug.h" @@ -29,8 +30,14 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "stringpool.h" #include "attribs.h" +#include "jit-recording.h" +#include "print-tree.h" #include +#include +#include + +using namespace gcc::jit; /* Attribute handling. */ @@ -86,6 +93,10 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = ATTR_EXCL (NULL, false, false, false) }; +hash_map target_builtins{}; +std::unordered_map target_function_types{}; +recording::context target_builtins_ctxt{NULL}; + /* Table of machine-independent attributes supported in libgccjit. */ const struct attribute_spec jit_attribute_table[] = { @@ -609,6 +620,8 @@ jit_langhook_init (void) eventually be controllable by a command line option. */ mpfr_set_default_prec (256); + targetm.init_builtins (); + return true; } @@ -676,11 +689,216 @@ jit_langhook_type_for_mode (machine_mode mode, int unsignedp) return NULL; } -/* Record a builtin function. We just ignore builtin functions. */ +recording::type* tree_type_to_jit_type (tree type) +{ + if (TREE_CODE (type) == VECTOR_TYPE) + { + tree inner_type = TREE_TYPE (type); + recording::type* element_type = tree_type_to_jit_type (inner_type); + poly_uint64 size = TYPE_VECTOR_SUBPARTS (type); + long constant_size = size.to_constant(); + if (element_type != NULL) + return element_type->get_vector (constant_size); + return NULL; + } + if (TREE_CODE (type) == REFERENCE_TYPE) + { + // For __builtin_ms_va_start. + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type. + } + if (TREE_CODE (type) == RECORD_TYPE) + { + // For __builtin_sysv_va_copy. + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type. + } + for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++) + { + if (type == FLOATN_NX_TYPE_NODE (i)) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type. + } + } + if (type == void_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); + } + else if (type == ptr_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID_PTR); + } + else if (type == const_ptr_type_node) + { + // Void const ptr. + recording::type* result = new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID_PTR); + return new recording::memento_of_get_const (result); + } + else if (type == unsigned_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_INT); + } + else if (type == long_unsigned_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_LONG); + } + else if (type == integer_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_INT); + } + else if (type == long_integer_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_LONG); + } + else if (type == long_long_integer_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_LONG_LONG); + } + else if (type == signed_char_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_SIGNED_CHAR); + } + else if (type == char_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_CHAR); + } + else if (type == unsigned_intQI_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UINT8_T); + } + else if (type == short_integer_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_SHORT); + } + else if (type == short_unsigned_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_SHORT); + } + else if (type == complex_float_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_COMPLEX_FLOAT); + } + else if (type == complex_double_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE); + } + else if (type == complex_long_double_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE); + } + else if (type == float_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_FLOAT); + } + else if (type == double_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_DOUBLE); + } + else if (type == long_double_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_LONG_DOUBLE); + } + else if (type == bfloat16_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_BFLOAT16); + } + else if (type == dfloat128_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type. + } + else if (type == long_long_unsigned_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_LONG_LONG); + } + else if (type == boolean_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_BOOL); + } + else if (type == size_type_node) + { + return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_SIZE_T); + } + else if (TREE_CODE (type) == POINTER_TYPE) + { + tree inner_type = TREE_TYPE (type); + recording::type* element_type = tree_type_to_jit_type (inner_type); + return element_type->get_pointer(); + } + else + { + // Attempt to find an unqualified type when the current type has qualifiers. + tree tp = TYPE_MAIN_VARIANT (type); + for ( ; tp != NULL ; tp = TYPE_NEXT_VARIANT (tp)) + { + if (TYPE_QUALS (tp) == 0 && type != tp) + { + recording::type* result = tree_type_to_jit_type (tp); + if (result != NULL) + { + if (TYPE_READONLY (tp)) + result = new recording::memento_of_get_const (result); + if (TYPE_VOLATILE (tp)) + result = new recording::memento_of_get_volatile (result); + return result; + } + } + } + + fprintf (stderr, "Unknown type:\n"); + debug_tree (type); + abort (); + } + + return NULL; +} + +/* Record a builtin function. We save their types to be able to check types + in recording and for reflection. */ static tree jit_langhook_builtin_function (tree decl) { + if (TREE_CODE (decl) == FUNCTION_DECL) + { + const char* name = IDENTIFIER_POINTER (DECL_NAME (decl)); + target_builtins.put (name, decl); + + std::string string_name(name); + if (target_function_types.count (string_name) == 0) + { + tree function_type = TREE_TYPE (decl); + tree arg = TYPE_ARG_TYPES (function_type); + bool is_variadic = false; + + auto_vec param_types; + + while (arg != void_list_node) + { + if (arg == NULL) + { + is_variadic = true; + break; + } + if (arg != void_list_node) + { + recording::type* arg_type = tree_type_to_jit_type(TREE_VALUE (arg)); + if (arg_type == NULL) + return decl; + param_types.safe_push (arg_type); + } + arg = TREE_CHAIN (arg); + } + + tree result_type = TREE_TYPE (function_type); + recording::type* return_type = tree_type_to_jit_type(result_type); + + if (return_type == NULL) + return decl; + + recording::function_type* func_type = new recording::function_type (&target_builtins_ctxt, return_type, param_types.length (), + param_types.address (), is_variadic, false); + + target_function_types[string_name] = func_type; + } + } return decl; } diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc index e03e2fd23ae04..622a061ea8975 100644 --- a/gcc/jit/jit-builtins.cc +++ b/gcc/jit/jit-builtins.cc @@ -215,7 +215,8 @@ builtins_manager::make_builtin_function (enum built_in_function builtin_id) param_types.length (), params, func_type->is_variadic (), - builtin_id); + builtin_id, + false); delete[] params; /* PR/64020 - If the client code is using builtin cos or sin, @@ -582,7 +583,8 @@ builtins_manager::make_fn_type (enum jit_builtin_type, result = m_ctxt->new_function_type (return_type, num_args, param_types, - is_variadic); + is_variadic, + false); error: delete[] param_types; diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h index f9aead2f66c75..5c323411ea953 100644 --- a/gcc/jit/jit-common.h +++ b/gcc/jit/jit-common.h @@ -36,7 +36,7 @@ along with GCC; see the file COPYING3. If not see #endif #endif -const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_INT128_T + 1; +const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_BFLOAT16 + 1; /* This comment is included by the docs. diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 8d5b9a72852ab..55c6cc31e3def 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -281,6 +281,8 @@ get_tree_node_for_type (enum gcc_jit_types type_) case GCC_JIT_TYPE_FLOAT: return float_type_node; + case GCC_JIT_TYPE_BFLOAT16: + return bfloat16_type_node; case GCC_JIT_TYPE_DOUBLE: return double_type_node; case GCC_JIT_TYPE_LONG_DOUBLE: @@ -544,7 +546,8 @@ new_function (location *loc, int is_variadic, enum built_in_function builtin_id, const std::vector &attributes, - const std::vector> &string_attributes) + const std::vector> &string_attributes, + int is_target_builtin) { int i; param *param; @@ -579,6 +582,14 @@ new_function (location *loc, DECL_RESULT (fndecl) = resdecl; DECL_CONTEXT (resdecl) = fndecl; + if (is_target_builtin) + { + tree *decl = target_builtins.get(name); + if (decl != NULL) + fndecl = *decl; + else + add_error (loc, "cannot find target builtin %s", name); + } if (builtin_id) { gcc_assert (loc == NULL); @@ -1099,10 +1110,30 @@ playback::context::new_rvalue_from_vector (location *, vec_alloc (v, elements.length ()); for (unsigned i = 0; i < elements.length (); ++i) CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ()); - tree t_ctor = build_constructor (type->as_tree (), v); + tree t_ctor; + t_ctor = build_constructor (type->as_tree (), v); return new rvalue (this, t_ctor); } +/* Construct a playback::rvalue instance (wrapping a tree) for a + vector perm. */ + +playback::rvalue * +playback::context::new_rvalue_vector_perm (location *loc, + rvalue* elements1, + rvalue* elements2, + rvalue* mask) +{ + tree t_elements1 = elements1->as_tree (); + tree t_elements2 = elements2->as_tree (); + tree t_mask = mask->as_tree (); + + tree t_vector_perm = build3 (VEC_PERM_EXPR, TREE_TYPE (t_elements1), t_elements1, t_elements2, t_mask); + if (loc) + set_tree_location (t_vector_perm, loc); + return new rvalue (this, t_vector_perm); +} + /* Coerce a tree expression into a boolean tree expression. */ tree @@ -1648,6 +1679,134 @@ convert_vector (location *loc, return new rvalue (this, t_result); } +/* The following functions come from c-common.h. */ +/* Like c_mark_addressable but don't check register qualifier. */ +void +common_mark_addressable_vec (tree t) +{ + while (handled_component_p (t) || TREE_CODE (t) == C_MAYBE_CONST_EXPR) + { + t = TREE_OPERAND (t, 0); + } + if (!VAR_P (t) + && TREE_CODE (t) != PARM_DECL + && TREE_CODE (t) != COMPOUND_LITERAL_EXPR + && TREE_CODE (t) != TARGET_EXPR) + return; + if (!VAR_P (t) || !DECL_HARD_REGISTER (t)) + TREE_ADDRESSABLE (t) = 1; + if (TREE_CODE (t) == COMPOUND_LITERAL_EXPR) + TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (t)) = 1; + else if (TREE_CODE (t) == TARGET_EXPR) + TREE_ADDRESSABLE (TARGET_EXPR_SLOT (t)) = 1; +} + +/* Return true if TYPE is a vector type that should be subject to the GNU + vector extensions (as opposed to a vector type that is used only for + the purposes of defining target-specific built-in functions). */ + +inline bool +gnu_vector_type_p (const_tree type) +{ + return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type); +} + +/* Return nonzero if REF is an lvalue valid for this language. + Lvalues can be assigned, unless their type has TYPE_READONLY. + Lvalues can have their address taken, unless they have C_DECL_REGISTER. */ + +bool +lvalue_p (const_tree ref) +{ + const enum tree_code code = TREE_CODE (ref); + + switch (code) + { + case REALPART_EXPR: + case IMAGPART_EXPR: + case COMPONENT_REF: + return lvalue_p (TREE_OPERAND (ref, 0)); + + case C_MAYBE_CONST_EXPR: + return lvalue_p (TREE_OPERAND (ref, 1)); + + case COMPOUND_LITERAL_EXPR: + case STRING_CST: + return true; + + case MEM_REF: + case TARGET_MEM_REF: + /* MEM_REFs can appear from -fgimple parsing or folding, so allow them + here as well. */ + case INDIRECT_REF: + case ARRAY_REF: + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + case ERROR_MARK: + return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE); + + case BIND_EXPR: + return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE; + + default: + return false; + } +} + +bool +convert_vector_to_array_for_subscript (tree *vecp) +{ + bool ret = false; + if (gnu_vector_type_p (TREE_TYPE (*vecp))) + { + tree type = TREE_TYPE (*vecp); + + ret = !lvalue_p (*vecp); + + /* We are building an ARRAY_REF so mark the vector as addressable + to not run into the gimplifiers premature setting of DECL_GIMPLE_REG_P + for function parameters. */ + // NOTE: that was the missing piece for making vector access work with optimizations enabled. + common_mark_addressable_vec (*vecp); + + *vecp = build1 (VIEW_CONVERT_EXPR, + build_array_type_nelts (TREE_TYPE (type), + TYPE_VECTOR_SUBPARTS (type)), + *vecp); + } + return ret; +} + +/* Construct a playback::lvalue instance (wrapping a tree) for a + vector access. */ + +playback::lvalue * +playback::context:: +new_vector_access (location *loc, + rvalue *vector, + rvalue *index) +{ + gcc_assert (vector); + gcc_assert (index); + + /* For comparison, see: + c/c-typeck.cc: build_array_ref + */ + + tree t_vector = vector->as_tree (); + bool non_lvalue = convert_vector_to_array_for_subscript (&t_vector); + tree type = TREE_TYPE (TREE_TYPE (t_vector)); + tree t_result = build4 (ARRAY_REF, type, t_vector, index->as_tree (), NULL_TREE, NULL_TREE); + if (non_lvalue) + t_result = non_lvalue (t_result); + + if (loc) + set_tree_location (t_result, loc); + return new lvalue (this, t_result); +} + /* Construct a tree for a field access. */ tree diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index e650489c738ee..319fc9cf59aa3 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -112,7 +112,8 @@ class context : public log_user int is_variadic, enum built_in_function builtin_id, const std::vector &attributes, - const std::vector> &string_attributes); + const std::vector> &string_attributes, + int is_target_builtin); lvalue * new_global (location *loc, @@ -159,6 +160,12 @@ class context : public log_user type *type, const auto_vec &elements); + rvalue * + new_rvalue_vector_perm (location *loc, + rvalue* elements1, + rvalue* elements2, + rvalue* mask); + rvalue * new_unary_op (location *loc, enum gcc_jit_unary_op op, @@ -208,6 +215,11 @@ class context : public log_user rvalue *vector, type *type); + lvalue * + new_vector_access (location *loc, + rvalue *vector, + rvalue *index); + void set_str_option (enum gcc_jit_str_option opt, const char *value); @@ -843,4 +855,6 @@ extern playback::context *active_playback_ctxt; } // namespace gcc +extern hash_map target_builtins; + #endif /* JIT_PLAYBACK_H */ diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index e23015bdd9215..c48a3fbe0ad55 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -933,14 +933,16 @@ recording::function_type * recording::context::new_function_type (recording::type *return_type, int num_params, recording::type **param_types, - int is_variadic) + int is_variadic, + int is_target_builtin) { recording::function_type *fn_type = new function_type (this, return_type, num_params, param_types, - is_variadic); + is_variadic, + is_target_builtin); record (fn_type); return fn_type; } @@ -962,7 +964,8 @@ recording::context::new_function_ptr_type (recording::location *, /* unused loc = new_function_type (return_type, num_params, param_types, - is_variadic); + is_variadic, + false); /* Return a pointer-type to the function type. */ return fn_type->get_pointer (); @@ -1005,7 +1008,7 @@ recording::context::new_function (recording::location *loc, loc, kind, return_type, new_string (name), num_params, params, is_variadic, - builtin_id); + builtin_id, false); record (result); m_functions.safe_push (result); @@ -1044,6 +1047,52 @@ recording::context::get_builtin_function (const char *name) return bm->get_builtin_function (name); } +/* Create a recording::function instance for a target-specific builtin. + + Implements the post-error-checking part of + gcc_jit_context_get_target_builtin_function. */ + +recording::function * +recording::context::get_target_builtin_function (const char *name) +{ + const char *asm_name = name; + if (target_function_types.count (name) == 0) + { + fprintf (stderr, "Cannot find target builtin %s\n", name); + return NULL; + } + + recording::function_type* func_type = target_function_types[name]->copy (this)->dyn_cast_function_type (); + const vec& param_types = func_type->get_param_types (); + recording::param **params = new recording::param *[param_types.length ()]; + + int i; + recording::type *param_type; + FOR_EACH_VEC_ELT (param_types, i, param_type) + { + char buf[16]; + snprintf (buf, 16, "arg%d", i); + params[i] = new_param (NULL, + param_type, + buf); + } + + recording::function *result = + new recording::function (this, + NULL, + GCC_JIT_FUNCTION_IMPORTED, // FIXME + func_type->get_return_type (), + new_string (asm_name), + param_types.length (), + params, + func_type->is_variadic (), + BUILT_IN_NONE, + true); + record (result); + + return result; +} + /* Create a recording::global instance and add it to this context's list of mementos. @@ -1108,6 +1157,18 @@ recording::context::new_rvalue_from_vector (location *loc, return result; } +recording::rvalue * +recording::context::new_rvalue_vector_perm (location *loc, + rvalue *elements1, + rvalue *elements2, + rvalue *mask) +{ + recording::rvalue *result + = new memento_of_new_rvalue_vector_perm (this, loc, elements1, elements2, mask); + record (result); + return result; +} + recording::rvalue * recording::context::new_ctor (recording::location *loc, recording::type *type, @@ -1326,6 +1387,22 @@ recording::context::new_convert_vector (recording::location *loc, return result; } +/* Create a recording::vector_access instance and add it to this context's list + of mementos. + + Implements the post-error-checking part of + gcc_jit_context_new_vector_access. */ + +recording::lvalue * +recording::context::new_vector_access (recording::location *loc, + recording::rvalue *vector, + recording::rvalue *index) +{ + recording::lvalue *result = new vector_access (this, loc, vector, index); + record (result); + return result; +} + /* Create a recording::case_ instance and add it to this context's list of mementos. @@ -2395,6 +2472,8 @@ recording::memento_of_get_type::get_size () case GCC_JIT_TYPE_FLOAT: size = FLOAT_TYPE_SIZE; break; + case GCC_JIT_TYPE_BFLOAT16: + return GET_MODE_UNIT_SIZE (BFmode); case GCC_JIT_TYPE_DOUBLE: size = DOUBLE_TYPE_SIZE; break; @@ -2454,6 +2533,7 @@ recording::memento_of_get_type::dereference () case GCC_JIT_TYPE_INT64_T: case GCC_JIT_TYPE_INT128_T: case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: case GCC_JIT_TYPE_COMPLEX_FLOAT: @@ -2518,6 +2598,7 @@ recording::memento_of_get_type::is_int () const return true; case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: return false; @@ -2576,6 +2657,7 @@ recording::memento_of_get_type::is_signed () const case GCC_JIT_TYPE_UINT128_T: case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: @@ -2635,6 +2717,7 @@ recording::memento_of_get_type::is_float () const return false; case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: return true; @@ -2698,6 +2781,7 @@ recording::memento_of_get_type::is_bool () const return false; case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_BFLOAT16: case GCC_JIT_TYPE_DOUBLE: case GCC_JIT_TYPE_LONG_DOUBLE: return false; @@ -2777,6 +2861,7 @@ static const char * const get_type_strings[] = { "__int32_t", /* GCC_JIT_TYPE_INT32_T */ "__int64_t", /* GCC_JIT_TYPE_INT64_T */ "__int128_t", /* GCC_JIT_TYPE_INT128_T */ + "bfloat16", /* GCC_JIT_TYPE_BFLOAT16 */ }; @@ -2823,6 +2908,7 @@ static const char * const get_type_enum_strings[] = { "GCC_JIT_TYPE_INT32_T", "GCC_JIT_TYPE_INT64_T", "GCC_JIT_TYPE_INT128_T", + "GCC_JIT_TYPE_BFLOAT16", }; void @@ -3121,11 +3207,13 @@ recording::function_type::function_type (context *ctxt, type *return_type, int num_params, type **param_types, - int is_variadic) + int is_variadic, + int is_target_builtin) : type (ctxt), m_return_type (return_type), m_param_types (), - m_is_variadic (is_variadic) + m_is_variadic (is_variadic), + m_is_target_builtin (is_target_builtin) { for (int i = 0; i< num_params; i++) m_param_types.safe_push (param_types[i]); @@ -4074,7 +4162,8 @@ recording::function::function (context *ctxt, int num_params, recording::param **params, int is_variadic, - enum built_in_function builtin_id) + enum built_in_function builtin_id, + int is_target_builtin) : memento (ctxt), m_loc (loc), m_kind (kind), @@ -4087,7 +4176,8 @@ recording::function::function (context *ctxt, m_blocks (), m_fn_ptr_type (NULL), m_attributes(), - m_string_attributes() + m_string_attributes(), + m_is_target_builtin (is_target_builtin) { for (int i = 0; i< num_params; i++) { @@ -4148,7 +4238,8 @@ recording::function::replay_into (replayer *r) m_is_variadic, m_builtin_id, m_attributes, - m_string_attributes)); + m_string_attributes, + m_is_target_builtin)); } /* Implementation of recording::memento::make_debug_string for @@ -4418,7 +4509,8 @@ recording::function::get_address (recording::location *loc) = m_ctxt->new_function_type (m_return_type, m_params.length (), param_types.address (), - m_is_variadic); + m_is_variadic, + m_is_target_builtin); m_fn_ptr_type = fn_type->get_pointer (); } gcc_assert (m_fn_ptr_type); @@ -5502,6 +5594,91 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r) elements_id); } +/* The implementation of class + gcc::jit::recording::memento_of_new_rvalue_vector_perm. */ + +/* The constructor for + gcc::jit::recording::memento_of_new_rvalue_vector_perm. */ + +recording::memento_of_new_rvalue_vector_perm:: +memento_of_new_rvalue_vector_perm (context *ctxt, + location *loc, + rvalue *elements1, + rvalue *elements2, + rvalue *mask) +: rvalue (ctxt, loc, elements1->get_type ()), + m_elements1 (elements1), + m_elements2 (elements2), + m_mask (mask) +{ +} + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_new_rvalue_vector_perm. */ + +void +recording::memento_of_new_rvalue_vector_perm::replay_into (replayer *r) +{ + playback::rvalue *playback_elements1 = m_elements1->playback_rvalue (); + playback::rvalue *playback_elements2 = m_elements2->playback_rvalue (); + playback::rvalue *playback_mask = m_mask->playback_rvalue (); + + set_playback_obj (r->new_rvalue_vector_perm (playback_location (r, m_loc), + playback_elements1, + playback_elements2, + playback_mask)); +} + +/* Implementation of pure virtual hook recording::rvalue::visit_children + for recording::memento_of_new_rvalue_from_vector. */ + + void +recording::memento_of_new_rvalue_vector_perm::visit_children (rvalue_visitor *v) +{ + v->visit (m_elements1); + v->visit (m_elements2); + v->visit (m_mask); +} + +/* Implementation of recording::memento::make_debug_string for + vectors. */ + + recording::string * +recording::memento_of_new_rvalue_vector_perm::make_debug_string () +{ + /* Now build a string. */ + string *result = string::from_printf (m_ctxt, + "shufflevector(%s, %s, %s)", + m_elements1->get_debug_string (), + m_elements2->get_debug_string (), + m_mask->get_debug_string ()); + + return result; + +} + +/* Implementation of recording::memento::write_reproducer for + vectors. */ + + void +recording::memento_of_new_rvalue_vector_perm::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "vector"); + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_vector_perm (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_location *loc */\n" + " %s, /* gcc_jit_rvalue **elements1*/\n" + " %s, /* gcc_jit_rvalue **elements2*/\n" + " %s); /* gcc_jit_rvalue **mask*/\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_loc), + r.get_identifier_as_rvalue (m_elements1), + r.get_identifier_as_rvalue (m_elements2), + r.get_identifier_as_rvalue (m_mask)); +} + + void recording::ctor::visit_children (rvalue_visitor *v) { @@ -6395,6 +6572,30 @@ recording::convert_vector::visit_children (rvalue_visitor *v) v->visit (m_vector); } +/* The implementation of class gcc::jit::recording::vector_access. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::vector_access. */ + +void +recording::vector_access::replay_into (replayer *r) +{ + set_playback_obj ( + r->new_vector_access (playback_location (r, m_loc), + m_vector->playback_rvalue (), + m_index->playback_rvalue ())); +} + +/* Implementation of pure virtual hook recording::rvalue::visit_children + for recording::vector_access. */ + +void +recording::vector_access::visit_children (rvalue_visitor *v) +{ + v->visit (m_vector); + v->visit (m_index); +} + /* Implementation of recording::memento::make_debug_string for array accesses. */ @@ -6427,6 +6628,35 @@ recording::convert_vector::write_reproducer (reproducer &r) r.get_identifier_as_type (m_type)); } +recording::string * +recording::vector_access::make_debug_string () +{ + enum precedence prec = get_precedence (); + return string::from_printf (m_ctxt, + "%s[%s]", + m_vector->get_debug_string_parens (prec), + m_index->get_debug_string_parens (prec)); +} + +/* Implementation of recording::memento::write_reproducer for + vector_access. */ + +void +recording::vector_access::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "lvalue"); + r.write (" gcc_jit_lvalue *%s = \n" + " gcc_jit_context_new_vector_access (%s, /* gcc_jit_context *ctxt */\n" + " %s, /*gcc_jit_location *loc */\n" + " %s, /* gcc_jit_rvalue *vector */\n" + " %s); /* gcc_jit_rvalue *index */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_loc), + r.get_identifier_as_rvalue (m_vector), + r.get_identifier_as_rvalue (m_index)); +} + /* The implementation of class gcc::jit::recording::access_field_of_lvalue. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 5ee368e6d2b4f..a3c3fc1a161b9 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -28,12 +28,16 @@ along with GCC; see the file COPYING3. If not see #include #include +#include +#include + class timer; +extern std::unordered_map target_function_types; + namespace gcc { namespace jit { - extern const char * const unary_op_reproducer_strings[]; extern const char * const binary_op_reproducer_strings[]; @@ -120,7 +124,8 @@ class context : public log_user new_function_type (type *return_type, int num_params, type **param_types, - int is_variadic); + int is_variadic, + int is_target_builtin); type * new_function_ptr_type (location *loc, @@ -147,6 +152,9 @@ class context : public log_user function * get_builtin_function (const char *name); + function * + get_target_builtin_function (const char *name); + lvalue * new_global (location *loc, enum gcc_jit_global_kind kind, @@ -177,6 +185,12 @@ class context : public log_user vector_type *type, rvalue **elements); + rvalue * + new_rvalue_vector_perm (location *loc, + rvalue *elements1, + rvalue *elements2, + rvalue *mask); + rvalue * new_unary_op (location *loc, enum gcc_jit_unary_op op, @@ -224,6 +238,11 @@ class context : public log_user rvalue *vector, type *type); + lvalue * + new_vector_access (location *loc, + rvalue *vector, + rvalue *index); + case_ * new_case (rvalue *min_value, rvalue *max_value, @@ -550,6 +569,8 @@ class type : public memento these types. */ virtual size_t get_size () { gcc_unreachable (); } + virtual type* copy(context* ctxt) = 0; + /* Dynamic casts. */ virtual function_type *dyn_cast_function_type () { return NULL; } virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; } @@ -628,6 +649,11 @@ class memento_of_get_type : public type size_t get_size () final override; + type* copy(context* ctxt) final override + { + return ctxt->get_type (m_kind); + } + bool accepts_writes_from (type *rtype) final override { if (m_kind == GCC_JIT_TYPE_VOID_PTR) @@ -679,6 +705,13 @@ class memento_of_get_pointer : public type type *dereference () final override { return m_other_type; } + type* copy(context* ctxt) final override + { + type* result = new memento_of_get_pointer (m_other_type->copy (ctxt)); + ctxt->record (result); + return result; + } + size_t get_size () final override; bool accepts_writes_from (type *rtype) final override; @@ -734,6 +767,13 @@ class memento_of_get_const : public decorated_type memento_of_get_const (type *other_type) : decorated_type (other_type) {} + type* copy(context* ctxt) final override + { + type* result = new memento_of_get_const (m_other_type->copy (ctxt)); + ctxt->record (result); + return result; + } + /* Strip off the "const", giving the underlying type. */ type *unqualified () final override { return m_other_type; } @@ -767,6 +807,13 @@ class memento_of_get_volatile : public decorated_type return m_other_type->is_same_type_as (other->is_volatile ()); } + type* copy(context* ctxt) final override + { + type* result = new memento_of_get_volatile (m_other_type->copy (ctxt)); + ctxt->record (result); + return result; + } + /* Strip off the "volatile", giving the underlying type. */ type *unqualified () final override { return m_other_type; } @@ -787,11 +834,20 @@ class memento_of_get_aligned : public decorated_type : decorated_type (other_type), m_alignment_in_bytes (alignment_in_bytes) {} + type* copy(context* ctxt) final override + { + type* result = new memento_of_get_aligned (m_other_type->copy (ctxt), m_alignment_in_bytes); + ctxt->record (result); + return result; + } + /* Strip off the alignment, giving the underlying type. */ type *unqualified () final override { return m_other_type; } void replay_into (replayer *) final override; + vector_type *dyn_cast_vector_type () final override { return m_other_type->dyn_cast_vector_type (); } + private: string * make_debug_string () final override; void write_reproducer (reproducer &r) final override; @@ -808,6 +864,13 @@ class vector_type : public decorated_type : decorated_type (other_type), m_num_units (num_units) {} + type* copy(context* ctxt) final override + { + type* result = new vector_type(m_other_type->copy (ctxt), m_num_units); + ctxt->record (result); + return result; + } + size_t get_num_units () const { return m_num_units; } vector_type *dyn_cast_vector_type () final override { return this; } @@ -850,6 +913,13 @@ class array_type : public type type *dereference () final override; + type* copy(context* ctxt) final override + { + type* result = new array_type (ctxt, m_loc, m_element_type->copy (ctxt), m_num_elements); + ctxt->record (result); + return result; + } + bool is_int () const final override { return false; } bool is_float () const final override { return false; } bool is_bool () const final override { return false; } @@ -877,7 +947,8 @@ class function_type : public type type *return_type, int num_params, type **param_types, - int is_variadic); + int is_variadic, + int is_target_builtin); type *dereference () final override; function_type *dyn_cast_function_type () final override { return this; } @@ -885,6 +956,18 @@ class function_type : public type bool is_same_type_as (type *other) final override; + type* copy(context* ctxt) final override + { + auto_vec new_params{}; + for (size_t i = 0; i < m_param_types.length (); i++) + new_params.safe_push (m_param_types[i]->copy (ctxt)); + + type* result = new function_type (ctxt, m_return_type->copy (ctxt), m_param_types.length (), new_params.address (), + m_is_variadic, m_is_target_builtin); + ctxt->record (result); + return result; + } + bool is_int () const final override { return false; } bool is_float () const final override { return false; } bool is_bool () const final override { return false; } @@ -897,6 +980,7 @@ class function_type : public type type * get_return_type () const { return m_return_type; } const vec &get_param_types () const { return m_param_types; } int is_variadic () const { return m_is_variadic; } + int is_target_builtin () const { return m_is_target_builtin; } string * make_debug_string_with_ptr (); @@ -913,6 +997,7 @@ class function_type : public type type *m_return_type; auto_vec m_param_types; int m_is_variadic; + int m_is_target_builtin; }; class field : public memento @@ -1014,9 +1099,11 @@ class compound_type : public type return static_cast (m_playback_obj); } -private: +protected: location *m_loc; string *m_name; + +private: fields *m_fields; }; @@ -1029,6 +1116,13 @@ class struct_ : public compound_type struct_ *dyn_cast_struct () final override { return this; } + type* copy(context* ctxt) final override + { + type* result = new struct_ (ctxt, m_loc, m_name); + ctxt->record (result); + return result; + } + type * as_type () { return this; } @@ -1076,6 +1170,13 @@ class union_ : public compound_type void replay_into (replayer *r) final override; + type* copy(context* ctxt) final override + { + type* result = new union_ (ctxt, m_loc, m_name); + ctxt->record (result); + return result; + } + bool is_union () const final override { return true; } private: @@ -1295,7 +1396,8 @@ class function : public memento int num_params, param **params, int is_variadic, - enum built_in_function builtin_id); + enum built_in_function builtin_id, + int is_target_builtin); void replay_into (replayer *r) final override; @@ -1329,6 +1431,8 @@ class function : public memento void write_to_dump (dump &d) final override; + bool is_target_builtin () const { return m_is_target_builtin; } + void validate (); void dump_to_dot (const char *path); @@ -1356,6 +1460,7 @@ class function : public memento type *m_fn_ptr_type; std::vector m_attributes; std::vector> m_string_attributes; + int m_is_target_builtin; }; class block : public memento @@ -1651,6 +1756,33 @@ class memento_of_new_rvalue_from_vector : public rvalue auto_vec m_elements; }; +class memento_of_new_rvalue_vector_perm : public rvalue +{ +public: + memento_of_new_rvalue_vector_perm (context *ctxt, + location *loc, + rvalue *elements1, + rvalue *elements2, + rvalue *mask); + + void replay_into (replayer *r) final override; + + void visit_children (rvalue_visitor *) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + enum precedence get_precedence () const final override + { + return PRECEDENCE_PRIMARY; + } + +private: + rvalue *m_elements1; + rvalue *m_elements2; + rvalue *m_mask; +}; + class ctor : public rvalue { public: @@ -1962,6 +2094,35 @@ class convert_vector : public rvalue type *m_type; }; +class vector_access : public lvalue +{ +public: + vector_access (context *ctxt, + location *loc, + rvalue *vector, + rvalue *index) + : lvalue (ctxt, loc, vector->get_type ()->dyn_cast_vector_type ()->get_element_type ()), + m_vector (vector), + m_index (index) + {} + + void replay_into (replayer *r) final override; + + void visit_children (rvalue_visitor *v) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + enum precedence get_precedence () const final override + { + return PRECEDENCE_POSTFIX; + } + +private: + rvalue *m_vector; + rvalue *m_index; +}; + class access_field_of_lvalue : public lvalue { public: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index dd5d6a739e172..915b932d6c15f 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -1761,6 +1761,23 @@ gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt, reinterpret_cast(values)); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::get_target_builtin_function method, in + jit-recording.c. */ + +gcc_jit_function * +gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt, + const char *name) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL (name, ctxt, NULL, "NULL name"); + + return static_cast (ctxt->get_target_builtin_function (name)); +} + /* Public entrypoint. See description in libgccjit.h. */ extern gcc_jit_lvalue * @@ -2455,6 +2472,8 @@ gcc_jit_context_new_cast (gcc_jit_context *ctxt, /* LOC can be NULL. */ RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); + gcc::jit::recording::vector_type *vector_type = type->dyn_cast_vector_type (); + RETURN_NULL_IF_FAIL (vector_type == NULL, ctxt, loc, "cannot cast vector types"); RETURN_NULL_IF_FAIL_PRINTF3 ( is_valid_cast (rvalue->get_type (), type), ctxt, loc, @@ -2546,6 +2565,35 @@ gcc_jit_context_convert_vector (gcc_jit_context *ctxt, return (gcc_jit_rvalue *)ctxt->new_convert_vector (loc, vector, type); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::new_vector_access method in + jit-recording.cc. */ + +extern gcc_jit_lvalue * +gcc_jit_context_new_vector_access (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_rvalue *index) +{ + RETURN_NULL_IF_FAIL (index, ctxt, loc, "NULL index"); + RETURN_NULL_IF_FAIL_PRINTF2 ( + vector->get_type ()->dyn_cast_vector_type (), + ctxt, loc, + "vector: %s (type: %s) is not a vector", + vector->get_debug_string (), + vector->get_type ()->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF2 ( + index->get_type ()->is_numeric (), + ctxt, loc, + "index: %s (type: %s) is not of numeric type", + index->get_debug_string (), + index->get_type ()->get_debug_string ()); + + return (gcc_jit_lvalue *)ctxt->new_vector_access (loc, vector, index); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the @@ -4218,6 +4266,74 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt, (gcc::jit::recording::rvalue **)elements); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::new_rvalue_vector_perm method, in + jit-recording.cc. */ + +gcc_jit_rvalue * +gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *elements1, + gcc_jit_rvalue *elements2, + gcc_jit_rvalue *mask) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL ctxt"); + JIT_LOG_FUNC (ctxt->get_logger ()); + + /* LOC can be NULL. */ + + gcc::jit::recording::type *elements1_type = elements1->get_type (); + gcc::jit::recording::type *elements2_type = elements2->get_type (); + RETURN_NULL_IF_FAIL_PRINTF4 ( + compatible_types (elements1->get_type ()->unqualified (), + elements2->get_type ()->unqualified ()), + ctxt, loc, + "mismatching types for vector perm:" + " elements1: %s (type: %s) elements2: %s (type: %s)", + elements1->get_debug_string (), + elements1_type->get_debug_string (), + elements2->get_debug_string (), + elements2_type->get_debug_string ()); + + gcc::jit::recording::type *mask_type = mask->get_type (); + gcc::jit::recording::vector_type *mask_vector_type = mask_type->dyn_cast_vector_type (); + gcc::jit::recording::vector_type *elements1_vector_type = elements1_type->dyn_cast_vector_type (); + + size_t mask_len = mask_vector_type->get_num_units (); + size_t elements1_len = elements1_vector_type->get_num_units (); + + RETURN_NULL_IF_FAIL_PRINTF2 ( + mask_len == elements1_len, + ctxt, loc, + "mismatching length for mask:" + " elements1 length: %ld mask length: %ld", + mask_len, + elements1_len); + + gcc::jit::recording::type *mask_element_type = mask_vector_type->get_element_type (); + + RETURN_NULL_IF_FAIL ( + mask_element_type->is_int (), + ctxt, loc, + "elements of mask must be of an integer type"); + + gcc::jit::recording::type *elements1_element_type = elements1_vector_type->get_element_type (); + size_t mask_element_size = mask_element_type->get_size (); + size_t elements1_element_size = elements1_element_type->get_size (); + + RETURN_NULL_IF_FAIL_PRINTF2 ( + mask_element_size == elements1_element_size, + ctxt, loc, + "mismatching size for mask element type:" + " elements1 element type: %ld mask element type: %ld", + mask_element_size, + elements1_element_size); + + return (gcc_jit_rvalue *)ctxt->new_rvalue_vector_perm(loc, elements1, elements2, mask); +} + /* A mutex around the cached state in parse_basever. Ideally this would be within parse_basever, but the mutex is only needed by libgccjit. */ diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 3938e154d80e9..7fbfe8b344846 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -604,7 +604,9 @@ enum gcc_jit_types GCC_JIT_TYPE_INT16_T, GCC_JIT_TYPE_INT32_T, GCC_JIT_TYPE_INT64_T, - GCC_JIT_TYPE_INT128_T + GCC_JIT_TYPE_INT128_T, + + GCC_JIT_TYPE_BFLOAT16, }; extern gcc_jit_type * @@ -1021,6 +1023,12 @@ extern gcc_jit_lvalue * gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global, gcc_jit_rvalue *init_value); +/* Create a reference to a machine-specific builtin function (sometimes called + intrinsic functions). */ +extern gcc_jit_function * +gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt, + const char *name); + #define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer /* Set an initial value for a global, which must be an array of @@ -1301,6 +1309,12 @@ gcc_jit_context_convert_vector (gcc_jit_context *ctxt, gcc_jit_rvalue *vector, gcc_jit_type *type); +extern gcc_jit_lvalue * +gcc_jit_context_new_vector_access (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_rvalue *index); + /* Field access is provided separately for both lvalues and rvalues. */ /* Accessing a field of an lvalue of struct type, analogous to: @@ -1851,6 +1865,21 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt, size_t num_elements, gcc_jit_rvalue **elements); +/* Build a permutation vector rvalue from an 3 arrays of elements. + + "vec_type" should be a vector type, created using gcc_jit_type_get_vector. + + This API entrypoint was added in LIBGCCJIT_ABI_25; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_TARGET_BUILTIN +*/ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *elements1, + gcc_jit_rvalue *elements2, + gcc_jit_rvalue *mask); + #define LIBGCCJIT_HAVE_gcc_jit_version /* Functions to retrieve libgccjit version. diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 8027444471e6a..e3afe74a9bb70 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -301,7 +301,6 @@ LIBGCCJIT_ABI_29 { LIBGCCJIT_ABI_30 { global: gcc_jit_lvalue_add_attribute; -<<<<<<< HEAD } LIBGCCJIT_ABI_29; LIBGCCJIT_ABI_31 { @@ -310,3 +309,10 @@ LIBGCCJIT_ABI_31 { gcc_jit_block_add_try_finally; gcc_jit_function_set_personality_function; } LIBGCCJIT_ABI_30; + +LIBGCCJIT_ABI_32 { + global: + gcc_jit_context_get_target_builtin_function; + gcc_jit_context_new_rvalue_vector_perm; + gcc_jit_context_new_vector_access; +} LIBGCCJIT_ABI_31; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 80606076e7870..988e14ae9bcd4 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -319,6 +319,9 @@ /* test-setting-alignment.c: This can't be in the testcases array as it is target-specific. */ +/* test-target-builtins.c: This can't be in the testcases array as it + is target-specific. */ + /* test-string-literal.c */ #define create_code create_code_string_literal #define verify_code verify_code_string_literal diff --git a/gcc/testsuite/jit.dg/test-target-builtins.c b/gcc/testsuite/jit.dg/test-target-builtins.c new file mode 100644 index 0000000000000..0ffb48e97f64b --- /dev/null +++ b/gcc/testsuite/jit.dg/test-target-builtins.c @@ -0,0 +1,77 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +#define TEST_PROVIDES_MAIN +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + CHECK_NON_NULL (gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_ia32_xgetbv")); + gcc_jit_function *builtin_eh_pointer = gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_eh_pointer"); + CHECK_NON_NULL (builtin_eh_pointer); + + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *void_ptr = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); + gcc_jit_function *func_main = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "main", + 0, NULL, + 0); + gcc_jit_rvalue *zero = gcc_jit_context_zero (ctxt, int_type); + gcc_jit_block *block = gcc_jit_function_new_block (func_main, NULL); + gcc_jit_lvalue *variable = gcc_jit_function_new_local(func_main, NULL, void_ptr, "variable"); + gcc_jit_block_add_assignment (block, NULL, variable, + gcc_jit_context_new_call (ctxt, NULL, builtin_eh_pointer, 1, &zero)); + gcc_jit_block_end_with_return (block, NULL, zero); +} + +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; +} From c97bc65933ed3a11d4ddaa4a5aa712ff70822c53 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 4 Mar 2023 00:44:49 -0500 Subject: [PATCH 20/45] Make new_array_type take unsigned long --- gcc/jit/jit-playback.cc | 2 +- gcc/jit/jit-playback.h | 2 +- gcc/jit/jit-recording.cc | 6 +++--- gcc/jit/jit-recording.h | 8 ++++---- gcc/jit/libgccjit.cc | 2 +- gcc/jit/libgccjit.h | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 55c6cc31e3def..6e948486031fa 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -329,7 +329,7 @@ playback::type * playback::context:: new_array_type (playback::location *loc, playback::type *element_type, - int num_elements) + unsigned long num_elements) { gcc_assert (element_type); diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 319fc9cf59aa3..b767fec6da884 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -74,7 +74,7 @@ class context : public log_user type * new_array_type (location *loc, type *element_type, - int num_elements); + unsigned long num_elements); field * new_field (location *loc, diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index c48a3fbe0ad55..5aae457dc550e 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -840,7 +840,7 @@ recording::context::get_int_type (int num_bytes, int is_signed) recording::type * recording::context::new_array_type (recording::location *loc, recording::type *element_type, - int num_elements) + unsigned long num_elements) { /*if (struct_ *s = element_type->dyn_cast_struct ()) if (!s->get_fields ()) @@ -3175,7 +3175,7 @@ recording::string * recording::array_type::make_debug_string () { return string::from_printf (m_ctxt, - "%s[%d]", + "%s[%ld]", m_element_type->get_debug_string (), m_num_elements); } @@ -3191,7 +3191,7 @@ recording::array_type::write_reproducer (reproducer &r) " gcc_jit_context_new_array_type (%s,\n" " %s, /* gcc_jit_location *loc */\n" " %s, /* gcc_jit_type *element_type */\n" - " %i); /* int num_elements */\n", + " %li); /* int num_elements */\n", id, r.get_identifier (get_context ()), r.get_identifier (m_loc), diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index a3c3fc1a161b9..68a792a7cd574 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -99,7 +99,7 @@ class context : public log_user type * new_array_type (location *loc, type *element_type, - int num_elements); + unsigned long num_elements); field * new_field (location *loc, @@ -904,7 +904,7 @@ class array_type : public type array_type (context *ctxt, location *loc, type *element_type, - int num_elements) + unsigned long num_elements) : type (ctxt), m_loc (loc), m_element_type (element_type), @@ -925,7 +925,7 @@ class array_type : public type bool is_bool () const final override { return false; } type *is_pointer () final override { return NULL; } type *is_array () final override { return m_element_type; } - int num_elements () { return m_num_elements; } + unsigned long num_elements () { return m_num_elements; } bool is_signed () const final override { return false; } void replay_into (replayer *) final override; @@ -937,7 +937,7 @@ class array_type : public type private: location *m_loc; type *m_element_type; - int m_num_elements; + unsigned long m_num_elements; }; class function_type : public type diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 915b932d6c15f..84bde4d5220f3 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -765,7 +765,7 @@ gcc_jit_type * gcc_jit_context_new_array_type (gcc_jit_context *ctxt, gcc_jit_location *loc, gcc_jit_type *element_type, - int num_elements) + unsigned long num_elements) { RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context"); JIT_LOG_FUNC (ctxt->get_logger ()); diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 7fbfe8b344846..05cc45fd0decf 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -654,7 +654,7 @@ extern gcc_jit_type * gcc_jit_context_new_array_type (gcc_jit_context *ctxt, gcc_jit_location *loc, gcc_jit_type *element_type, - int num_elements); + unsigned long num_elements); /* Struct-handling. */ From 3e63da67f22648ef9edf883c5d80259b49a2e715 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 23 Jan 2023 17:21:36 -0500 Subject: [PATCH 21/45] Add support for the variable inline attributes --- gcc/jit/jit-playback.cc | 38 +++++++++++++++++++++++++++++--------- gcc/jit/libgccjit.h | 3 +++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 6e948486031fa..0b107754ca8a6 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -514,6 +514,12 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) { switch (attr) { + case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE: + return "always_inline"; + case GCC_JIT_FN_ATTRIBUTE_INLINE: + return NULL; + case GCC_JIT_FN_ATTRIBUTE_NOINLINE: + return "noinline"; case GCC_JIT_FN_ATTRIBUTE_TARGET: return "target"; case GCC_JIT_FN_ATTRIBUTE_USED: @@ -643,17 +649,29 @@ new_function (location *loc, for (auto attr: attributes) { - tree ident = get_identifier (fn_attribute_to_string (attr)); - + if (attr == GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE) + { + DECL_DECLARED_INLINE_P (fndecl) = 1; + DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1; + } + else if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE) + DECL_DECLARED_INLINE_P (fndecl) = 1; + else if (attr == GCC_JIT_FN_ATTRIBUTE_NOINLINE) + DECL_UNINLINABLE (fndecl) = 1; /* See handle_used_attribute in gcc/c-family/c-attribs.cc. */ - if (attr == GCC_JIT_FN_ATTRIBUTE_USED) + else if (attr == GCC_JIT_FN_ATTRIBUTE_USED) { TREE_USED (fndecl) = 1; DECL_PRESERVE_P (fndecl) = 1; } - DECL_ATTRIBUTES (fndecl) = - tree_cons (ident, NULL_TREE, DECL_ATTRIBUTES (fndecl)); + const char* attribute = fn_attribute_to_string (attr); + if (attribute) + { + tree ident = get_identifier (attribute); + DECL_ATTRIBUTES (fndecl) = + tree_cons (ident, NULL_TREE, DECL_ATTRIBUTES (fndecl)); + } } for (auto attr: string_attributes) @@ -661,16 +679,18 @@ new_function (location *loc, gcc_jit_fn_attribute& name = std::get<0>(attr); std::string& value = std::get<1>(attr); tree attribute_value = build_tree_list (NULL_TREE, ::build_string (value.length () + 1, value.c_str ())); - tree ident = get_identifier (fn_attribute_to_string (name)); + const char* attribute = fn_attribute_to_string (name); + tree ident = attribute ? get_identifier (attribute) : NULL; /* See handle_target_attribute in gcc/c-family/c-attribs.cc. */ if (name == GCC_JIT_FN_ATTRIBUTE_TARGET) /* We need to call valid_attribute_p so that the hook set-up some internal options. */ - if (!targetm.target_option.valid_attribute_p (fndecl, ident, attribute_value, 0)) + if (!ident || !targetm.target_option.valid_attribute_p (fndecl, ident, attribute_value, 0)) continue; - DECL_ATTRIBUTES (fndecl) = - tree_cons (ident, attribute_value, DECL_ATTRIBUTES (fndecl)); + if (ident) + DECL_ATTRIBUTES (fndecl) = + tree_cons (ident, attribute_value, DECL_ATTRIBUTES (fndecl)); } function *func = new function (this, fndecl, kind); diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 05cc45fd0decf..4ce2d36b8d425 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2076,6 +2076,9 @@ gcc_jit_type_set_packed (gcc_jit_type *type); /* Function attributes. */ enum gcc_jit_fn_attribute { + GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE, + GCC_JIT_FN_ATTRIBUTE_INLINE, + GCC_JIT_FN_ATTRIBUTE_NOINLINE, GCC_JIT_FN_ATTRIBUTE_TARGET, GCC_JIT_FN_ATTRIBUTE_USED, GCC_JIT_FN_ATTRIBUTE_VISIBILITY, From 19869202b426021595b50781b0b0476a0c8d7036 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 16 Apr 2023 13:19:20 -0400 Subject: [PATCH 22/45] Fix bug related to the personality function --- gcc/expr.cc | 23 +++++++++++++++++++++++ gcc/jit/dummy-frontend.cc | 35 +++++++++++++++++++++++++++++++++++ gcc/jit/libgccjit.cc | 7 +++++++ gcc/jit/libgccjit.h | 2 ++ gcc/jit/libgccjit.map | 1 + gcc/tree-eh.cc | 5 ++--- gcc/tree.h | 1 + 7 files changed, 71 insertions(+), 3 deletions(-) diff --git a/gcc/expr.cc b/gcc/expr.cc index 15be1c8db9991..7fa2c114cb2ff 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -13365,6 +13365,7 @@ const_vector_from_tree (tree exp) tree build_personality_function (const char *lang) { + // TODO: rewrite by calling build_personality_function_with_name. const char *unwind_and_version; tree decl, type; char *name; @@ -13406,6 +13407,28 @@ build_personality_function (const char *lang) return decl; } +tree +build_personality_function_with_name (const char *name) +{ + tree decl, type; + + type = build_function_type_list (unsigned_type_node, + integer_type_node, integer_type_node, + long_long_unsigned_type_node, + ptr_type_node, ptr_type_node, NULL_TREE); + decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, + get_identifier (name), type); + DECL_ARTIFICIAL (decl) = 1; + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + + /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with + are the flags assigned by targetm.encode_section_info. */ + SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL); + + return decl; +} + /* Extracts the personality function of DECL and returns the corresponding libfunc. */ diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index 897511be8da88..7ef09d7128858 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -157,6 +157,20 @@ const struct attribute_spec jit_format_attribute_table[] = { NULL, 0, 0, false, false, false, false, NULL, NULL } }; +char* jit_personality_func_name = NULL; +static tree personality_decl; + +/* FIXME: This is a hack to preserve trees that we create from the + garbage collector. */ + +static GTY (()) tree jit_gc_root; + +void +jit_preserve_from_gc (tree t) +{ + jit_gc_root = tree_cons (NULL_TREE, t, jit_gc_root); +} + /* Attribute handlers. */ /* Handle a "noreturn" attribute; arguments as in @@ -589,6 +603,8 @@ jit_end_diagnostic (diagnostic_context *context, static bool jit_langhook_init (void) { + jit_gc_root = NULL_TREE; + personality_decl = NULL_TREE; gcc_assert (gcc::jit::active_playback_ctxt); JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ()); @@ -920,6 +936,25 @@ jit_langhook_getdecls (void) return NULL; } +static tree +jit_langhook_eh_personality (void) +{ + if (personality_decl == NULL_TREE) + { + if (jit_personality_func_name != NULL) { + personality_decl = build_personality_function_with_name (jit_personality_func_name); + jit_preserve_from_gc(personality_decl); + } + else { + return lhd_gcc_personality(); + } + } + return personality_decl; +} + +#undef LANG_HOOKS_EH_PERSONALITY +#define LANG_HOOKS_EH_PERSONALITY jit_langhook_eh_personality + #undef LANG_HOOKS_NAME #define LANG_HOOKS_NAME "libgccjit" diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 84bde4d5220f3..bbf9423193065 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -3753,6 +3753,13 @@ gcc_jit_function_set_personality_function (gcc_jit_function *fn, fn->set_personality_function (personality_func); } +extern char* jit_personality_func_name; + +void +gcc_jit_set_global_personality_function_name (char* name) { + jit_personality_func_name = name; +} + /* Public entrypoint. See description in libgccjit.h. The real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 4ce2d36b8d425..f5537adbc919f 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1847,6 +1847,8 @@ void gcc_jit_function_set_personality_function (gcc_jit_function *fn, gcc_jit_function *personality_func); +extern void +gcc_jit_set_global_personality_function_name (char* name); #define LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index e3afe74a9bb70..a10a85ceaceaf 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -315,4 +315,5 @@ LIBGCCJIT_ABI_32 { gcc_jit_context_get_target_builtin_function; gcc_jit_context_new_rvalue_vector_perm; gcc_jit_context_new_vector_access; + gcc_jit_set_global_personality_function_name; } LIBGCCJIT_ABI_31; diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc index b734f6be4168e..41cf57d2b305f 100644 --- a/gcc/tree-eh.cc +++ b/gcc/tree-eh.cc @@ -4882,10 +4882,9 @@ pass_cleanup_eh::execute (function *fun) /* If the function no longer needs an EH personality routine clear it. This exposes cross-language inlining opportunities and avoids references to a never defined personality routine. */ - // TODO: uncomment and find out why this doesn't work. - /*if (DECL_FUNCTION_PERSONALITY (current_function_decl) + if (DECL_FUNCTION_PERSONALITY (current_function_decl) && function_needs_eh_personality (fun) != eh_personality_lang) - DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE;*/ + DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE; return ret; } diff --git a/gcc/tree.h b/gcc/tree.h index e730a2a3e56bd..99695c647fe4a 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -6479,6 +6479,7 @@ extern tree get_inner_reference (tree, poly_int64_pod *, poly_int64_pod *, tree *, machine_mode *, int *, int *, int *); extern tree build_personality_function (const char *); +extern tree build_personality_function_with_name (const char *); struct GTY(()) int_n_trees_t { /* These parts are initialized at runtime */ From d3790a8d30b32fa5beb45981d1d5e16391f08560 Mon Sep 17 00:00:00 2001 From: Heath123 Date: Tue, 27 Jun 2023 15:29:10 +0100 Subject: [PATCH 23/45] Fix compilation error when bfloat is unsupported --- gcc/jit/jit-recording.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 5aae457dc550e..603731b7fd4fc 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -2472,8 +2472,10 @@ recording::memento_of_get_type::get_size () case GCC_JIT_TYPE_FLOAT: size = FLOAT_TYPE_SIZE; break; + #ifdef HAVE_BFmode case GCC_JIT_TYPE_BFLOAT16: return GET_MODE_UNIT_SIZE (BFmode); + #endif case GCC_JIT_TYPE_DOUBLE: size = DOUBLE_TYPE_SIZE; break; From 67178244993ecbef6772be3c3407eb9b7db6b297 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 30 Jun 2023 15:09:17 +0200 Subject: [PATCH 24/45] fixup! WIP: Add support for function attributes --- gcc/jit/jit-playback.cc | 2 ++ gcc/jit/libgccjit.h | 1 + 2 files changed, 3 insertions(+) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 0b107754ca8a6..7a2d3dd091150 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -526,6 +526,8 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) return "used"; case GCC_JIT_FN_ATTRIBUTE_VISIBILITY: return "visibility"; + case GCC_JIT_FN_ATTRIBUTE_COLD: + return "cold"; } return NULL; } diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index f5537adbc919f..67d1355fff23b 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2084,6 +2084,7 @@ enum gcc_jit_fn_attribute GCC_JIT_FN_ATTRIBUTE_TARGET, GCC_JIT_FN_ATTRIBUTE_USED, GCC_JIT_FN_ATTRIBUTE_VISIBILITY, + GCC_JIT_FN_ATTRIBUTE_COLD, }; /* Add an attribute to a function. */ From ad0631239333cfb885ca755f4d9c816fa329004e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 30 Jun 2023 21:16:07 +0200 Subject: [PATCH 25/45] fixup! WIP: Add support for function attributes Add test for cold attribute in libgccjit --- gcc/testsuite/jit.dg/test-cold-attribute.c | 54 ++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 gcc/testsuite/jit.dg/test-cold-attribute.c diff --git a/gcc/testsuite/jit.dg/test-cold-attribute.c b/gcc/testsuite/jit.dg/test-cold-attribute.c new file mode 100644 index 0000000000000..8dc7ec5a34b57 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-cold-attribute.c @@ -0,0 +1,54 @@ +/* { 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 cold + 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-cold-attribute.c.s" +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: +int +__attribute__ ((cold)) +t() +{ + return -1; +} + + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_function *func_t = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "t", + 0, NULL, + 0); + gcc_jit_function_add_attribute(func_t, GCC_JIT_FN_ATTRIBUTE_COLD); + gcc_jit_block *block = gcc_jit_function_new_block (func_t, NULL); + gcc_jit_rvalue *ret = gcc_jit_context_new_rvalue_from_int (ctxt, + int_type, + -1); + + gcc_jit_block_end_with_return (block, NULL, ret); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* { dg-final { jit-verify-assembler-output "orl" } } */ From 7e02bf4d96dc54eb786136af06f59830366383d6 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 26 Jun 2023 18:29:15 -0400 Subject: [PATCH 26/45] Add ability to get CPU features --- gcc/Makefile.in | 29 ++++- gcc/config.gcc | 56 ++++++++++ gcc/config/default-jit.cc | 28 +++++ gcc/config/i386/i386-jit.cc | 216 ++++++++++++++++++++++++++++++++++++ gcc/config/i386/i386-jit.h | 26 +++++ gcc/config/i386/t-i386 | 4 + gcc/config/linux-jit.cc | 48 ++++++++ gcc/config/t-linux | 4 + gcc/configure | 14 +++ gcc/configure.ac | 14 +++ gcc/doc/tm.texi | 38 +++++++ gcc/doc/tm.texi.in | 20 ++++ gcc/genhooks.cc | 1 + gcc/jit/Make-lang.in | 8 +- gcc/jit/jit-playback.cc | 2 + gcc/jit/jit-playback.h | 17 ++- gcc/jit/jit-recording.cc | 19 ++++ gcc/jit/jit-recording.h | 3 + gcc/jit/jit-target-def.h | 20 ++++ gcc/jit/jit-target.cc | 94 ++++++++++++++++ gcc/jit/jit-target.def | 70 ++++++++++++ gcc/jit/jit-target.h | 70 ++++++++++++ gcc/jit/libgccjit.cc | 43 +++++++ gcc/jit/libgccjit.h | 19 ++++ gcc/jit/libgccjit.map | 9 ++ 25 files changed, 865 insertions(+), 7 deletions(-) create mode 100644 gcc/config/default-jit.cc create mode 100644 gcc/config/i386/i386-jit.cc create mode 100644 gcc/config/i386/i386-jit.h create mode 100644 gcc/config/linux-jit.cc create mode 100644 gcc/jit/jit-target-def.h create mode 100644 gcc/jit/jit-target.cc create mode 100644 gcc/jit/jit-target.def create mode 100644 gcc/jit/jit-target.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 6aed2cda3cafb..4c092094343c4 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -574,6 +574,8 @@ tm_p_file_list=@tm_p_file_list@ tm_p_include_list=@tm_p_include_list@ tm_d_file_list=@tm_d_file_list@ tm_d_include_list=@tm_d_include_list@ +tm_jit_file_list=@tm_jit_file_list@ +tm_jit_include_list=@tm_jit_include_list@ build_xm_file_list=@build_xm_file_list@ build_xm_include_list=@build_xm_include_list@ build_xm_defines=@build_xm_defines@ @@ -868,6 +870,7 @@ CONFIG_H = config.h $(host_xm_file_list) TCONFIG_H = tconfig.h $(xm_file_list) TM_P_H = tm_p.h $(tm_p_file_list) TM_D_H = tm_d.h $(tm_d_file_list) +TM_JIT_H = tm_jit.h $(tm_jit_file_list) GTM_H = tm.h $(tm_file_list) insn-constants.h TM_H = $(GTM_H) insn-flags.h $(OPTIONS_H) @@ -926,10 +929,12 @@ TARGET_DEF = target.def target-hooks-macros.h target-insns.def C_TARGET_DEF = c-family/c-target.def target-hooks-macros.h COMMON_TARGET_DEF = common/common-target.def target-hooks-macros.h D_TARGET_DEF = d/d-target.def target-hooks-macros.h +JIT_TARGET_DEF = jit/jit-target.def target-hooks-macros.h TARGET_H = $(TM_H) target.h $(TARGET_DEF) insn-modes.h insn-codes.h C_TARGET_H = c-family/c-target.h $(C_TARGET_DEF) COMMON_TARGET_H = common/common-target.h $(INPUT_H) $(COMMON_TARGET_DEF) D_TARGET_H = d/d-target.h $(D_TARGET_DEF) +JIT_TARGET_H = jit/jit-target.h $(JIT_TARGET_DEF) MACHMODE_H = machmode.h mode-classes.def HOOKS_H = hooks.h HOSTHOOKS_DEF_H = hosthooks-def.h $(HOOKS_H) @@ -1230,6 +1235,9 @@ CXX_TARGET_OBJS=@cxx_target_objs@ # Target specific, D specific object file D_TARGET_OBJS=@d_target_objs@ +# Target specific, JIT specific object file +JIT_TARGET_OBJS=@jit_target_objs@ + # Target specific, Fortran specific object file FORTRAN_TARGET_OBJS=@fortran_target_objs@ @@ -1947,6 +1955,7 @@ tconfig.h: cs-tconfig.h ; @true tm.h: cs-tm.h ; @true tm_p.h: cs-tm_p.h ; @true tm_d.h: cs-tm_d.h ; @true +tm_jit.h: cs-tm_jit.h ; @true cs-config.h: Makefile TARGET_CPU_DEFAULT="" \ @@ -1978,6 +1987,11 @@ cs-tm_d.h: Makefile HEADERS="$(tm_d_include_list)" DEFINES="" \ $(SHELL) $(srcdir)/mkconfig.sh tm_d.h +cs-tm_jit.h: Makefile + TARGET_CPU_DEFAULT="" \ + HEADERS="$(tm_jit_include_list)" DEFINES="" \ + $(SHELL) $(srcdir)/mkconfig.sh tm_jit.h + # Don't automatically run autoconf, since configure.ac might be accidentally # newer than configure. Also, this writes into the source directory which # might be on a read-only file system. If configured for maintainer mode @@ -2619,6 +2633,15 @@ s-d-target-hooks-def-h: build/genhooks$(build_exeext) d/d-target-hooks-def.h $(STAMP) s-d-target-hooks-def-h +jit/jit-target-hooks-def.h: s-jit-target-hooks-def-h; @true + +s-jit-target-hooks-def-h: build/genhooks$(build_exeext) + $(RUN_GEN) build/genhooks$(build_exeext) "JIT Target Hook" \ + > tmp-jit-target-hooks-def.h + $(SHELL) $(srcdir)/../move-if-change tmp-jit-target-hooks-def.h \ + jit/jit-target-hooks-def.h + $(STAMP) s-jit-target-hooks-def-h + # check if someone mistakenly only changed tm.texi. # We use a different pathname here to avoid a circular dependency. s-tm-texi: $(srcdir)/doc/../doc/tm.texi @@ -2794,7 +2817,7 @@ s-gtype: $(EXTRA_GTYPE_DEPS) build/gengtype$(build_exeext) \ -r gtype.state $(STAMP) s-gtype -generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \ +generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_JIT_H) $(TM_H) multilib.h \ $(simple_generated_h) specs.h \ tree-check.h genrtl.h insn-modes.h insn-modes-inline.h \ tm-preds.h tm-constrs.h \ @@ -2803,7 +2826,7 @@ generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \ common/common-target-hooks-def.h pass-instances.def \ gimple-match.cc generic-match.cc \ c-family/c-target-hooks-def.h d/d-target-hooks-def.h \ - case-cfn-macros.h \ + jit/jit-target-hooks-def.h case-cfn-macros.h \ cfn-operators.pd omp-device-properties.h # @@ -2937,7 +2960,7 @@ build/genrecog.o : genrecog.cc $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ $(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) \ $(HASH_TABLE_H) inchash.h build/genhooks.o : genhooks.cc $(TARGET_DEF) $(C_TARGET_DEF) \ - $(COMMON_TARGET_DEF) $(D_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h + $(COMMON_TARGET_DEF) $(D_TARGET_DEF) $(JIT_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h build/genmddump.o : genmddump.cc $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ $(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) build/genmatch.o : genmatch.cc $(BCONFIG_H) $(SYSTEM_H) \ diff --git a/gcc/config.gcc b/gcc/config.gcc index c4633e869ac06..6a0fc540bcba9 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -146,6 +146,9 @@ # d_target_objs List of extra target-dependent objects that be # linked into the D compiler only. # +# jit_target_objs List of extra target-dependent objects that be +# linked into the jit compiler only. +# # fortran_target_objs List of extra target-dependent objects that be # linked into the fortran compiler only. # @@ -201,6 +204,9 @@ # # target_has_targetdm Set to yes or no depending on whether the target # has its own definition of targetdm. +# +# target_has_targetjitm Set to yes or no depending on whether the target +# has its own definition of targetdm. out_file= common_out_file= @@ -217,10 +223,12 @@ extra_options= c_target_objs= cxx_target_objs= d_target_objs= +jit_target_objs= fortran_target_objs= target_has_targetcm=no target_has_targetm_common=yes target_has_targetdm=no +target_has_targetjitm=no tm_defines= xm_defines= # Set this to force installation and use of collect2. @@ -338,6 +346,7 @@ aarch64*-*-*) c_target_objs="aarch64-c.o" cxx_target_objs="aarch64-c.o" d_target_objs="aarch64-d.o" + #jit_target_objs="aarch64-jit.o" extra_objs="aarch64-builtins.o aarch-common.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o aarch64-sve-builtins-sve2.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch64-bti-insert.o aarch64-cc-fusion.o" target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.cc \$(srcdir)/config/aarch64/aarch64-sve-builtins.h \$(srcdir)/config/aarch64/aarch64-sve-builtins.cc" target_has_targetm_common=yes @@ -368,6 +377,7 @@ arm*-*-*) c_target_objs="arm-c.o" cxx_target_objs="arm-c.o" d_target_objs="arm-d.o" + #jit_target_objs="arm-jit.o" extra_options="${extra_options} arm/arm-tables.opt" target_gtfiles="\$(srcdir)/config/arm/arm-builtins.cc \$(srcdir)/config/arm/arm-mve-builtins.h \$(srcdir)/config/arm/arm-mve-builtins.cc" ;; @@ -401,6 +411,7 @@ i[34567]86-*-* | x86_64-*-*) c_target_objs="i386-c.o" cxx_target_objs="i386-c.o" d_target_objs="i386-d.o" + jit_target_objs="i386-jit.o" extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o i386-options.o i386-builtins.o i386-expand.o i386-features.o" target_gtfiles="\$(srcdir)/config/i386/i386-builtins.cc \$(srcdir)/config/i386/i386-expand.cc \$(srcdir)/config/i386/i386-options.cc" extra_options="${extra_options} fused-madd.opt" @@ -462,6 +473,7 @@ microblaze*-*-*) mips*-*-*) cpu_type=mips d_target_objs="mips-d.o" + #jit_target_objs="mips-jit.o" extra_headers="loongson.h loongson-mmiintrin.h msa.h" extra_objs="frame-header-opt.o" extra_options="${extra_options} g.opt fused-madd.opt mips/mips-tables.opt" @@ -532,6 +544,7 @@ riscv*) extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-v.o riscv-vsetvl.o" extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o" d_target_objs="riscv-d.o" + #jit_target_objs="riscv-jit.o" extra_headers="riscv_vector.h" target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc" target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.h" @@ -548,11 +561,13 @@ sparc*-*-*) c_target_objs="sparc-c.o" cxx_target_objs="sparc-c.o" d_target_objs="sparc-d.o" + #jit_target_objs="sparc-jit.o" extra_headers="visintrin.h" ;; s390*-*-*) cpu_type=s390 d_target_objs="s390-d.o" + #jit_target_objs="s390-jit.o" extra_options="${extra_options} fused-madd.opt" extra_headers="s390intrin.h htmintrin.h htmxlintrin.h vecintrin.h" ;; @@ -588,6 +603,12 @@ then tm_d_file="${tm_d_file} ${cpu_type}/${cpu_type}-d.h" fi +tm_jit_file= +if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-jit.h +then + tm_jit_file="${tm_jit_file} ${cpu_type}/${cpu_type}-jit.h" +fi + extra_modes= if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-modes.def then @@ -754,9 +775,11 @@ case ${target} in c_target_objs="${c_target_objs} darwin-c.o" cxx_target_objs="${cxx_target_objs} darwin-c.o" d_target_objs="${d_target_objs} darwin-d.o" + #jit_target_objs="${jit_target_objs} darwin-jit.o" fortran_target_objs="darwin-f.o" target_has_targetcm=yes target_has_targetdm=yes + #target_has_targetjitm=yes extra_objs="${extra_objs} darwin.o" extra_gcc_objs="darwin-driver.o" default_use_cxa_atexit=yes @@ -785,8 +808,10 @@ case ${target} in default_use_cxa_atexit=yes use_gcc_stdint=wrap d_target_objs="${d_target_objs} dragonfly-d.o" + #jit_target_objs="${jit_target_objs} dragonfly-jit.o" tmake_file="${tmake_file} t-dragonfly" target_has_targetdm=yes + #target_has_targetjitm=yes ;; *-*-freebsd*) # This is the generic ELF configuration of FreeBSD. Later @@ -836,8 +861,10 @@ case ${target} in esac use_gcc_stdint=wrap d_target_objs="${d_target_objs} freebsd-d.o" + #jit_target_objs="${jit_target_objs} freebsd-jit.o" tmake_file="${tmake_file} t-freebsd" target_has_targetdm=yes + #target_has_targetjitm=yes ;; *-*-fuchsia*) native_system_header_dir=/include @@ -910,19 +937,27 @@ case ${target} in case $target in *-*-*linux*) d_target_objs="${d_target_objs} linux-d.o" + jit_target_objs="${jit_target_objs} linux-jit.o" target_has_targetdm=yes + target_has_targetjitm=yes ;; *-*-kfreebsd*-gnu) d_target_objs="${d_target_objs} kfreebsd-d.o" + #jit_target_objs="${jit_target_objs} kfreebsd-jit.o" target_has_targetdm=yes + #target_has_targetjitm=yes ;; *-*-kopensolaris*-gnu) d_target_objs="${d_target_objs} kopensolaris-d.o" + #jit_target_objs="${jit_target_objs} kopensolaris-jit.o" target_has_targetdm=yes + #target_has_targetjitm=yes ;; *-*-gnu*) d_target_objs="${d_target_objs} gnu-d.o" + #jit_target_objs="${jit_target_objs} gnu-jit.o" target_has_targetdm=yes + #target_has_targetjitm=yes ;; esac ;; @@ -931,6 +966,7 @@ case ${target} in tmake_file="t-netbsd t-slibgcc" extra_objs="${extra_objs} netbsd.o" d_target_objs="${d_target_objs} netbsd-d.o" + #jit_target_objs="${jit_target_objs} netbsd-jit.o" gas=yes gnu_ld=yes use_gcc_stdint=wrap @@ -940,6 +976,7 @@ case ${target} in nbsd_tm_file="netbsd.h netbsd-stdint.h netbsd-elf.h" default_use_cxa_atexit=yes target_has_targetdm=yes + #target_has_targetjitm=yes case ${target} in arm*-* | i[34567]86-* | powerpc*-* | sparc*-* | x86_64-*) default_gnu_indirect_function=yes @@ -959,7 +996,9 @@ case ${target} in ;; esac d_target_objs="${d_target_objs} openbsd-d.o" + #jit_target_objs="${jit_target_objs} openbsd-jit.o" target_has_targetdm=yes + #target_has_targetjitm=yes ;; *-*-phoenix*) gas=yes @@ -1016,6 +1055,7 @@ case ${target} in c_target_objs="${c_target_objs} sol2-c.o" cxx_target_objs="${cxx_target_objs} sol2-c.o sol2-cxx.o" d_target_objs="${d_target_objs} sol2-d.o" + #jit_target_objs="${jit_target_objs} sol2-jit.o" extra_objs="${extra_objs} sol2.o sol2-stubs.o" extra_options="${extra_options} sol2.opt" case ${enable_threads}:${have_pthread_h}:${have_thread_h} in @@ -1024,6 +1064,7 @@ case ${target} in ;; esac target_has_targetdm=yes + #target_has_targetjitm=yes ;; *-*-*vms*) extra_options="${extra_options} vms/vms.opt" @@ -1760,6 +1801,7 @@ hppa*64*-*-linux*) pa/pa64-linux.h" tmake_file="${tmake_file} pa/t-pa pa/t-linux" d_target_objs="${d_target_objs} pa-d.o" + #jit_target_objs="${jit_target_objs} pa-jit.o" gas=yes gnu_ld=yes ;; hppa*-*-linux*) @@ -1768,6 +1810,7 @@ hppa*-*-linux*) pa/pa32-regs.h pa/pa32-linux.h" tmake_file="${tmake_file} pa/t-pa pa/t-linux" d_target_objs="${d_target_objs} pa-d.o" + #jit_target_objs="${jit_target_objs} pa-jit.o" ;; hppa*-*-openbsd*) target_cpu_default="MASK_PA_11" @@ -1776,6 +1819,7 @@ hppa*-*-openbsd*) extra_options="${extra_options} openbsd.opt" tmake_file="pa/t-pa" d_target_objs="${d_target_objs} pa-d.o" + #jit_target_objs="${jit_target_objs} pa-jit.o" gas=yes gnu_ld=yes ;; @@ -1813,6 +1857,7 @@ hppa*64*-*-hpux11*) pa/pa-hpux1010.opt pa/pa64-hpux.opt hpux11.opt" tmake_file="pa/t-pa t-slibgcc" d_target_objs="${d_target_objs} pa-d.o" + #jit_target_objs="${jit_target_objs} pa-jit.o" case x${enable_threads} in x | xyes | xposix ) thread_file=posix @@ -2086,7 +2131,9 @@ i[34567]86-*-cygwin*) c_target_objs="${c_target_objs} msformat-c.o" cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o" d_target_objs="${d_target_objs} cygwin-d.o" + #jit_target_objs="${jit_target_objs} cygwin-jit.o" target_has_targetdm="yes" + #target_has_targetjitm=yes if test x$enable_threads = xyes; then thread_file='posix' fi @@ -2104,7 +2151,9 @@ x86_64-*-cygwin*) c_target_objs="${c_target_objs} msformat-c.o" cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o" d_target_objs="${d_target_objs} cygwin-d.o" + #jit_target_objs="${jit_target_objs} cygwin-jit.o" target_has_targetdm="yes" + #target_has_targetjitm=yes if test x$enable_threads = xyes; then thread_file='posix' fi @@ -2118,8 +2167,10 @@ i[34567]86-*-mingw* | x86_64-*-mingw*) c_target_objs="${c_target_objs} winnt-c.o" cxx_target_objs="${cxx_target_objs} winnt-c.o" d_target_objs="${d_target_objs} winnt-d.o" + #jit_target_objs="${jit_target_objs} winnt-jit.o" target_has_targetcm="yes" target_has_targetdm="yes" + #target_has_targetjitm=yes case ${target} in x86_64-*-* | *-w64-*) need_64bit_isa=yes @@ -3582,6 +3633,10 @@ if [ "$target_has_targetdm" = "no" ]; then d_target_objs="$d_target_objs default-d.o" fi +if [ "$target_has_targetjitm" = "no" ]; then + jit_target_objs="$jit_target_objs default-jit.o" +fi + # Support for --with-cpu and related options (and a few unrelated options, # too). case ${with_cpu} in @@ -5752,6 +5807,7 @@ case ${target} in c_target_objs="${c_target_objs} ${cpu_type}-c.o" cxx_target_objs="${cxx_target_objs} ${cpu_type}-c.o" d_target_objs="${d_target_objs} ${cpu_type}-d.o" + jit_target_objs="${jit_target_objs} ${cpu_type}-jit.o" tmake_file="${cpu_type}/t-${cpu_type} ${tmake_file}" ;; diff --git a/gcc/config/default-jit.cc b/gcc/config/default-jit.cc new file mode 100644 index 0000000000000..6bee98a79ce27 --- /dev/null +++ b/gcc/config/default-jit.cc @@ -0,0 +1,28 @@ +/* Default JIT language target hooks initializer. + Copyright (C) 2023 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm_jit.h" +#include "jit/jit-target.h" +#include "jit/jit-target-def.h" + +/* Do not include tm.h or tm_p.h here; definitions needed by the target + architecture to initialize targetjitm should instead be added to tm_jit.h. */ + +struct gcc_targetdm targetjitm = TARGETJITM_INITIALIZER; diff --git a/gcc/config/i386/i386-jit.cc b/gcc/config/i386/i386-jit.cc new file mode 100644 index 0000000000000..3014baefc30b6 --- /dev/null +++ b/gcc/config/i386/i386-jit.cc @@ -0,0 +1,216 @@ +/* Subroutines for the JIT front end on the x86 architecture. + Copyright (C) 2023 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#define IN_TARGET_CODE 1 + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "tm.h" +#include "tm_jit.h" +#include "jit/jit-target.h" +#include "jit/jit-target-def.h" + +/* Implement TARGET_JIT_CPU_VERSIONS for x86 targets. */ + +void +ix86_jit_target_versions (void) +{ + if (TARGET_64BIT) + { + jit_add_target_info ("target_arch", "x86_64"); + + // TODO + /*if (TARGET_X32) + jit_add_target_info ("target_arch", "D_X32");*/ + } + else + jit_add_target_info ("target_arch", "x86"); +} + +/* Implement TARGET_JIT_REGISTER_CPU_TARGET_INFO. */ + +extern const char *host_detect_local_cpu (int argc, const char **argv); + +#if TARGET_64BIT_DEFAULT +const char* x86_bits = "64"; +#else +const char* x86_bits = "32"; +#endif + +void +ix86_jit_register_target_info (void) +{ + const char *params[] = {"arch", x86_bits}; + const char *arch = host_detect_local_cpu (2, params); + + const char* arg = "-march="; + const char* arg_pos = strstr(arch, arg); + const char* arg_value = arg_pos + strlen(arg); + const char* arg_value_end = strchr(arg_value, ' '); + + size_t len = arg_value_end - arg_value; + char *cpu = new char[len]; + strncpy(cpu, arg_value, len); + cpu[len] = '\0'; + jit_target_set_arch (cpu); + + jit_target_set_128bit_int_support (targetm.scalar_mode_supported_p (TImode)); + + free (const_cast (arch)); + + if (TARGET_MMX) + jit_add_target_info ("target_feature", "mmx"); + if (TARGET_SSE) + jit_add_target_info("target_feature", "sse"); + if (TARGET_SSE2) + jit_add_target_info("target_feature", "sse2"); + if (TARGET_SSE3) + jit_add_target_info("target_feature", "sse3"); + if (TARGET_SSSE3) + jit_add_target_info("target_feature", "ssse3"); + if (TARGET_SSE4_1) + jit_add_target_info("target_feature", "sse4.1"); + if (TARGET_SSE4_2) + jit_add_target_info("target_feature", "sse4.2"); + if (TARGET_AES) + jit_add_target_info("target_feature", "aes"); + if (TARGET_SHA) + jit_add_target_info("target_feature", "sha"); + if (TARGET_AVX) + jit_add_target_info("target_feature", "avx"); + if (TARGET_AVX2) + jit_add_target_info("target_feature", "avx2"); + if (TARGET_AVX512F) + jit_add_target_info("target_feature", "avx512f"); + if (TARGET_AVX512ER) + jit_add_target_info("target_feature", "avx512er"); + if (TARGET_AVX512CD) + jit_add_target_info("target_feature", "avx512cd"); + if (TARGET_AVX512PF) + jit_add_target_info("target_feature", "avx512pf"); + if (TARGET_AVX512DQ) + jit_add_target_info("target_feature", "avx512dq"); + if (TARGET_AVX512BW) + jit_add_target_info("target_feature", "avx512bw"); + if (TARGET_AVX512VL) + jit_add_target_info("target_feature", "avx512vl"); + if (TARGET_AVX512VBMI) + jit_add_target_info("target_feature", "avx512vbmi"); + if (TARGET_AVX512IFMA) + jit_add_target_info("target_feature", "avx512ifma"); + if (TARGET_AVX512VPOPCNTDQ) + jit_add_target_info("target_feature", "avx512vpopcntdq"); + if (TARGET_FMA) + jit_add_target_info("target_feature", "fma"); + if (TARGET_RTM) + jit_add_target_info("target_feature", "rtm"); + if (TARGET_SSE4A) + jit_add_target_info("target_feature", "sse4a"); + if (TARGET_BMI) { + jit_add_target_info("target_feature", "bmi1"); + jit_add_target_info("target_feature", "bmi"); + } + if (TARGET_BMI2) + jit_add_target_info("target_feature", "bmi2"); + if (TARGET_LZCNT) + jit_add_target_info("target_feature", "lzcnt"); + if (TARGET_TBM) + jit_add_target_info("target_feature", "tbm"); + if (TARGET_POPCNT) + jit_add_target_info("target_feature", "popcnt"); + if (TARGET_RDRND) { + jit_add_target_info("target_feature", "rdrand"); + jit_add_target_info("target_feature", "rdrnd"); + } + if (TARGET_F16C) + jit_add_target_info("target_feature", "f16c"); + if (TARGET_RDSEED) + jit_add_target_info("target_feature", "rdseed"); + if (TARGET_ADX) + jit_add_target_info("target_feature", "adx"); + if (TARGET_FXSR) + jit_add_target_info("target_feature", "fxsr"); + if (TARGET_XSAVE) + jit_add_target_info("target_feature", "xsave"); + if (TARGET_XSAVEOPT) + jit_add_target_info("target_feature", "xsaveopt"); + if (TARGET_XSAVEC) + jit_add_target_info("target_feature", "xsavec"); + if (TARGET_XSAVES) + jit_add_target_info("target_feature", "xsaves"); + if (TARGET_VPCLMULQDQ) { + jit_add_target_info("target_feature", "pclmulqdq"); + jit_add_target_info("target_feature", "vpclmulqdq"); + } + if (TARGET_CMPXCHG16B) + jit_add_target_info("target_feature", "cmpxchg16b"); + if (TARGET_MOVBE) + jit_add_target_info("target_feature", "movbe"); + if (TARGET_AVX512VBMI2) + jit_add_target_info("target_feature", "avx512vbmi2"); + if (TARGET_PKU) + jit_add_target_info("target_feature", "pku"); + if (TARGET_AVX512VNNI) + jit_add_target_info("target_feature", "avx512vnni"); + if (TARGET_AVX512BF16) + jit_add_target_info("target_feature", "avx512bf16"); + if (TARGET_AVX512BITALG) + jit_add_target_info("target_feature", "avx512bitalg"); + if (TARGET_AVX512VP2INTERSECT) + jit_add_target_info("target_feature", "avx512vp2intersect"); + if (TARGET_PCLMUL) + jit_add_target_info("target_feature", "pclmul"); + if (TARGET_GFNI) + jit_add_target_info("target_feature", "gfni"); + if (TARGET_FMA4) + jit_add_target_info("target_feature", "fma4"); + if (TARGET_XOP) + jit_add_target_info("target_feature", "xop"); + + // this is only enabled by choice in llvm, never by default - TODO determine if gcc enables it + // jit_add_target_info("target_feature", "sse-unaligned-mem"); + + if (TARGET_VAES) + jit_add_target_info("target_feature", "vaes"); + if (TARGET_LWP) + jit_add_target_info("target_feature", "lwp"); + if (TARGET_FSGSBASE) + jit_add_target_info("target_feature", "fsgsbase"); + if (TARGET_SHSTK) + jit_add_target_info("target_feature", "shstk"); + if (TARGET_PRFCHW) + jit_add_target_info("target_feature", "prfchw"); + if (TARGET_SAHF) // would this be better as TARGET_USE_SAHF? + jit_add_target_info("target_feature", "sahf"); + if (TARGET_MWAITX) + jit_add_target_info("target_feature", "mwaitx"); + if (TARGET_CLZERO) + jit_add_target_info("target_feature", "clzero"); + if (TARGET_CLDEMOTE) + jit_add_target_info("target_feature", "cldemote"); + if (TARGET_PTWRITE) + jit_add_target_info("target_feature", "ptwrite"); + bool hasERMSB = ix86_arch == PROCESSOR_HASWELL || ix86_arch == PROCESSOR_SKYLAKE + || ix86_arch == PROCESSOR_SKYLAKE_AVX512 || ix86_arch == PROCESSOR_CANNONLAKE + || ix86_arch == PROCESSOR_ICELAKE_CLIENT || ix86_arch == PROCESSOR_ICELAKE_SERVER + || ix86_arch == PROCESSOR_CASCADELAKE || ix86_arch == PROCESSOR_TIGERLAKE + || ix86_arch == PROCESSOR_COOPERLAKE; + if (hasERMSB) + jit_add_target_info("target_feature", "ermsbd"); +} diff --git a/gcc/config/i386/i386-jit.h b/gcc/config/i386/i386-jit.h new file mode 100644 index 0000000000000..8cfccba405f4c --- /dev/null +++ b/gcc/config/i386/i386-jit.h @@ -0,0 +1,26 @@ +/* Definitions for the jit front end on the x86 architecture. + Copyright (C) 2023 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +/* In i386-jit.cc */ +extern void ix86_jit_target_versions (void); +extern void ix86_jit_register_target_info (void); +extern bool ix86_jit_has_stdcall_convention (unsigned int *, unsigned int *); + +/* Target hooks for jit language. */ +#define TARGET_JIT_CPU_VERSIONS ix86_jit_target_versions +#define TARGET_JIT_REGISTER_CPU_TARGET_INFO ix86_jit_register_target_info +#define TARGET_JIT_HAS_STDCALL_CONVENTION ix86_jit_has_stdcall_convention diff --git a/gcc/config/i386/t-i386 b/gcc/config/i386/t-i386 index ffdbbdfe8cefb..8421b4dba429a 100644 --- a/gcc/config/i386/t-i386 +++ b/gcc/config/i386/t-i386 @@ -46,6 +46,10 @@ i386-d.o: $(srcdir)/config/i386/i386-d.cc $(COMPILE) $< $(POSTCOMPILE) +i386-jit.o: $(srcdir)/config/i386/i386-jit.cc + $(COMPILE) $< + $(POSTCOMPILE) + i386-options.o: $(srcdir)/config/i386/i386-options.cc $(COMPILE) $< $(POSTCOMPILE) diff --git a/gcc/config/linux-jit.cc b/gcc/config/linux-jit.cc new file mode 100644 index 0000000000000..20f0d8b4c6567 --- /dev/null +++ b/gcc/config/linux-jit.cc @@ -0,0 +1,48 @@ +/* Linux support needed only by jit front-end. + Copyright (C) 2023 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tm_jit.h" +#include "jit/jit-target.h" +#include "jit/jit-target-def.h" + +// TODO: remove this hook? +/* Implement TARGET_JIT_OS_VERSIONS for Linux targets. */ + +static void +linux_jit_os_builtins (void) +{ +} + +// TODO: remove this hook? +/* Implement TARGET_JIT_REGISTER_OS_TARGET_INFO for Linux targets. */ + +static void +linux_jit_register_target_info (void) +{ +} + +#undef TARGET_JIT_OS_VERSIONS +#define TARGET_JIT_OS_VERSIONS linux_jit_os_builtins + +#undef TARGET_JIT_REGISTER_OS_TARGET_INFO +#define TARGET_JIT_REGISTER_OS_TARGET_INFO linux_jit_register_target_info + +struct gcc_targetjitm targetjitm = TARGETJITM_INITIALIZER; diff --git a/gcc/config/t-linux b/gcc/config/t-linux index 03966d5ce968c..0be3fb24404d0 100644 --- a/gcc/config/t-linux +++ b/gcc/config/t-linux @@ -23,3 +23,7 @@ linux.o: $(srcdir)/config/linux.cc linux-d.o: $(srcdir)/config/linux-d.cc $(COMPILE) $< $(POSTCOMPILE) + +linux-jit.o: $(srcdir)/config/linux-jit.cc + $(COMPILE) $< + $(POSTCOMPILE) diff --git a/gcc/configure b/gcc/configure index 254f9b6c9430d..dbbc21381d487 100755 --- a/gcc/configure +++ b/gcc/configure @@ -645,6 +645,7 @@ GMPINC GMPLIBS target_cpu_default d_target_objs +jit_target_objs fortran_target_objs cxx_target_objs c_target_objs @@ -654,6 +655,8 @@ xm_include_list xm_file_list tm_d_include_list tm_d_file_list +tm_jit_include_list +tm_jit_file_list tm_p_include_list tm_p_file_list tm_defines @@ -13506,6 +13509,17 @@ for f in $tm_d_file; do esac done +tm_jit_file_list= +tm_jit_include_list= +for f in $tm_jit_file; do + case $f in + * ) + tm_jit_file_list="${tm_jit_file_list} \$(srcdir)/config/$f" + tm_jit_include_list="${tm_jit_include_list} config/$f" + ;; + esac +done + xm_file_list= xm_include_list= for f in $xm_file; do diff --git a/gcc/configure.ac b/gcc/configure.ac index 62bc908b991ff..0513895f7d976 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -2371,6 +2371,17 @@ for f in $tm_d_file; do esac done +tm_jit_file_list= +tm_jit_include_list= +for f in $tm_jit_file; do + case $f in + * ) + tm_jit_file_list="${tm_jit_file_list} \$(srcdir)/config/$f" + tm_jit_include_list="${tm_jit_include_list} config/$f" + ;; + esac +done + xm_file_list= xm_include_list= for f in $xm_file; do @@ -7328,6 +7339,8 @@ AC_SUBST(tm_p_file_list) AC_SUBST(tm_p_include_list) AC_SUBST(tm_d_file_list) AC_SUBST(tm_d_include_list) +AC_SUBST(tm_jit_file_list) +AC_SUBST(tm_jit_include_list) AC_SUBST(xm_file_list) AC_SUBST(xm_include_list) AC_SUBST(xm_defines) @@ -7336,6 +7349,7 @@ AC_SUBST(c_target_objs) AC_SUBST(cxx_target_objs) AC_SUBST(fortran_target_objs) AC_SUBST(d_target_objs) +AC_SUBST(jit_target_objs) AC_SUBST(target_cpu_default) AC_SUBST_FILE(language_hooks) diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 8fe49c2ba3dbb..f6f39b079a879 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -115,6 +115,14 @@ initialize @code{targetdm} themselves, they should set @code{target_has_targetdm=yes} in @file{config.gcc}; otherwise a default definition is used. +Similarly, there is a @code{targetjitm} variable for hooks that are +specific to the jit front end, documented as ``JIT Target Hook''. +This is declared in @file{jit/jit-target.h}, the initializer +@code{TARGETJITM_INITIALIZER} in @file{jit/jit-target-def.h}. If targets +initialize @code{targetjitm} themselves, they should set +@code{target_has_targetjitm=yes} in @file{config.gcc}; otherwise a default +definition is used. + @node Driver @section Controlling the Compilation Driver, @file{gcc} @cindex driver @@ -10902,6 +10910,36 @@ if they have external linkage. If this flag is false, then instantiated decls will be emitted as weak symbols. The default is @code{false}. @end deftypevr +@node JIT Language and ABI +@section JIT ABI parameters +@cindex parameters, jit abi + +@deftypefn {JIT Target Hook} void TARGET_JIT_CPU_VERSIONS (void) +Declare all environmental version identifiers relating to the target CPU +using the function @code{builtin_version}, which takes a string representing +the name of the version. Version identifiers predefined by this hook apply +to all modules that are being compiled and imported. +@end deftypefn + +@deftypefn {JIT Target Hook} void TARGET_JIT_OS_VERSIONS (void) +Similarly to @code{TARGET_JIT_CPU_VERSIONS}, but is used for versions +relating to the target operating system. +@end deftypefn + +@deftypefn {JIT Target Hook} void TARGET_JIT_REGISTER_CPU_TARGET_INFO (void) +Register all target information keys relating to the target CPU using the +function @code{jit_add_target_info_handlers}, which takes a +@samp{struct jit_target_info_spec} (defined in @file{jit/jit-target.h}). The keys +added by this hook are made available at compile time by the +@code{__traits(getTargetInfo)} extension, the result is an expression +describing the requested target information. +@end deftypefn + +@deftypefn {JIT Target Hook} void TARGET_JIT_REGISTER_OS_TARGET_INFO (void) +Same as @code{TARGET_JIT_CPU_TARGET_INFO}, but is used for keys relating to +the target operating system. +@end deftypefn + @node Named Address Spaces @section Adding support for named address spaces @cindex named address spaces diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 62c49ac46de69..b7da440f817a9 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -115,6 +115,14 @@ initialize @code{targetdm} themselves, they should set @code{target_has_targetdm=yes} in @file{config.gcc}; otherwise a default definition is used. +Similarly, there is a @code{targetjitm} variable for hooks that are +specific to the jit front end, documented as ``JIT Target Hook''. +This is declared in @file{jit/jit-target.h}, the initializer +@code{TARGETJITM_INITIALIZER} in @file{jit/jit-target-def.h}. If targets +initialize @code{targetjitm} themselves, they should set +@code{target_has_targetjitm=yes} in @file{config.gcc}; otherwise a default +definition is used. + @node Driver @section Controlling the Compilation Driver, @file{gcc} @cindex driver @@ -7127,6 +7135,18 @@ floating-point support; they are not included in this mechanism. @hook TARGET_D_TEMPLATES_ALWAYS_COMDAT +@node JIT Language and ABI +@section JIT ABI parameters +@cindex parameters, jit abi + +@hook TARGET_JIT_CPU_VERSIONS + +@hook TARGET_JIT_OS_VERSIONS + +@hook TARGET_JIT_REGISTER_CPU_TARGET_INFO + +@hook TARGET_JIT_REGISTER_OS_TARGET_INFO + @node Named Address Spaces @section Adding support for named address spaces @cindex named address spaces diff --git a/gcc/genhooks.cc b/gcc/genhooks.cc index 8bcf99292073b..0d4b13b7a71fc 100644 --- a/gcc/genhooks.cc +++ b/gcc/genhooks.cc @@ -35,6 +35,7 @@ static struct hook_desc hook_array[] = { #include "c-family/c-target.def" #include "common/common-target.def" #include "d/d-target.def" +#include "jit/jit-target.def" #undef DEFHOOK }; diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in index 248ec45b72953..cca0980b42325 100644 --- a/gcc/jit/Make-lang.in +++ b/gcc/jit/Make-lang.in @@ -120,7 +120,7 @@ jit.serial = $(LIBGCCJIT_FILENAME) # Tell GNU make to ignore these if they exist. .PHONY: jit -jit_OBJS = attribs.o \ +JIT_OBJS = attribs.o \ jit/dummy-frontend.o \ jit/libgccjit.o \ jit/jit-logging.o \ @@ -129,13 +129,17 @@ jit_OBJS = attribs.o \ jit/jit-result.o \ jit/jit-tempdir.o \ jit/jit-builtins.o \ + jit/jit-target.o \ jit/jit-spec.o \ gcc.o ifneq (,$(findstring mingw,$(target))) -jit_OBJS += jit/jit-w32.o +JIT_OBJS += jit/jit-w32.o endif +# All language-specific object files for jit. +jit_OBJS = $(JIT_OBJS) $(JIT_TARGET_OBJS) + # Use strict warnings for this front end. jit-warn = $(STRICT_WARN) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 0b107754ca8a6..c7ada1203b6a7 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see #include "jit-result.h" #include "jit-builtins.h" #include "jit-tempdir.h" +#include "jit-target.h" #ifdef _WIN32 #include "jit-w32.h" @@ -3607,6 +3608,7 @@ replay () JIT_LOG_SCOPE (get_logger ()); init_types (); + jit_target_init (); /* Replay the recorded events: */ timevar_push (TV_JIT_REPLAY); diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index b767fec6da884..d153f4945d8c2 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -48,9 +48,10 @@ set_variable_attribute(const std::vector. */ + +#include "jit/jit-target-hooks-def.h" +#include "tree.h" +#include "hooks.h" diff --git a/gcc/jit/jit-target.cc b/gcc/jit/jit-target.cc new file mode 100644 index 0000000000000..ad41376fa7fc8 --- /dev/null +++ b/gcc/jit/jit-target.cc @@ -0,0 +1,94 @@ +/* jit-target.cc -- Target interface for the jit front end. + Copyright (C) 2023 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" + +#include "tree.h" +#include "memmodel.h" +#include "fold-const.h" +#include "diagnostic.h" +#include "stor-layout.h" +#include "tm.h" +#include "tm_p.h" +#include "target.h" +#include "calls.h" + +#include "jit-target.h" + +#include + +static target_info jit_target_info; + +/* Initialize all variables of the Target structure. */ + +void +jit_target_init () +{ + /* Initialize target info tables, the keys required by the language are added + last, so that the OS and CPU handlers can override. */ + targetjitm.jit_register_cpu_target_info (); + targetjitm.jit_register_os_target_info (); +} + +/* Add all target info in HANDLERS to JIT_TARGET_INFO for use by + jit_has_target_value(). */ + +void +jit_add_target_info (const char *key, const char *value) +{ + if (jit_target_info.m_info.find (key) == jit_target_info.m_info.end()) + jit_target_info.m_info.insert ({key, {value}}); + else + jit_target_info.m_info[key].insert(value); +} + +void +jit_target_set_arch (const char* arch) +{ + jit_target_info.m_arch = arch; +} + +void +jit_target_set_128bit_int_support (bool support) +{ + jit_target_info.m_supports_128bit_int = support; +} + +target_info::~target_info() +{ + free (const_cast ((const void *) m_arch)); +} + +target_info * +jit_get_target_info () +{ + target_info *info = new target_info {std::move(jit_target_info)}; + jit_target_info = target_info{}; + return info; +} + +bool +target_info::has_target_value (const char *key, const char *value) +{ + if (m_info.find (key) == m_info.end ()) + return false; + + auto& set = m_info[key]; + return set.find (value) != set.end (); +} diff --git a/gcc/jit/jit-target.def b/gcc/jit/jit-target.def new file mode 100644 index 0000000000000..92648ac25d8cf --- /dev/null +++ b/gcc/jit/jit-target.def @@ -0,0 +1,70 @@ +/* jit-target.def -- Target hook definitions for the jit front end. + Copyright (C) 2023 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not see + . */ + +/* See target-hooks-macros.h for details of macros that should be + provided by the including file, and how to use them here. */ + +#include "target-hooks-macros.h" + +#undef HOOK_TYPE +#define HOOK_TYPE "JIT Target Hook" + +HOOK_VECTOR (TARGETJITM_INITIALIZER, gcc_targetjitm) + +#undef HOOK_PREFIX +#define HOOK_PREFIX "TARGET_" + +/* Environmental version identifiers relating to the target CPU. */ +DEFHOOK +(jit_cpu_versions, + "Declare all environmental version identifiers relating to the target CPU\n\ +using the function @code{builtin_version}, which takes a string representing\n\ +the name of the version. Version identifiers predefined by this hook apply\n\ +to all modules that are being compiled and imported.", + void, (void), + hook_void_void) + +/* Environmental version identifiers relating to the target OS. */ +DEFHOOK +(jit_os_versions, + "Similarly to @code{TARGET_JIT_CPU_VERSIONS}, but is used for versions\n\ +relating to the target operating system.", + void, (void), + hook_void_void) + +/* getTargetInfo keys relating to the target CPU. */ +DEFHOOK +(jit_register_cpu_target_info, + "Register all target information keys relating to the target CPU using the\n\ +function @code{jit_add_target_info_handlers}, which takes a\n\ +@samp{struct jit_target_info_spec} (defined in @file{jit/jit-target.h}). The keys\n\ +added by this hook are made available at compile time by the\n\ +@code{__traits(getTargetInfo)} extension, the result is an expression\n\ +describing the requested target information.", + void, (void), + hook_void_void) + +/* getTargetInfo keys relating to the target OS. */ +DEFHOOK +(jit_register_os_target_info, + "Same as @code{TARGET_JIT_CPU_TARGET_INFO}, but is used for keys relating to\n\ +the target operating system.", + void, (void), + hook_void_void) + +/* Close the 'struct gcc_targetdm' definition. */ +HOOK_VECTOR_END (C90_EMPTY_HACK) diff --git a/gcc/jit/jit-target.h b/gcc/jit/jit-target.h new file mode 100644 index 0000000000000..09fd7941c2ef1 --- /dev/null +++ b/gcc/jit/jit-target.h @@ -0,0 +1,70 @@ +/* jit-target.h -- Data structure definitions for target-specific jit behavior. + Copyright (C) 2023 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not see + . */ + +#ifndef GCC_JIT_TARGET_H +#define GCC_JIT_TARGET_H + +#define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME; +#define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) TYPE (* NAME) PARAMS; +#define DEFHOOK_UNDOC DEFHOOK +#define HOOKSTRUCT(FRAGMENT) FRAGMENT + +#include "jit-target.def" + +#include +#include + +static size_t hash_cstr(const char *s) +{ + const size_t seed = 0; + return std::_Hash_bytes(s, std::strlen(s), seed); +} + +struct CStringHash { + size_t operator()(const char* const &string) const { + auto res = hash_cstr (string); + return res; + } +}; + +struct CStringEqual { + bool operator()(const char* const &string1, const char* const &string2) const { + return strcmp (string1, string2) == 0; + } +}; + +struct target_info { + public: + ~target_info(); + + bool has_target_value (const char *key, const char *value); + + std::unordered_map, CStringHash, CStringEqual> m_info; + const char *m_arch = nullptr; + bool m_supports_128bit_int = false; +}; + +/* Each target can provide their own. */ +extern struct gcc_targetjitm targetjitm; + +extern void jit_target_init (); +extern void jit_target_set_arch (const char* arch); +extern void jit_target_set_128bit_int_support (bool support); +extern void jit_add_target_info (const char *key, const char *value); +extern target_info * jit_get_target_info (); + +#endif /* GCC_JIT_TARGET_H */ diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index bbf9423193065..f8cdfc4a91066 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see #include "libgccjit.h" #include "jit-recording.h" #include "jit-result.h" +#include "jit-target.h" /* The opaque types used by the public API are actually subclasses of the gcc::jit::recording classes. */ @@ -44,6 +45,10 @@ struct gcc_jit_result : public gcc::jit::result { }; +struct gcc_jit_target_info : public target_info +{ +}; + struct gcc_jit_object : public gcc::jit::recording::memento { }; @@ -3849,6 +3854,44 @@ gcc_jit_context_compile_to_file (gcc_jit_context *ctxt, ctxt->compile_to_file (output_kind, output_path); } +gcc_jit_target_info * +gcc_jit_context_get_target_info (gcc_jit_context *ctxt) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + + ctxt->log ("get_target_info of ctxt: %p", (void *)ctxt); + + ctxt->get_target_info (); + + return (gcc_jit_target_info*) jit_get_target_info (); +} + +void +gcc_jit_target_info_release (gcc_jit_target_info *info) +{ + RETURN_IF_FAIL (info, NULL, NULL, "NULL info"); + delete info; +} + +bool +gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info, + const char *feature) +{ + return info->has_target_value ("target_feature", feature); +} + +const char * +gcc_jit_target_info_arch (gcc_jit_target_info *info) +{ + return info->m_arch; +} + +bool +gcc_jit_target_info_supports_128bit_int (gcc_jit_target_info *info) +{ + return info->m_supports_128bit_int; +} /* Public entrypoint. See description in libgccjit.h. diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index f5537adbc919f..38b0f69ddd47b 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -52,6 +52,9 @@ typedef struct gcc_jit_context gcc_jit_context; /* A gcc_jit_result encapsulates the result of an in-memory compilation. */ typedef struct gcc_jit_result gcc_jit_result; +/* A gcc_jit_target_info encapsulates the target info. */ +typedef struct gcc_jit_target_info gcc_jit_target_info; + /* An object created within a context. Such objects are automatically cleaned up when the context is released. @@ -2071,6 +2074,22 @@ gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *vector_type); extern gcc_jit_type * gcc_jit_type_unqualified (gcc_jit_type *type); +extern gcc_jit_target_info * +gcc_jit_context_get_target_info (gcc_jit_context *ctxt); + +extern void +gcc_jit_target_info_release (gcc_jit_target_info *info); + +extern bool +gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info, + const char *feature); + +extern const char * +gcc_jit_target_info_arch (gcc_jit_target_info *info); + +extern bool +gcc_jit_target_info_supports_128bit_int (gcc_jit_target_info *info); + /* Given type "T", get type "T __attribute__ ((packed))". */ extern void gcc_jit_type_set_packed (gcc_jit_type *type); diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index a10a85ceaceaf..e52de0057a50b 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -317,3 +317,12 @@ LIBGCCJIT_ABI_32 { gcc_jit_context_new_vector_access; gcc_jit_set_global_personality_function_name; } LIBGCCJIT_ABI_31; + +LIBGCCJIT_ABI_33 { + global: + gcc_jit_context_get_target_info; + gcc_jit_target_info_release; + gcc_jit_target_info_cpu_supports; + gcc_jit_target_info_arch; + gcc_jit_target_info_supports_128bit_int; +} LIBGCCJIT_ABI_32; From 809825d5627ef98b4f35e452fbc0bce4a10c0e2f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 6 Jul 2023 16:51:17 +0200 Subject: [PATCH 27/45] fixup! WIP: Add support for function attributes Add support for returns_twice attribute in libgccjit --- gcc/jit/jit-playback.cc | 5 +++++ gcc/jit/libgccjit.h | 1 + 2 files changed, 6 insertions(+) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 0cfa119ed7417..3f16e8a297515 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -529,6 +529,8 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) return "visibility"; case GCC_JIT_FN_ATTRIBUTE_COLD: return "cold"; + case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE: + return "returns_twice"; } return NULL; } @@ -667,6 +669,9 @@ new_function (location *loc, TREE_USED (fndecl) = 1; DECL_PRESERVE_P (fndecl) = 1; } + /* See handle_returns_twice_attribute in gcc/c-family/c-attribs.cc. */ + else if (attr == GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE) + DECL_IS_RETURNS_TWICE (fndecl) = 1; const char* attribute = fn_attribute_to_string (attr); if (attribute) diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 057e4779f61c0..dc70c3644931c 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2104,6 +2104,7 @@ enum gcc_jit_fn_attribute GCC_JIT_FN_ATTRIBUTE_USED, GCC_JIT_FN_ATTRIBUTE_VISIBILITY, GCC_JIT_FN_ATTRIBUTE_COLD, + GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE, }; /* Add an attribute to a function. */ From 2cfd66973f16da9df03ebbb60f19d4102bb941e7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jul 2023 21:26:24 +0200 Subject: [PATCH 28/45] Change return value of `gcc_jit_target_info_cpu_supports` and of `gcc_jit_target_info_supports_128bit_int` from bool to int --- gcc/jit/libgccjit.cc | 4 ++-- gcc/jit/libgccjit.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index f8cdfc4a91066..050e68b738c6a 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -3874,7 +3874,7 @@ gcc_jit_target_info_release (gcc_jit_target_info *info) delete info; } -bool +int gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info, const char *feature) { @@ -3887,7 +3887,7 @@ gcc_jit_target_info_arch (gcc_jit_target_info *info) return info->m_arch; } -bool +int gcc_jit_target_info_supports_128bit_int (gcc_jit_target_info *info) { return info->m_supports_128bit_int; diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index dc70c3644931c..181be5a727a40 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2080,14 +2080,14 @@ gcc_jit_context_get_target_info (gcc_jit_context *ctxt); extern void gcc_jit_target_info_release (gcc_jit_target_info *info); -extern bool +extern int gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info, const char *feature); extern const char * gcc_jit_target_info_arch (gcc_jit_target_info *info); -extern bool +extern int gcc_jit_target_info_supports_128bit_int (gcc_jit_target_info *info); /* Given type "T", get type "T __attribute__ ((packed))". */ From 6dae9ee45e166a08a253d596370123235ce45c06 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jul 2023 21:40:51 +0200 Subject: [PATCH 29/45] fixup! WIP: Add support for function attributes Add support for pure attribute in libgccjit --- gcc/jit/jit-playback.cc | 3 + gcc/jit/libgccjit.h | 1 + gcc/testsuite/jit.dg/jit.exp | 33 +++++ gcc/testsuite/jit.dg/test-pure-attribute.c | 134 +++++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 gcc/testsuite/jit.dg/test-pure-attribute.c diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 3f16e8a297515..6fdda09eb1e7a 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -672,6 +672,9 @@ new_function (location *loc, /* See handle_returns_twice_attribute in gcc/c-family/c-attribs.cc. */ else if (attr == GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE) DECL_IS_RETURNS_TWICE (fndecl) = 1; + /* See handle_pure_attribute in gcc/c-family/c-attribs.cc. */ + else if (attr == GCC_JIT_FN_ATTRIBUTE_PURE) + DECL_PURE_P (fndecl) = 1; const char* attribute = fn_attribute_to_string (attr); if (attribute) diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 181be5a727a40..9663be4a0694c 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2105,6 +2105,7 @@ enum gcc_jit_fn_attribute GCC_JIT_FN_ATTRIBUTE_VISIBILITY, GCC_JIT_FN_ATTRIBUTE_COLD, GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE, + GCC_JIT_FN_ATTRIBUTE_PURE, }; /* Add an attribute to a function. */ diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp index 3568dbb9d6334..45a6b25b62b69 100644 --- a/gcc/testsuite/jit.dg/jit.exp +++ b/gcc/testsuite/jit.dg/jit.exp @@ -895,8 +895,41 @@ proc jit-verify-assembler-output { args } { pass "${asm_filename} output pattern test, ${dg-output-text}" verbose "Passed test for output pattern ${dg-output-text}" 3 } +} + +# Assuming that a .s file has been written out named +# OUTPUT_FILENAME, check that the argument doesn't match +# the output file. +proc jit-verify-assembler-output-not { args } { + verbose "jit-verify-assembler: $args" + + set dg-output-text [lindex $args 0] + verbose "dg-output-text: ${dg-output-text}" + upvar 2 name name + verbose "name: $name" + + upvar 2 prog prog + verbose "prog: $prog" + set asm_filename [jit-get-output-filename $prog] + verbose " asm_filename: ${asm_filename}" + + # Read the assembly file. + set f [open $asm_filename r] + set content [read $f] + close $f + + # Verify that the assembly matches the regex. + if { [regexp ${dg-output-text} $content] } { + fail "${asm_filename} output pattern test, is ${content}, should match ${dg-output-text}" + verbose "Failed test for output pattern ${dg-output-text}" 3 + } else { + pass "${asm_filename} output pattern test, ${dg-output-text}" + verbose "Passed test for output pattern ${dg-output-text}" 3 + } } + + # Assuming that a .o file has been written out named # OUTPUT_FILENAME, invoke the driver to try to turn it into # an executable, and try to run the result. diff --git a/gcc/testsuite/jit.dg/test-pure-attribute.c b/gcc/testsuite/jit.dg/test-pure-attribute.c new file mode 100644 index 0000000000000..049c495faacf6 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-pure-attribute.c @@ -0,0 +1,134 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +/* We don't want set_options() in harness.h to set -O3 to see that the cold + attribute affects the optimizations. */ +#define TEST_ESCHEWS_SET_OPTIONS +static void set_options (gcc_jit_context *ctxt, const char *argv0) +{ + // Set "-O3". + gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3); +} + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-pure-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__ ((pure)) +int foo (int x); +int xxx(void) +{ + int x = 45; + int sum = 0; + + while (x >>= 1) + sum += foo (x) * 2; + return sum; +} + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Creating the `foo` function. */ + gcc_jit_param *n = + gcc_jit_context_new_param (ctxt, NULL, int_type, "x"); + gcc_jit_param *params[1] = {n}; + gcc_jit_function *foo_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + int_type, + "foo", + 1, params, + 0); + gcc_jit_function_add_attribute(foo_func, GCC_JIT_FN_ATTRIBUTE_PURE); + + /* Creating the `xxx` function. */ + gcc_jit_function *xxx_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "xxx", + 0, NULL, + 0); + + gcc_jit_block *block = gcc_jit_function_new_block (xxx_func, NULL); + + /* Build locals: */ + gcc_jit_lvalue *x = + gcc_jit_function_new_local (xxx_func, NULL, int_type, "x"); + gcc_jit_lvalue *sum = + gcc_jit_function_new_local (xxx_func, NULL, int_type, "sum"); + + /* int x = 45 */ + gcc_jit_block_add_assignment ( + block, NULL, + x, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 45)); + /* int sum = 0 */ + gcc_jit_block_add_assignment ( + block, NULL, + sum, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)); + + /* while (x >>= 1) { sum += foo (x) * 2; } */ + gcc_jit_block *loop_cond = + gcc_jit_function_new_block (xxx_func, "loop_cond"); + gcc_jit_block *loop_body = + gcc_jit_function_new_block (xxx_func, "loop_body"); + gcc_jit_block *after_loop = + gcc_jit_function_new_block (xxx_func, "after_loop"); + + gcc_jit_block_end_with_jump (block, NULL, loop_cond); + + + /* if (x >>= 1) */ + /* Since gccjit doesn't (yet?) have support for `>>=` operator, we will decompose it into: + `if (x = x >> 1)` */ + gcc_jit_block_add_assignment_op ( + loop_cond, NULL, + x, + GCC_JIT_BINARY_OP_RSHIFT, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1)); + /* The condition itself */ + gcc_jit_block_end_with_conditional ( + loop_cond, NULL, + gcc_jit_context_new_comparison ( + ctxt, NULL, + GCC_JIT_COMPARISON_NE, + gcc_jit_lvalue_as_rvalue (x), + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)), + after_loop, + loop_body); + + /* sum += foo (x) * 2; */ + gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue(x); + gcc_jit_block_add_assignment_op ( + loop_body, NULL, + x, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, int_type, + gcc_jit_context_new_call (ctxt, NULL, foo_func, 1, &arg), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + int_type, + 2))); + gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond); + + /* return sum; */ + gcc_jit_block_end_with_return (after_loop, NULL, gcc_jit_lvalue_as_rvalue(sum)); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* Check that the loop was optimized away */ +/* { dg-final { jit-verify-assembler-output-not "jne" } } */ From 63cce91df900f5e5cf9bf80c6ad53480e157d894 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 21 Jul 2023 11:03:59 +0200 Subject: [PATCH 30/45] fixup! WIP: Add support for function attributes Add support for const attribute in libgccjit --- gcc/jit/jit-playback.cc | 5 + gcc/jit/libgccjit.h | 1 + gcc/testsuite/jit.dg/test-const-attribute.c | 134 ++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 gcc/testsuite/jit.dg/test-const-attribute.c diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 6fdda09eb1e7a..915f8ab23bd23 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -531,6 +531,8 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) return "cold"; case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE: return "returns_twice"; + case GCC_JIT_FN_ATTRIBUTE_CONST: + return "const"; } return NULL; } @@ -675,6 +677,9 @@ new_function (location *loc, /* See handle_pure_attribute in gcc/c-family/c-attribs.cc. */ else if (attr == GCC_JIT_FN_ATTRIBUTE_PURE) DECL_PURE_P (fndecl) = 1; + /* See handle_const_attribute in gcc/c-family/c-attribs.cc. */ + else if (attr == GCC_JIT_FN_ATTRIBUTE_CONST) + TREE_READONLY (fndecl) = 1; const char* attribute = fn_attribute_to_string (attr); if (attribute) diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 9663be4a0694c..60eaf39bff6ea 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2106,6 +2106,7 @@ enum gcc_jit_fn_attribute GCC_JIT_FN_ATTRIBUTE_COLD, GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE, GCC_JIT_FN_ATTRIBUTE_PURE, + GCC_JIT_FN_ATTRIBUTE_CONST, }; /* Add an attribute to a function. */ diff --git a/gcc/testsuite/jit.dg/test-const-attribute.c b/gcc/testsuite/jit.dg/test-const-attribute.c new file mode 100644 index 0000000000000..c06742d163f52 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-const-attribute.c @@ -0,0 +1,134 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +/* We don't want set_options() in harness.h to set -O3 to see that the const + attribute affects the optimizations. */ +#define TEST_ESCHEWS_SET_OPTIONS +static void set_options (gcc_jit_context *ctxt, const char *argv0) +{ + // Set "-O3". + gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3); +} + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-const-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__ ((const)) +int foo (int x); +int xxx(void) +{ + int x = 45; + int sum = 0; + + while (x >>= 1) + sum += foo (x) * 2; + return sum; +} + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Creating the `foo` function. */ + gcc_jit_param *n = + gcc_jit_context_new_param (ctxt, NULL, int_type, "x"); + gcc_jit_param *params[1] = {n}; + gcc_jit_function *foo_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + int_type, + "foo", + 1, params, + 0); + gcc_jit_function_add_attribute(foo_func, GCC_JIT_FN_ATTRIBUTE_CONST); + + /* Creating the `xxx` function. */ + gcc_jit_function *xxx_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "xxx", + 0, NULL, + 0); + + gcc_jit_block *block = gcc_jit_function_new_block (xxx_func, NULL); + + /* Build locals: */ + gcc_jit_lvalue *x = + gcc_jit_function_new_local (xxx_func, NULL, int_type, "x"); + gcc_jit_lvalue *sum = + gcc_jit_function_new_local (xxx_func, NULL, int_type, "sum"); + + /* int x = 45 */ + gcc_jit_block_add_assignment ( + block, NULL, + x, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 45)); + /* int sum = 0 */ + gcc_jit_block_add_assignment ( + block, NULL, + sum, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)); + + /* while (x >>= 1) { sum += foo (x) * 2; } */ + gcc_jit_block *loop_cond = + gcc_jit_function_new_block (xxx_func, "loop_cond"); + gcc_jit_block *loop_body = + gcc_jit_function_new_block (xxx_func, "loop_body"); + gcc_jit_block *after_loop = + gcc_jit_function_new_block (xxx_func, "after_loop"); + + gcc_jit_block_end_with_jump (block, NULL, loop_cond); + + + /* if (x >>= 1) */ + /* Since gccjit doesn't (yet?) have support for `>>=` operator, we will decompose it into: + `if (x = x >> 1)` */ + gcc_jit_block_add_assignment_op ( + loop_cond, NULL, + x, + GCC_JIT_BINARY_OP_RSHIFT, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1)); + /* The condition itself */ + gcc_jit_block_end_with_conditional ( + loop_cond, NULL, + gcc_jit_context_new_comparison ( + ctxt, NULL, + GCC_JIT_COMPARISON_NE, + gcc_jit_lvalue_as_rvalue (x), + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)), + after_loop, + loop_body); + + /* sum += foo (x) * 2; */ + gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue(x); + gcc_jit_block_add_assignment_op ( + loop_body, NULL, + x, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, int_type, + gcc_jit_context_new_call (ctxt, NULL, foo_func, 1, &arg), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + int_type, + 2))); + gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond); + + /* return sum; */ + gcc_jit_block_end_with_return (after_loop, NULL, gcc_jit_lvalue_as_rvalue(sum)); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* Check that the loop was optimized away */ +/* { dg-final { jit-verify-assembler-output-not "jne" } } */ From 65eb3d50bb7ba7c46be08cd272251910d3e51df0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 21 Jul 2023 14:48:43 +0200 Subject: [PATCH 31/45] fixup! WIP: Add support for function attributes Add missing `attribute_to_string` handling for `pure` --- gcc/jit/jit-playback.cc | 2 ++ gcc/testsuite/jit.dg/test-pure-attribute.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 915f8ab23bd23..88e1b21203020 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -531,6 +531,8 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) return "cold"; case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE: return "returns_twice"; + case GCC_JIT_FN_ATTRIBUTE_PURE: + return "pure"; case GCC_JIT_FN_ATTRIBUTE_CONST: return "const"; } diff --git a/gcc/testsuite/jit.dg/test-pure-attribute.c b/gcc/testsuite/jit.dg/test-pure-attribute.c index 049c495faacf6..0c9ba1366e0c6 100644 --- a/gcc/testsuite/jit.dg/test-pure-attribute.c +++ b/gcc/testsuite/jit.dg/test-pure-attribute.c @@ -5,7 +5,7 @@ #include "libgccjit.h" -/* We don't want set_options() in harness.h to set -O3 to see that the cold +/* We don't want set_options() in harness.h to set -O3 to see that the pure attribute affects the optimizations. */ #define TEST_ESCHEWS_SET_OPTIONS static void set_options (gcc_jit_context *ctxt, const char *argv0) From 9d5b6b20efa20825926196759d50706a604c64a8 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 25 May 2023 15:40:15 -0400 Subject: [PATCH 32/45] Fix GGC --- gcc/ipa-fnsummary.cc | 2 ++ gcc/ipa-icf.cc | 9 +++++++++ gcc/ipa-profile.cc | 10 ++++++++++ gcc/ipa-prop.cc | 18 ++++++++++++++++++ gcc/ipa-prop.h | 2 ++ gcc/ipa-sra.cc | 12 ++++++++++++ gcc/ipa-utils.h | 7 +++++++ gcc/toplev.cc | 18 +++++++++++++----- 8 files changed, 73 insertions(+), 5 deletions(-) diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc index 63bd525b4c56e..8e0aee01fce48 100644 --- a/gcc/ipa-fnsummary.cc +++ b/gcc/ipa-fnsummary.cc @@ -4986,4 +4986,6 @@ void ipa_fnsummary_cc_finalize (void) { ipa_free_fn_summary (); + // TODO: this commit contains many fixes that don't necessarily help fixing the bug in the GC. Remove those fixes. + ipa_free_size_summary (); } diff --git a/gcc/ipa-icf.cc b/gcc/ipa-icf.cc index cb9f768d85de6..20d3793574585 100644 --- a/gcc/ipa-icf.cc +++ b/gcc/ipa-icf.cc @@ -3656,3 +3656,12 @@ make_pass_ipa_icf (gcc::context *ctxt) { return new ipa_icf::pass_ipa_icf (ctxt); } + +/* Reset all state within ipa-icf.cc so that we can rerun the compiler + within the same process. For use by toplev::finalize. */ + +void +ipa_icf_cc_finalize (void) +{ + ipa_icf::optimizer = NULL; +} diff --git a/gcc/ipa-profile.cc b/gcc/ipa-profile.cc index 78a40a118bcaa..8083b8195a80b 100644 --- a/gcc/ipa-profile.cc +++ b/gcc/ipa-profile.cc @@ -1065,3 +1065,13 @@ make_pass_ipa_profile (gcc::context *ctxt) { return new pass_ipa_profile (ctxt); } + +/* Reset all state within ipa-profile.cc so that we can rerun the compiler + within the same process. For use by toplev::finalize. */ + +void +ipa_profile_cc_finalize (void) +{ + delete call_sums; + call_sums = NULL; +} diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index 16c4b03655820..36b2a104a54f6 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -6001,5 +6001,23 @@ ipcp_transform_function (struct cgraph_node *node) return modified_mem_access ? TODO_update_ssa_only_virtuals : 0; } +/* Reset all state within ipa-prop.cc so that we can rerun the compiler + within the same process. For use by toplev::finalize. */ + +void +ipa_prop_cc_finalize (void) +{ + if (function_insertion_hook_holder) + symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder); + function_insertion_hook_holder = NULL; + + if (ipa_edge_args_sum) + ggc_delete (ipa_edge_args_sum); + ipa_edge_args_sum = NULL; + + if (ipa_node_params_sum) + ggc_delete (ipa_node_params_sum); + ipa_node_params_sum = NULL; +} #include "gt-ipa-prop.h" diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index ea062e00a65b0..10a30d05b947d 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -1162,6 +1162,8 @@ bool ipcp_get_parm_bits (tree, tree *, widest_int *); bool unadjusted_ptr_and_unit_offset (tree op, tree *ret, poly_int64 *offset_ret); +void ipa_prop_cc_finalize (void); + /* From tree-sra.cc: */ tree build_ref_for_offset (location_t, tree, poly_int64, bool, tree, gimple_stmt_iterator *, bool); diff --git a/gcc/ipa-sra.cc b/gcc/ipa-sra.cc index 4d7c25c8784af..8a4b17c8c7f53 100644 --- a/gcc/ipa-sra.cc +++ b/gcc/ipa-sra.cc @@ -4540,5 +4540,17 @@ make_pass_ipa_sra (gcc::context *ctxt) return new pass_ipa_sra (ctxt); } +/* Reset all state within ipa-sra.cc so that we can rerun the compiler + within the same process. For use by toplev::finalize. */ + +void +ipa_sra_cc_finalize (void) +{ + if (func_sums) + ggc_delete (func_sums); + func_sums = NULL; + delete call_sums; + call_sums = NULL; +} #include "gt-ipa-sra.h" diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index e7322e1bf4c36..8733ff48cdadd 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -55,6 +55,13 @@ bool ipa_make_function_pure (cgraph_node *, bool, bool); /* In ipa-profile.cc */ bool ipa_propagate_frequency (struct cgraph_node *node); +void ipa_profile_cc_finalize (void); + +/* In ipa-icf.cc */ +void ipa_icf_cc_finalize (void); + +/* In ipa-sra.cc */ +void ipa_sra_cc_finalize (void); /* In ipa-devirt.cc */ diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 4469e0f069dd2..7a379494af35d 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -75,6 +75,7 @@ along with GCC; see the file COPYING3. If not see #include "symbol-summary.h" #include "tree-vrp.h" #include "ipa-prop.h" +#include "ipa-utils.h" #include "gcse.h" #include "omp-offload.h" #include "edit-context.h" @@ -1079,11 +1080,14 @@ general_init (const char *argv0, bool init_signals) init_ggc (); init_stringpool (); input_location = UNKNOWN_LOCATION; - line_table = ggc_alloc (); - linemap_init (line_table, BUILTINS_LOCATION); - line_table->reallocator = realloc_for_line_map; - line_table->round_alloc_size = ggc_round_alloc_size; - line_table->default_range_bits = 5; + if (!line_table) + { + line_table = ggc_alloc (); + linemap_init (line_table, BUILTINS_LOCATION); + line_table->reallocator = realloc_for_line_map; + line_table->round_alloc_size = ggc_round_alloc_size; + line_table->default_range_bits = 5; + } init_ttree (); /* Initialize register usage now so switches may override. */ @@ -2327,7 +2331,11 @@ toplev::finalize (void) ipa_fnsummary_cc_finalize (); ipa_modref_cc_finalize (); ipa_edge_modifications_finalize (); + ipa_icf_cc_finalize (); + ipa_prop_cc_finalize (); + ipa_profile_cc_finalize (); + ipa_sra_cc_finalize (); cgraph_cc_finalize (); cgraphunit_cc_finalize (); symtab_thunks_cc_finalize (); From eba45e495e6801967e9ffe4575e9589c5faef74f Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 27 Jul 2023 11:25:51 -0400 Subject: [PATCH 33/45] fixup! WIP: Add support for function attributes Implement weak and alias function attributes --- gcc/jit/jit-playback.cc | 19 +++++++++++++++++++ gcc/jit/libgccjit.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 88e1b21203020..fcc274213de52 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -515,6 +515,8 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) { switch (attr) { + case GCC_JIT_FN_ATTRIBUTE_ALIAS: + return "alias"; case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE: return "always_inline"; case GCC_JIT_FN_ATTRIBUTE_INLINE: @@ -535,6 +537,8 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) return "pure"; case GCC_JIT_FN_ATTRIBUTE_CONST: return "const"; + case GCC_JIT_FN_ATTRIBUTE_WEAK: + return "weak"; } return NULL; } @@ -682,6 +686,9 @@ new_function (location *loc, /* See handle_const_attribute in gcc/c-family/c-attribs.cc. */ else if (attr == GCC_JIT_FN_ATTRIBUTE_CONST) TREE_READONLY (fndecl) = 1; + /* See handle_weak_attribute in gcc/c-family/c-attribs.cc. */ + else if (attr == GCC_JIT_FN_ATTRIBUTE_WEAK) + declare_weak (fndecl); const char* attribute = fn_attribute_to_string (attr); if (attribute) @@ -706,6 +713,15 @@ new_function (location *loc, if (!ident || !targetm.target_option.valid_attribute_p (fndecl, ident, attribute_value, 0)) continue; + /* See handle_alias_ifunc_attribute in gcc/c-family/c-attribs.cc. */ + if (name == GCC_JIT_FN_ATTRIBUTE_ALIAS) + { + tree id = get_identifier (value.c_str ()); + /* This counts as a use of the object pointed to. */ + TREE_USED (id) = 1; + DECL_INITIAL (fndecl) = error_mark_node; + } + if (ident) DECL_ATTRIBUTES (fndecl) = tree_cons (ident, attribute_value, DECL_ATTRIBUTES (fndecl)); @@ -2282,6 +2298,9 @@ postprocess () current_function_decl = NULL; } + else + /* Add to cgraph to output aliases: */ + rest_of_decl_compilation (m_inner_fndecl, true, 0); } /* Don't leak vec's internal buffer (in non-GC heap) when we are diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 60eaf39bff6ea..10a2a21017d5c 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2097,6 +2097,7 @@ gcc_jit_type_set_packed (gcc_jit_type *type); /* Function attributes. */ enum gcc_jit_fn_attribute { + GCC_JIT_FN_ATTRIBUTE_ALIAS, GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE, GCC_JIT_FN_ATTRIBUTE_INLINE, GCC_JIT_FN_ATTRIBUTE_NOINLINE, @@ -2107,6 +2108,7 @@ enum gcc_jit_fn_attribute GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE, GCC_JIT_FN_ATTRIBUTE_PURE, GCC_JIT_FN_ATTRIBUTE_CONST, + GCC_JIT_FN_ATTRIBUTE_WEAK, }; /* Add an attribute to a function. */ From 90db2685bb8b21016013bcd6e71eb47ef88c356a Mon Sep 17 00:00:00 2001 From: Rowan Hope Date: Sat, 29 Jul 2023 15:42:20 +0100 Subject: [PATCH 34/45] Change the type of targetjitm to gcc_targetjitm --- gcc/config/default-jit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/config/default-jit.cc b/gcc/config/default-jit.cc index 6bee98a79ce27..6c76c8e0728d0 100644 --- a/gcc/config/default-jit.cc +++ b/gcc/config/default-jit.cc @@ -25,4 +25,4 @@ along with GCC; see the file COPYING3. If not see /* Do not include tm.h or tm_p.h here; definitions needed by the target architecture to initialize targetjitm should instead be added to tm_jit.h. */ -struct gcc_targetdm targetjitm = TARGETJITM_INITIALIZER; +struct gcc_targetjitm targetjitm = TARGETJITM_INITIALIZER; From 840bab39b6fbf047ed985e0936aca4bf2c511a10 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Aug 2023 22:48:11 +0200 Subject: [PATCH 35/45] [PATCH] Add support for `restrict` attribute on function parameters gcc/jit/Changelog: * jit-playback.cc: Remove trailing whitespace characters. * jit-playback.h: Add get_restrict method. * jit-recording.cc: Add get_restrict methods. * jit-recording.h: Add get_restrict methods. * libgccjit++.h: Add get_restrict methods. * libgccjit.cc: Add gcc_jit_type_get_restrict. * libgccjit.h: Declare gcc_jit_type_get_restrict. * libgccjit.map: Declare gcc_jit_type_get_restrict. gcc/testsuite/ChangeLog: * jit.dg/test-restrict.c: Add test for __restrict__ attribute. Signed-off-by: Guillaume Gomez --- gcc/jit/jit-playback.cc | 2 +- gcc/jit/jit-playback.h | 5 ++ gcc/jit/jit-recording.cc | 47 +++++++++++++++++ gcc/jit/jit-recording.h | 39 +++++++++++++- gcc/jit/libgccjit++.h | 6 +++ gcc/jit/libgccjit.cc | 14 +++++ gcc/jit/libgccjit.h | 4 ++ gcc/jit/libgccjit.map | 5 ++ gcc/testsuite/jit.dg/test-restrict.c | 77 ++++++++++++++++++++++++++++ 9 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-restrict.c diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 88e1b21203020..0eb4e94fdc414 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -3793,7 +3793,7 @@ if (t) \ NAME_TYPE (complex_float_type_node, "complex float"); NAME_TYPE (complex_double_type_node, "complex double"); NAME_TYPE (complex_long_double_type_node, "complex long double"); - + m_const_char_ptr = build_pointer_type( build_qualified_type (char_type_node, TYPE_QUAL_CONST)); diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index d153f4945d8c2..fb4f7b8b65bd5 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -490,6 +490,11 @@ class type : public wrapper return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE)); } + type *get_restrict () const + { + return new type (build_qualified_type (m_inner, TYPE_QUAL_RESTRICT)); + } + type *get_aligned (size_t alignment_in_bytes) const; type *get_vector (size_t num_units) const; diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index f962c9748c4a6..f1ac808452228 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -2380,6 +2380,19 @@ recording::type::get_const () return result; } +/* Given a type T, get the type restrict T. + + Implements the post-error-checking part of + gcc_jit_type_get_restrict. */ + +recording::type * +recording::type::get_restrict () +{ + recording::type *result = new memento_of_get_restrict (this); + m_ctxt->record (result); + return result; +} + /* Given a type T, get the type volatile T. Implements the post-error-checking part of @@ -3090,6 +3103,40 @@ recording::memento_of_get_volatile::write_reproducer (reproducer &r) r.get_identifier_as_type (m_other_type)); } +/* The implementation of class gcc::jit::recording::memento_of_get_restrict. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_get_restrict. */ + +void +recording::memento_of_get_restrict::replay_into (replayer *) +{ + set_playback_obj (m_other_type->playback_type ()->get_restrict ()); +} + +/* Implementation of recording::memento::make_debug_string for + results of get_restrict, prepending "restrict ". */ + +recording::string * +recording::memento_of_get_restrict::make_debug_string () +{ + return string::from_printf (m_ctxt, + "restrict %s", m_other_type->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for restrict + types. */ + +void +recording::memento_of_get_restrict::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "type"); + r.write (" gcc_jit_type *%s =\n" + " gcc_jit_type_get_restrict (%s);\n", + id, + r.get_identifier_as_type (m_other_type)); +} + /* The implementation of class gcc::jit::recording::memento_of_get_aligned. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 929bbe37c3f4c..0f20bbacff287 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -555,6 +555,7 @@ class type : public memento type *get_pointer (); type *get_const (); type *get_volatile (); + type *get_restrict (); type *get_aligned (size_t alignment_in_bytes); type *get_vector (size_t num_units); @@ -603,6 +604,7 @@ class type : public memento virtual bool is_bool () const = 0; virtual type *is_pointer () = 0; virtual type *is_volatile () { return NULL; } + virtual type *is_restrict () { return NULL; } virtual type *is_const () { return NULL; } virtual type *is_array () = 0; virtual struct_ *is_struct () { return NULL; } @@ -737,7 +739,7 @@ class memento_of_get_pointer : public type }; /* A decorated version of a type, for get_const, get_volatile, - get_aligned, and get_vector. */ + get_aligned, get_restrict, and get_vector. */ class decorated_type : public type { @@ -810,7 +812,7 @@ class memento_of_get_volatile : public decorated_type return m_other_type->is_same_type_as (other->is_volatile ()); } - type* copy(context* ctxt) final override + type* copy (context* ctxt) final override { type* result = new memento_of_get_volatile (m_other_type->copy (ctxt)); ctxt->record (result); @@ -829,6 +831,39 @@ class memento_of_get_volatile : public decorated_type void write_reproducer (reproducer &r) final override; }; +/* Result of "gcc_jit_type_get_restrict". */ +class memento_of_get_restrict : public decorated_type +{ +public: + memento_of_get_restrict (type *other_type) + : decorated_type (other_type) {} + + bool is_same_type_as (type *other) final override + { + if (!other->is_restrict ()) + return false; + return m_other_type->is_same_type_as (other->is_restrict ()); + } + + type* copy (context* ctxt) final override + { + type* result = new memento_of_get_restrict (m_other_type->copy (ctxt)); + ctxt->record (result); + return result; + } + + /* Strip off the "restrict", giving the underlying type. */ + type *unqualified () final override { return m_other_type; } + + type *is_restrict () final override { return m_other_type; } + + void replay_into (replayer *) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; +}; + /* Result of "gcc_jit_type_get_aligned". */ class memento_of_get_aligned : public decorated_type { diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 4b88e877bc927..b430f7eb04936 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -1410,6 +1410,12 @@ type::get_const () return type (gcc_jit_type_get_const (get_inner_type ())); } +inline type +type::get_restrict () +{ + return type (gcc_jit_type_get_restrict (get_inner_type ())); +} + inline type type::get_volatile () { diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 050e68b738c6a..9b87e0569d6ed 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -539,6 +539,20 @@ gcc_jit_type_get_volatile (gcc_jit_type *type) return (gcc_jit_type *)type->get_volatile (); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::get_restrict method, in + jit-recording.cc. */ + +gcc_jit_type * +gcc_jit_type_get_restrict (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + + return (gcc_jit_type *)type->get_restrict (); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 60eaf39bff6ea..2e0d08a06d8f2 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -635,6 +635,10 @@ gcc_jit_type_get_const (gcc_jit_type *type); extern gcc_jit_type * gcc_jit_type_get_volatile (gcc_jit_type *type); +/* Given type "T", get type "restrict T". */ +extern gcc_jit_type * +gcc_jit_type_get_restrict (gcc_jit_type *type); + #define LIBGCCJIT_HAVE_SIZED_INTEGERS /* Given types LTYPE and RTYPE, return non-zero if they are compatible. diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index e52de0057a50b..cc62216412b59 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -326,3 +326,8 @@ LIBGCCJIT_ABI_33 { gcc_jit_target_info_arch; gcc_jit_target_info_supports_128bit_int; } LIBGCCJIT_ABI_32; + +LIBGCCJIT_ABI_34 { + global: + gcc_jit_type_get_restrict; +} LIBGCCJIT_ABI_33; diff --git a/gcc/testsuite/jit.dg/test-restrict.c b/gcc/testsuite/jit.dg/test-restrict.c new file mode 100644 index 0000000000000..4c8c4407f9152 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-restrict.c @@ -0,0 +1,77 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include +#include + +#include "libgccjit.h" + +/* We don't want set_options() in harness.h to set -O3 to see that the cold + attribute affects the optimizations. */ +#define TEST_ESCHEWS_SET_OPTIONS +static void set_options (gcc_jit_context *ctxt, const char *argv0) +{ + // Set "-O3". + gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3); +} + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-restrict.c.s" +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: +void t(int *__restrict__ a, int *__restrict__ b, char *__restrict__ c) { + *a += *c; + *b += *c; +} + */ + 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 *pint_restrict_type = gcc_jit_type_get_restrict(pint_type); + + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + gcc_jit_param *a = + gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "a"); + gcc_jit_param *b = + gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "b"); + gcc_jit_param *c = + gcc_jit_context_new_param (ctxt, NULL, pint_restrict_type, "c"); + gcc_jit_param *params[3] = {a, b, c}; + + gcc_jit_function *func_t = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "t", + 3, params, + 0); + + gcc_jit_block *block = gcc_jit_function_new_block (func_t, NULL); + + /* *a += *c; */ + gcc_jit_block_add_assignment_op ( + block, NULL, + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (a), NULL), + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (c), NULL))); + /* *b += *c; */ + gcc_jit_block_add_assignment_op ( + block, NULL, + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (b), NULL), + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (c), NULL))); + + gcc_jit_block_end_with_void_return (block, NULL); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* { dg-final { jit-verify-assembler-output "addl %eax, (%rdi) + addl %eax, (%rsi)" } } */ From 64199db8f0e44e6fd9624de0a9cfd74dad69ec1c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 18 Aug 2023 17:48:54 -0400 Subject: [PATCH 36/45] Upload LTO artifacts --- .github/workflows/main.yml | 11 +++++++++-- gcc/sort.cc | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5fab7cf772c06..4cc9b57bba171 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,10 +23,17 @@ jobs: ls mkdir build install cd build - ../gcc/configure --enable-host-shared --enable-languages=jit,c++ --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install + ../gcc/configure --enable-host-shared --enable-languages=jit,c++,lto --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install make -j4 + ls -R + echo "*************************" + tree - uses: actions/upload-artifact@v2 with: name: libgccjit.so - path: /home/runner/work/gcc/build/gcc/libgccjit.so + path: | + /home/runner/work/gcc/build/gcc/libgccjit.so + /home/runner/work/gcc/build/gcc/lto1 + /home/runner/work/gcc/build/gcc/liblto_plugin.so + /home/runner/work/gcc/build/gcc/lto-wrapper diff --git a/gcc/sort.cc b/gcc/sort.cc index 9a0113fb62fbe..c7fbd5c51ec09 100644 --- a/gcc/sort.cc +++ b/gcc/sort.cc @@ -293,7 +293,8 @@ gcc_sort_r (void *vbase, size_t n, size_t size, sort_r_cmp_fn *cmp, void *data) if (buf != scratch) free (buf); #if CHECKING_P - qsort_chk (vbase, n, size, cmp, data); + // FIXME: LTO in rustc_codegen_gcc should work even with this check enabled. + //qsort_chk (vbase, n, size, cmp, data); #endif } From a6b3e98e788e3826632d57cc41406ea7998749ea Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 18 Aug 2023 21:28:56 -0400 Subject: [PATCH 37/45] Add crt artifacts --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4cc9b57bba171..eab8b0810d574 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,3 +37,5 @@ jobs: /home/runner/work/gcc/build/gcc/lto1 /home/runner/work/gcc/build/gcc/liblto_plugin.so /home/runner/work/gcc/build/gcc/lto-wrapper + /home/runner/work/gcc/build/gcc/crtbeginS.o + /home/runner/work/gcc/build/gcc/crtendS.o From 16686cbc03eb62f18939c8b78b8761e862c32ff7 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 21 Aug 2023 19:52:33 -0400 Subject: [PATCH 38/45] Add gcc binary artifact --- .github/workflows/main.yml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index eab8b0810d574..4fd729fc08bf1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,11 +23,29 @@ jobs: ls mkdir build install cd build - ../gcc/configure --enable-host-shared --enable-languages=jit,c++,lto --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install + ../gcc/configure --enable-host-shared --enable-languages=c,jit,c++,lto --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install/usr --libdir=$(pwd)/../install/usr/lib --libexecdir=$(pwd)/../install/usr/lib make -j4 - ls -R - echo "*************************" - tree + make install + + - name: Build Debian package + run: | + cd .. + mkdir install/DEBIAN + cat > install/DEBIAN/control << EOF + Package: gcc-13 + Version: 13 + Architecture: amd64 + Maintainer: Antoni Boucher + Description: gcc 13 for rustc_codegen_gcc CI + EOF + dpkg-deb --root-owner-group --build install + mv install.deb gcc-13.deb + + - uses: actions/upload-artifact@v3 + with: + name: gcc-13 + path: /home/runner/work/gcc/gcc-13.deb + if-no-files-found: error - uses: actions/upload-artifact@v2 with: From 94f1362d9d4a7504b4b067e54c5e5c6da960811a Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 24 Aug 2023 17:59:05 -0400 Subject: [PATCH 39/45] Do not build c++ frontend --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4fd729fc08bf1..554d0a790e158 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,7 +23,7 @@ jobs: ls mkdir build install cd build - ../gcc/configure --enable-host-shared --enable-languages=c,jit,c++,lto --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install/usr --libdir=$(pwd)/../install/usr/lib --libexecdir=$(pwd)/../install/usr/lib + ../gcc/configure --enable-host-shared --enable-languages=c,jit,lto --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install/usr --libdir=$(pwd)/../install/usr/lib --libexecdir=$(pwd)/../install/usr/lib make -j4 make install From c4d7ad5c51268734293a2d64696781ba9bdbf112 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 29 Aug 2023 17:30:44 +0200 Subject: [PATCH 40/45] fixup! [PATCH] Add support for `restrict` attribute on function parameters add missing `is_pointer` check in `gcc_jit_type_get_restrict` --- gcc/jit/libgccjit.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 9b87e0569d6ed..2088fe824a66b 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -549,6 +549,7 @@ gcc_jit_type * gcc_jit_type_get_restrict (gcc_jit_type *type) { RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + RETURN_NULL_IF_FAIL (type->is_pointer (), NULL, NULL, "not a pointer type"); return (gcc_jit_type *)type->get_restrict (); } From 2c415c4b77539a70858f9eaca75d7f3f9121b3a5 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 9 Sep 2023 13:12:57 -0400 Subject: [PATCH 41/45] Add debug prints to debug issue --- gcc/config/i386/i386-jit.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gcc/config/i386/i386-jit.cc b/gcc/config/i386/i386-jit.cc index 3014baefc30b6..33c80c2de05c9 100644 --- a/gcc/config/i386/i386-jit.cc +++ b/gcc/config/i386/i386-jit.cc @@ -59,15 +59,20 @@ ix86_jit_register_target_info (void) const char *params[] = {"arch", x86_bits}; const char *arch = host_detect_local_cpu (2, params); + fprintf (stderr, "***************************** Arch: %s\n**********************************", arch); + const char* arg = "-march="; const char* arg_pos = strstr(arch, arg); + fprintf (stderr, "***************************** arg_pos: %s\n**********************************", arg_pos); const char* arg_value = arg_pos + strlen(arg); + fprintf (stderr, "***************************** arg_value: %s\n**********************************", arg_value); const char* arg_value_end = strchr(arg_value, ' '); size_t len = arg_value_end - arg_value; char *cpu = new char[len]; strncpy(cpu, arg_value, len); cpu[len] = '\0'; + fprintf (stderr, "***************************** cpu: %s\n**********************************", cpu); jit_target_set_arch (cpu); jit_target_set_128bit_int_support (targetm.scalar_mode_supported_p (TImode)); From 327499ccaf0b92315e470f89674b2f995abe80de Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 13 Sep 2023 17:16:57 -0400 Subject: [PATCH 42/45] Fix CPU feature detection --- gcc/config/i386/i386-jit.cc | 23 +++++++---------------- gcc/jit/jit-target.cc | 9 ++------- gcc/jit/jit-target.h | 7 +++---- gcc/jit/libgccjit.cc | 2 +- 4 files changed, 13 insertions(+), 28 deletions(-) diff --git a/gcc/config/i386/i386-jit.cc b/gcc/config/i386/i386-jit.cc index 33c80c2de05c9..49e54aa799075 100644 --- a/gcc/config/i386/i386-jit.cc +++ b/gcc/config/i386/i386-jit.cc @@ -57,28 +57,19 @@ void ix86_jit_register_target_info (void) { const char *params[] = {"arch", x86_bits}; - const char *arch = host_detect_local_cpu (2, params); - - fprintf (stderr, "***************************** Arch: %s\n**********************************", arch); + const char* local_cpu = host_detect_local_cpu (2, params); + std::string arch = local_cpu; + free (const_cast (local_cpu)); const char* arg = "-march="; - const char* arg_pos = strstr(arch, arg); - fprintf (stderr, "***************************** arg_pos: %s\n**********************************", arg_pos); - const char* arg_value = arg_pos + strlen(arg); - fprintf (stderr, "***************************** arg_value: %s\n**********************************", arg_value); - const char* arg_value_end = strchr(arg_value, ' '); - - size_t len = arg_value_end - arg_value; - char *cpu = new char[len]; - strncpy(cpu, arg_value, len); - cpu[len] = '\0'; - fprintf (stderr, "***************************** cpu: %s\n**********************************", cpu); + size_t arg_pos = arch.find (arg) + strlen (arg); + size_t end_pos = arch.find (" ", arg_pos); + + std::string cpu = arch.substr (arg_pos, end_pos - arg_pos); jit_target_set_arch (cpu); jit_target_set_128bit_int_support (targetm.scalar_mode_supported_p (TImode)); - free (const_cast (arch)); - if (TARGET_MMX) jit_add_target_info ("target_feature", "mmx"); if (TARGET_SSE) diff --git a/gcc/jit/jit-target.cc b/gcc/jit/jit-target.cc index ad41376fa7fc8..671ed24b20f94 100644 --- a/gcc/jit/jit-target.cc +++ b/gcc/jit/jit-target.cc @@ -59,7 +59,7 @@ jit_add_target_info (const char *key, const char *value) } void -jit_target_set_arch (const char* arch) +jit_target_set_arch (std::string const& arch) { jit_target_info.m_arch = arch; } @@ -70,15 +70,10 @@ jit_target_set_128bit_int_support (bool support) jit_target_info.m_supports_128bit_int = support; } -target_info::~target_info() -{ - free (const_cast ((const void *) m_arch)); -} - target_info * jit_get_target_info () { - target_info *info = new target_info {std::move(jit_target_info)}; + target_info *info = new target_info {jit_target_info}; jit_target_info = target_info{}; return info; } diff --git a/gcc/jit/jit-target.h b/gcc/jit/jit-target.h index 09fd7941c2ef1..b313faf9cbd52 100644 --- a/gcc/jit/jit-target.h +++ b/gcc/jit/jit-target.h @@ -25,6 +25,7 @@ #include "jit-target.def" +#include #include #include @@ -49,12 +50,10 @@ struct CStringEqual { struct target_info { public: - ~target_info(); - bool has_target_value (const char *key, const char *value); std::unordered_map, CStringHash, CStringEqual> m_info; - const char *m_arch = nullptr; + std::string m_arch; bool m_supports_128bit_int = false; }; @@ -62,7 +61,7 @@ struct target_info { extern struct gcc_targetjitm targetjitm; extern void jit_target_init (); -extern void jit_target_set_arch (const char* arch); +extern void jit_target_set_arch (std::string const& arch); extern void jit_target_set_128bit_int_support (bool support); extern void jit_add_target_info (const char *key, const char *value); extern target_info * jit_get_target_info (); diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 2088fe824a66b..00f4dce1d33f9 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -3899,7 +3899,7 @@ gcc_jit_target_info_cpu_supports (gcc_jit_target_info *info, const char * gcc_jit_target_info_arch (gcc_jit_target_info *info) { - return info->m_arch; + return info->m_arch.c_str (); } int From 64dee482f007d1fbdf04aac9970b8420a33dbcc3 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 19 Sep 2023 22:10:47 -0400 Subject: [PATCH 43/45] Implement sizeof --- gcc/jit/jit-playback.cc | 10 ++++++++ gcc/jit/jit-playback.h | 3 +++ gcc/jit/jit-recording.cc | 52 ++++++++++++++++++++++++++++++++++++++++ gcc/jit/jit-recording.h | 28 ++++++++++++++++++++++ gcc/jit/libgccjit.cc | 17 +++++++++++++ gcc/jit/libgccjit.h | 4 ++++ gcc/jit/libgccjit.map | 5 ++++ 7 files changed, 119 insertions(+) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index ee8b985b13037..aff8b518c5a01 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -1131,6 +1131,16 @@ new_rvalue_from_const (type *type, /* Construct a playback::rvalue instance (wrapping a tree). */ +playback::rvalue * +playback::context:: +new_sizeof (type *type) +{ + tree inner = TYPE_SIZE_UNIT (type->as_tree ()); + return new rvalue (this, inner); +} + +/* Construct a playback::rvalue instance (wrapping a tree). */ + playback::rvalue * playback::context:: new_string_literal (const char *value) diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index fb4f7b8b65bd5..dc56675c53f39 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -153,6 +153,9 @@ class context : public log_user new_rvalue_from_const (type *type, HOST_TYPE value); + rvalue * + new_sizeof (type *type); + rvalue * new_string_literal (const char *value); diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index f1ac808452228..b6b7540bb3ce7 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -1125,6 +1125,21 @@ recording::context::new_global_init_rvalue (lvalue *variable, gbl->set_rvalue_init (init); /* Needed by the global for write dump. */ } +/* Create a recording::memento_of_sizeof instance and add it + to this context's list of mementos. + + Implements the post-error-checking part of + gcc_jit_context_new_sizeof. */ + +recording::rvalue * +recording::context::new_sizeof (recording::type *type) +{ + recording::rvalue *result = + new memento_of_new_sizeof (this, NULL, type); + record (result); + return result; +} + /* Create a recording::memento_of_new_string_literal instance and add it to this context's list of mementos. @@ -5535,6 +5550,43 @@ memento_of_new_rvalue_from_const ::write_reproducer (reproducer &r) } // namespace recording +/* The implementation of class gcc::jit::recording::memento_of_new_sizeof. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_new_sizeof. */ + +void +recording::memento_of_new_sizeof::replay_into (replayer *r) +{ + set_playback_obj (r->new_sizeof (m_type->playback_type ())); +} + +/* Implementation of recording::memento::make_debug_string for + sizeof expressions. */ + +recording::string * +recording::memento_of_new_sizeof::make_debug_string () +{ + return string::from_printf (m_ctxt, + "sizeof (%s)", + m_type->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for sizeof + expressions. */ + +void +recording::memento_of_new_sizeof::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "rvalue"); + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_sizeof (%s, /* gcc_jit_context *ctxt */\n" + " %s); /* gcc_jit_type *type */\n", + id, + r.get_identifier (get_context ()), + m_type->get_debug_string ()); +} + /* The implementation of class gcc::jit::recording::memento_of_new_string_literal. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 0f20bbacff287..986057263463b 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -177,6 +177,9 @@ class context : public log_user new_rvalue_from_const (type *type, HOST_TYPE value); + rvalue * + new_sizeof (type *type); + rvalue * new_string_literal (const char *value); @@ -1723,6 +1726,31 @@ class memento_of_new_rvalue_from_const : public rvalue HOST_TYPE m_value; }; +class memento_of_new_sizeof : public rvalue +{ +public: + memento_of_new_sizeof (context *ctxt, + location *loc, + type *type) + : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_INT)), + m_type (type) {} + + void replay_into (replayer *r) final override; + + void visit_children (rvalue_visitor *) final override {} + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + enum precedence get_precedence () const final override + { + return PRECEDENCE_PRIMARY; + } + +private: + type *m_type; +}; + class memento_of_new_string_literal : public rvalue { public: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 00f4dce1d33f9..d23733a6d9fbc 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -2128,6 +2128,23 @@ gcc_jit_context_null (gcc_jit_context *ctxt, return gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::new_sizeof method in + jit-recording.cc. */ + +gcc_jit_rvalue * +gcc_jit_context_new_sizeof (gcc_jit_context *ctxt, + gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + + return ((gcc_jit_rvalue *)ctxt + ->new_sizeof (type)); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index f77d7ffcc7a0d..7612d523ad22b 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1102,6 +1102,10 @@ extern gcc_jit_rvalue * gcc_jit_context_null (gcc_jit_context *ctxt, gcc_jit_type *pointer_type); +extern gcc_jit_rvalue * +gcc_jit_context_new_sizeof (gcc_jit_context *ctxt, + gcc_jit_type *type); + /* String literals. */ extern gcc_jit_rvalue * gcc_jit_context_new_string_literal (gcc_jit_context *ctxt, diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index cc62216412b59..df81163aa07ba 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -331,3 +331,8 @@ LIBGCCJIT_ABI_34 { global: gcc_jit_type_get_restrict; } LIBGCCJIT_ABI_33; + +LIBGCCJIT_ABI_35 { + global: + gcc_jit_context_new_sizeof; +} LIBGCCJIT_ABI_34; From 6f655757739c438e8302714e37a3f16de824dc89 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Sep 2023 16:36:06 +0200 Subject: [PATCH 44/45] Add `add_integer_array_attribute` function and add support for NonNull attribute --- gcc/jit/dummy-frontend.cc | 481 ++++++++++++++++++++++++++-- gcc/jit/jit-playback.cc | 78 +++-- gcc/jit/jit-playback.h | 3 + gcc/jit/jit-recording.cc | 42 +++ gcc/jit/jit-recording.h | 2 + gcc/jit/libgccjit.cc | 13 + gcc/jit/libgccjit.h | 5 +- gcc/jit/libgccjit.map | 1 + gcc/testsuite/jit.dg/test-nonnull.c | 94 ++++++ 9 files changed, 650 insertions(+), 69 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-nonnull.c diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index 7ef09d7128858..d3d1b2a120f2f 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "jit-recording.h" #include "print-tree.h" +#include "cgraph.h" #include #include @@ -41,25 +42,35 @@ using namespace gcc::jit; /* Attribute handling. */ -static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); -static tree handle_leaf_attribute (tree *, tree, tree, int, bool *); +static tree handle_alias_attribute (tree *, tree, tree, int, bool *); +static tree handle_always_inline_attribute (tree *, tree, tree, int, + bool *); +static tree handle_cold_attribute (tree *, tree, tree, int, bool *); static tree handle_const_attribute (tree *, tree, tree, int, bool *); +static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); +static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); +static tree handle_format_attribute (tree *, tree, tree, int, bool *); +static tree handle_leaf_attribute (tree *, tree, tree, int, bool *); static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); -static tree handle_pure_attribute (tree *, tree, tree, int, bool *); -static tree handle_novops_attribute (tree *, tree, tree, int, bool *); +static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); +static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); -static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); -static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); -static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); -static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); +static tree handle_novops_attribute (tree *, tree, tree, int, bool *); static tree handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *); -static tree ignore_attribute (tree *, tree, tree, int, bool *); +static tree handle_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); +static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); +static tree handle_target_attribute (tree *, tree, tree, int, bool *); +static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); +static tree handle_used_attribute (tree *, tree, tree, int, bool *); +static tree handle_visibility_attribute (tree *, tree, tree, int, + bool *); +static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ; -static tree handle_format_attribute (tree *, tree, tree, int, bool *); -static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); -static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); +static tree ignore_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -88,11 +99,34 @@ static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] = static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = { ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("alloc_align", true, true, true), + ATTR_EXCL ("alloc_size", true, true, true), + ATTR_EXCL ("malloc", true, true, true), ATTR_EXCL ("noreturn", true, true, true), ATTR_EXCL ("pure", true, true, true), ATTR_EXCL (NULL, false, false, false) }; +static const struct attribute_spec::exclusions attr_inline_exclusions[] = +{ + ATTR_EXCL ("noinline", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] = +{ + ATTR_EXCL ("cold", true, true, true), + ATTR_EXCL ("hot", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + +static const struct attribute_spec::exclusions attr_noinline_exclusions[] = +{ + ATTR_EXCL ("always_inline", true, true, true), + ATTR_EXCL ("gnu_inline", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + hash_map target_builtins{}; std::unordered_map target_function_types{}; recording::context target_builtins_ctxt{NULL}; @@ -102,22 +136,33 @@ const struct attribute_spec jit_attribute_table[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ - { "noreturn", 0, 0, true, false, false, false, - handle_noreturn_attribute, - attr_noreturn_exclusions }, - { "leaf", 0, 0, true, false, false, false, - handle_leaf_attribute, NULL }, + { "alias", 1, 1, true, false, false, false, + handle_alias_attribute, NULL }, + { "always_inline", 0, 0, true, false, false, false, + handle_always_inline_attribute, + attr_inline_exclusions }, + { "cold", 0, 0, true, false, false, false, + handle_cold_attribute, + attr_cold_hot_exclusions }, /* The same comments as for noreturn attributes apply to const ones. */ { "const", 0, 0, true, false, false, false, handle_const_attribute, attr_const_pure_exclusions }, + { "fn spec", 1, 1, false, true, true, false, + handle_fnspec_attribute, NULL }, + + { "leaf", 0, 0, true, false, false, false, + handle_leaf_attribute, NULL }, { "malloc", 0, 0, true, false, false, false, handle_malloc_attribute, NULL }, - { "pure", 0, 0, true, false, false, false, - handle_pure_attribute, - attr_const_pure_exclusions }, + { "noreturn", 0, 0, true, false, false, false, + handle_noreturn_attribute, + attr_noreturn_exclusions }, { "no vops", 0, 0, true, false, false, false, handle_novops_attribute, NULL }, + { "noinline", 0, 0, true, false, false, false, + handle_noinline_attribute, + attr_noinline_exclusions }, { "nonnull", 0, -1, false, true, true, false, handle_nonnull_attribute, NULL }, { "nothrow", 0, 0, true, false, false, false, @@ -125,21 +170,30 @@ const struct attribute_spec jit_attribute_table[] = { "patchable_function_entry", 1, 2, true, false, false, false, handle_patchable_function_entry_attribute, NULL }, + { "pure", 0, 0, true, false, false, false, + handle_pure_attribute, + attr_const_pure_exclusions }, { "returns_twice", 0, 0, true, false, false, false, handle_returns_twice_attribute, attr_returns_twice_exclusions }, { "sentinel", 0, 1, false, true, true, false, handle_sentinel_attribute, NULL }, + { "target", 1, -1, true, false, false, false, + handle_target_attribute, NULL }, { "type generic", 0, 0, false, true, true, false, handle_type_generic_attribute, NULL }, - { "fn spec", 1, 1, false, true, true, false, - handle_fnspec_attribute, NULL }, { "transaction_pure", 0, 0, false, true, true, false, handle_transaction_pure_attribute, NULL }, /* For internal use only. The leading '*' both prevents its usage in source code and signals that it may be overridden by machine tables. */ { "*tm regparm", 0, 0, false, true, true, false, ignore_attribute, NULL }, + { "used", 0, 0, true, false, false, false, + handle_used_attribute, NULL }, + { "visibility", 1, 1, false, false, false, false, + handle_visibility_attribute, NULL }, + { "weak", 0, 0, true, false, false, false, + handle_weak_attribute, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -227,10 +281,6 @@ handle_const_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { - if (TREE_CODE (*node) != FUNCTION_DECL - || !fndecl_built_in_p (*node)) - inform (UNKNOWN_LOCATION, "%s:%s: %E: %E", __FILE__, __func__, *node, name); - tree type = TREE_TYPE (*node); /* See FIXME comment on noreturn in c_common_attribute_table. */ @@ -505,6 +555,385 @@ handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), return NULL_TREE; } +/* Handle an "visibility" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_visibility_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), + bool *ARG_UNUSED (no_add_attrs)) +{ + tree decl = *node; + tree id = TREE_VALUE (args); + enum symbol_visibility vis; + + if (TYPE_P (*node)) + { + if (TREE_CODE (*node) == ENUMERAL_TYPE) + /* OK */; + else if (!RECORD_OR_UNION_TYPE_P (*node)) + { + warning (OPT_Wattributes, "%qE attribute ignored on non-class types", + name); + return NULL_TREE; + } + else if (TYPE_FIELDS (*node)) + { + error ("%qE attribute ignored because %qT is already defined", + name, *node); + return NULL_TREE; + } + } + else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl)) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + return NULL_TREE; + } + + if (TREE_CODE (id) != STRING_CST) + { + error ("visibility argument not a string"); + return NULL_TREE; + } + + /* If this is a type, set the visibility on the type decl. */ + if (TYPE_P (decl)) + { + decl = TYPE_NAME (decl); + if (!decl) + return NULL_TREE; + if (TREE_CODE (decl) == IDENTIFIER_NODE) + { + warning (OPT_Wattributes, "%qE attribute ignored on types", + name); + return NULL_TREE; + } + } + + if (strcmp (TREE_STRING_POINTER (id), "default") == 0) + vis = VISIBILITY_DEFAULT; + else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0) + vis = VISIBILITY_INTERNAL; + else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0) + vis = VISIBILITY_HIDDEN; + else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0) + vis = VISIBILITY_PROTECTED; + else + { + error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs", + name, "default", "hidden", "protected", "internal"); + vis = VISIBILITY_DEFAULT; + } + + if (DECL_VISIBILITY_SPECIFIED (decl) + && vis != DECL_VISIBILITY (decl)) + { + tree attributes = (TYPE_P (*node) + ? TYPE_ATTRIBUTES (*node) + : DECL_ATTRIBUTES (decl)); + if (lookup_attribute ("visibility", attributes)) + error ("%qD redeclared with different visibility", decl); + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && lookup_attribute ("dllimport", attributes)) + error ("%qD was declared %qs which implies default visibility", + decl, "dllimport"); + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && lookup_attribute ("dllexport", attributes)) + error ("%qD was declared %qs which implies default visibility", + decl, "dllexport"); + } + + DECL_VISIBILITY (decl) = vis; + DECL_VISIBILITY_SPECIFIED (decl) = 1; + + /* Go ahead and attach the attribute to the node as well. This is needed + so we can determine whether we have VISIBILITY_DEFAULT because the + visibility was not specified, or because it was explicitly overridden + from the containing scope. */ + + return NULL_TREE; +} + +/* Handle a "always_inline" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_always_inline_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + if (lookup_attribute ("noinline", DECL_ATTRIBUTES (*node))) + { + warning (OPT_Wattributes, "%qE attribute ignored due to conflict " + "with %qs attribute", name, "noinline"); + *no_add_attrs = true; + } + else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node))) + { + warning (OPT_Wattributes, "%qE attribute ignored due to conflict " + "with %qs attribute", name, "target_clones"); + *no_add_attrs = true; + } + else + /* Set the attribute and mark it for disregarding inline + limits. */ + DECL_DISREGARD_INLINE_LIMITS (*node) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "cold" and attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + || TREE_CODE (*node) == LABEL_DECL) + { + /* Attribute cold processing is done later with lookup_attribute. */ + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "noinline" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_noinline_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node))) + { + warning (OPT_Wattributes, "%qE attribute ignored due to conflict " + "with attribute %qs", name, "always_inline"); + *no_add_attrs = true; + } + else + DECL_UNINLINABLE (*node) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "weak" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_weak_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (*node)) + { + warning (OPT_Wattributes, "inline function %q+D declared weak", *node); + *no_add_attrs = true; + } + else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node))) + { + error ("indirect function %q+D cannot be declared weak", *node); + *no_add_attrs = true; + return NULL_TREE; + } + else if (VAR_OR_FUNCTION_DECL_P (*node)) + declare_weak (*node); + else + warning (OPT_Wattributes, "%qE attribute ignored", name); + + return NULL_TREE; +} + +/* Handle a "target" attribute. */ + +static tree +handle_target_attribute (tree *node, tree name, tree args, int flags, + bool *no_add_attrs) +{ + /* Ensure we have a function type. */ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (*node))) + { + warning (OPT_Wattributes, "%qE attribute ignored due to conflict " + "with %qs attribute", name, "target_clones"); + *no_add_attrs = true; + } + else if (! targetm.target_option.valid_attribute_p (*node, name, args, + flags)) + *no_add_attrs = true; + + /* Check that there's no empty string in values of the attribute. */ + for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t)) + { + tree value = TREE_VALUE (t); + if (TREE_CODE (value) == STRING_CST + && TREE_STRING_LENGTH (value) == 1 + && TREE_STRING_POINTER (value)[0] == '\0') + { + warning (OPT_Wattributes, "empty string in attribute %"); + *no_add_attrs = true; + } + } + + return NULL_TREE; +} + +/* Handle a "used" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree node = *pnode; + + if (TREE_CODE (node) == FUNCTION_DECL + || (VAR_P (node) && TREE_STATIC (node)) + || (TREE_CODE (node) == TYPE_DECL)) + { + TREE_USED (node) = 1; + DECL_PRESERVE_P (node) = 1; + if (VAR_P (node)) + DECL_READ_P (node) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle an "alias" or "ifunc" attribute; arguments as in + struct attribute_spec.handler, except that IS_ALIAS tells us + whether this is an alias as opposed to ifunc attribute. */ + +static tree +handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args, + bool *no_add_attrs) +{ + tree decl = *node; + + if (TREE_CODE (decl) != FUNCTION_DECL + && (!is_alias || !VAR_P (decl))) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) + || (TREE_CODE (decl) != FUNCTION_DECL + && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) + /* A static variable declaration is always a tentative definition, + but the alias is a non-tentative definition which overrides. */ + || (TREE_CODE (decl) != FUNCTION_DECL + && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl))) + { + error ("%q+D defined both normally and as %qE attribute", decl, name); + *no_add_attrs = true; + return NULL_TREE; + } + else if (!is_alias + && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl)) + || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))) + { + error ("weak %q+D cannot be defined %qE", decl, name); + *no_add_attrs = true; + return NULL_TREE; + } + + /* Note that the very first time we process a nested declaration, + decl_function_context will not be set. Indeed, *would* never + be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that + we do below. After such frobbery, pushdecl would set the context. + In any case, this is never what we want. */ + else if (decl_function_context (decl) == 0 && current_function_decl == NULL) + { + tree id; + + id = TREE_VALUE (args); + if (TREE_CODE (id) != STRING_CST) + { + error ("attribute %qE argument not a string", name); + *no_add_attrs = true; + return NULL_TREE; + } + id = get_identifier (TREE_STRING_POINTER (id)); + /* This counts as a use of the object pointed to. */ + TREE_USED (id) = 1; + + if (TREE_CODE (decl) == FUNCTION_DECL) + DECL_INITIAL (decl) = error_mark_node; + else + TREE_STATIC (decl) = 1; + + if (!is_alias) + { + /* ifuncs are also aliases, so set that attribute too. */ + DECL_ATTRIBUTES (decl) + = tree_cons (get_identifier ("alias"), args, + DECL_ATTRIBUTES (decl)); + DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"), + NULL, DECL_ATTRIBUTES (decl)); + } + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + if (decl_in_symtab_p (*node)) + { + struct symtab_node *n = symtab_node::get (decl); + if (n && n->refuse_visibility_changes) + error ("%+qD declared %qs after being used", + decl, is_alias ? "alias" : "ifunc"); + } + + + return NULL_TREE; +} + +/* Handle an "alias" or "ifunc" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_alias_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs); +} + /* (end of attribute-handling). */ /* Language-dependent contents of a type. */ diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index aff8b518c5a01..d8712ed14be61 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -539,6 +539,8 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr) return "const"; case GCC_JIT_FN_ATTRIBUTE_WEAK: return "weak"; + case GCC_JIT_FN_ATTRIBUTE_NONNULL: + return "nonnull"; } return NULL; } @@ -566,6 +568,7 @@ new_function (location *loc, enum built_in_function builtin_id, const std::vector &attributes, const std::vector> &string_attributes, + const std::vector>> &int_array_attributes, int is_target_builtin) { int i; @@ -601,6 +604,8 @@ new_function (location *loc, DECL_RESULT (fndecl) = resdecl; DECL_CONTEXT (resdecl) = fndecl; + tree fn_attributes = NULL_TREE; + if (is_target_builtin) { tree *decl = target_builtins.get(name); @@ -654,48 +659,24 @@ new_function (location *loc, DECL_DECLARED_INLINE_P (fndecl) = 1; /* Add attribute "always_inline": */ - DECL_ATTRIBUTES (fndecl) = + fn_attributes = tree_cons (get_identifier ("always_inline"), NULL, - DECL_ATTRIBUTES (fndecl)); + fn_attributes); } + /* All attributes need to be declared in `dummy-frontend.cc` and more + specifically in `jit_attribute_table`. */ for (auto attr: attributes) { - if (attr == GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE) - { + if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE) DECL_DECLARED_INLINE_P (fndecl) = 1; - DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1; - } - else if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE) - DECL_DECLARED_INLINE_P (fndecl) = 1; - else if (attr == GCC_JIT_FN_ATTRIBUTE_NOINLINE) - DECL_UNINLINABLE (fndecl) = 1; - /* See handle_used_attribute in gcc/c-family/c-attribs.cc. */ - else if (attr == GCC_JIT_FN_ATTRIBUTE_USED) - { - TREE_USED (fndecl) = 1; - DECL_PRESERVE_P (fndecl) = 1; - } - /* See handle_returns_twice_attribute in gcc/c-family/c-attribs.cc. */ - else if (attr == GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE) - DECL_IS_RETURNS_TWICE (fndecl) = 1; - /* See handle_pure_attribute in gcc/c-family/c-attribs.cc. */ - else if (attr == GCC_JIT_FN_ATTRIBUTE_PURE) - DECL_PURE_P (fndecl) = 1; - /* See handle_const_attribute in gcc/c-family/c-attribs.cc. */ - else if (attr == GCC_JIT_FN_ATTRIBUTE_CONST) - TREE_READONLY (fndecl) = 1; - /* See handle_weak_attribute in gcc/c-family/c-attribs.cc. */ - else if (attr == GCC_JIT_FN_ATTRIBUTE_WEAK) - declare_weak (fndecl); const char* attribute = fn_attribute_to_string (attr); if (attribute) { tree ident = get_identifier (attribute); - DECL_ATTRIBUTES (fndecl) = - tree_cons (ident, NULL_TREE, DECL_ATTRIBUTES (fndecl)); + fn_attributes = tree_cons (ident, NULL_TREE, fn_attributes); } } @@ -713,20 +694,33 @@ new_function (location *loc, if (!ident || !targetm.target_option.valid_attribute_p (fndecl, ident, attribute_value, 0)) continue; - /* See handle_alias_ifunc_attribute in gcc/c-family/c-attribs.cc. */ - if (name == GCC_JIT_FN_ATTRIBUTE_ALIAS) + if (ident) + fn_attributes = tree_cons (ident, attribute_value, fn_attributes); + } + + for (auto attr: int_array_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + std::vector& values = std::get<1>(attr); + + const char* attribute = fn_attribute_to_string (name); + tree ident = attribute ? get_identifier (attribute) : NULL; + + if (!ident) + continue; + + tree tree_list = NULL_TREE; + tree *p_tree_list = &tree_list; + for (auto value : values) { - tree id = get_identifier (value.c_str ()); - /* This counts as a use of the object pointed to. */ - TREE_USED (id) = 1; - DECL_INITIAL (fndecl) = error_mark_node; + tree int_value = build_int_cst (integer_type_node, value); + *p_tree_list = build_tree_list (NULL, int_value); + p_tree_list = &TREE_CHAIN (*p_tree_list); } - - if (ident) - DECL_ATTRIBUTES (fndecl) = - tree_cons (ident, attribute_value, DECL_ATTRIBUTES (fndecl)); + fn_attributes = tree_cons (ident, tree_list, fn_attributes); } + decl_attributes (&fndecl, fn_attributes, 0); function *func = new function (this, fndecl, kind); m_functions.safe_push (func); return func; @@ -2396,7 +2390,7 @@ add_try_catch (location *loc, { catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body); tree try_catch = build2 (TRY_CATCH_EXPR, void_type_node, - try_body, catch_body); + try_body, catch_body); add_stmt (try_catch); } } @@ -3794,7 +3788,7 @@ void playback::context:: init_types () { - /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc + /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc for reference. If TYPE_NAME is not set, debug info will not contain types */ #define NAME_TYPE(t,n) \ if (t) \ diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index dc56675c53f39..3ea17e6607126 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -37,6 +37,8 @@ namespace gcc { namespace jit { +const char* fn_attribute_to_string(gcc_jit_fn_attribute attr); + /********************************************************************** Playback. **********************************************************************/ @@ -114,6 +116,7 @@ class context : public log_user enum built_in_function builtin_id, const std::vector &attributes, const std::vector> &string_attributes, + const std::vector>> &int_array_attributes, int is_target_builtin); lvalue * diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index b6b7540bb3ce7..501ece9d137e0 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -4260,6 +4260,7 @@ recording::function::function (context *ctxt, m_fn_ptr_type (NULL), m_attributes(), m_string_attributes(), + m_int_array_attributes(), m_is_target_builtin (is_target_builtin) { for (int i = 0; i< num_params; i++) @@ -4322,6 +4323,7 @@ recording::function::replay_into (replayer *r) m_builtin_id, m_attributes, m_string_attributes, + m_int_array_attributes, m_is_target_builtin)); } @@ -4401,6 +4403,40 @@ recording::function::new_block (const char *name) void recording::function::write_to_dump (dump &d) { + for (auto attr: m_attributes) + { + const char* attribute = fn_attribute_to_string (attr); + if (attribute) + d.write("__attribute(%s)__\n", attribute); + } + for (auto attr: m_string_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + std::string& value = std::get<1>(attr); + const char* attribute = fn_attribute_to_string (name); + + if (attribute) + d.write("__attribute(%s(\"%s\"))__\n", attribute, value.c_str()); + } + for (auto attr: m_int_array_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + std::vector& values = std::get<1>(attr); + const char* attribute = fn_attribute_to_string (name); + if (attribute) + { + d.write("__attribute(%s(", attribute); + for (int i = 0; i < values.size(); ++i) + { + if (i > 0) + d.write(", %d", values[i]); + else + d.write("%d", values[i]); + } + d.write("))__\n"); + } + } + switch (m_kind) { default: gcc_unreachable (); @@ -4615,6 +4651,12 @@ recording::function::add_string_attribute (gcc_jit_fn_attribute attribute, const m_string_attributes.push_back (std::make_pair (attribute, std::string (value))); } +void +recording::function::add_integer_array_attribute (gcc_jit_fn_attribute attribute, const int* value, size_t length) +{ + m_int_array_attributes.push_back (std::make_pair (attribute, std::vector (value, value + length))); +} + /* Implementation of recording::memento::make_debug_string for functions. */ diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 986057263463b..844dae37245ab 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -1483,6 +1483,7 @@ class function : public memento void add_attribute (gcc_jit_fn_attribute attribute); void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value); + void add_integer_array_attribute (gcc_jit_fn_attribute attribute, const int* value, size_t length); private: string * make_debug_string () final override; @@ -1501,6 +1502,7 @@ class function : public memento type *m_fn_ptr_type; std::vector m_attributes; std::vector> m_string_attributes; + std::vector>> m_int_array_attributes; int m_is_target_builtin; }; diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index d23733a6d9fbc..8e974f45d1c49 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -4234,6 +4234,19 @@ gcc_jit_function_add_string_attribute (gcc_jit_function *func, gcc_jit_fn_attrib func->add_string_attribute (attribute, value); } +/* This function adds an attribute with multiple integer values. For example + `nonnull(1, 2)`. The numbers in `values` are supposed to map how they + should be written in C code. So for `nonnull(1, 2)`, you should pass `1` + and `2` in `values` (and set `length` to `2`). */ +void +gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute, const int* values, size_t length) +{ + RETURN_IF_FAIL (func, NULL, NULL, "NULL func"); + RETURN_IF_FAIL (values, NULL, NULL, "NULL values"); + + func->add_integer_array_attribute (attribute, values, length); +} + void gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, gcc_jit_variable_attribute attribute, const char* value) { diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 7612d523ad22b..273865ca335b9 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2117,16 +2117,19 @@ enum gcc_jit_fn_attribute GCC_JIT_FN_ATTRIBUTE_PURE, GCC_JIT_FN_ATTRIBUTE_CONST, GCC_JIT_FN_ATTRIBUTE_WEAK, + GCC_JIT_FN_ATTRIBUTE_NONNULL, }; /* Add an attribute to a function. */ -// TODO: also support integer values. extern void gcc_jit_function_add_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute); extern void gcc_jit_function_add_string_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const char* value); +extern void +gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const int* value, size_t length); + /* Variable attributes. */ enum gcc_jit_variable_attribute { diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index df81163aa07ba..f27febaaf1b18 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -335,4 +335,5 @@ LIBGCCJIT_ABI_34 { LIBGCCJIT_ABI_35 { global: gcc_jit_context_new_sizeof; + gcc_jit_function_add_integer_array_attribute; } LIBGCCJIT_ABI_34; diff --git a/gcc/testsuite/jit.dg/test-nonnull.c b/gcc/testsuite/jit.dg/test-nonnull.c new file mode 100644 index 0000000000000..3306f8906576b --- /dev/null +++ b/gcc/testsuite/jit.dg/test-nonnull.c @@ -0,0 +1,94 @@ +/* { 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 nonnull + 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-nonnull.c.s" +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + +__attribute__((nonnull(1))) +int t(int *a) { + if (!a) { + return -1; + } + return *a; +} + */ + 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_param *a = + gcc_jit_context_new_param (ctxt, NULL, pint_type, "a"); + + gcc_jit_function *func_t = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "t", + 1, &a, + 0); + /* Adding `nonnull(1)` attribute. */ + int indexes[1] = {1}; + gcc_jit_function_add_integer_array_attribute ( + func_t, + GCC_JIT_FN_ATTRIBUTE_NONNULL, + indexes, + 1 + ); + + /* if (!a) { + return -1; + } */ + gcc_jit_block *if_cond = + gcc_jit_function_new_block (func_t, "if_cond"); + gcc_jit_block *if_body = + gcc_jit_function_new_block (func_t, "if_body"); + gcc_jit_block *after_if = + gcc_jit_function_new_block (func_t, "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))); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* Check that the "if block" was optimized away */ +/* { dg-final { jit-verify-assembler-output-not "testq" } } */ +/* { dg-final { jit-verify-assembler-output-not "-1" } } */ From 1ddee47c4486c6ecda0caf985ef974a2bd3b3f49 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 17 Oct 2023 21:06:18 +0200 Subject: [PATCH 45/45] Improve handling of function inlining a bit more --- gcc/jit/jit-playback.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index d8712ed14be61..ccb6ebcaa9f19 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -670,7 +670,10 @@ new_function (location *loc, for (auto attr: attributes) { if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE) + { DECL_DECLARED_INLINE_P (fndecl) = 1; + continue; + } const char* attribute = fn_attribute_to_string (attr); if (attribute)