This patch makes gcc::pipeline and opt_pass instances be allocated within the GC-heap, and adds traversal hooks for GC/PCH, so that passes can own refs to other GC-allocated objects.
gcc/ Make opt_pass and gcc::pipeline be GC-managed, so that pass instances can own GC refs. * Makefile.in (GTFILES): Add pipeline.h and tree-pass.h. * context.c (gcc::context::gt_ggc_mx): Traverse passes_. (gcc::context::gt_pch_nx): Likewise. (gcc::context::gt_pch_nx): Likewise. * passes.c (opt_pass::operator new): New. (opt_pass::gt_ggc_mx): New. (opt_pass::gt_pch_nx): New. (opt_pass::gt_pch_nx_with_op): New. (gt_ggc_mx (opt_pass *)): New. (gt_pch_nx (opt_pass *)): New. (gt_pch_nx_opt_pass): New. (pipeline::operator new): New. (pipeline::gt_ggc_mx): New. (pipeline::gt_pch_nx): New. (pipeline::gt_pch_nx_with_op): New. (gt_ggc_mx (pipeline *)): New. (gt_pch_nx (pipeline *)): New. (gt_pch_nx_pipeline): New. * pipeline.h (class pipeline): Add GTY((user)) marking. (pipeline::operator new): New. (pipeline::gt_ggc_mx): New. (pipeline::gt_pch_nx): New. (pipeline::gt_pch_nx_with_op): New. (gt_ggc_mx (pipeline *)): New. (gt_pch_nx (pipeline *)): New. (gt_pch_nx_pipeline): New. * tree-pass.h (class opt_pass): Add GTY((user)) marking. (opt_pass::operator new): New. (opt_pass::gt_ggc_mx): New. (opt_pass::gt_pch_nx): New. (opt_pass::gt_pch_nx_with_op): New. (gt_ggc_mx (opt_pass *)): New. (gt_pch_nx (opt_pass *)): New. (gt_pch_nx_opt_pass): New. --- gcc/Makefile.in | 2 + gcc/context.c | 9 ++-- gcc/passes.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/pipeline.h | 15 +++++- gcc/tree-pass.h | 19 ++++++- 5 files changed, 198 insertions(+), 7 deletions(-) diff --git a/gcc/Makefile.in b/gcc/Makefile.in index e9d6247..ec42f7b 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -3820,6 +3820,8 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/asan.c \ $(srcdir)/tsan.c \ $(srcdir)/context.h \ + $(srcdir)/pipeline.h \ + $(srcdir)/tree-pass.h \ @all_gtfiles@ # Compute the list of GT header files from the corresponding C sources, diff --git a/gcc/context.c b/gcc/context.c index 72135ed..4d9f0c6 100644 --- a/gcc/context.c +++ b/gcc/context.c @@ -42,20 +42,19 @@ gcc::context::context() void gcc::context::gt_ggc_mx () { - /* Currently a no-op. */ + ::gt_ggc_mx (passes_); } void gcc::context::gt_pch_nx () { - /* Currently a no-op. */ + ::gt_pch_nx (passes_); } void -gcc::context::gt_pch_nx (gt_pointer_operator op ATTRIBUTE_UNUSED, - void *cookie ATTRIBUTE_UNUSED) +gcc::context::gt_pch_nx (gt_pointer_operator op, void *cookie) { - /* Currently a no-op. */ + op (&passes_, cookie); } void gt_ggc_mx (gcc::context *ctxt) diff --git a/gcc/passes.c b/gcc/passes.c index ce5cdeb..dd1b0ba 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -82,6 +82,33 @@ struct opt_pass *current_pass; static void register_pass_name (struct opt_pass *, const char *); +void* +opt_pass::operator new (size_t sz) +{ + return ggc_internal_cleared_alloc_stat (sz MEM_STAT_INFO); +} + +void opt_pass::gt_ggc_mx () +{ + ::gt_ggc_mx (ctxt_); + ::gt_ggc_mx (sub); + ::gt_ggc_mx (next); +} + +void opt_pass::gt_pch_nx () +{ + ::gt_pch_nx (ctxt_); + ::gt_pch_nx (sub); + ::gt_pch_nx (next); +} + +void opt_pass::gt_pch_nx_with_op (gt_pointer_operator op, void *cookie) +{ + op (&(ctxt_), cookie); + op (&(sub), cookie); + op (&(next), cookie); +} + /* Most passes are single-instance (within their context) and thus don't need to implement cloning, but passes that support multiple instances *must* provide their own implementation of the clone method. @@ -116,6 +143,118 @@ opt_pass::opt_pass(const pass_data &data, context *ctxt) { } +void gt_ggc_mx (opt_pass *p) +{ + if (ggc_test_and_set_mark (p)) + p->gt_ggc_mx (); +} + +void gt_pch_nx (opt_pass *p) +{ + if (gt_pch_note_object (p, p, ::gt_pch_nx_opt_pass)) + p->gt_pch_nx (); +} + +void gt_pch_nx_opt_pass (void *this_obj, void *p, + gt_pointer_operator op, void *cookie) +{ + opt_pass *pass = (opt_pass*)p; + if (p == this_obj) + pass->gt_pch_nx_with_op (op, cookie); +} + +void* +pipeline::operator new (size_t sz) +{ + return ggc_internal_cleared_alloc_stat (sz MEM_STAT_INFO); +} + +void +pipeline::gt_ggc_mx () +{ + ::gt_ggc_mx (all_passes); + ::gt_ggc_mx (all_small_ipa_passes); + ::gt_ggc_mx (all_lowering_passes); + ::gt_ggc_mx (all_regular_ipa_passes); + ::gt_ggc_mx (all_lto_gen_passes); + ::gt_ggc_mx (all_late_ipa_passes); + + for (int i = 0; i < passes_by_id_size; i++) + ::gt_ggc_mx (passes_by_id[i]); + +#define INSERT_PASSES_AFTER(PASS) +#define PUSH_INSERT_PASSES_WITHIN(PASS) +#define POP_INSERT_PASSES() +#define NEXT_PASS(PASS, NUM) ::gt_ggc_mx (PASS ## _ ## NUM); +#define TERMINATE_PASS_LIST() + +#include "pass-instances.def" + +#undef INSERT_PASSES_AFTER +#undef PUSH_INSERT_PASSES_WITHIN +#undef POP_INSERT_PASSES +#undef NEXT_PASS +#undef TERMINATE_PASS_LIST + +} + +void +pipeline::gt_pch_nx () +{ + ::gt_pch_nx (all_passes); + ::gt_pch_nx (all_small_ipa_passes); + ::gt_pch_nx (all_lowering_passes); + ::gt_pch_nx (all_regular_ipa_passes); + ::gt_pch_nx (all_lto_gen_passes); + ::gt_pch_nx (all_late_ipa_passes); + + for (int i = 0; i < passes_by_id_size; i++) + ::gt_pch_nx (passes_by_id[i]); + +#define INSERT_PASSES_AFTER(PASS) +#define PUSH_INSERT_PASSES_WITHIN(PASS) +#define POP_INSERT_PASSES() +#define NEXT_PASS(PASS, NUM) ::gt_pch_nx (PASS ## _ ## NUM); +#define TERMINATE_PASS_LIST() + +#include "pass-instances.def" + +#undef INSERT_PASSES_AFTER +#undef PUSH_INSERT_PASSES_WITHIN +#undef POP_INSERT_PASSES +#undef NEXT_PASS +#undef TERMINATE_PASS_LIST + +} + +void +pipeline::gt_pch_nx_with_op (gt_pointer_operator op, void *cookie) +{ + op (&(all_passes), cookie); + op (&(all_small_ipa_passes), cookie); + op (&(all_lowering_passes), cookie); + op (&(all_regular_ipa_passes), cookie); + op (&(all_lto_gen_passes), cookie); + op (&(all_late_ipa_passes), cookie); + + for (int i = 0; i < passes_by_id_size; i++) + op (&(passes_by_id[i]), cookie); + +#define INSERT_PASSES_AFTER(PASS) +#define PUSH_INSERT_PASSES_WITHIN(PASS) +#define POP_INSERT_PASSES() +#define NEXT_PASS(PASS, NUM) op (&(PASS ## _ ## NUM), cookie); +#define TERMINATE_PASS_LIST() + +#include "pass-instances.def" + +#undef INSERT_PASSES_AFTER +#undef PUSH_INSERT_PASSES_WITHIN +#undef POP_INSERT_PASSES +#undef NEXT_PASS +#undef TERMINATE_PASS_LIST + +} void pipeline::execute_early_local_passes () @@ -129,6 +268,27 @@ pipeline::execute_pass_mode_switching () return pass_mode_switching_1->execute (); } +void gt_ggc_mx (pipeline *p) +{ + if (ggc_test_and_set_mark (p)) + p->gt_ggc_mx (); +} + +void gt_pch_nx (pipeline *p) +{ + if (gt_pch_note_object (p, p, ::gt_pch_nx_pipeline)) + p->gt_pch_nx (); + +} + +void gt_pch_nx_pipeline (void *this_obj, void *p, + gt_pointer_operator op, void *cookie) +{ + pipeline *passes = (pipeline *)p; + if (p == this_obj) + passes->gt_pch_nx_with_op (op, cookie); +} + /* Call from anywhere to find out what pass this is. Useful for printing out debugging information deep inside an service diff --git a/gcc/pipeline.h b/gcc/pipeline.h index 60bde5c..66b8212 100644 --- a/gcc/pipeline.h +++ b/gcc/pipeline.h @@ -44,11 +44,19 @@ namespace gcc { class context; -class pipeline +class GTY((user)) pipeline { public: + /* Ensure that instances are allocated in the GC-managed heap. */ + void *operator new (size_t sz); + pipeline(context *ctxt); + /* GTY((user)) methods. */ + void gt_ggc_mx (); + void gt_pch_nx (); + void gt_pch_nx_with_op (gt_pointer_operator op, void *cookie); + void register_pass (struct register_pass_info *pass_info); void register_one_dump_file (struct opt_pass *pass); @@ -122,5 +130,10 @@ private: } // namespace gcc +extern void gt_ggc_mx (gcc::pipeline *passes); +extern void gt_pch_nx (gcc::pipeline *passes); +extern void gt_pch_nx_pipeline (void *this_obj, void *p, + gt_pointer_operator op, void *cookie); + #endif /* ! GCC_PIPELINE_H */ diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 41d5d92..c3e89d4 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -76,11 +76,22 @@ namespace gcc /* An instance of a pass. This is also "pass_data" to minimize the changes in existing code. */ -class opt_pass : public pass_data +class GTY((user)) opt_pass : public pass_data { public: + /* Ensure that instances are allocated in the GC-managed heap. */ + void *operator new (size_t sz); + virtual ~opt_pass () { } + /* GTY((user)) methods, to be called once per traversal. + opt_pass subclasses with additional GC-managed data should overide + these, chain up to the base class implementation, then walk their + extra fields. */ + virtual void gt_ggc_mx (); + virtual void gt_pch_nx (); + virtual void gt_pch_nx_with_op (gt_pointer_operator op, void *cookie); + /* Create a copy of this pass. Passes that can have multiple instances must provide their own @@ -117,6 +128,12 @@ protected: gcc::context *ctxt_; }; +/* GTY((user)) methods. */ +extern void gt_ggc_mx (opt_pass *p); +extern void gt_pch_nx (opt_pass *p); +extern void gt_pch_nx_opt_pass (void *this_obj, void *p, + gt_pointer_operator op, void *cookie); + /* Description of GIMPLE pass. */ class gimple_opt_pass : public opt_pass { -- 1.7.11.7