From 5d534a214bf96605d1eeff44d41ced3a7d4397f6 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 19 Sep 2023 22:10:47 -0400 Subject: [PATCH] libgccjit: Implement sizeof operator gcc/jit/ChangeLog: * docs/topics/compatibility.rst (LIBGCCJIT_ABI_27): New ABI tag. * docs/topics/expressions.rst: Document gcc_jit_context_new_sizeof. * jit-playback.cc (new_sizeof): New method. * jit-playback.h (new_sizeof): New method. * jit-recording.cc (recording::context::new_sizeof, recording::memento_of_sizeof::replay_into, recording::memento_of_sizeof::make_debug_string, recording::memento_of_sizeof::write_reproducer): New methods. * jit-recording.h (class memento_of_sizeof): New class. * libgccjit.cc (gcc_jit_context_new_sizeof): New function. * libgccjit.h (gcc_jit_context_new_sizeof): New function. * libgccjit.map: New function. gcc/testsuite/ChangeLog: * jit.dg/all-non-failing-tests.h: New test. * jit.dg/test-sizeof.c: New test. --- gcc/jit/docs/topics/compatibility.rst | 7 +++ gcc/jit/docs/topics/expressions.rst | 14 ++++++ 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 | 18 +++++++ gcc/jit/libgccjit.h | 12 +++++ gcc/jit/libgccjit.map | 5 ++ gcc/testsuite/jit.dg/all-non-failing-tests.h | 10 ++++ gcc/testsuite/jit.dg/test-sizeof.c | 50 +++++++++++++++++++ 11 files changed, 209 insertions(+) create mode 100644 gcc/testsuite/jit.dg/test-sizeof.c diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index cbf5b414d8c..9cfb054f653 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -390,3 +390,10 @@ on functions and variables: * :func:`gcc_jit_function_add_string_attribute` * :func:`gcc_jit_function_add_integer_array_attribute` * :func:`gcc_jit_lvalue_add_string_attribute` + +.. _LIBGCCJIT_ABI_27: + +``LIBGCCJIT_ABI_27`` +-------------------- +``LIBGCCJIT_ABI_27`` covers the addition of +:func:`gcc_jit_context_new_sizeof` diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 35ee05ca597..c3f4f61eb06 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -126,6 +126,20 @@ Simple expressions underlying string, so it is valid to pass in a pointer to an on-stack buffer. +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_sizeof (gcc_jit_context *ctxt, \ + gcc_jit_type *type) + + Generate an rvalue that is equal to the size of ``type``. + + The parameter ``type`` must be non-NULL. + + This is equivalent to this C code: + + .. code-block:: c + + sizeof (type) + Constructor expressions *********************** diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 84df6c100e6..e277b013259 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -1110,6 +1110,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 05bafcd21c4..aa6a086613c 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -162,6 +162,9 @@ public: 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 6ffadbea127..68a2e860c1f 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -1077,6 +1077,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_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. @@ -5457,6 +5472,43 @@ memento_of_new_rvalue_from_const ::write_reproducer (reproducer &r) } // namespace recording +/* The implementation of class gcc::jit::recording::memento_of_sizeof. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_sizeof. */ + +void +recording::memento_of_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_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_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 ()), + r.get_identifier (m_type)); +} + /* 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 ab5ba6c7fbe..d8d16f4fe29 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -169,6 +169,9 @@ public: new_rvalue_from_const (type *type, HOST_TYPE value); + rvalue * + new_sizeof (type *type); + rvalue * new_string_literal (const char *value); @@ -1605,6 +1608,31 @@ private: HOST_TYPE m_value; }; +class memento_of_sizeof : public rvalue +{ +public: + memento_of_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 bf0150f6047..f40a9781405 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -2073,6 +2073,24 @@ 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"); + RETURN_NULL_IF_FAIL (type, ctxt, NULL, "NULL type"); + 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 235cab053e0..74e847b2dec 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1093,6 +1093,18 @@ extern gcc_jit_rvalue * gcc_jit_context_null (gcc_jit_context *ctxt, gcc_jit_type *pointer_type); +#define LIBGCCJIT_HAVE_gcc_jit_context_new_sizeof + +/* Generates an rvalue that is equal to the size of type. + + This API entrypoint was added in LIBGCCJIT_ABI_27; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_sizeof */ + +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 dfb8a9d51fb..99aa5970be1 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -284,3 +284,8 @@ LIBGCCJIT_ABI_26 { gcc_jit_lvalue_add_string_attribute; gcc_jit_function_add_integer_array_attribute; } LIBGCCJIT_ABI_25; + +LIBGCCJIT_ABI_27 { + global: + gcc_jit_context_new_sizeof; +} LIBGCCJIT_ABI_26; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index d09a31ec764..14a0a321550 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -353,6 +353,13 @@ /* test-setting-alignment.c: This can't be in the testcases array as it is target-specific. */ +/* test-sizeof.c */ +#define create_code create_code_sizeof +#define verify_code verify_code_sizeof +#include "test-sizeof.c" +#undef create_code +#undef verify_code + /* test-string-literal.c */ #define create_code create_code_string_literal #define verify_code verify_code_string_literal @@ -553,6 +560,9 @@ const struct testcase testcases[] = { {"reflection", create_code_reflection , verify_code_reflection }, + {"sizeof", + create_code_sizeof, + verify_code_sizeof}, {"string_literal", create_code_string_literal, verify_code_string_literal}, diff --git a/gcc/testsuite/jit.dg/test-sizeof.c b/gcc/testsuite/jit.dg/test-sizeof.c new file mode 100644 index 00000000000..6aef9027b4f --- /dev/null +++ b/gcc/testsuite/jit.dg/test-sizeof.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: +int +my_sizeof () +{ + return sizeof(int32_t); +} + */ + gcc_jit_type *int32 = + gcc_jit_context_get_int_type (ctxt, 4, 1); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, + NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "my_sizeof", + 0, NULL, 0); + + gcc_jit_block *initial = + gcc_jit_function_new_block (func, "initial"); + + gcc_jit_block_end_with_return(initial, NULL, + gcc_jit_context_new_sizeof(ctxt, int32)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*my_sizeof_type) (); + CHECK_NON_NULL (result); + my_sizeof_type my_sizeof = + (my_sizeof_type)gcc_jit_result_get_code (result, "my_sizeof"); + CHECK_NON_NULL (my_sizeof); + int val = my_sizeof (); + CHECK_VALUE (val, 4); +}