Address spaces are target-specific, meaning that any test for address
spaces must be target-specific, meaning that they're abnormally
susceptible to bitrot. This patch aims to help fix that, by providing a
helper that can (and, in the forthcoming C++ Named Address Spaces patch,
does) help write target-independent self-test for address-space related
logic. It contains enough address spaces with various relationships to
one-another to exercise all cases.
The helper should revert the compiler state to how it was when it
started, i.e. its effects should not contaminate other self-tests.
gcc/c-family/ChangeLog:
* c-common.h (c_register_addr_space): Add comment about the
correlation with address_space_test.
(selftest::addr_space_test): New class. RAII-style
helper for setting up target-independent address space support
state.
* c-common.cc (selftest::addr_space_test::addr_space_test):
Implement.
(selftest::addr_space_test::~addr_space_test): Ditto.
---
gcc/c-family/c-common.cc | 97 ++++++++++++++++++++++++++++++++++++++++
gcc/c-family/c-common.h | 46 +++++++++++++++++++
2 files changed, 143 insertions(+)
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e05551e51192..89d9ea75bfdc 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -20,6 +20,10 @@ along with GCC; see the file COPYING3. If not see
#define GCC_C_COMMON_C
#include "config.h"
+#if CHECKING_P
+# define INCLUDE_ALGORITHM
+# define INCLUDE_ITERATOR
+#endif
#include "system.h"
#include "coretypes.h"
#include "target.h"
@@ -2930,6 +2934,9 @@ c_build_bitfield_integer_type (unsigned HOST_WIDE_INT
width, int unsignedp)
void
c_register_addr_space (const char *word, addr_space_t as)
{
+ /* Note that selftest::addr_space_test below must perform the opposite of
+ this logic, and ergo it has an inverse of this function. Keep in mind
+ when modifying. */
int rid = RID_FIRST_ADDR_SPACE + as;
tree id;
@@ -10714,4 +10721,94 @@ c_hardbool_type_attr_1 (tree type, tree *false_value,
tree *true_value)
return attr;
}
+#if CHECKING_P
+selftest::addr_space_test::addr_space_test ()
+{
+ /* c_register_addr_space is a no-op if this condition is met. */
+ gcc_assert (!(c_dialect_objc () || flag_no_asm));
+
+ /* Save the old keywords. */
+ std::copy (&ridpointers[RID_FIRST_ADDR_SPACE],
+ &ridpointers[RID_LAST_ADDR_SPACE + 1],
+ this->old_ridpointers);
+
+ /* Un-register them. */
+ for (auto rid : this->old_ridpointers)
+ {
+ if (!rid)
+ continue;
+
+ C_SET_RID_CODE (rid, 0);
+ c_unmake_keyword (rid);
+ }
+
+ std::fill (&ridpointers[RID_FIRST_ADDR_SPACE],
+ &ridpointers[RID_LAST_ADDR_SPACE + 1],
+ nullptr);
+ c_register_addr_space ("__as0", 0);
+ c_register_addr_space ("__as1", 1);
+ c_register_addr_space ("__as2", 2);
+ c_register_addr_space ("__as3", 3);
+ c_register_addr_space ("__as4", 4);
+ c_register_addr_space ("__as5", 5);
+
+ /* We don't fully replace all the contents of the below, just enough for
+ tests. */
+ this->old_addr_space_hooks = targetm.addr_space;
+ targetm.addr_space.subset_p = [] (addr_space_t sub, addr_space_t super)
+ {
+ /* Each set is its own (biggest) subset. */
+ if (super == sub)
+ return true;
+
+ /* 0 is the superset of all other address spaces, except for 4 and 5. */
+ if (super == 0 && sub != 4 && sub != 5)
+ return true;
+
+ /* ... because 4 contains 5 (but not vice-versa!). */
+ if (super == 4 && sub == 5)
+ return true;
+
+ /* 2 and 3 overlap. */
+ if ((super == 3 && sub == 2)
+ || (super == 2 && sub == 3))
+ return true;
+ return false;
+ };
+ targetm.addr_space.address_mode
+ = targetm.addr_space.pointer_mode
+ = [] (addr_space_t)
+ { return Pmode; };
+}
+
+selftest::addr_space_test::~addr_space_test ()
+{
+ for (size_t i = RID_FIRST_ADDR_SPACE; i <= RID_LAST_ADDR_SPACE; i++)
+ {
+ tree id = ridpointers[i];
+ if (!id)
+ continue;
+
+ /* Reverse the effects of c_register_addr_space. */
+ C_SET_RID_CODE (id, 0);
+ c_unmake_keyword (id);
+ }
+
+ /* Restore the old keywords. */
+ std::copy (std::begin (this->old_ridpointers), std::end
(this->old_ridpointers),
+ &ridpointers[RID_FIRST_ADDR_SPACE]);
+ for (size_t i = RID_FIRST_ADDR_SPACE; i <= RID_LAST_ADDR_SPACE; i++)
+ {
+ tree id = ridpointers[i];
+ if (!id)
+ continue;
+
+ C_SET_RID_CODE (id, i);
+ c_make_keyword (id);
+ }
+
+ targetm.addr_space = this->old_addr_space_hooks;
+}
+#endif
+
#include "gt-c-family-c-common.h"
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 569edc064014..e027b24d2ca2 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1763,6 +1763,52 @@ namespace selftest {
/* The entrypoint for running all of the above tests. */
extern void c_family_tests (void);
+
+ /* Declarations for utilities. */
+ /* A class that sets up various hooks for address-space testing.
+
+ Namely, it creates a situation where the generic address space is the
+ superset of 1, 2, and 3, address spaces 1 and 2 are disjoint, address
+ spaces 2 and 3 overlap fully, and address space 4 is distinct from all,
+ except for 5, which is a proper subset of it.
+
+ In the table below, if the column label is a superset of the row label,
+ the field is marked with X.
+
+ | / | AS0 | AS1 | AS2 | AS3 | AS4 | AS5 |
+ |-----+-----+-----+-----+-----|-----|-----|
+ | AS0 | X | | | | | |
+ | AS1 | X | X | | | | |
+ | AS2 | X | | X | X | | |
+ | AS3 | X | | X | X | | |
+ | AS4 | | | | | X | |
+ | AS5 | | | | | X | X |
+
+ The address spaces can be visualized also as:
+
+ |---------AS0---------| |---AS4---|
+ | |-AS1-| |-AS2-| | | |-AS5-| |
+ | | | |-AS3-| | | | | |
+ */
+
+ class addr_space_test
+ {
+ /* A copy of the addr_space related RID pointers. We'll register a few of
+ our own instead. */
+ tree old_ridpointers[RID_LAST_ADDR_SPACE - RID_FIRST_ADDR_SPACE + 1];
+ /* Previous addr_space hooks. */
+ decltype (targetm.addr_space) old_addr_space_hooks;
+ public:
+ addr_space_test ();
+ ~addr_space_test ();
+
+ /* Immobilize this object. */
+ addr_space_test (const addr_space_test&) = delete;
+ addr_space_test (addr_space_test&&) = delete;
+ addr_space_test &operator= (const addr_space_test&) = delete;
+ addr_space_test &operator= (addr_space_test&&) = delete;
+ };
+
} // namespace selftest
#endif /* #if CHECKING_P */
--
2.55.0