From 8dc11afcf6ad66276116211f6b1b9d9ced7c5588 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Wed, 14 Jun 2023 19:48:55 -0700 Subject: [PATCH] Upgrade portcosmo patch and GCC third party docs --- libc/calls/tcgetwinsize.c | 1 - third_party/gcc/README.cosmo | 11 +- third_party/gcc/portcosmo.patch | 3777 ++++++++++++++++--------------- 3 files changed, 1914 insertions(+), 1875 deletions(-) diff --git a/libc/calls/tcgetwinsize.c b/libc/calls/tcgetwinsize.c index 32eb6f63c..efa1b067f 100644 --- a/libc/calls/tcgetwinsize.c +++ b/libc/calls/tcgetwinsize.c @@ -34,7 +34,6 @@ int tcgetwinsize(int fd, struct winsize *ws) { int rc; if (IsAsan() && !__asan_is_valid(ws, sizeof(*ws))) { - ws = 0; rc = efault(); } else if (fd >= 0) { if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { diff --git a/third_party/gcc/README.cosmo b/third_party/gcc/README.cosmo index dbe836485..4ec2cb051 100644 --- a/third_party/gcc/README.cosmo +++ b/third_party/gcc/README.cosmo @@ -12,17 +12,16 @@ ORIGIN @ahgamut's musl-cross-make fork https://github.com/ahgamut/musl-cross-make/ - d0f33e2162cf5e5b30cdf3b3accc0d0f7756830c + e58abc1110b335a3341e8ad5821ad8e3880d9bb2 MODIFICATIONS ahgamut's musl-cross-make fork includes a 2kLOC patch that modifies GCC so it'll compile C code like `switch(errno){case EINVAL: etc.}` - -SEE ALSO - - third_party/gcc/portcosmo.patch + see third_party/gcc/portcosmo.patch for GCC 11.2.0 for our changes NOTES - My name is Justine Tunney and I approve of these binaries. + These binaries were compiled by Justine Tunney. You have the freedom + to obtain the original source source code, apply our patch, and enjoy + all the freedoms promised to you by the GNU General Public License. diff --git a/third_party/gcc/portcosmo.patch b/third_party/gcc/portcosmo.patch index 48480095f..b5f5301f0 100644 --- a/third_party/gcc/portcosmo.patch +++ b/third_party/gcc/portcosmo.patch @@ -1,1869 +1,1910 @@ -commit d0f33e2162cf5e5b30cdf3b3accc0d0f7756830c -Author: Gautham -Date: Sun Jun 4 22:42:41 2023 -0500 - - enable patching errno constants with -fportcosmo - - https://github.com/ahgamut/gcc/tree/portcosmo-11.2 - - diff the above fork with gcc-11.2.0 to get the diff in this commit. the - patched gcc allows using Cosmopolitan magic numbers in switch cases and - struct initializations in the following way: - - - build gcc using this patch - - - if ENOSYS is in your switch case, define a value in a separate header - as follows: - - static const int __tmpcosmo_ENOSYS = -23486391; // any value - - - pass the -fportcosmo flag when compiling your file, and include the - header containing the above temporary values - - - the patched gcc will do the necessary AST transformation so that the - actual ENOSYS value is used. - -diff --git a/patches/gcc-11.2.0/0006-portcosmo.diff b/patches/gcc-11.2.0/0006-portcosmo.diff -new file mode 100644 -index 0000000..1700611 ---- /dev/null -+++ b/patches/gcc-11.2.0/0006-portcosmo.diff -@@ -0,0 +1,1838 @@ -+diff --git a/gcc/Makefile.in b/gcc/Makefile.in -+index 8a5fb3fd9..3a7498db8 100644 -+--- a/gcc/Makefile.in -++++ b/gcc/Makefile.in -+@@ -1231,6 +1231,10 @@ GCC_OBJS = gcc.o gcc-main.o ggc-none.o -+ -+ c-family-warn = $(STRICT_WARN) -+ -++PORTCOSMO_OBJS = c-family/portcosmo.o c-family/subcontext.o\ -++ c-family/initstruct.o c-family/ifswitch.o \ -++ c-family/unpatch_int.o c-family/unpatch_ast.o -++ -+ # Language-specific object files shared by all C-family front ends. -+ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ -+ c-family/c-format.o c-family/c-gimplify.o c-family/c-indentation.o \ -+@@ -1238,7 +1242,8 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ -+ c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \ -+ c-family/c-semantics.o c-family/c-ada-spec.o \ -+ c-family/c-ubsan.o c-family/known-headers.o \ -+- c-family/c-attribs.o c-family/c-warn.o c-family/c-spellcheck.o -++ c-family/c-attribs.o c-family/c-warn.o c-family/c-spellcheck.o \ -++ $(PORTCOSMO_OBJS) -+ -+ # Analyzer object files -+ ANALYZER_OBJS = \ -+diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c -+index d227686a0..a1d4c81ec 100644 -+--- a/gcc/c-family/c-common.c -++++ b/gcc/c-family/c-common.c -+@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see -+ #include "c-spellcheck.h" -+ #include "selftest.h" -+ #include "debug.h" -++#include "c-family/portcosmo.h" -+ -+ cpp_reader *parse_in; /* Declared in c-pragma.h. */ -+ -+@@ -2112,8 +2113,16 @@ check_case_value (location_t loc, tree value) -+ value = perform_integral_promotions (value); -+ else if (value != error_mark_node) -+ { -+- error_at (loc, "case label does not reduce to an integer constant"); -+- value = error_mark_node; -++ if (flag_portcosmo) { -++ value = patch_case_nonconst(loc, value); -++ if (value == NULL_TREE) { -++ error_at (loc, "case label does not reduce to an integer constant"); -++ value = error_mark_node; -++ } -++ } else { -++ error_at (loc, "case label does not reduce to an integer constant"); -++ value = error_mark_node; -++ } -+ } -+ -+ constant_expression_warning (value); -+diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c -+index 89e05a4c5..bf1d8b445 100644 -+--- a/gcc/c-family/c-opts.c -++++ b/gcc/c-family/c-opts.c -+@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see -+ #include "mkdeps.h" -+ #include "dumpfile.h" -+ #include "file-prefix-map.h" /* add_*_prefix_map() */ -++#include "c-family/portcosmo.h" -+ -+ #ifndef DOLLARS_IN_IDENTIFIERS -+ # define DOLLARS_IN_IDENTIFIERS true -+@@ -1196,6 +1197,11 @@ c_common_init (void) -+ return false; -+ } -+ -++ if (flag_portcosmo) -++ { -++ portcosmo_setup(); -++ } -++ -+ return true; -+ } -+ -+@@ -1281,6 +1287,10 @@ c_common_finish (void) -+ /* For performance, avoid tearing down cpplib's internal structures -+ with cpp_destroy (). */ -+ cpp_finish (parse_in, deps_stream); -++ if(flag_portcosmo) -++ { -++ portcosmo_teardown(); -++ } -+ -+ if (deps_stream && deps_stream != out_stream && deps_stream != stdout -+ && (ferror (deps_stream) || fclose (deps_stream))) -+@@ -1288,6 +1298,7 @@ c_common_finish (void) -+ -+ if (out_stream && (ferror (out_stream) || fclose (out_stream))) -+ fatal_error (input_location, "when writing output to %s: %m", out_fname); -++ -+ } -+ -+ /* Either of two environment variables can specify output of -+diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt -+index 2005b783c..a69a9a349 100644 -+--- a/gcc/c-family/c.opt -++++ b/gcc/c-family/c.opt -+@@ -1881,6 +1881,10 @@ fopenmp-simd -+ C ObjC C++ ObjC++ Var(flag_openmp_simd) -+ Enable OpenMP's SIMD directives. -+ -++fportcosmo -++C C++ RejectNegative Var(flag_portcosmo) -++Enable AST rewriting for Cosmopolitan Libc magic numbers. -++ -+ foperator-names -+ C++ ObjC++ -+ Recognize C++ keywords like \"compl\" and \"xor\". -+diff --git a/gcc/c-family/ifswitch.cc b/gcc/c-family/ifswitch.cc -+new file mode 100644 -+index 000000000..148b2c2b4 -+--- /dev/null -++++ b/gcc/c-family/ifswitch.cc -+@@ -0,0 +1,236 @@ -++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -++╞══════════════════════════════════════════════════════════════════════════════╡ -++│ Copyright © 2022, Gautham Venkatasubramanian │ -++│ │ -++│ Permission to use, copy, modify, and/or distribute this software for │ -++│ any purpose with or without fee is hereby granted, provided that the │ -++│ above copyright notice and this permission notice appear in all copies. │ -++│ │ -++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -++│ PERFORMANCE OF THIS SOFTWARE. │ -++╚─────────────────────────────────────────────────────────────────────────────*/ -++#include "c-family/ifswitch.h" -++ -++static tree get_switch_body(tree swexpr) { -++ auto body = SWITCH_STMT_BODY(swexpr); -++ if (TREE_CODE(body) == BIND_EXPR) { -++ body = BIND_EXPR_BODY(body); -++ } -++ return body; -++} -++ -++source_range get_switch_bounds(tree sws) { -++ auto body = get_switch_body(sws); -++ source_range rng; -++ rng.m_start = MAX_LOCATION_T; -++ rng.m_finish = MAX_LOCATION_T; -++ if (STATEMENT_LIST_HEAD(body) && STATEMENT_LIST_TAIL(body)) { -++ /* otherwise this is an empty switch statement */ -++ auto rng1 = EXPR_LOCATION_RANGE(STATEMENT_LIST_HEAD(body)->stmt); -++ auto rng2 = EXPR_LOCATION_RANGE(STATEMENT_LIST_TAIL(body)->stmt); -++ rng.m_start = rng1.m_start; -++ rng.m_finish = rng2.m_finish; -++ } -++ return rng; -++} -++ -++unsigned int count_mods_in_switch(tree swexpr, subu_list *list) { -++ tree body = get_switch_body(swexpr); -++ tree t = NULL_TREE; -++ tree replacement = NULL_TREE; -++ subu_node *use = NULL; -++ unsigned int count = 0; -++ for (auto i = tsi_start(body); !tsi_end_p(i); tsi_next(&i)) { -++ t = tsi_stmt(i); -++ if (TREE_CODE(t) == CASE_LABEL_EXPR) { -++ if (get_subu_elem(list, EXPR_LOCATION(t), -++ &use) /* on a line we substituted */ -++ && CASE_LOW(t) != NULL_TREE /* not a x..y range */ -++ && CASE_HIGH(t) == NULL_TREE /* not a default */ -++ && arg_should_be_unpatched(CASE_LOW(t), use, &replacement) -++ /* the case is the one we substituted */) { -++ DEBUGF("we substituted a case label at %u,%u\n", EXPR_LOC_LINE(t), -++ EXPR_LOC_COL(t)); -++ // debug_tree(CASE_LOW(t)); -++ count += 1; -++ } -++ } -++ } -++ return count; -++} -++ -++tree build_modded_label(unsigned int swcount, const char *case_str, -++ location_t loc = UNKNOWN_LOCATION) { -++ char dest[STRING_BUFFER_SIZE] = {0}; -++ snprintf(dest, sizeof(dest), "__tmpcosmo_%u_%s", swcount, case_str); -++ tree lab = build_decl(loc, LABEL_DECL, get_identifier(dest), void_type_node); -++ /* gcc's GIMPLE needs to know that this label -++ * is within the current function declaration */ -++ DECL_CONTEXT(lab) = current_function_decl; -++ return build1(LABEL_EXPR, void_type_node, lab); -++} -++ -++tree build_modded_exit_label(unsigned int swcount) { -++ return build_modded_label(swcount, "__end"); -++} -++ -++static inline tree build_modded_if_stmt(tree condition, tree then_clause, -++ tree else_clause = NULL_TREE) { -++ return build3(COND_EXPR, void_type_node, condition, then_clause, else_clause); -++} -++ -++tree modded_case_label(tree t, unsigned int i, tree swcond, vec *&ifs, -++ SubContext *ctx, tree *default_label) { -++ // debug_tree(t); -++ tree result; -++ tree replacement = NULL_TREE; -++ subu_node *use = NULL; -++ char case_str[STRING_BUFFER_SIZE] = {0}; -++ -++ if (CASE_LOW(t) == NULL_TREE) { -++ DEBUGF("default case\n"); -++ /* default label of the switch case, needs to be last */ -++ result = build_modded_label(ctx->switchcount, "__dflt", EXPR_LOCATION(t)); -++ *default_label = result; -++ } else if (CASE_LOW(t) != NULL_TREE && CASE_HIGH(t) == NULL_TREE) { -++ /* a case label */ -++ if (get_subu_elem(ctx->mods, EXPR_LOCATION(t), &use) -++ /* the case is on a line we substituted */ -++ && arg_should_be_unpatched(CASE_LOW(t), use, &replacement) -++ /* the case value is the one we substituted */) { -++ DEBUGF("modded case\n"); -++ result = -++ build_modded_label(ctx->switchcount, use->name, EXPR_LOCATION(t)); -++ ifs->safe_push(build_modded_if_stmt( -++ build2(EQ_EXPR, integer_type_node, swcond, replacement), -++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(result)))); -++ remove_subu_elem(ctx->mods, use); -++ replacement = NULL_TREE; -++ } else { -++ /* a case label that we didn't substitute */ -++ DEBUGF("unmodded case\n"); -++ snprintf(case_str, sizeof(case_str), "%x_", i); -++ result = build_modded_label(ctx->switchcount, case_str, EXPR_LOCATION(t)); -++ ifs->safe_push(build_modded_if_stmt( -++ build2(EQ_EXPR, integer_type_node, swcond, CASE_LOW(t)), -++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(result)))); -++ } -++ } else { -++ DEBUGF("unmodded case range\n"); -++ /* CASE_LOW(t) != NULL_TREE && CASE_HIGH(t) != NULL_TREE */ -++ /* this is a case x .. y sort of range */ -++ snprintf(case_str, sizeof(case_str), "%x_", i); -++ result = build_modded_label(ctx->switchcount, case_str, EXPR_LOCATION(t)); -++ ifs->safe_push(build_modded_if_stmt( -++ build2(TRUTH_ANDIF_EXPR, integer_type_node, -++ build2(GE_EXPR, integer_type_node, swcond, CASE_LOW(t)), -++ build2(LE_EXPR, integer_type_node, swcond, CASE_HIGH(t))), -++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(result)))); -++ } -++ return result; -++} -++ -++tree build_modded_switch_stmt(tree swexpr, SubContext *ctx) { -++ int case_count = 0, break_count = 0; -++ int has_default = 0; -++ -++ tree swcond = save_expr(SWITCH_STMT_COND(swexpr)); -++ tree swbody = get_switch_body(swexpr); -++ tree *tp = NULL; -++ char dest[STRING_BUFFER_SIZE] = {0}; -++ -++ vec *ifs; -++ vec_alloc(ifs, 0); -++ -++ tree exit_label = build_modded_exit_label(ctx->switchcount); -++ tree default_label = NULL_TREE; -++ -++ for (auto it = tsi_start(swbody); !tsi_end_p(it); tsi_next(&it)) { -++ tp = tsi_stmt_ptr(it); -++ if (TREE_CODE(*tp) == CASE_LABEL_EXPR) { -++ case_count += 1; -++ has_default = has_default || (CASE_LOW(*tp) == NULL_TREE); -++ /* replace the case statement with a goto */ -++ *tp = -++ modded_case_label(*tp, case_count, swcond, ifs, ctx, &default_label); -++ } else if (TREE_CODE(*tp) == BREAK_STMT) { -++ break_count += 1; -++ /* replace the break statement with a goto to the end */ -++ *tp = build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(exit_label)); -++ } else if (TREE_CODE(*tp) == BIND_EXPR) { -++ for (auto it2 = tsi_start(BIND_EXPR_BODY(*tp)); !tsi_end_p(it2); -++ tsi_next(&it2)) { -++ auto tp2 = tsi_stmt_ptr(it2); -++ if (TREE_CODE(*tp2) == BREAK_STMT) { -++ break_count += 1; -++ /* replace the break statement with a goto to the end */ -++ *tp2 = -++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(exit_label)); -++ } -++ } -++ } -++ } -++ /* add all the if statements to the start of the switch body */ -++ /* TODO: do we have to combine them via COND_EXPR_ELSE? why, -++ * is it not possible to just them as a list one after the other? */ -++ tree res; -++ unsigned int zz = 0; -++ if (ifs->length() > 0) { -++ res = (*ifs)[0]; -++ for (zz = 1; zz < ifs->length(); ++zz) { -++ COND_EXPR_ELSE(res) = (*ifs)[zz]; -++ res = (*ifs)[zz]; -++ } -++ /* if we have a valid default for the switch, -++ * it should be the final else branch */ -++ if (default_label && default_label != NULL_TREE) { -++ COND_EXPR_ELSE(res) = -++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(default_label)); -++ } else { -++ /* if we don't have a default, then the final else branch -++ * should just jump to after the switch */ -++ COND_EXPR_ELSE(res) = -++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(exit_label)); -++ } -++ /* reset to the start of the if-else tree */ -++ res = (*ifs)[0]; -++ } else if (has_default && default_label != NULL_TREE) { -++ /* this switch has only a default? ok... */ -++ res = build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(default_label)); -++ } else { -++ /* this switch has no cases, and no default?! */ -++ warning_at(EXPR_LOCATION(swcond), 0, "switch without cases or default?"); -++ res = build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(exit_label)); -++ } -++ auto it = tsi_start(swbody); -++ tsi_link_before(&it, res, TSI_SAME_STMT); -++ tsi_link_before(&it, build_empty_stmt(UNKNOWN_LOCATION), TSI_SAME_STMT); -++ -++ /* add the 'outside' of the switch, ie the 'finally' -++ * aka the target of the break statements, the 'exit_label', -++ * to the end of the switch body */ -++ append_to_statement_list(build_empty_stmt(UNKNOWN_LOCATION), &swbody); -++ append_to_statement_list(exit_label, &swbody); -++ append_to_statement_list(build_empty_stmt(UNKNOWN_LOCATION), &swbody); -++ /* -++ snprintf(dest, sizeof(dest), -++ "above switch had %d cases replaced and %d breaks\n", case_count, -++ break_count); -++ append_to_statement_list(build_call_expr(VAR_NAME_AS_TREE("printf"), 1, -++ BUILD_STRING_AS_TREE(dest)), -++ &swbody); */ -++ -++ /* debug_tree(swbody); */ -++ /* we are returning SWITCH_STMT_BODY(swexpr), -++ * instead of just swbody, because sometimes, -++ * SWITCH_STMT_BODY(swexpr) may be a BIND_EXPR -++ * that has some scoping-related information. */ -++ return SWITCH_STMT_BODY(swexpr); -++} -+diff --git a/gcc/c-family/ifswitch.h b/gcc/c-family/ifswitch.h -+new file mode 100644 -+index 000000000..ccf78067f -+--- /dev/null -++++ b/gcc/c-family/ifswitch.h -+@@ -0,0 +1,10 @@ -++#ifndef IFSWITCH_H -++#define IFSWITCH_H -++#include "c-family/portcosmo.internal.h" -++#include "c-family/subcontext.h" -++ -++source_range get_switch_bounds(tree); -++unsigned int count_mods_in_switch(tree, subu_list *); -++tree build_modded_switch_stmt(tree, SubContext *); -++ -++#endif /* IFSWITCH_H */ -+diff --git a/gcc/c-family/initstruct.cc b/gcc/c-family/initstruct.cc -+new file mode 100644 -+index 000000000..6a0d4a78e -+--- /dev/null -++++ b/gcc/c-family/initstruct.cc -+@@ -0,0 +1,422 @@ -++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -++╞══════════════════════════════════════════════════════════════════════════════╡ -++│ Copyright © 2022, Gautham Venkatasubramanian │ -++│ │ -++│ Permission to use, copy, modify, and/or distribute this software for │ -++│ any purpose with or without fee is hereby granted, provided that the │ -++│ above copyright notice and this permission notice appear in all copies. │ -++│ │ -++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -++│ PERFORMANCE OF THIS SOFTWARE. │ -++╚─────────────────────────────────────────────────────────────────────────────*/ -++#include "c-family/initstruct.h" -++ -++void portcosmo_finish_decl(void *gcc_data) { -++ handle_decl(gcc_data, (void *)(&cosmo_ctx)); -++} -++ -++void set_values_based_on_ctor(tree ctor, subu_list *list, tree body, tree lhs, -++ location_t bound) { -++ subu_node *use = NULL; -++ unsigned int iprev = 0; -++ bool started = true; -++ tree replacement = NULL_TREE; -++ -++ while (list->count > 0 && LOCATION_BEFORE2(list->start, bound)) { -++ tree index = NULL_TREE; -++ tree val = NULL_TREE; -++ unsigned int i = 0; -++ int found = 0; -++ FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(ctor), i, index, val) { -++ DEBUGF("value %u is %s\n", i, get_tree_code_str(val)); -++ if (!started && i <= iprev) continue; -++ if (TREE_CODE(val) == INTEGER_CST) { -++ for (use = list->head; use; use = use->next) { -++ found = arg_should_be_unpatched(val, use, &replacement); -++ if (found) break; -++ } -++ if (found) { -++ iprev = i; -++ started = false; -++ break; -++ } -++ } else if (TREE_CODE(val) == CONSTRUCTOR) { -++ auto sub = access_at(lhs, index); -++ // debug_tree(sub); -++ set_values_based_on_ctor(val, list, body, sub, bound); -++ use = NULL; /* might've gotten stomped */ -++ if (list->count == 0) return; -++ get_subu_elem(list, list->start, &use); -++ } -++ } -++ if (found) { -++ auto modexpr = build2(MODIFY_EXPR, TREE_TYPE(index), -++ access_at(lhs, index), replacement); -++ // debug_tree(modexpr); -++ append_to_statement_list(modexpr, &body); -++ remove_subu_elem(list, use); -++ replacement = NULL_TREE; -++ DEBUGF("found; %d left\n", list->count); -++ } else { -++ /* we did not find any (more) substitutions to fix */ -++ DEBUGF("exiting; %d left\n", list->count); -++ break; -++ } -++ } -++} -++ -++/* initstruct/global.cc */ -++ -++void update_global_decls(tree dcl, SubContext *ctx) { -++ tree body = alloc_stmt_list(); -++ subu_node *use = NULL; -++ char chk[STRING_BUFFER_SIZE]; -++ -++ /* dcl, the global declaration we have is like these: -++ * -++ * static int foo = __tmpcosmo_VAR; -++ * static struct toy myvalue = {.x=1, .y=__tmpcosmo_VAR}; -++ * -++ * we're going to add functions as follows: -++ * -++ * static int foo = __tmpcosmo_VAR; -++ * __attribute__((constructor)) __hidden_ctor1() { -++ * foo = VAR; -++ * } -++ * static struct toy myvalue = {.x=1, .y=__tmpcosmo_VAR}; -++ * __attribute__((constructor)) __hidden_ctor2() { -++ * myvalue.y = VAR; -++ * } -++ * -++ * the modifier functions have the constructor attribute, -++ * so it they run before anything uses the static. it -++ * works recursively too: you can have a struct of structs, -++ * an array of structs, whatever, and it will figure out -++ * where the substitutions are and attempt to mod them. -++ * -++ * a unique constructor for each declaration. probably -++ * we could have a common constructor for the entire -++ * file, but that's left as an exercise for the reader. */ -++ if (INTEGRAL_TYPE_P(TREE_TYPE(dcl)) && -++ get_subu_elem(ctx->mods, ctx->mods->start, &use) && -++ /* use is non-NULL if get_subu_elem succeeds */ -++ check_magic_equal(DECL_INITIAL(dcl), use->name)) { -++ if (TREE_READONLY(dcl)) { -++ error_at(EXPR_LOCATION(dcl), "cannot substitute this constant\n"); -++ /* actually I can, but the issue is if one of gcc's optimizations -++ * perform constant folding(and they do), I don't know all the spots -++ * where this variable has been folded, so I can't substitute there */ -++ ctx->active = 0; -++ return; -++ } -++ append_to_statement_list( -++ build2(MODIFY_EXPR, void_type_node, dcl, VAR_NAME_AS_TREE(use->name)), -++ &body); -++ /* -++ append_to_statement_list( -++ build_call_expr(VAR_NAME_AS_TREE("printf"), 2, -++ BUILD_STRING_AS_TREE("ctor initstruct %s\n"), -++ BUILD_STRING_AS_TREE(IDENTIFIER_NAME(dcl))), -++ &body); -++ */ -++ remove_subu_elem(ctx->mods, use); -++ cgraph_build_static_cdtor('I', body, 0); -++ } else if ((RECORD_TYPE == TREE_CODE(TREE_TYPE(dcl)) || -++ ARRAY_TYPE == TREE_CODE(TREE_TYPE(dcl))) && -++ DECL_INITIAL(dcl) != NULL_TREE) { -++ if (TREE_READONLY(dcl)) { -++ warning_at(DECL_SOURCE_LOCATION(dcl), 0, -++ "not sure if modding const structs is good\n"); -++ TREE_READONLY(dcl) = 0; -++ } -++ if (LOCATION_BEFORE2(ctx->mods->end, input_location)) { -++ set_values_based_on_ctor(DECL_INITIAL(dcl), ctx->mods, body, dcl, -++ input_location); -++ } else { -++ set_values_based_on_ctor(DECL_INITIAL(dcl), ctx->mods, body, dcl, -++ ctx->mods->end); -++ } -++ /* -++ append_to_statement_list( -++ build_call_expr(VAR_NAME_AS_TREE("printf"), 2, -++ BUILD_STRING_AS_TREE("ctor initstruct %s\n"), -++ BUILD_STRING_AS_TREE(IDENTIFIER_NAME(dcl))), -++ &body); -++ */ -++ cgraph_build_static_cdtor('I', body, 0); -++ DEBUGF("uploaded ctor\n"); -++ } -++} -++ -++void handle_decl(void *gcc_data, void *user_data) { -++ tree t = (tree)gcc_data; -++ SubContext *ctx = (SubContext *)user_data; -++ if (ctx->active && ctx->mods->count > 0 && DECL_INITIAL(t) != NULL && -++ DECL_CONTEXT(t) == NULL_TREE) { -++ int internal_use = -++ !strncmp(IDENTIFIER_NAME(t), "__tmpcosmo_", strlen("__tmpcosmo_")); -++ if (internal_use || DECL_EXTERNAL(t)) { -++ error_at(input_location, "the ACTUALLY is before the declaration!\n"); -++ ctx->active = 0; -++ return; -++ } -++ auto rng = EXPR_LOCATION_RANGE(t); -++ rng.m_start = DECL_SOURCE_LOCATION(t); -++ rng.m_finish = input_location; -++ -++ DEBUGF("handle_decl with %s %u,%u - %u-%u\n", IDENTIFIER_NAME(t), -++ LOCATION_LINE(rng.m_start), LOCATION_COLUMN(rng.m_start), -++ LOCATION_LINE(rng.m_finish), LOCATION_COLUMN(rng.m_finish)); -++ ctx->initcount += ctx->mods->count; -++ update_global_decls(t, ctx); -++ /* now at this stage, all uses of our macros have been -++ * fixed, INCLUDING case labels. Let's confirm that: */ -++ check_context_clear(ctx, MAX_LOCATION_T); -++ } -++} -++ -++/* initstruct/local.cc */ -++ -++static inline tree build_modded_if_stmt(tree condition, tree then_clause, -++ tree else_clause = NULL_TREE) { -++ return build3(COND_EXPR, void_type_node, condition, then_clause, else_clause); -++} -++ -++int build_modded_int_declaration(tree *dxpr, SubContext *ctx, subu_node *use) { -++ char chk[STRING_BUFFER_SIZE]; -++ tree dcl = DECL_EXPR_DECL(*dxpr); -++ tree replacement = NULL_TREE; -++ -++ if (INTEGRAL_TYPE_P(TREE_TYPE(dcl)) && -++ arg_should_be_unpatched(DECL_INITIAL(dcl), use, &replacement)) { -++ if (TREE_READONLY(dcl)) { -++ error_at(EXPR_LOCATION(dcl), "cannot substitute this constant\n"); -++ /* actually I can, but the issue is if one of gcc's optimizations -++ * perform constant folding(and they do), I don't know all the spots -++ * where this variable has been folded, so I can't substitute there */ -++ ctx->active = 0; -++ return 0; -++ } -++ -++ if (!TREE_STATIC(dcl)) { -++ DECL_INITIAL(dcl) = replacement; -++ remove_subu_elem(ctx->mods, use); -++ replacement = NULL_TREE; -++ return 1; -++ } -++ -++ DEBUGF("fixing decl for a static integer\n"); -++ /* (*dxpr), the statement we have is this: -++ * -++ * static int myvalue = __tmpcosmo_VAR; -++ * -++ * we're going to modify it to this: -++ * -++ * static int myvalue = __tmpcosmo_VAR; -++ * static uint8 __chk_ifs_myvalue = 0; -++ * if(__chk_ifs_myvalue != 1) { -++ * __chk_ifs_myvalue = 1; -++ * myvalue = VAR; -++ * } -++ * -++ * so the modified statement runs exactly once, -++ * whenever the function is first called, right -++ * after the initialization of the variable we -++ * wanted to modify. */ -++ -++ /* build __chk_ifs_myvalue */ -++ snprintf(chk, sizeof(chk), "__chk_ifs_%s", IDENTIFIER_NAME(dcl)); -++ tree chknode = build_decl(DECL_SOURCE_LOCATION(dcl), VAR_DECL, -++ get_identifier(chk), uint8_type_node); -++ DECL_INITIAL(chknode) = build_int_cst(uint8_type_node, 0); -++ TREE_STATIC(chknode) = TREE_STATIC(dcl); -++ TREE_USED(chknode) = TREE_USED(dcl); -++ DECL_READ_P(chknode) = DECL_READ_P(dcl); -++ DECL_CONTEXT(chknode) = DECL_CONTEXT(dcl); -++ DECL_CHAIN(chknode) = DECL_CHAIN(dcl); -++ DECL_CHAIN(dcl) = chknode; -++ -++ /* create the then clause of the if statement */ -++ tree then_clause = alloc_stmt_list(); -++ append_to_statement_list(build2(MODIFY_EXPR, void_type_node, chknode, -++ build_int_cst(uint8_type_node, 1)), -++ &then_clause); -++ append_to_statement_list( -++ build2(MODIFY_EXPR, void_type_node, dcl, replacement), -++ &then_clause); -++ /* -++ append_to_statement_list( -++ build_call_expr(VAR_NAME_AS_TREE("printf"), 1, -++ BUILD_STRING_AS_TREE("initstruct magic\n")), -++ &then_clause); -++ */ -++ -++ /* create the if statement into the overall result mentioned above */ -++ tree res = alloc_stmt_list(); -++ append_to_statement_list(*dxpr, &res); -++ append_to_statement_list(build1(DECL_EXPR, void_type_node, chknode), &res); -++ append_to_statement_list( -++ build_modded_if_stmt(build2(NE_EXPR, void_type_node, chknode, -++ build_int_cst(uint8_type_node, 1)), -++ then_clause), -++ &res); -++ /* overwrite the input tree with our new statements */ -++ *dxpr = res; -++ // debug_tree(res); -++ remove_subu_elem(ctx->mods, use); -++ replacement = NULL_TREE; -++ return 1; -++ } -++ return 0; -++} -++ -++void modify_local_struct_ctor(tree ctor, subu_list *list, location_t bound) { -++ subu_node *use = NULL; -++ unsigned int iprev = 0; -++ bool started = true; -++ tree replacement = NULL_TREE; -++ -++ while (list->count > 0 && LOCATION_BEFORE2(list->start, bound)) { -++ tree val = NULL_TREE; -++ unsigned int i = 0; -++ int found = 0; -++ FOR_EACH_CONSTRUCTOR_VALUE(CONSTRUCTOR_ELTS(ctor), i, val) { -++ DEBUGF("value %u is %s\n", i, get_tree_code_str(val)); -++ // debug_tree(val); -++ if (TREE_CODE(val) == INTEGER_CST) { -++ for (use = list->head; use; use = use->next) { -++ found = arg_should_be_unpatched(val, use, &replacement); -++ if (found) break; -++ } -++ if (found) { -++ iprev = i; -++ started = false; -++ break; -++ } -++ } else if (TREE_CODE(val) == CONSTRUCTOR) { -++ modify_local_struct_ctor(val, list, bound); -++ use = NULL; /* might've gotten stomped */ -++ if (list->count == 0 || LOCATION_AFTER2(list->start, bound)) return; -++ } -++ } -++ if (found) { -++ DEBUGF("found\n"); -++ // debug_tree(CONSTRUCTOR_ELT(ctor, i)->index); -++ CONSTRUCTOR_ELT(ctor, i)->value = replacement; -++ // debug_tree(CONSTRUCTOR_ELT(ctor, i)->value); -++ remove_subu_elem(list, use); -++ replacement = NULL_TREE; -++ } else { -++ /* we did not find any (more) substitutions to fix */ -++ break; -++ } -++ } -++} -++ -++void build_modded_declaration(tree *dxpr, SubContext *ctx, location_t bound) { -++ char chk[STRING_BUFFER_SIZE]; -++ tree dcl = DECL_EXPR_DECL(*dxpr); -++ subu_node *use = NULL; -++ subu_list *list = ctx->mods; -++ unsigned int oldcount = list->count; -++ -++ // debug_tree(DECL_INITIAL(dcl)); -++ -++ if (INTEGRAL_TYPE_P(TREE_TYPE(dcl))) { -++ get_subu_elem(list, list->start, &use); -++ if (build_modded_int_declaration(dxpr, ctx, use)) { -++ use = NULL; -++ ctx->initcount += 1; -++ } -++ return; -++ } -++ -++ if ((RECORD_TYPE == TREE_CODE(TREE_TYPE(dcl)) || -++ ARRAY_TYPE == TREE_CODE(TREE_TYPE(dcl))) && -++ DECL_INITIAL(dcl) != NULL_TREE) { -++ if (TREE_READONLY(dcl)) { -++ warning_at(EXPR_LOCATION(*dxpr), 0, -++ "not sure if modding const structs is good\n"); -++ TREE_READONLY(dcl) = 0; -++ build_modded_declaration(dxpr, ctx, bound); -++ return; -++ } else if (TREE_STATIC(dcl)) { -++ DEBUGF("fixing decl for a static struct\n"); -++ /* (*dxpr), the statement we have is this: -++ * -++ * static struct toy myvalue = {.x=1, .y=__tmpcosmo_VAR}; -++ * -++ * we're going to modify it to this: -++ * -++ * static struct toy myvalue = {.x=1, .y=__tmpcosmo_VAR}; -++ * static uint8 __chk_ifs_myvalue = 0; -++ * if(__chk_ifs_myvalue != 1) { -++ * __chk_ifs_myvalue = 1; -++ * myvalue.y = VAR; -++ * } -++ * -++ * so the modified statement runs exactly once, -++ * whenever the function is first called, right -++ * after the initialization of the variable we -++ * wanted to modify. */ -++ -++ /* build __chk_ifs_myvalue */ -++ snprintf(chk, sizeof(chk), "__chk_ifs_%s", IDENTIFIER_NAME(dcl)); -++ tree chknode = build_decl(DECL_SOURCE_LOCATION(dcl), VAR_DECL, -++ get_identifier(chk), uint8_type_node); -++ DECL_INITIAL(chknode) = build_int_cst(uint8_type_node, 0); -++ TREE_STATIC(chknode) = TREE_STATIC(dcl); -++ TREE_USED(chknode) = TREE_USED(dcl); -++ DECL_READ_P(chknode) = DECL_READ_P(dcl); -++ DECL_CONTEXT(chknode) = DECL_CONTEXT(dcl); -++ DECL_CHAIN(chknode) = DECL_CHAIN(dcl); -++ DECL_CHAIN(dcl) = chknode; -++ -++ /* build a scope block for the temporary value */ -++ tree tmpscope = build0(BLOCK, void_type_node); -++ BLOCK_SUPERCONTEXT(tmpscope) = TREE_BLOCK(*dxpr); -++ // debug_tree(BLOCK_SUPERCONTEXT(tmpscope)); -++ -++ /* create the then clause of the if statement */ -++ tree then_clause = alloc_stmt_list(); -++ append_to_statement_list(build2(MODIFY_EXPR, void_type_node, chknode, -++ build_int_cst(uint8_type_node, 1)), -++ &then_clause); -++ set_values_based_on_ctor(DECL_INITIAL(dcl), ctx->mods, then_clause, dcl, -++ bound); -++ /* -++ append_to_statement_list( -++ build_call_expr(VAR_NAME_AS_TREE("printf"), 2, -++ BUILD_STRING_AS_TREE("initstruct magic %lu bytes\n"), -++ DECL_SIZE_UNIT(dcl)), -++ &then_clause); -++ */ -++ -++ /* create the if statement into the overall result mentioned above */ -++ tree res = alloc_stmt_list(); -++ append_to_statement_list(*dxpr, &res); -++ append_to_statement_list(build1(DECL_EXPR, void_type_node, chknode), -++ &res); -++ append_to_statement_list( -++ build_modded_if_stmt(build2(NE_EXPR, void_type_node, chknode, -++ build_int_cst(uint8_type_node, 1)), -++ then_clause), -++ &res); -++ /* overwrite the input tree with our new statements */ -++ *dxpr = res; -++ } else { -++ /* if it's a local struct, we can -++ * just mod the constructor itself */ -++ auto ctor = DECL_INITIAL(dcl); -++ modify_local_struct_ctor(ctor, list, bound); -++ } -++ } -++ ctx->initcount += (oldcount - list->count); -++} -+diff --git a/gcc/c-family/initstruct.h b/gcc/c-family/initstruct.h -+new file mode 100644 -+index 000000000..f77fba707 -+--- /dev/null -++++ b/gcc/c-family/initstruct.h -+@@ -0,0 +1,15 @@ -++#ifndef INITSTRUCT_H -++#define INITSTRUCT_H -++#include "c-family/portcosmo.internal.h" -++/* gcc utils first */ -++#include "c-family/subcontext.h" -++ -++void build_modded_declaration(tree *, SubContext *, location_t); -++int build_modded_int_declaration(tree *, SubContext *, subu_node *); -++tree copy_struct_ctor(tree); -++void modify_local_struct_ctor(tree, subu_list *, location_t); -++ -++void set_values_based_on_ctor(tree, subu_list *, tree, tree, location_t); -++void handle_decl(void *, void *); -++tree access_at(tree, tree); -++#endif /* INITSTRUCT_H */ -+diff --git a/gcc/c-family/portcosmo.cc b/gcc/c-family/portcosmo.cc -+new file mode 100644 -+index 000000000..4716500b5 -+--- /dev/null -++++ b/gcc/c-family/portcosmo.cc -+@@ -0,0 +1,171 @@ -++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -++╞══════════════════════════════════════════════════════════════════════════════╡ -++│ Copyright © 2022, Gautham Venkatasubramanian │ -++│ │ -++│ Permission to use, copy, modify, and/or distribute this software for │ -++│ any purpose with or without fee is hereby granted, provided that the │ -++│ above copyright notice and this permission notice appear in all copies. │ -++│ │ -++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -++│ PERFORMANCE OF THIS SOFTWARE. │ -++╚─────────────────────────────────────────────────────────────────────────────*/ -++#include "c-family/portcosmo.internal.h" -++#include "c-family/subcontext.h" -++#include "c-family/ifswitch.h" -++#include "c-family/initstruct.h" -++ -++static tree maybe_get_ifsw_identifier(const char *); -++static tree patch_int_nonconst(location_t, tree, const char **); -++ -++struct SubContext cosmo_ctx; -++static int ctx_inited = 0; -++ -++void portcosmo_setup() { -++ if (flag_portcosmo && 0 == ctx_inited) { -++ construct_context(&cosmo_ctx); -++ ctx_inited = 1; -++ } -++} -++ -++void portcosmo_teardown() { -++ if (flag_portcosmo && 1 == ctx_inited) { -++ cleanup_context(&cosmo_ctx); -++ ctx_inited = 0; -++ } -++} -++ -++void portcosmo_show_tree(location_t loc, tree t) { -++ INFORM(loc, "attempting case substitution at: line %u, col %u\n", -++ LOCATION_LINE(loc), LOCATION_COLUMN(loc)); -++ debug_tree(t); -++} -++ -++tree patch_case_nonconst(location_t loc, tree t) { -++ INFORM(loc, "attempting case substitution at: line %u, col %u\n", -++ LOCATION_LINE(loc), LOCATION_COLUMN(loc)); -++ tree subs = NULL_TREE; -++ const char *name = NULL; -++ if (cosmo_ctx.active) { -++ subs = patch_int_nonconst(loc, t, &name); -++ if (subs != NULL_TREE) { -++ DEBUGF("folding...\n"); -++ subs = c_fully_fold(subs, false, NULL, false); -++ /* this substitution was successful, so record -++ * the location for rewriting the thing later */ -++ add_context_subu(&cosmo_ctx, loc, name, strlen(name), -++ PORTCOSMO_SWCASE); -++ } -++ } -++ return subs; -++} -++ -++tree patch_init_nonconst(location_t loc, tree t) { -++ INFORM(loc, "attempting init substitution at: line %u, col %u\n", -++ LOCATION_LINE(loc), LOCATION_COLUMN(loc)); -++ tree subs = NULL_TREE; -++ const char *name = NULL; -++ if (cosmo_ctx.active) { -++ subs = patch_int_nonconst(loc, t, &name); -++ if (subs != NULL_TREE) { -++ DEBUGF("folding...\n"); -++ subs = c_fully_fold(subs, false, NULL, false); -++ /* this substitution was successful, so record -++ * the location for rewriting the thing later */ -++ add_context_subu(&cosmo_ctx, loc, name, strlen(name), -++ PORTCOSMO_INITVAL); -++ } -++ } -++ return subs; -++} -++ -++/* internal functions */ -++ -++static tree patch_int_nonconst(location_t loc, tree t, const char **res) { -++ /* t may be an integer inside a case label, or -++ * t may be an integer inside an initializer */ -++ tree subs = NULL_TREE; -++ switch (TREE_CODE(t)) { -++ case VAR_DECL: -++ subs = maybe_get_ifsw_identifier(IDENTIFIER_NAME(t)); -++ if (subs != NULL_TREE && TREE_STATIC(subs) && TREE_READONLY(subs)) { -++ subs = DECL_INITIAL(subs); -++ *res = IDENTIFIER_NAME(t); -++ DEBUGF("substitution exists %s\n", *res); -++ } -++ break; -++ case NOP_EXPR: -++ subs = patch_int_nonconst(loc, TREE_OPERAND(t, 0), res); -++ if (subs != NULL_TREE) { -++ subs = build1(NOP_EXPR, integer_type_node, subs); -++ } -++ break; -++ case NEGATE_EXPR: -++ subs = patch_int_nonconst(loc, TREE_OPERAND(t, 0), res); -++ if (subs != NULL_TREE) { -++ subs = build1(NEGATE_EXPR, integer_type_node, subs); -++ } -++ break; -++ case BIT_NOT_EXPR: -++ subs = patch_int_nonconst(loc, TREE_OPERAND(t, 0), res); -++ if (subs != NULL_TREE) { -++ subs = build1(BIT_NOT_EXPR, integer_type_node, subs); -++ } -++ break; -++ default: -++ subs = NULL_TREE; -++ } -++ return subs; -++} -++ -++const char *get_tree_code_str(tree expr) { -++#define END_OF_BASE_TREE_CODES -++#define DEFTREECODE(a, b, c, d) \ -++ case a: \ -++ return b; -++ switch (TREE_CODE(expr)) { -++#include "all-tree.def" -++ default: -++ return ""; -++ } -++#undef DEFTREECODE -++#undef END_OF_BASE_TREE_CODES -++} -++ -++static tree maybe_get_ifsw_identifier(const char *s) { -++ char *result = (char *)xmalloc(strlen("__tmpcosmo_") + strlen(s) + 1); -++ strcpy(result, "__tmpcosmo_"); -++ strcat(result, s); -++ tree t = maybe_get_identifier(result); -++ free(result); -++ if (t != NULL_TREE && lookup_name(t) != NULL_TREE) { -++ return lookup_name(t); -++ } -++ return NULL_TREE; -++} -++ -++tree get_ifsw_identifier(char *s) { -++ char *result = (char *)xmalloc(strlen("__tmpcosmo_") + strlen(s) + 1); -++ strcpy(result, "__tmpcosmo_"); -++ strcat(result, s); -++ tree t = lookup_name(get_identifier(result)); -++ free(result); -++ return t; -++} -++ -++int get_value_of_const(char *name) { -++ tree vx = get_ifsw_identifier(name); -++ int z = tree_to_shwi(DECL_INITIAL(vx)); -++ return z; -++} -++ -++int check_magic_equal(tree value, char *varname) { -++ tree vx = get_ifsw_identifier(varname); -++ return tree_int_cst_equal(value, DECL_INITIAL(vx)); -++} -+diff --git a/gcc/c-family/portcosmo.h b/gcc/c-family/portcosmo.h -+new file mode 100644 -+index 000000000..b25d8257b -+--- /dev/null -++++ b/gcc/c-family/portcosmo.h -+@@ -0,0 +1,13 @@ -++#ifndef PORTCOSMO_H -++#define PORTCOSMO_H -++#include -++ -++void portcosmo_setup(); -++void portcosmo_teardown(); -++void portcosmo_pre_genericize(void*); -++void portcosmo_finish_decl(void*); -++void portcosmo_show_tree(location_t, tree); -++tree patch_case_nonconst(location_t, tree); -++tree patch_init_nonconst(location_t, tree); -++ -++#endif /* PORTCOSMO_H */ -+diff --git a/gcc/c-family/portcosmo.internal.h b/gcc/c-family/portcosmo.internal.h -+new file mode 100644 -+index 000000000..1d361bfa7 -+--- /dev/null -++++ b/gcc/c-family/portcosmo.internal.h -+@@ -0,0 +1,55 @@ -++#ifndef PORTCOSMO_INTERNAL_H -++#define PORTCOSMO_INTERNAL_H -++/* first stdlib headers */ -++#include -++/* now all the plugin headers */ -++#include -++/* first gcc-plugin, then the others */ -++#include -++#include -++#include -++#include -++#include -++#include -++#include -++#include -++#include -++#include -++ -++const char *get_tree_code_str(tree); -++int get_value_of_const(char *); -++tree get_ifsw_identifier(char *); -++int check_magic_equal(tree, char *); -++ -++#define EXPR_LOC_LINE(x) LOCATION_LINE(EXPR_LOCATION((x))) -++#define EXPR_LOC_COL(x) LOCATION_COLUMN(EXPR_LOCATION((x))) -++#define LOCATION_APPROX(x, y) (LOCATION_LINE((x)) == LOCATION_LINE((y))) -++#define LOCATION_BEFORE(x, y) (LOCATION_LINE((x)) <= LOCATION_LINE((y))) -++#define LOCATION_AFTER(x, y) (LOCATION_LINE((x)) >= LOCATION_LINE((y))) -++ -++#define LOCATION_BEFORE2(x, y) \ -++ (LOCATION_LINE((x)) < LOCATION_LINE((y)) || \ -++ (LOCATION_LINE((x)) == LOCATION_LINE((y)) && \ -++ LOCATION_COLUMN((x)) <= LOCATION_COLUMN((y)))) -++#define LOCATION_AFTER2(x, y) \ -++ (LOCATION_LINE((x)) > LOCATION_LINE((y)) || \ -++ (LOCATION_LINE((x)) == LOCATION_LINE((y)) && \ -++ LOCATION_COLUMN((x)) >= LOCATION_COLUMN((y)))) -++ -++#define VAR_NAME_AS_TREE(fname) lookup_name(get_identifier((fname))) -++#define IDENTIFIER_NAME(z) IDENTIFIER_POINTER(DECL_NAME((z))) -++#define BUILD_STRING_AS_TREE(str) build_string_literal(strlen((str)) + 1, (str)) -++ -++#if 0 -++#define DEBUGF(...) fprintf(stderr, " " __VA_ARGS__) -++#define INFORM(...) inform(__VA_ARGS__) -++#else -++#define DEBUGF(...) -++#define INFORM(...) -++#endif -++ -++#define STRING_BUFFER_SIZE 192 -++ -++void handle_pre_genericize(void *, void *); -++ -++#endif /* PORTCOSMO.INTERNAL_H */ -+diff --git a/gcc/c-family/subcontext.cc b/gcc/c-family/subcontext.cc -+new file mode 100644 -+index 000000000..e3e02800d -+--- /dev/null -++++ b/gcc/c-family/subcontext.cc -+@@ -0,0 +1,241 @@ -++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -++╞══════════════════════════════════════════════════════════════════════════════╡ -++│ Copyright © 2022, Gautham Venkatasubramanian │ -++│ │ -++│ Permission to use, copy, modify, and/or distribute this software for │ -++│ any purpose with or without fee is hereby granted, provided that the │ -++│ above copyright notice and this permission notice appear in all copies. │ -++│ │ -++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -++│ PERFORMANCE OF THIS SOFTWARE. │ -++╚─────────────────────────────────────────────────────────────────────────────*/ -++#include "c-family/subcontext.h" -++ -++subu_node *build_subu(const location_t loc, const char *name, -++ unsigned int namelen, SubstType tp) { -++ /* xmalloc because malloc is poisoned by gcc-plugin's system.h */ -++ subu_node *res = (subu_node *)xmalloc(sizeof(subu_node)); -++ res->next = NULL; -++ res->loc = loc; -++ res->name = xstrndup(name, namelen); -++ res->tp = tp; -++ DEBUGF("allocated subu_node at %p\n", res); -++ return res; -++}; -++ -++void delete_subu(subu_node *node) { -++ DEBUGF("freeing subu_node at %p, %u,%u\n", node, LOCATION_LINE(node->loc), -++ LOCATION_COLUMN(node->loc)); -++ node->loc = 0x0; -++ free(node->name); -++ node->next = NULL; -++ node->tp = PORTCOSMO_UNKNOWN; -++ free(node); -++} -++ -++subu_list *init_subu_list() { -++ subu_list *res = (subu_list *)xmalloc(sizeof(subu_list)); -++ res->head = NULL; -++ res->count = 0; -++ res->start = 0; -++ res->end = 0; -++ DEBUGF("allocated subu_list at %p\n", res); -++ return res; -++} -++ -++static void recount_subu_list(subu_list *list) { -++ int i = 0; -++ location_t s = MAX_LOCATION_T; -++ location_t e = 0; -++ subu_node *it; -++ for (it = list->head; it != NULL; it = it->next) { -++ i += 1; -++ /* is it possible to compare for s and e? */ -++ if (s == MAX_LOCATION_T || LOCATION_BEFORE2(it->loc, s)) s = it->loc; -++ if (LOCATION_AFTER2(it->loc, e)) e = it->loc; -++ } -++ if (LOCATION_AFTER2(s, e)) { -++ s = e; -++ } -++ list->start = s; -++ list->end = e; -++ list->count = i; -++ DEBUGF("list with %d subus, start = %u,%u end = %u,%u\n", list->count, -++ LOCATION_LINE(list->start), LOCATION_COLUMN(list->start), -++ LOCATION_LINE(list->end), LOCATION_COLUMN(list->end)); -++} -++ -++void add_subu_elem(subu_list *list, subu_node *node) { -++ subu_node *tmp; -++ if (list->head == NULL) { -++ list->head = node; -++ } else { -++ for (tmp = list->head; tmp->next != NULL; tmp = tmp->next) -++ ; -++ tmp->next = node; -++ node->next = NULL; -++ } -++ recount_subu_list(list); -++} -++ -++void pop_subu_list(subu_list *list) { -++ if (list->head != NULL) { -++ subu_node *tmp = list->head; -++ list->head = list->head->next; -++ delete_subu(tmp); -++ } -++ recount_subu_list(list); -++} -++ -++int valid_subu_bounds(subu_list *list, location_t start, location_t end) { -++ /* return 1 if the bounds of list and provided bounds overlap */ -++ if (LOCATION_BEFORE(list->start, end) && LOCATION_AFTER(list->start, start)) -++ return 1; -++ if (LOCATION_BEFORE(start, list->end) && LOCATION_AFTER(start, list->start)) -++ return 1; -++ return 0; -++} -++ -++int check_loc_in_bound(subu_list *list, location_t loc) { -++ /* return 1 if loc is within the bounds */ -++ if (LOCATION_BEFORE(list->start, loc) && LOCATION_AFTER(list->end, loc)) { -++ return 1; -++ } else { -++ return 0; -++ } -++} -++ -++int get_subu_elem(subu_list *list, location_t loc, subu_node **node) { -++ /* *node is overwritten on returning 1 ie success */ -++ subu_node *it = list->head; -++ for (; it != NULL; it = it->next) { -++ if (LOCATION_APPROX(it->loc, loc)) { -++ *node = it; -++ return 1; -++ } -++ } -++ return 0; -++} -++ -++int get_subu_elem2(subu_list *list, source_range rng, subu_node **node) { -++ /* *node is overwritten on returning 1 ie success */ -++ /* returns the first node found within rng's bounds */ -++ subu_node *it = list->head; -++ for (; it != NULL; it = it->next) { -++ if (LOCATION_BEFORE(rng.m_start, it->loc) && -++ LOCATION_AFTER(rng.m_finish, it->loc)) { -++ *node = it; -++ return 1; -++ } -++ } -++ return 0; -++} -++ -++void remove_subu_elem(subu_list *list, subu_node *node) { -++ subu_node *cur, *prev; -++ if (list->head != NULL) { -++ if (list->head == node) { -++ cur = list->head; -++ list->head = list->head->next; -++ delete_subu(cur); -++ } else { -++ prev = list->head; -++ cur = list->head->next; -++ for (; cur != NULL; prev = cur, cur = cur->next) { -++ if (cur == node) { -++ prev->next = cur->next; -++ delete_subu(cur); -++ break; -++ } -++ } -++ } -++ recount_subu_list(list); -++ } -++} -++ -++void clear_subu_list(subu_list *list) { -++ subu_node *it, *tmp; -++ for (it = list->head; it != NULL;) { -++ tmp = it; -++ it = it->next; -++ delete_subu(tmp); -++ } -++ list->head = NULL; -++ list->count = 0; -++ list->start = 0; -++ list->end = 0; -++} -++ -++void delete_subu_list(subu_list *list) { -++ clear_subu_list(list); -++ free(list); -++ DEBUGF("freeing subu_list at %p\n", list); -++} -++ -++int check_empty_subu_list(subu_list *list, location_t start) { -++ /* we should have modded all locations before start, and so -++ * list should not contain any entries which have a location -++ * before start */ -++ int errcount = 0; -++ for (auto it = list->head; it; it = it->next) { -++ if (start == MAX_LOCATION_T || LOCATION_BEFORE2(it->loc, start)) { -++ error_at(it->loc, "unable to substitute constant\n"); -++ errcount += 1; -++ } -++ } -++ if (errcount != 0) { -++ /* DON'T DELETE! */ -++ clear_subu_list(list); -++ } -++ return errcount == 0; -++} -++ -++void construct_context(SubContext *ctx) { -++ ctx->active = 1; -++ ctx->mods = init_subu_list(); -++ ctx->prev = NULL; -++ ctx->switchcount = 0; -++ ctx->initcount = 0; -++ ctx->subcount = 0; -++} -++ -++void add_context_subu(SubContext *ctx, const location_t loc, const char *defn, -++ unsigned int at, SubstType st) { -++ if (ctx->mods == NULL) return; -++ add_subu_elem(ctx->mods, build_subu(loc, defn, at, st)); -++} -++ -++void check_context_clear(SubContext *ctx, location_t start) { -++ if (ctx->mods) { -++ ctx->active = check_empty_subu_list(ctx->mods, start); -++ } -++} -++ -++void cleanup_context(SubContext *ctx) { -++ check_context_clear(ctx, MAX_LOCATION_T); -++ if (ctx->mods) { -++ delete_subu_list(ctx->mods); -++ ctx->mods = NULL; -++ } -++ ctx->prev = NULL; -++ if (ctx->switchcount > 0) { -++ inform(UNKNOWN_LOCATION, "rewrote %u switch statements", ctx->switchcount); -++ } -++ ctx->switchcount = 0; -++ if (ctx->initcount > 0) { -++ inform(UNKNOWN_LOCATION, "modified %u initializations", ctx->initcount); -++ } -++ ctx->initcount = 0; -++ if (ctx->subcount > 0) { -++ inform(UNKNOWN_LOCATION, "modified %u other macro uses", ctx->subcount); -++ } -++ ctx->subcount = 0; -++ ctx->active = 0; -++} -+diff --git a/gcc/c-family/subcontext.h b/gcc/c-family/subcontext.h -+new file mode 100644 -+index 000000000..558e4fd06 -+--- /dev/null -++++ b/gcc/c-family/subcontext.h -+@@ -0,0 +1,81 @@ -++#ifndef SUBCONTEXT_H -++#define SUBCONTEXT_H -++#include "c-family/portcosmo.internal.h" -++ -++enum SubstType { -++ PORTCOSMO_UNKNOWN = 0, -++ PORTCOSMO_SWCASE = 1, -++ PORTCOSMO_INITVAL = 2 -++}; -++ -++struct _subu_node { -++ /* a node indicating that an ifswitch substitution has occurred. -++ * -++ * Details include: -++ * -++ * - location_t of the substitution -++ * - char* of name of the macro that was substituted (alloc'd) -++ * - whether the substitution was inside a switch statement -++ * - _subu_node* pointer to the next element in the list (NULL if last) -++ * -++ * the idea is that every time one of our modified macros is used, -++ * we record the substitution, and then we delete this record if -++ * we find the appropriate location_t during pre-genericize and -++ * construct the necessary parse trees at that point. -++ * -++ * at the end of compilation (ie PLUGIN_FINISH), there should be -++ * no subu_nodes allocated. -++ */ -++ location_t loc; -++ SubstType tp; -++ char *name; -++ struct _subu_node *next; -++}; -++ -++typedef struct _subu_node subu_node; -++ -++struct _subu_list { -++ subu_node *head; -++ /* inclusive bounds, range containing all recorded substitutions */ -++ location_t start, end; -++ /* number of substitutions */ -++ int count; -++}; -++typedef struct _subu_list subu_list; -++ -++int check_loc_in_bound(subu_list *, location_t); -++int valid_subu_bounds(subu_list *, location_t, location_t); -++int get_subu_elem(subu_list *, location_t, subu_node **); -++int get_subu_elem2(subu_list *, source_range, subu_node **); -++void remove_subu_elem(subu_list *, subu_node *); -++ -++/* Substitution Context */ -++struct SubContext { -++ /* record all macro uses */ -++ subu_list *mods; -++ /* address of the previous statement we walked through, -++ * in case we missed modding it and have to retry */ -++ tree *prev; -++ /* count number of switch statements rewritten */ -++ unsigned int switchcount; -++ /* count number of initializations rewritten */ -++ unsigned int initcount; -++ /* count number of other substitutions rewritten */ -++ unsigned int subcount; -++ /* if zero, it means we haven't started or something -++ * went wrong somewhere */ -++ int active; -++}; -++ -++void add_context_subu(SubContext *, const location_t, const char *, -++ unsigned int, SubstType); -++void construct_context(SubContext *); -++void check_context_clear(SubContext *, location_t); -++void cleanup_context(SubContext *); -++ -++int arg_should_be_unpatched(tree, const subu_node *, tree *); -++ -++/* declaring cosmo_ctx here so initstruct knows it exists */ -++extern struct SubContext cosmo_ctx; -++ -++#endif /* SUBCONTEXT_H */ -+diff --git a/gcc/c-family/unpatch_ast.cc b/gcc/c-family/unpatch_ast.cc -+new file mode 100644 -+index 000000000..56b5b9a01 -+--- /dev/null -++++ b/gcc/c-family/unpatch_ast.cc -+@@ -0,0 +1,115 @@ -++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -++╞══════════════════════════════════════════════════════════════════════════════╡ -++│ Copyright © 2022, Gautham Venkatasubramanian │ -++│ │ -++│ Permission to use, copy, modify, and/or distribute this software for │ -++│ any purpose with or without fee is hereby granted, provided that the │ -++│ above copyright notice and this permission notice appear in all copies. │ -++│ │ -++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -++│ PERFORMANCE OF THIS SOFTWARE. │ -++╚─────────────────────────────────────────────────────────────────────────────*/ -++#include "c-family/ifswitch.h" -++#include "c-family/initstruct.h" -++ -++tree check_usage(tree *tp, int *check_subtree, void *data) { -++ SubContext *ctx = (SubContext *)(data); -++ tree t = *tp; -++ tree z; -++ subu_node *use = NULL; -++ location_t loc = EXPR_LOCATION(t); -++ source_range rng = EXPR_LOCATION_RANGE(t); -++ -++ if (ctx->active == 0 || ctx->mods->count == 0) { -++ /* DEBUGF("substitutions complete\n"); */ -++ *check_subtree = 0; -++ return NULL_TREE; -++ } -++ -++ if (LOCATION_AFTER2(loc, rng.m_start)) { -++ loc = rng.m_start; -++ } else { -++ rng.m_start = loc; -++ } -++ -++ if (ctx->prev && LOCATION_BEFORE2(ctx->mods->start, rng.m_start)) { -++ auto vloc = DECL_SOURCE_LOCATION(DECL_EXPR_DECL(*(ctx->prev))); -++ /* below inequality holds inside this if condition: -++ * vloc <= ctx->mods->start <= rng.m_start -++ * this means that there was a macro substitution -++ * between vloc and rng.m_start, which was not -++ * eliminated when we went through the other parts -++ * of the parse tree earlier. thus, the decl_expr -++ * that we have stored in ctx->prev needs to be -++ * checked for possible macro substitutions */ -++ DEBUGF( -++ "did we miss a decl? vloc=%u,%u, loc=%u,%u, rng.mstart=%u,%u, " -++ "start=%u,%u\n", -++ LOCATION_LINE(vloc), LOCATION_COLUMN(vloc), // -++ LOCATION_LINE(loc), LOCATION_COLUMN(loc), // -++ LOCATION_LINE(rng.m_start), LOCATION_COLUMN(rng.m_start), -++ LOCATION_LINE(ctx->mods->start), LOCATION_COLUMN(ctx->mods->start)); -++ auto z = ctx->initcount; -++ build_modded_declaration(ctx->prev, ctx, rng.m_start); -++ if (z != ctx->initcount) { -++ ctx->prev = NULL; -++ check_context_clear(ctx, loc); -++ } -++ } -++ -++ if (TREE_CODE(t) == DECL_EXPR && TREE_STATIC(DECL_EXPR_DECL(t))) { -++ INFORM(loc, "should we mod this?\n"); -++ ctx->prev = tp; -++ } -++ -++ if (TREE_CODE(t) == SWITCH_STMT) { -++ rng = get_switch_bounds(t); -++ if (valid_subu_bounds(ctx->mods, rng.m_start, rng.m_finish) && -++ count_mods_in_switch(t, ctx->mods) > 0) { -++ /* this is one of the switch statements -++ * where we modified a case label */ -++ DEBUGF("modding the switch \n"); -++ *tp = build_modded_switch_stmt(t, ctx); -++ DEBUGF("we modded it??\n"); -++ walk_tree_without_duplicates(tp, check_usage, ctx); -++ /* due to the above call, I don't need to check -++ * any subtrees from this current location */ -++ *check_subtree = 0; -++ ctx->switchcount += 1; -++ return NULL_TREE; -++ } -++ } -++ -++ return NULL_TREE; -++} -++ -++void handle_pre_genericize(void *gcc_data, void *user_data) { -++ tree t = (tree)gcc_data; -++ SubContext *ctx = (SubContext *)user_data; -++ tree t2; -++ if (ctx->active && TREE_CODE(t) == FUNCTION_DECL && -++ DECL_INITIAL(t) != NULL && TREE_STATIC(t)) { -++ /* this function is defined within the file I'm processing */ -++ if (ctx->mods->count == 0) { -++ // DEBUGF("no substitutions were made in %s\n", IDENTIFIER_NAME(t)); -++ return; -++ } -++ t2 = DECL_SAVED_TREE(t); -++ ctx->prev = NULL; -++ walk_tree_without_duplicates(&t2, check_usage, ctx); -++ /* now at this stage, all uses of our macros have been -++ * fixed, INCLUDING case labels. Let's confirm that: */ -++ check_context_clear(ctx, MAX_LOCATION_T); -++ } -++} -++ -++void portcosmo_pre_genericize(void *gcc_data) { -++ handle_pre_genericize(gcc_data, (void *)(&cosmo_ctx)); -++} -+diff --git a/gcc/c-family/unpatch_int.cc b/gcc/c-family/unpatch_int.cc -+new file mode 100644 -+index 000000000..08c96b544 -+--- /dev/null -++++ b/gcc/c-family/unpatch_int.cc -+@@ -0,0 +1,63 @@ -++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -++╞══════════════════════════════════════════════════════════════════════════════╡ -++│ Copyright © 2022, Gautham Venkatasubramanian │ -++│ │ -++│ Permission to use, copy, modify, and/or distribute this software for │ -++│ any purpose with or without fee is hereby granted, provided that the │ -++│ above copyright notice and this permission notice appear in all copies. │ -++│ │ -++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -++│ PERFORMANCE OF THIS SOFTWARE. │ -++╚─────────────────────────────────────────────────────────────────────────────*/ -++#include "c-family/subcontext.h" -++ -++int arg_should_be_unpatched(tree arg, const subu_node *use, tree *rep_ptr) { -++ /* if we are returning 1, rep_ptr has been set. -++ * if we are returning 0, rep_ptr is unchanged. -++ * use is not affected! */ -++ if (TREE_CODE(arg) == INTEGER_CST) { -++ tree vx = DECL_INITIAL(get_ifsw_identifier(use->name)); -++ if (tree_int_cst_equal(arg, vx)) { -++ /* if this is an integer constant, AND its -++ * value is equal to the macro we substituted, -++ * then we replace the correct variable here */ -++ *rep_ptr = -++ build1(NOP_EXPR, integer_type_node, VAR_NAME_AS_TREE(use->name)); -++ INFORM(use->loc, "unpatched an integer here with %s\n", use->name); -++ return 1; -++ } -++ /* here you might want to handle some -++ * minimal constant folding algebra, -++ * like -VAR or ~VAR */ -++ if (tree_fits_poly_int64_p(vx) && tree_fits_poly_int64_p(arg)) { -++ auto v1 = tree_to_poly_int64(vx); -++ auto v2 = tree_to_poly_int64(arg); -++ -++ /* handle the -VAR case */ -++ if (known_eq(v1, -v2)) { -++ INFORM(use->loc, "unpatched an integer here with -%s\n", use->name); -++ *rep_ptr = -++ build1(NEGATE_EXPR, integer_type_node, VAR_NAME_AS_TREE(use->name)); -++ return 1; -++ } -++ -++ /* handle the ~VAR case */ -++ if (known_eq(v1, ~v2)) { -++ INFORM(use->loc, "unpatched an integer here with ~%s\n", use->name); -++ *rep_ptr = build1(BIT_NOT_EXPR, integer_type_node, -++ VAR_NAME_AS_TREE(use->name)); -++ return 1; -++ } -++ } -++ return 0; -++ } -++ -++ return 0; -++} -+diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in -+index a1cdee872..ce57e8a27 100644 -+--- a/gcc/c/Make-lang.in -++++ b/gcc/c/Make-lang.in -+@@ -55,8 +55,10 @@ C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \ -+ c/c-fold.o c/gimple-parser.o \ -+ $(C_COMMON_OBJS) $(C_TARGET_OBJS) -+ -++PORTCOSMO_C_OBJS = c/portcosmo_bcref.o -++ -+ # Language-specific object files for C. -+-C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS) -++C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS) $(PORTCOSMO_C_OBJS) -+ c_OBJS = $(C_OBJS) cc1-checksum.o c/gccspec.o -+ -+ # Use strict warnings for this front end. -+diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c -+index 53b2b5b63..51f3a72e5 100644 -+--- a/gcc/c/c-decl.c -++++ b/gcc/c/c-decl.c -+@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3. If not see -+ #include "c-family/name-hint.h" -+ #include "c-family/known-headers.h" -+ #include "c-family/c-spellcheck.h" -++#include "c-family/portcosmo.h" -+ #include "context.h" /* For 'g'. */ -+ #include "omp-general.h" -+ #include "omp-offload.h" /* For offload_vars. */ -+@@ -5685,6 +5686,9 @@ finish_decl (tree decl, location_t init_loc, tree init, -+ && !DECL_HARD_REGISTER (decl)) -+ targetm.lower_local_decl_alignment (decl); -+ -++ if(flag_portcosmo) { -++ portcosmo_finish_decl(decl); -++ } -+ invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); -+ } -+ -+@@ -10277,6 +10281,10 @@ finish_function (location_t end_loc) -+ { -+ if (!decl_function_context (fndecl)) -+ { -++ if (flag_portcosmo) -++ { -++ portcosmo_pre_genericize(fndecl); -++ } -+ invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl); -+ c_genericize (fndecl); -+ -+diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c -+index b5d139e5d..2df309eba 100644 -+--- a/gcc/c/c-typeck.c -++++ b/gcc/c/c-typeck.c -+@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see -+ #include "omp-general.h" -+ #include "c-family/c-objc.h" -+ #include "c-family/c-ubsan.h" -++#include "c-family/portcosmo.h" -+ #include "gomp-constants.h" -+ #include "spellcheck-tree.h" -+ #include "gcc-rich-location.h" -+@@ -8170,8 +8171,17 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, -+ && !initializer_constant_valid_p (inside_init, -+ TREE_TYPE (inside_init))) -+ { -+- error_init (init_loc, "initializer element is not constant"); -+- inside_init = error_mark_node; -++ if (flag_portcosmo) { -++ inside_init = patch_init_nonconst(init_loc, inside_init); -++ if (inside_init == NULL_TREE) { -++ error_init (init_loc, "initializer element is not constant"); -++ inside_init = error_mark_node; -++ } -++ } -++ else { -++ error_init (init_loc, "initializer element is not constant"); -++ inside_init = error_mark_node; -++ } -+ } -+ else if (require_constant && !maybe_const) -+ pedwarn_init (init_loc, OPT_Wpedantic, -+@@ -9787,7 +9797,7 @@ output_init_element (location_t loc, tree value, tree origtype, -+ /* Proceed to check the constness of the original initializer. */ -+ if (!initializer_constant_valid_p (value, TREE_TYPE (value))) -+ { -+- if (require_constant_value) -++ if (require_constant_value && !flag_portcosmo) -+ { -+ error_init (loc, "initializer element is not constant"); -+ value = error_mark_node; -+diff --git a/gcc/c/portcosmo_bcref.cc b/gcc/c/portcosmo_bcref.cc -+new file mode 100644 -+index 000000000..2c6a58296 -+--- /dev/null -++++ b/gcc/c/portcosmo_bcref.cc -+@@ -0,0 +1,30 @@ -++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -++╞══════════════════════════════════════════════════════════════════════════════╡ -++│ Copyright © 2022, Gautham Venkatasubramanian │ -++│ │ -++│ Permission to use, copy, modify, and/or distribute this software for │ -++│ any purpose with or without fee is hereby granted, provided that the │ -++│ above copyright notice and this permission notice appear in all copies. │ -++│ │ -++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -++│ PERFORMANCE OF THIS SOFTWARE. │ -++╚─────────────────────────────────────────────────────────────────────────────*/ -++#include "c-family/initstruct.h" -++ -++/* initstruct/common.cc */ -++ -++tree access_at(tree obj, tree ind) { -++ if (TREE_CODE(TREE_TYPE(obj)) == ARRAY_TYPE) { -++ return build_array_ref(input_location, obj, ind); -++ } -++ return build_component_ref(input_location, obj, -++ get_identifier(IDENTIFIER_NAME(ind)), -++ DECL_SOURCE_LOCATION(ind)); -++} -+diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in -+index 155be74ef..2fe9484ff 100644 -+--- a/gcc/cp/Make-lang.in -++++ b/gcc/cp/Make-lang.in -+@@ -84,6 +84,10 @@ g++-cross$(exeext): xg++$(exeext) -+ CXX_C_OBJS = attribs.o incpath.o \ -+ $(C_COMMON_OBJS) $(CXX_TARGET_OBJS) -+ -++# initstruct has some issues building with cc1plus, -++# so we provide nothing for now -++PORTCOSMO_CXX_OBJS = cp/portcosmo_bcref_cp.o -++ -+ # Language-specific object files for C++ and Objective C++. -+ CXX_AND_OBJCXX_OBJS = \ -+ cp/call.o cp/class.o cp/constexpr.o cp/constraint.o \ -+@@ -101,7 +105,7 @@ CXX_AND_OBJCXX_OBJS = \ -+ cp/rtti.o \ -+ cp/search.o cp/semantics.o \ -+ cp/tree.o cp/typeck.o cp/typeck2.o \ -+- cp/vtable-class-hierarchy.o $(CXX_C_OBJS) -++ cp/vtable-class-hierarchy.o $(CXX_C_OBJS) $(PORTCOSMO_CXX_OBJS) -+ -+ ifeq ($(if $(wildcard ../stage_current),$(shell cat \ -+ ../stage_current)),stageautofeedback) -+diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c -+index 5e101ffb8..1f68dddbf 100644 -+--- a/gcc/cp/decl.c -++++ b/gcc/cp/decl.c -+@@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see -+ #include "context.h" /* For 'g'. */ -+ #include "omp-general.h" -+ #include "omp-offload.h" /* For offload_vars. */ -++#include "c-family/portcosmo.h" -+ -+ /* Possible cases of bad specifiers type used by bad_specifiers. */ -+ enum bad_spec_place { -+@@ -8246,6 +8247,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, -+ && !DECL_HARD_REGISTER (decl)) -+ targetm.lower_local_decl_alignment (decl); -+ -++ if (flag_portcosmo) { -++ portcosmo_finish_decl(decl); -++ } -+ invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); -+ } -+ -+@@ -17459,8 +17463,13 @@ finish_function (bool inline_p) -+ maybe_save_constexpr_fundef (fndecl); -+ -+ /* Invoke the pre-genericize plugin before we start munging things. */ -+- if (!processing_template_decl) -++ if (!processing_template_decl) { -++ if (flag_portcosmo) -++ { -++ portcosmo_pre_genericize(fndecl); -++ } -+ invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl); -++ } -+ -+ /* Perform delayed folding before NRV transformation. */ -+ if (!processing_template_decl -+diff --git a/gcc/cp/portcosmo_bcref_cp.cc b/gcc/cp/portcosmo_bcref_cp.cc -+new file mode 100644 -+index 000000000..bf01d9aeb -+--- /dev/null -++++ b/gcc/cp/portcosmo_bcref_cp.cc -+@@ -0,0 +1,42 @@ -++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -++╞══════════════════════════════════════════════════════════════════════════════╡ -++│ Copyright © 2022, Gautham Venkatasubramanian │ -++│ │ -++│ Permission to use, copy, modify, and/or distribute this software for │ -++│ any purpose with or without fee is hereby granted, provided that the │ -++│ above copyright notice and this permission notice appear in all copies. │ -++│ │ -++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -++│ PERFORMANCE OF THIS SOFTWARE. │ -++╚─────────────────────────────────────────────────────────────────────────────*/ -++#include "config.h" -++#include "system.h" -++#include "coretypes.h" -++#include "target.h" -++#include "c-family/c-target.h" -++#include "cp-tree.h" -++#include "tree.h" -++#include "stringpool.h" -++ -++#define IDENTIFIER_NAME(z) IDENTIFIER_POINTER(DECL_NAME((z))) -++ -++/* initstruct/common.cc */ -++ -++tree access_at(tree obj, tree ind) { -++ return cp_build_addr_expr(ind, 0); -++ /* -++ if (TREE_CODE(TREE_TYPE(obj)) == ARRAY_TYPE) { -++ return build_array_ref(input_location, obj, ind); -++ } -++ return build_component_ref(input_location, obj, -++ get_identifier(IDENTIFIER_NAME(ind)), -++ DECL_SOURCE_LOCATION(ind)); -++ */ -++} +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index 8a5fb3fd9..3a7498db8 100644 +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in +@@ -1231,6 +1231,10 @@ GCC_OBJS = gcc.o gcc-main.o ggc-none.o + + c-family-warn = $(STRICT_WARN) + ++PORTCOSMO_OBJS = c-family/portcosmo.o c-family/subcontext.o\ ++ c-family/initstruct.o c-family/ifswitch.o \ ++ c-family/unpatch_int.o c-family/unpatch_ast.o + + # Language-specific object files shared by all C-family front ends. + C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ + c-family/c-format.o c-family/c-gimplify.o c-family/c-indentation.o \ +@@ -1238,7 +1242,8 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ + c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \ + c-family/c-semantics.o c-family/c-ada-spec.o \ + c-family/c-ubsan.o c-family/known-headers.o \ +- c-family/c-attribs.o c-family/c-warn.o c-family/c-spellcheck.o ++ c-family/c-attribs.o c-family/c-warn.o c-family/c-spellcheck.o \ ++ $(PORTCOSMO_OBJS) + + # Analyzer object files + ANALYZER_OBJS = \ +diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c +index d227686a0..a1d4c81ec 100644 +--- a/gcc/c-family/c-common.c ++++ b/gcc/c-family/c-common.c +@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see + #include "c-spellcheck.h" + #include "selftest.h" + #include "debug.h" ++#include "c-family/portcosmo.h" + + cpp_reader *parse_in; /* Declared in c-pragma.h. */ + +@@ -2112,8 +2113,16 @@ check_case_value (location_t loc, tree value) + value = perform_integral_promotions (value); + else if (value != error_mark_node) + { +- error_at (loc, "case label does not reduce to an integer constant"); +- value = error_mark_node; ++ if (flag_portcosmo) { ++ value = patch_case_nonconst(loc, value); ++ if (value == NULL_TREE) { ++ error_at (loc, "case label does not reduce to an integer constant"); ++ value = error_mark_node; ++ } ++ } else { ++ error_at (loc, "case label does not reduce to an integer constant"); ++ value = error_mark_node; ++ } + } + + constant_expression_warning (value); +diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c +index 89e05a4c5..15c26f507 100644 +--- a/gcc/c-family/c-opts.c ++++ b/gcc/c-family/c-opts.c +@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see + #include "mkdeps.h" + #include "dumpfile.h" + #include "file-prefix-map.h" /* add_*_prefix_map() */ ++#include "c-family/portcosmo.h" + + #ifndef DOLLARS_IN_IDENTIFIERS + # define DOLLARS_IN_IDENTIFIERS true +@@ -1131,6 +1132,10 @@ c_common_post_options (const char **pfilename) + cpp_post_options (parse_in); + init_global_opts_from_cpp (&global_options, cpp_get_options (parse_in)); + ++ if (flag_portcosmo) ++ { ++ portcosmo_setup(); ++ } + input_location = UNKNOWN_LOCATION; + + *pfilename = this_input_filename +@@ -1281,6 +1286,10 @@ c_common_finish (void) + /* For performance, avoid tearing down cpplib's internal structures + with cpp_destroy (). */ + cpp_finish (parse_in, deps_stream); ++ if(flag_portcosmo) ++ { ++ portcosmo_teardown(); ++ } + + if (deps_stream && deps_stream != out_stream && deps_stream != stdout + && (ferror (deps_stream) || fclose (deps_stream))) +@@ -1288,6 +1297,7 @@ c_common_finish (void) + + if (out_stream && (ferror (out_stream) || fclose (out_stream))) + fatal_error (input_location, "when writing output to %s: %m", out_fname); ++ + } + + /* Either of two environment variables can specify output of +diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt +index 2005b783c..a69a9a349 100644 +--- a/gcc/c-family/c.opt ++++ b/gcc/c-family/c.opt +@@ -1881,6 +1881,10 @@ fopenmp-simd + C ObjC C++ ObjC++ Var(flag_openmp_simd) + Enable OpenMP's SIMD directives. + ++fportcosmo ++C C++ RejectNegative Var(flag_portcosmo) ++Enable AST rewriting for Cosmopolitan Libc magic numbers. ++ + foperator-names + C++ ObjC++ + Recognize C++ keywords like \"compl\" and \"xor\". +diff --git a/gcc/c-family/ifswitch.cc b/gcc/c-family/ifswitch.cc +new file mode 100644 +index 000000000..0dab740f1 +--- /dev/null ++++ b/gcc/c-family/ifswitch.cc +@@ -0,0 +1,226 @@ ++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ ++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ++╞══════════════════════════════════════════════════════════════════════════════╡ ++│ Copyright © 2022, Gautham Venkatasubramanian │ ++│ │ ++│ Permission to use, copy, modify, and/or distribute this software for │ ++│ any purpose with or without fee is hereby granted, provided that the │ ++│ above copyright notice and this permission notice appear in all copies. │ ++│ │ ++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ ++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ ++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ ++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ ++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ ++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ ++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ ++│ PERFORMANCE OF THIS SOFTWARE. │ ++╚─────────────────────────────────────────────────────────────────────────────*/ ++#include "c-family/ifswitch.h" ++ ++static tree get_switch_body(tree swexpr) { ++ auto body = SWITCH_STMT_BODY(swexpr); ++ if (TREE_CODE(body) == BIND_EXPR) { ++ body = BIND_EXPR_BODY(body); ++ } ++ return body; ++} ++ ++source_range get_switch_bounds(tree sws) { ++ auto body = get_switch_body(sws); ++ source_range rng; ++ rng.m_start = MAX_LOCATION_T; ++ rng.m_finish = MAX_LOCATION_T; ++ if (STATEMENT_LIST_HEAD(body) && STATEMENT_LIST_TAIL(body)) { ++ /* otherwise this is an empty switch statement */ ++ auto rng1 = EXPR_LOCATION_RANGE(STATEMENT_LIST_HEAD(body)->stmt); ++ auto rng2 = EXPR_LOCATION_RANGE(STATEMENT_LIST_TAIL(body)->stmt); ++ rng.m_start = rng1.m_start; ++ rng.m_finish = rng2.m_finish; ++ } ++ return rng; ++} ++ ++unsigned int count_mods_in_switch(tree swexpr, subu_list *list) { ++ tree body = get_switch_body(swexpr); ++ tree t = NULL_TREE; ++ tree replacement = NULL_TREE; ++ subu_node *use = NULL; ++ unsigned int count = 0; ++ for (auto i = tsi_start(body); !tsi_end_p(i); tsi_next(&i)) { ++ t = tsi_stmt(i); ++ if (TREE_CODE(t) == CASE_LABEL_EXPR) { ++ if (get_subu_elem(list, EXPR_LOCATION(t), ++ &use) /* on a line we substituted */ ++ && CASE_LOW(t) != NULL_TREE /* not a x..y range */ ++ && CASE_HIGH(t) == NULL_TREE /* not a default */ ++ && arg_should_be_unpatched(CASE_LOW(t), use, &replacement) ++ /* the case is the one we substituted */) { ++ DEBUGF("we substituted a case label at %u,%u\n", EXPR_LOC_LINE(t), ++ EXPR_LOC_COL(t)); ++ count += 1; ++ } ++ } ++ } ++ return count; ++} ++ ++tree build_modded_label(unsigned int swcount, const char *case_str, ++ location_t loc = UNKNOWN_LOCATION) { ++ char dest[STRING_BUFFER_SIZE] = {0}; ++ snprintf(dest, sizeof(dest), "__tmpcosmo_%u_%s", swcount, case_str); ++ tree lab = build_decl(loc, LABEL_DECL, get_identifier(dest), void_type_node); ++ /* gcc's GIMPLE needs to know that this label ++ * is within the current function declaration */ ++ DECL_CONTEXT(lab) = current_function_decl; ++ return build1(LABEL_EXPR, void_type_node, lab); ++} ++ ++tree build_modded_exit_label(unsigned int swcount) { ++ return build_modded_label(swcount, "__end"); ++} ++ ++static inline tree build_modded_if_stmt(tree condition, tree then_clause, ++ tree else_clause = NULL_TREE) { ++ return build3(COND_EXPR, void_type_node, condition, then_clause, else_clause); ++} ++ ++tree modded_case_label(tree t, unsigned int i, tree swcond, vec *&ifs, ++ SubContext *ctx, tree *default_label) { ++ tree result; ++ tree replacement = NULL_TREE; ++ subu_node *use = NULL; ++ char case_str[STRING_BUFFER_SIZE] = {0}; ++ ++ if (CASE_LOW(t) == NULL_TREE) { ++ DEBUGF("default case\n"); ++ /* default label of the switch case, needs to be last */ ++ result = build_modded_label(ctx->switchcount, "__dflt", EXPR_LOCATION(t)); ++ *default_label = result; ++ } else if (CASE_LOW(t) != NULL_TREE && CASE_HIGH(t) == NULL_TREE) { ++ /* a case label */ ++ if (get_subu_elem(ctx->mods, EXPR_LOCATION(t), &use) ++ /* the case is on a line we substituted */ ++ && arg_should_be_unpatched(CASE_LOW(t), use, &replacement) ++ /* the case value is the one we substituted */) { ++ DEBUGF("modded case\n"); ++ result = ++ build_modded_label(ctx->switchcount, use->name, EXPR_LOCATION(t)); ++ ifs->safe_push(build_modded_if_stmt( ++ build2(EQ_EXPR, integer_type_node, swcond, replacement), ++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(result)))); ++ remove_subu_elem(ctx->mods, use); ++ replacement = NULL_TREE; ++ } else { ++ /* a case label that we didn't substitute */ ++ DEBUGF("unmodded case\n"); ++ snprintf(case_str, sizeof(case_str), "%x_", i); ++ result = build_modded_label(ctx->switchcount, case_str, EXPR_LOCATION(t)); ++ ifs->safe_push(build_modded_if_stmt( ++ build2(EQ_EXPR, integer_type_node, swcond, CASE_LOW(t)), ++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(result)))); ++ } ++ } else { ++ DEBUGF("unmodded case range\n"); ++ /* CASE_LOW(t) != NULL_TREE && CASE_HIGH(t) != NULL_TREE */ ++ /* this is a case x .. y sort of range */ ++ snprintf(case_str, sizeof(case_str), "%x_", i); ++ result = build_modded_label(ctx->switchcount, case_str, EXPR_LOCATION(t)); ++ ifs->safe_push(build_modded_if_stmt( ++ build2(TRUTH_ANDIF_EXPR, integer_type_node, ++ build2(GE_EXPR, integer_type_node, swcond, CASE_LOW(t)), ++ build2(LE_EXPR, integer_type_node, swcond, CASE_HIGH(t))), ++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(result)))); ++ } ++ return result; ++} ++ ++tree build_modded_switch_stmt(tree swexpr, SubContext *ctx) { ++ int case_count = 0, break_count = 0; ++ int has_default = 0; ++ ++ tree swcond = save_expr(SWITCH_STMT_COND(swexpr)); ++ tree swbody = get_switch_body(swexpr); ++ tree *tp = NULL; ++ char dest[STRING_BUFFER_SIZE] = {0}; ++ ++ vec *ifs; ++ vec_alloc(ifs, 0); ++ ++ tree exit_label = build_modded_exit_label(ctx->switchcount); ++ tree default_label = NULL_TREE; ++ ++ for (auto it = tsi_start(swbody); !tsi_end_p(it); tsi_next(&it)) { ++ tp = tsi_stmt_ptr(it); ++ if (TREE_CODE(*tp) == CASE_LABEL_EXPR) { ++ case_count += 1; ++ has_default = has_default || (CASE_LOW(*tp) == NULL_TREE); ++ /* replace the case statement with a goto */ ++ *tp = ++ modded_case_label(*tp, case_count, swcond, ifs, ctx, &default_label); ++ } else if (TREE_CODE(*tp) == BREAK_STMT) { ++ break_count += 1; ++ /* replace the break statement with a goto to the end */ ++ *tp = build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(exit_label)); ++ } else if (TREE_CODE(*tp) == BIND_EXPR) { ++ for (auto it2 = tsi_start(BIND_EXPR_BODY(*tp)); !tsi_end_p(it2); ++ tsi_next(&it2)) { ++ auto tp2 = tsi_stmt_ptr(it2); ++ if (TREE_CODE(*tp2) == BREAK_STMT) { ++ break_count += 1; ++ /* replace the break statement with a goto to the end */ ++ *tp2 = ++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(exit_label)); ++ } ++ } ++ } ++ } ++ /* add all the if statements to the start of the switch body */ ++ /* TODO: do we have to combine them via COND_EXPR_ELSE? why, ++ * is it not possible to have them as a list one after the other? */ ++ tree res; ++ unsigned int zz = 0; ++ if (ifs->length() > 0) { ++ res = (*ifs)[0]; ++ for (zz = 1; zz < ifs->length(); ++zz) { ++ COND_EXPR_ELSE(res) = (*ifs)[zz]; ++ res = (*ifs)[zz]; ++ } ++ /* if we have a valid default for the switch, ++ * it should be the final else branch */ ++ if (default_label && default_label != NULL_TREE) { ++ COND_EXPR_ELSE(res) = ++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(default_label)); ++ } else { ++ /* if we don't have a default, then the final else branch ++ * should just jump to after the switch */ ++ COND_EXPR_ELSE(res) = ++ build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(exit_label)); ++ } ++ /* reset to the start of the if-else tree */ ++ res = (*ifs)[0]; ++ } else if (has_default && default_label != NULL_TREE) { ++ /* this switch has only a default? ok... */ ++ res = build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(default_label)); ++ } else { ++ /* this switch has no cases, and no default?! */ ++ warning_at(EXPR_LOCATION(swcond), 0, "switch without cases or default?"); ++ res = build1(GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL(exit_label)); ++ } ++ auto it = tsi_start(swbody); ++ tsi_link_before(&it, res, TSI_SAME_STMT); ++ tsi_link_before(&it, build_empty_stmt(UNKNOWN_LOCATION), TSI_SAME_STMT); ++ ++ /* add the 'outside' of the switch, ie the 'finally' ++ * aka the target of the break statements, the 'exit_label', ++ * to the end of the switch body */ ++ append_to_statement_list(build_empty_stmt(UNKNOWN_LOCATION), &swbody); ++ append_to_statement_list(exit_label, &swbody); ++ append_to_statement_list(build_empty_stmt(UNKNOWN_LOCATION), &swbody); ++ ++ /* we are returning SWITCH_STMT_BODY(swexpr), ++ * instead of just swbody, because sometimes, ++ * SWITCH_STMT_BODY(swexpr) may be a BIND_EXPR ++ * that has some scoping-related information. */ ++ return SWITCH_STMT_BODY(swexpr); ++} +diff --git a/gcc/c-family/ifswitch.h b/gcc/c-family/ifswitch.h +new file mode 100644 +index 000000000..ccf78067f +--- /dev/null ++++ b/gcc/c-family/ifswitch.h +@@ -0,0 +1,10 @@ ++#ifndef IFSWITCH_H ++#define IFSWITCH_H ++#include "c-family/portcosmo.internal.h" ++#include "c-family/subcontext.h" ++ ++source_range get_switch_bounds(tree); ++unsigned int count_mods_in_switch(tree, subu_list *); ++tree build_modded_switch_stmt(tree, SubContext *); ++ ++#endif /* IFSWITCH_H */ +diff --git a/gcc/c-family/initstruct.cc b/gcc/c-family/initstruct.cc +new file mode 100644 +index 000000000..b0162406c +--- /dev/null ++++ b/gcc/c-family/initstruct.cc +@@ -0,0 +1,396 @@ ++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ ++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ++╞══════════════════════════════════════════════════════════════════════════════╡ ++│ Copyright © 2022, Gautham Venkatasubramanian │ ++│ │ ++│ Permission to use, copy, modify, and/or distribute this software for │ ++│ any purpose with or without fee is hereby granted, provided that the │ ++│ above copyright notice and this permission notice appear in all copies. │ ++│ │ ++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ ++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ ++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ ++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ ++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ ++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ ++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ ++│ PERFORMANCE OF THIS SOFTWARE. │ ++╚─────────────────────────────────────────────────────────────────────────────*/ ++#include "c-family/initstruct.h" ++ ++void portcosmo_finish_decl(void *gcc_data) { ++ handle_decl(gcc_data, (void *)(&cosmo_ctx)); ++} ++ ++void set_values_based_on_ctor(tree ctor, subu_list *list, tree body, tree lhs, ++ location_t bound) { ++ subu_node *use = NULL; ++ unsigned int iprev = 0; ++ bool started = true; ++ tree replacement = NULL_TREE; ++ ++ while (list->count > 0 && LOCATION_BEFORE2(list->start, bound)) { ++ tree index = NULL_TREE; ++ tree val = NULL_TREE; ++ unsigned int i = 0; ++ int found = 0; ++ FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(ctor), i, index, val) { ++ DEBUGF("value %u is %s\n", i, get_tree_code_str(val)); ++ if (!started && i <= iprev) continue; ++ if (TREE_CODE(val) == INTEGER_CST) { ++ for (use = list->head; use; use = use->next) { ++ found = arg_should_be_unpatched(val, use, &replacement); ++ if (found) break; ++ } ++ if (found) { ++ iprev = i; ++ started = false; ++ break; ++ } ++ } else if (TREE_CODE(val) == CONSTRUCTOR) { ++ auto sub = access_at(lhs, index); ++ set_values_based_on_ctor(val, list, body, sub, bound); ++ use = NULL; /* might've gotten stomped */ ++ if (list->count == 0) return; ++ get_subu_elem(list, list->start, &use); ++ } ++ } ++ if (found) { ++ auto modexpr = build2(MODIFY_EXPR, TREE_TYPE(index), ++ access_at(lhs, index), replacement); ++ append_to_statement_list(modexpr, &body); ++ remove_subu_elem(list, use); ++ replacement = NULL_TREE; ++ DEBUGF("found; %d left\n", list->count); ++ } else { ++ /* we did not find any (more) substitutions to fix */ ++ DEBUGF("exiting; %d left\n", list->count); ++ break; ++ } ++ } ++} ++ ++/* initstruct/global.cc */ ++ ++void update_global_decls(tree dcl, SubContext *ctx) { ++ tree body = alloc_stmt_list(); ++ subu_node *use = NULL; ++ char chk[STRING_BUFFER_SIZE]; ++ ++ /* dcl, the global declaration we have is like these: ++ * ++ * static int foo = __tmpcosmo_VAR; ++ * static struct toy myvalue = {.x=1, .y=__tmpcosmo_VAR}; ++ * ++ * we're going to add functions as follows: ++ * ++ * static int foo = __tmpcosmo_VAR; ++ * __attribute__((constructor)) __hidden_ctor1() { ++ * foo = VAR; ++ * } ++ * static struct toy myvalue = {.x=1, .y=__tmpcosmo_VAR}; ++ * __attribute__((constructor)) __hidden_ctor2() { ++ * myvalue.y = VAR; ++ * } ++ * ++ * the modifier functions have the constructor attribute, ++ * so it they run before anything uses the static. it ++ * works recursively too: you can have a struct of structs, ++ * an array of structs, whatever, and it will figure out ++ * where the substitutions are and attempt to mod them. ++ * ++ * a unique constructor for each declaration. probably ++ * we could have a common constructor for the entire ++ * file, but that's left as an exercise for the reader. */ ++ if (INTEGRAL_TYPE_P(TREE_TYPE(dcl)) && ++ get_subu_elem(ctx->mods, ctx->mods->start, &use) && ++ /* use is non-NULL if get_subu_elem succeeds */ ++ check_magic_equal(DECL_INITIAL(dcl), use->name)) { ++ if (TREE_READONLY(dcl)) { ++ error_at(EXPR_LOCATION(dcl), "cannot substitute this constant\n"); ++ /* actually I can, but the issue is if one of gcc's optimizations ++ * perform constant folding(and they do), I don't know all the spots ++ * where this variable has been folded, so I can't substitute there */ ++ ctx->active = 0; ++ return; ++ } ++ append_to_statement_list( ++ build2(MODIFY_EXPR, void_type_node, dcl, VAR_NAME_AS_TREE(use->name)), ++ &body); ++ remove_subu_elem(ctx->mods, use); ++ cgraph_build_static_cdtor('I', body, 0); ++ } else if ((RECORD_TYPE == TREE_CODE(TREE_TYPE(dcl)) || ++ ARRAY_TYPE == TREE_CODE(TREE_TYPE(dcl))) && ++ DECL_INITIAL(dcl) != NULL_TREE) { ++ if (TREE_READONLY(dcl)) { ++ warning_at(DECL_SOURCE_LOCATION(dcl), 0, ++ "not sure if modding const structs is good\n"); ++ TREE_READONLY(dcl) = 0; ++ } ++ if (LOCATION_BEFORE2(ctx->mods->end, input_location)) { ++ set_values_based_on_ctor(DECL_INITIAL(dcl), ctx->mods, body, dcl, ++ input_location); ++ } else { ++ set_values_based_on_ctor(DECL_INITIAL(dcl), ctx->mods, body, dcl, ++ ctx->mods->end); ++ } ++ cgraph_build_static_cdtor('I', body, 0); ++ DEBUGF("uploaded ctor\n"); ++ } ++} ++ ++void handle_decl(void *gcc_data, void *user_data) { ++ tree t = (tree)gcc_data; ++ SubContext *ctx = (SubContext *)user_data; ++ if (TREE_CODE(t) != VAR_DECL) return; ++ if (ctx->active && ctx->mods->count > 0 && DECL_INITIAL(t) != NULL && ++ DECL_CONTEXT(t) == NULL_TREE) { ++ int internal_use = ++ !strncmp(IDENTIFIER_NAME(t), "__tmpcosmo_", strlen("__tmpcosmo_")); ++ if (internal_use || DECL_EXTERNAL(t)) { ++ error_at(input_location, "the ACTUALLY is before the declaration!\n"); ++ ctx->active = 0; ++ return; ++ } ++ auto rng = EXPR_LOCATION_RANGE(t); ++ rng.m_start = DECL_SOURCE_LOCATION(t); ++ rng.m_finish = input_location; ++ ++ DEBUGF("handle_decl with %s %u,%u - %u-%u\n", IDENTIFIER_NAME(t), ++ LOCATION_LINE(rng.m_start), LOCATION_COLUMN(rng.m_start), ++ LOCATION_LINE(rng.m_finish), LOCATION_COLUMN(rng.m_finish)); ++ ctx->initcount += ctx->mods->count; ++ update_global_decls(t, ctx); ++ /* now at this stage, all uses of our macros have been ++ * fixed, INCLUDING case labels. Let's confirm that: */ ++ check_context_clear(ctx, MAX_LOCATION_T); ++ } ++} ++ ++/* initstruct/local.cc */ ++ ++static inline tree build_modded_if_stmt(tree condition, tree then_clause, ++ tree else_clause = NULL_TREE) { ++ return build3(COND_EXPR, void_type_node, condition, then_clause, else_clause); ++} ++ ++int build_modded_int_declaration(tree *dxpr, SubContext *ctx, subu_node *use) { ++ char chk[STRING_BUFFER_SIZE]; ++ tree dcl = DECL_EXPR_DECL(*dxpr); ++ tree replacement = NULL_TREE; ++ ++ if (INTEGRAL_TYPE_P(TREE_TYPE(dcl)) && ++ arg_should_be_unpatched(DECL_INITIAL(dcl), use, &replacement)) { ++ if (TREE_READONLY(dcl)) { ++ error_at(EXPR_LOCATION(dcl), "cannot substitute this constant\n"); ++ /* actually I can, but the issue is if one of gcc's optimizations ++ * perform constant folding(and they do), I don't know all the spots ++ * where this variable has been folded, so I can't substitute there */ ++ ctx->active = 0; ++ return 0; ++ } ++ ++ if (!TREE_STATIC(dcl)) { ++ DECL_INITIAL(dcl) = replacement; ++ remove_subu_elem(ctx->mods, use); ++ replacement = NULL_TREE; ++ return 1; ++ } ++ ++ DEBUGF("fixing decl for a static integer\n"); ++ /* (*dxpr), the statement we have is this: ++ * ++ * static int myvalue = __tmpcosmo_VAR; ++ * ++ * we're going to modify it to this: ++ * ++ * static int myvalue = __tmpcosmo_VAR; ++ * static uint8 __chk_ifs_myvalue = 0; ++ * if(__chk_ifs_myvalue != 1) { ++ * __chk_ifs_myvalue = 1; ++ * myvalue = VAR; ++ * } ++ * ++ * so the modified statement runs exactly once, ++ * whenever the function is first called, right ++ * after the initialization of the variable we ++ * wanted to modify. */ ++ ++ /* build __chk_ifs_myvalue */ ++ snprintf(chk, sizeof(chk), "__chk_ifs_%s", IDENTIFIER_NAME(dcl)); ++ tree chknode = build_decl(DECL_SOURCE_LOCATION(dcl), VAR_DECL, ++ get_identifier(chk), uint8_type_node); ++ DECL_INITIAL(chknode) = build_int_cst(uint8_type_node, 0); ++ TREE_STATIC(chknode) = TREE_STATIC(dcl); ++ TREE_USED(chknode) = TREE_USED(dcl); ++ DECL_READ_P(chknode) = DECL_READ_P(dcl); ++ DECL_CONTEXT(chknode) = DECL_CONTEXT(dcl); ++ DECL_CHAIN(chknode) = DECL_CHAIN(dcl); ++ DECL_CHAIN(dcl) = chknode; ++ ++ /* create the then clause of the if statement */ ++ tree then_clause = alloc_stmt_list(); ++ append_to_statement_list(build2(MODIFY_EXPR, void_type_node, chknode, ++ build_int_cst(uint8_type_node, 1)), ++ &then_clause); ++ append_to_statement_list( ++ build2(MODIFY_EXPR, void_type_node, dcl, replacement), ++ &then_clause); ++ /* ++ append_to_statement_list( ++ build_call_expr(VAR_NAME_AS_TREE("printf"), 1, ++ BUILD_STRING_AS_TREE("initstruct magic\n")), ++ &then_clause); ++ */ ++ ++ /* create the if statement into the overall result mentioned above */ ++ tree res = alloc_stmt_list(); ++ append_to_statement_list(*dxpr, &res); ++ append_to_statement_list(build1(DECL_EXPR, void_type_node, chknode), &res); ++ append_to_statement_list( ++ build_modded_if_stmt(build2(NE_EXPR, void_type_node, chknode, ++ build_int_cst(uint8_type_node, 1)), ++ then_clause), ++ &res); ++ /* overwrite the input tree with our new statements */ ++ *dxpr = res; ++ remove_subu_elem(ctx->mods, use); ++ replacement = NULL_TREE; ++ return 1; ++ } ++ return 0; ++} ++ ++void modify_local_struct_ctor(tree ctor, subu_list *list, location_t bound) { ++ subu_node *use = NULL; ++ unsigned int iprev = 0; ++ bool started = true; ++ tree replacement = NULL_TREE; ++ ++ while (list->count > 0 && LOCATION_BEFORE2(list->start, bound)) { ++ tree val = NULL_TREE; ++ unsigned int i = 0; ++ int found = 0; ++ FOR_EACH_CONSTRUCTOR_VALUE(CONSTRUCTOR_ELTS(ctor), i, val) { ++ DEBUGF("value %u is %s\n", i, get_tree_code_str(val)); ++ if (TREE_CODE(val) == INTEGER_CST) { ++ for (use = list->head; use; use = use->next) { ++ found = arg_should_be_unpatched(val, use, &replacement); ++ if (found) break; ++ } ++ if (found) { ++ iprev = i; ++ started = false; ++ break; ++ } ++ } else if (TREE_CODE(val) == CONSTRUCTOR) { ++ modify_local_struct_ctor(val, list, bound); ++ use = NULL; /* might've gotten stomped */ ++ if (list->count == 0 || LOCATION_AFTER2(list->start, bound)) return; ++ } ++ } ++ if (found) { ++ DEBUGF("found\n"); ++ // debug_tree(CONSTRUCTOR_ELT(ctor, i)->index); ++ CONSTRUCTOR_ELT(ctor, i)->value = replacement; ++ // debug_tree(CONSTRUCTOR_ELT(ctor, i)->value); ++ remove_subu_elem(list, use); ++ replacement = NULL_TREE; ++ } else { ++ /* we did not find any (more) substitutions to fix */ ++ break; ++ } ++ } ++} ++ ++void build_modded_declaration(tree *dxpr, SubContext *ctx, location_t bound) { ++ char chk[STRING_BUFFER_SIZE]; ++ tree dcl = DECL_EXPR_DECL(*dxpr); ++ subu_node *use = NULL; ++ subu_list *list = ctx->mods; ++ unsigned int oldcount = list->count; ++ ++ if (INTEGRAL_TYPE_P(TREE_TYPE(dcl))) { ++ get_subu_elem(list, list->start, &use); ++ if (build_modded_int_declaration(dxpr, ctx, use)) { ++ use = NULL; ++ ctx->initcount += 1; ++ } ++ return; ++ } ++ ++ if ((RECORD_TYPE == TREE_CODE(TREE_TYPE(dcl)) || ++ ARRAY_TYPE == TREE_CODE(TREE_TYPE(dcl))) && ++ DECL_INITIAL(dcl) != NULL_TREE) { ++ if (TREE_READONLY(dcl)) { ++ warning_at(EXPR_LOCATION(*dxpr), 0, ++ "not sure if modding const structs is good\n"); ++ TREE_READONLY(dcl) = 0; ++ build_modded_declaration(dxpr, ctx, bound); ++ return; ++ } else if (TREE_STATIC(dcl)) { ++ DEBUGF("fixing decl for a static struct\n"); ++ /* (*dxpr), the statement we have is this: ++ * ++ * static struct toy myvalue = {.x=1, .y=__tmpcosmo_VAR}; ++ * ++ * we're going to modify it to this: ++ * ++ * static struct toy myvalue = {.x=1, .y=__tmpcosmo_VAR}; ++ * static uint8 __chk_ifs_myvalue = 0; ++ * if(__chk_ifs_myvalue != 1) { ++ * __chk_ifs_myvalue = 1; ++ * myvalue.y = VAR; ++ * } ++ * ++ * so the modified statement runs exactly once, ++ * whenever the function is first called, right ++ * after the initialization of the variable we ++ * wanted to modify. */ ++ ++ /* build __chk_ifs_myvalue */ ++ snprintf(chk, sizeof(chk), "__chk_ifs_%s", IDENTIFIER_NAME(dcl)); ++ tree chknode = build_decl(DECL_SOURCE_LOCATION(dcl), VAR_DECL, ++ get_identifier(chk), uint8_type_node); ++ DECL_INITIAL(chknode) = build_int_cst(uint8_type_node, 0); ++ TREE_STATIC(chknode) = TREE_STATIC(dcl); ++ TREE_USED(chknode) = TREE_USED(dcl); ++ DECL_READ_P(chknode) = DECL_READ_P(dcl); ++ DECL_CONTEXT(chknode) = DECL_CONTEXT(dcl); ++ DECL_CHAIN(chknode) = DECL_CHAIN(dcl); ++ DECL_CHAIN(dcl) = chknode; ++ ++ /* build a scope block for the temporary value */ ++ tree tmpscope = build0(BLOCK, void_type_node); ++ BLOCK_SUPERCONTEXT(tmpscope) = TREE_BLOCK(*dxpr); ++ // debug_tree(BLOCK_SUPERCONTEXT(tmpscope)); ++ ++ /* create the then clause of the if statement */ ++ tree then_clause = alloc_stmt_list(); ++ append_to_statement_list(build2(MODIFY_EXPR, void_type_node, chknode, ++ build_int_cst(uint8_type_node, 1)), ++ &then_clause); ++ set_values_based_on_ctor(DECL_INITIAL(dcl), ctx->mods, then_clause, dcl, ++ bound); ++ ++ /* create the if statement into the overall result mentioned above */ ++ tree res = alloc_stmt_list(); ++ append_to_statement_list(*dxpr, &res); ++ append_to_statement_list(build1(DECL_EXPR, void_type_node, chknode), ++ &res); ++ append_to_statement_list( ++ build_modded_if_stmt(build2(NE_EXPR, void_type_node, chknode, ++ build_int_cst(uint8_type_node, 1)), ++ then_clause), ++ &res); ++ /* overwrite the input tree with our new statements */ ++ *dxpr = res; ++ } else { ++ /* if it's a local struct, we can ++ * just mod the constructor itself */ ++ auto ctor = DECL_INITIAL(dcl); ++ modify_local_struct_ctor(ctor, list, bound); ++ } ++ } ++ ctx->initcount += (oldcount - list->count); ++} +diff --git a/gcc/c-family/initstruct.h b/gcc/c-family/initstruct.h +new file mode 100644 +index 000000000..f77fba707 +--- /dev/null ++++ b/gcc/c-family/initstruct.h +@@ -0,0 +1,15 @@ ++#ifndef INITSTRUCT_H ++#define INITSTRUCT_H ++#include "c-family/portcosmo.internal.h" ++/* gcc utils first */ ++#include "c-family/subcontext.h" ++ ++void build_modded_declaration(tree *, SubContext *, location_t); ++int build_modded_int_declaration(tree *, SubContext *, subu_node *); ++tree copy_struct_ctor(tree); ++void modify_local_struct_ctor(tree, subu_list *, location_t); ++ ++void set_values_based_on_ctor(tree, subu_list *, tree, tree, location_t); ++void handle_decl(void *, void *); ++tree access_at(tree, tree); ++#endif /* INITSTRUCT_H */ +diff --git a/gcc/c-family/portcosmo.cc b/gcc/c-family/portcosmo.cc +new file mode 100644 +index 000000000..37cd2847c +--- /dev/null ++++ b/gcc/c-family/portcosmo.cc +@@ -0,0 +1,208 @@ ++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ ++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ++╞══════════════════════════════════════════════════════════════════════════════╡ ++│ Copyright © 2022, Gautham Venkatasubramanian │ ++│ │ ++│ Permission to use, copy, modify, and/or distribute this software for │ ++│ any purpose with or without fee is hereby granted, provided that the │ ++│ above copyright notice and this permission notice appear in all copies. │ ++│ │ ++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ ++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ ++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ ++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ ++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ ++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ ++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ ++│ PERFORMANCE OF THIS SOFTWARE. │ ++╚─────────────────────────────────────────────────────────────────────────────*/ ++#include "c-family/portcosmo.internal.h" ++#include "c-family/subcontext.h" ++#include "c-family/ifswitch.h" ++#include "c-family/initstruct.h" ++ ++static tree patch_int_nonconst(location_t, tree, const char **); ++ ++struct SubContext cosmo_ctx; ++static int ctx_inited = 0; ++static void (*other_define) (cpp_reader *, location_t, cpp_hashnode *) = NULL; ++ ++void check_macro_define(cpp_reader *reader, location_t loc, ++ cpp_hashnode *node) { ++ const char *defn = (const char *)cpp_macro_definition(reader, node); ++ if (cosmo_ctx.active && strstr(defn, "__tmpcosmo_") == defn) ++ { ++ const char *arg_start = defn + strlen("__tmpcosmo_"); ++ const char *arg_end = strstr(arg_start, " "); ++ if (!arg_start || !arg_end || arg_end - arg_start < 1) return; ++ char* name = xstrndup(arg_start, arg_end - arg_start); ++ char* val = xstrdup(arg_end); ++ long long val2 = strtoll(arg_end, NULL, 0); ++ if (val2 == 0) { ++ cpp_error_at(parse_in, CPP_DL_ERROR, loc, ++ "cannot parse portcosmo temporary constant\n"); ++ cosmo_ctx.active = 0; ++ } else { ++ if (cosmo_ctx.map->get(name)) { ++ cpp_error_at(parse_in, CPP_DL_ERROR, loc, ++ "duplicate portcosmo temporary constant\n"); ++ cosmo_ctx.active = 0; ++ } else { ++ tmpconst z; ++ z.raw = val2; ++ z.t = build_int_cst(long_long_integer_type_node, val2); ++ cosmo_ctx.map->put(name, z); ++ // INFORM(loc, "added temporary for %s\n", name); ++ } ++ } ++ /* not freeing name because it's in the hashmap */ ++ free(val); ++ } ++ else if(other_define) { ++ DEBUGF("we should just let this be %s\n", defn); ++ other_define(reader, loc, node); ++ } ++} ++ ++void portcosmo_setup() { ++ cpp_callbacks *cbs = cpp_get_callbacks(parse_in); ++ if (flag_portcosmo && 0 == ctx_inited) { ++ construct_context(&cosmo_ctx); ++ ctx_inited = 1; ++ if (cbs) { ++ if (cbs->define) { ++ other_define = cbs->define; ++ /* TODO: do we need for cbs->undef as well? */ ++ } ++ cbs->define = check_macro_define; ++ } ++ } ++} ++ ++void portcosmo_teardown() { ++ if (flag_portcosmo && 1 == ctx_inited) { ++ cleanup_context(&cosmo_ctx); ++ ctx_inited = 0; ++ } ++} ++ ++void portcosmo_show_tree(location_t loc, tree t) { ++ INFORM(loc, "attempting case substitution at: line %u, col %u\n", ++ LOCATION_LINE(loc), LOCATION_COLUMN(loc)); ++ debug_tree(t); ++} ++ ++tree patch_case_nonconst(location_t loc, tree t) { ++ INFORM(loc, "attempting case substitution at: line %u, col %u\n", ++ LOCATION_LINE(loc), LOCATION_COLUMN(loc)); ++ tree subs = NULL_TREE; ++ const char *name = NULL; ++ if (cosmo_ctx.active) { ++ subs = patch_int_nonconst(loc, t, &name); ++ if (subs != NULL_TREE) { ++ DEBUGF("folding...\n"); ++ subs = c_fully_fold(subs, false, NULL, false); ++ /* this substitution was successful, so record ++ * the location for rewriting the thing later */ ++ add_context_subu(&cosmo_ctx, loc, name, strlen(name), ++ PORTCOSMO_SWCASE); ++ } ++ } ++ if (subs == NULL_TREE) { ++ inform(loc, "unable to find __tmpcosmo_ temporary"); ++ } ++ return subs; ++} ++ ++tree patch_init_nonconst(location_t loc, tree t) { ++ INFORM(loc, "attempting init substitution at: line %u, col %u\n", ++ LOCATION_LINE(loc), LOCATION_COLUMN(loc)); ++ tree subs = NULL_TREE; ++ const char *name = NULL; ++ if (cosmo_ctx.active) { ++ subs = patch_int_nonconst(loc, t, &name); ++ if (subs != NULL_TREE) { ++ DEBUGF("folding...\n"); ++ subs = c_fully_fold(subs, false, NULL, false); ++ /* this substitution was successful, so record ++ * the location for rewriting the thing later */ ++ add_context_subu(&cosmo_ctx, loc, name, strlen(name), ++ PORTCOSMO_INITVAL); ++ DEBUGF("done\n"); ++ } ++ } ++ if (subs == NULL_TREE) { ++ inform(loc, "unable to find __tmpcosmo_ temporary"); ++ } ++ return subs; ++} ++ ++/* internal functions */ ++ ++static tree patch_int_nonconst(location_t loc, tree t, const char **res) { ++ /* t may be an integer inside a case label, or ++ * t may be an integer inside an initializer */ ++ tree subs = NULL_TREE; ++ switch (TREE_CODE(t)) { ++ case VAR_DECL: ++ subs = maybe_get_tmpconst_value(IDENTIFIER_NAME(t)); ++ if (subs != NULL_TREE) { ++ *res = IDENTIFIER_NAME(t); ++ DEBUGF("substitution exists %s\n", *res); ++ } ++ break; ++ case CONVERT_EXPR: ++ subs = patch_int_nonconst(loc, TREE_OPERAND(t, 0), res); ++ if (subs != NULL_TREE) { ++ subs = build1(CONVERT_EXPR, integer_type_node, subs); ++ } ++ break; ++ case NOP_EXPR: ++ subs = patch_int_nonconst(loc, TREE_OPERAND(t, 0), res); ++ if (subs != NULL_TREE) { ++ subs = build1(NOP_EXPR, integer_type_node, subs); ++ } ++ break; ++ case NEGATE_EXPR: ++ subs = patch_int_nonconst(loc, TREE_OPERAND(t, 0), res); ++ if (subs != NULL_TREE) { ++ subs = build1(NEGATE_EXPR, integer_type_node, subs); ++ } ++ break; ++ case BIT_NOT_EXPR: ++ subs = patch_int_nonconst(loc, TREE_OPERAND(t, 0), res); ++ if (subs != NULL_TREE) { ++ subs = build1(BIT_NOT_EXPR, integer_type_node, subs); ++ } ++ break; ++ default: ++ subs = NULL_TREE; ++ } ++ return subs; ++} ++ ++const char *get_tree_code_str(tree expr) { ++#define END_OF_BASE_TREE_CODES ++#define DEFTREECODE(a, b, c, d) \ ++ case a: \ ++ return b; ++ switch (TREE_CODE(expr)) { ++#include "all-tree.def" ++ default: ++ return ""; ++ } ++#undef DEFTREECODE ++#undef END_OF_BASE_TREE_CODES ++} ++ ++tree maybe_get_tmpconst_value(const char *s) { ++ char *result = xstrdup(s); ++ tmpconst *z = cosmo_ctx.map->get(result); ++ free(result); ++ return z ? z->t : NULL_TREE; ++} ++ ++int check_magic_equal(tree value, char *varname) { ++ tree vx = maybe_get_tmpconst_value(varname); ++ return vx != NULL_TREE && tree_int_cst_equal(value, vx); ++} +diff --git a/gcc/c-family/portcosmo.h b/gcc/c-family/portcosmo.h +new file mode 100644 +index 000000000..b25d8257b +--- /dev/null ++++ b/gcc/c-family/portcosmo.h +@@ -0,0 +1,13 @@ ++#ifndef PORTCOSMO_H ++#define PORTCOSMO_H ++#include ++ ++void portcosmo_setup(); ++void portcosmo_teardown(); ++void portcosmo_pre_genericize(void*); ++void portcosmo_finish_decl(void*); ++void portcosmo_show_tree(location_t, tree); ++tree patch_case_nonconst(location_t, tree); ++tree patch_init_nonconst(location_t, tree); ++ ++#endif /* PORTCOSMO_H */ +diff --git a/gcc/c-family/portcosmo.internal.h b/gcc/c-family/portcosmo.internal.h +new file mode 100644 +index 000000000..77e59050a +--- /dev/null ++++ b/gcc/c-family/portcosmo.internal.h +@@ -0,0 +1,54 @@ ++#ifndef PORTCOSMO_INTERNAL_H ++#define PORTCOSMO_INTERNAL_H ++/* first stdlib headers */ ++#include ++/* now all the plugin headers */ ++#include ++/* first gcc-plugin, then the others */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++const char *get_tree_code_str(tree); ++tree maybe_get_tmpconst_value(const char *); ++int check_magic_equal(tree, char *); ++ ++#define EXPR_LOC_LINE(x) LOCATION_LINE(EXPR_LOCATION((x))) ++#define EXPR_LOC_COL(x) LOCATION_COLUMN(EXPR_LOCATION((x))) ++#define LOCATION_APPROX(x, y) (LOCATION_LINE((x)) == LOCATION_LINE((y))) ++#define LOCATION_BEFORE(x, y) (LOCATION_LINE((x)) <= LOCATION_LINE((y))) ++#define LOCATION_AFTER(x, y) (LOCATION_LINE((x)) >= LOCATION_LINE((y))) ++ ++#define LOCATION_BEFORE2(x, y) \ ++ (LOCATION_LINE((x)) < LOCATION_LINE((y)) || \ ++ (LOCATION_LINE((x)) == LOCATION_LINE((y)) && \ ++ LOCATION_COLUMN((x)) <= LOCATION_COLUMN((y)))) ++#define LOCATION_AFTER2(x, y) \ ++ (LOCATION_LINE((x)) > LOCATION_LINE((y)) || \ ++ (LOCATION_LINE((x)) == LOCATION_LINE((y)) && \ ++ LOCATION_COLUMN((x)) >= LOCATION_COLUMN((y)))) ++ ++#define VAR_NAME_AS_TREE(fname) lookup_name(get_identifier((fname))) ++#define IDENTIFIER_NAME(z) IDENTIFIER_POINTER(DECL_NAME((z))) ++#define BUILD_STRING_AS_TREE(str) build_string_literal(strlen((str)) + 1, (str)) ++ ++#if 0 ++#define DEBUGF(...) fprintf(stderr, " " __VA_ARGS__) ++#define INFORM(...) inform(__VA_ARGS__) ++#else ++#define DEBUGF(...) ++#define INFORM(...) ++#endif ++ ++#define STRING_BUFFER_SIZE 192 ++ ++void handle_pre_genericize(void *, void *); ++ ++#endif /* PORTCOSMO.INTERNAL_H */ +diff --git a/gcc/c-family/subcontext.cc b/gcc/c-family/subcontext.cc +new file mode 100644 +index 000000000..40d180b2c +--- /dev/null ++++ b/gcc/c-family/subcontext.cc +@@ -0,0 +1,245 @@ ++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ ++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ++╞══════════════════════════════════════════════════════════════════════════════╡ ++│ Copyright © 2022, Gautham Venkatasubramanian │ ++│ │ ++│ Permission to use, copy, modify, and/or distribute this software for │ ++│ any purpose with or without fee is hereby granted, provided that the │ ++│ above copyright notice and this permission notice appear in all copies. │ ++│ │ ++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ ++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ ++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ ++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ ++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ ++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ ++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ ++│ PERFORMANCE OF THIS SOFTWARE. │ ++╚─────────────────────────────────────────────────────────────────────────────*/ ++#include "c-family/subcontext.h" ++ ++subu_node *build_subu(const location_t loc, const char *name, ++ unsigned int namelen, SubstType tp) { ++ /* xmalloc because malloc is poisoned by gcc-plugin's system.h */ ++ subu_node *res = (subu_node *)xmalloc(sizeof(subu_node)); ++ res->next = NULL; ++ res->loc = loc; ++ res->name = xstrndup(name, namelen); ++ res->tp = tp; ++ DEBUGF("allocated subu_node at %p\n", res); ++ return res; ++}; ++ ++void delete_subu(subu_node *node) { ++ DEBUGF("freeing subu_node at %p, %u,%u\n", node, LOCATION_LINE(node->loc), ++ LOCATION_COLUMN(node->loc)); ++ node->loc = 0x0; ++ free(node->name); ++ node->next = NULL; ++ node->tp = PORTCOSMO_UNKNOWN; ++ free(node); ++} ++ ++subu_list *init_subu_list() { ++ subu_list *res = (subu_list *)xmalloc(sizeof(subu_list)); ++ res->head = NULL; ++ res->count = 0; ++ res->start = 0; ++ res->end = 0; ++ DEBUGF("allocated subu_list at %p\n", res); ++ return res; ++} ++ ++static void recount_subu_list(subu_list *list) { ++ int i = 0; ++ location_t s = MAX_LOCATION_T; ++ location_t e = 0; ++ subu_node *it; ++ for (it = list->head; it != NULL; it = it->next) { ++ i += 1; ++ /* is it possible to compare for s and e? */ ++ if (s == MAX_LOCATION_T || LOCATION_BEFORE2(it->loc, s)) s = it->loc; ++ if (LOCATION_AFTER2(it->loc, e)) e = it->loc; ++ } ++ if (LOCATION_AFTER2(s, e)) { ++ s = e; ++ } ++ list->start = s; ++ list->end = e; ++ list->count = i; ++ DEBUGF("list with %d subus, start = %u,%u end = %u,%u\n", list->count, ++ LOCATION_LINE(list->start), LOCATION_COLUMN(list->start), ++ LOCATION_LINE(list->end), LOCATION_COLUMN(list->end)); ++} ++ ++void add_subu_elem(subu_list *list, subu_node *node) { ++ subu_node *tmp; ++ if (list->head == NULL) { ++ list->head = node; ++ } else { ++ for (tmp = list->head; tmp->next != NULL; tmp = tmp->next) ++ ; ++ tmp->next = node; ++ node->next = NULL; ++ } ++ recount_subu_list(list); ++} ++ ++void pop_subu_list(subu_list *list) { ++ if (list->head != NULL) { ++ subu_node *tmp = list->head; ++ list->head = list->head->next; ++ delete_subu(tmp); ++ } ++ recount_subu_list(list); ++} ++ ++int valid_subu_bounds(subu_list *list, location_t start, location_t end) { ++ /* return 1 if the bounds of list and provided bounds overlap */ ++ if (LOCATION_BEFORE(list->start, end) && LOCATION_AFTER(list->start, start)) ++ return 1; ++ if (LOCATION_BEFORE(start, list->end) && LOCATION_AFTER(start, list->start)) ++ return 1; ++ return 0; ++} ++ ++int check_loc_in_bound(subu_list *list, location_t loc) { ++ /* return 1 if loc is within the bounds */ ++ if (LOCATION_BEFORE(list->start, loc) && LOCATION_AFTER(list->end, loc)) { ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++int get_subu_elem(subu_list *list, location_t loc, subu_node **node) { ++ /* *node is overwritten on returning 1 ie success */ ++ subu_node *it = list->head; ++ for (; it != NULL; it = it->next) { ++ if (LOCATION_APPROX(it->loc, loc)) { ++ *node = it; ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++int get_subu_elem2(subu_list *list, source_range rng, subu_node **node) { ++ /* *node is overwritten on returning 1 ie success */ ++ /* returns the first node found within rng's bounds */ ++ subu_node *it = list->head; ++ for (; it != NULL; it = it->next) { ++ if (LOCATION_BEFORE(rng.m_start, it->loc) && ++ LOCATION_AFTER(rng.m_finish, it->loc)) { ++ *node = it; ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++void remove_subu_elem(subu_list *list, subu_node *node) { ++ subu_node *cur, *prev; ++ if (list->head != NULL) { ++ if (list->head == node) { ++ cur = list->head; ++ list->head = list->head->next; ++ delete_subu(cur); ++ } else { ++ prev = list->head; ++ cur = list->head->next; ++ for (; cur != NULL; prev = cur, cur = cur->next) { ++ if (cur == node) { ++ prev->next = cur->next; ++ delete_subu(cur); ++ break; ++ } ++ } ++ } ++ recount_subu_list(list); ++ } ++} ++ ++void clear_subu_list(subu_list *list) { ++ subu_node *it, *tmp; ++ for (it = list->head; it != NULL;) { ++ tmp = it; ++ it = it->next; ++ delete_subu(tmp); ++ } ++ list->head = NULL; ++ list->count = 0; ++ list->start = 0; ++ list->end = 0; ++} ++ ++void delete_subu_list(subu_list *list) { ++ clear_subu_list(list); ++ free(list); ++ DEBUGF("freeing subu_list at %p\n", list); ++} ++ ++int check_empty_subu_list(subu_list *list, location_t start) { ++ /* we should have modded all locations before start, and so ++ * list should not contain any entries which have a location ++ * before start */ ++ int errcount = 0; ++ for (auto it = list->head; it; it = it->next) { ++ if (start == MAX_LOCATION_T || LOCATION_BEFORE2(it->loc, start)) { ++ error_at(it->loc, "unable to substitute constant\n"); ++ errcount += 1; ++ } ++ } ++ if (errcount != 0) { ++ /* DON'T DELETE! */ ++ clear_subu_list(list); ++ } ++ return errcount == 0; ++} ++ ++void construct_context(SubContext *ctx) { ++ ctx->active = 1; ++ ctx->mods = init_subu_list(); ++ ctx->prev = NULL; ++ ctx->switchcount = 0; ++ ctx->initcount = 0; ++ ctx->subcount = 0; ++ ctx->map = NULL; ++ ctx->map = hash_map_maybe_create(ctx->map); ++} ++ ++void add_context_subu(SubContext *ctx, const location_t loc, const char *defn, ++ unsigned int at, SubstType st) { ++ if (ctx->mods == NULL) return; ++ add_subu_elem(ctx->mods, build_subu(loc, defn, at, st)); ++} ++ ++void check_context_clear(SubContext *ctx, location_t start) { ++ if (ctx->mods) { ++ ctx->active = check_empty_subu_list(ctx->mods, start); ++ } ++} ++ ++void cleanup_context(SubContext *ctx) { ++ check_context_clear(ctx, MAX_LOCATION_T); ++ if (ctx->mods) { ++ delete_subu_list(ctx->mods); ++ ctx->mods = NULL; ++ } ++ ctx->prev = NULL; ++ if (ctx->switchcount > 0) { ++ inform(UNKNOWN_LOCATION, "rewrote %u switch statements", ctx->switchcount); ++ } ++ ctx->switchcount = 0; ++ if (ctx->initcount > 0) { ++ inform(UNKNOWN_LOCATION, "modified %u initializations", ctx->initcount); ++ } ++ ctx->initcount = 0; ++ if (ctx->subcount > 0) { ++ inform(UNKNOWN_LOCATION, "modified %u other macro uses", ctx->subcount); ++ } ++ ctx->subcount = 0; ++ ctx->active = 0; ++ delete ctx->map; ++ ctx->map = NULL; ++} +diff --git a/gcc/c-family/subcontext.h b/gcc/c-family/subcontext.h +new file mode 100644 +index 000000000..e4ffaad0c +--- /dev/null ++++ b/gcc/c-family/subcontext.h +@@ -0,0 +1,103 @@ ++#ifndef SUBCONTEXT_H ++#define SUBCONTEXT_H ++#include "c-family/portcosmo.internal.h" ++#include "hash-map-traits.h" ++#include "hash-map.h" ++#include "hash-traits.h" ++ ++enum SubstType { ++ PORTCOSMO_UNKNOWN = 0, ++ PORTCOSMO_SWCASE = 1, ++ PORTCOSMO_INITVAL = 2 ++}; ++ ++struct subu_node { ++ /* a node indicating that an ifswitch substitution has occurred. ++ * ++ * Details include: ++ * ++ * - location_t of the substitution ++ * - char* of name of the macro that was substituted (alloc'd) ++ * - whether the substitution was inside a switch statement ++ * - _subu_node* pointer to the next element in the list (NULL if last) ++ * ++ * the idea is that every time one of our modified macros is used, ++ * we record the substitution, and then we delete this record if ++ * we find the appropriate location_t during pre-genericize and ++ * construct the necessary parse trees at that point. ++ * ++ * at the end of compilation (ie PLUGIN_FINISH), there should be ++ * no subu_nodes allocated. ++ */ ++ location_t loc; ++ SubstType tp; ++ char *name; ++ struct subu_node *next; ++}; ++ ++typedef struct subu_node subu_node; ++ ++struct subu_list { ++ subu_node *head; ++ /* inclusive bounds, range containing all recorded substitutions */ ++ location_t start, end; ++ /* number of substitutions */ ++ int count; ++}; ++typedef struct subu_list subu_list; ++ ++int check_loc_in_bound(subu_list *, location_t); ++int valid_subu_bounds(subu_list *, location_t, location_t); ++int get_subu_elem(subu_list *, location_t, subu_node **); ++int get_subu_elem2(subu_list *, source_range, subu_node **); ++void remove_subu_elem(subu_list *, subu_node *); ++ ++struct tmpconst { ++ long long raw; ++ tree t; ++}; ++typedef struct tmpconst tmpconst; ++ ++struct free_string_hash : pointer_hash, typed_free_remove { ++ static inline hashval_t hash (char *id) { ++ return htab_hash_string (id); ++ }; ++ static inline bool equal (char *a, char *b) { ++ return strcmp(a, b) == 0; ++ }; ++}; ++using tmpmap_traits = simple_hashmap_traits; ++using tmpmap = hash_map; ++ ++/* Substitution Context */ ++struct SubContext { ++ /* record all macro uses */ ++ subu_list *mods; ++ /* address of the previous statement we walked through, ++ * in case we missed modding it and have to retry */ ++ tree *prev; ++ /* count number of switch statements rewritten */ ++ unsigned int switchcount; ++ /* count number of initializations rewritten */ ++ unsigned int initcount; ++ /* count number of other substitutions rewritten */ ++ unsigned int subcount; ++ /* if zero, it means we haven't started or something ++ * went wrong somewhere */ ++ int active; ++ /* store values of all temporary constants */ ++ tmpmap *map; ++}; ++ ++void add_context_subu(SubContext *, const location_t, const char *, ++ unsigned int, SubstType); ++void construct_context(SubContext *); ++void check_context_clear(SubContext *, location_t); ++void cleanup_context(SubContext *); ++ ++int arg_should_be_unpatched(tree, const subu_node *, tree *); ++ ++/* declaring cosmo_ctx here so initstruct knows it exists */ ++extern struct SubContext cosmo_ctx; ++ ++#endif /* SUBCONTEXT_H */ +diff --git a/gcc/c-family/unpatch_ast.cc b/gcc/c-family/unpatch_ast.cc +new file mode 100644 +index 000000000..56b5b9a01 +--- /dev/null ++++ b/gcc/c-family/unpatch_ast.cc +@@ -0,0 +1,115 @@ ++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ ++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ++╞══════════════════════════════════════════════════════════════════════════════╡ ++│ Copyright © 2022, Gautham Venkatasubramanian │ ++│ │ ++│ Permission to use, copy, modify, and/or distribute this software for │ ++│ any purpose with or without fee is hereby granted, provided that the │ ++│ above copyright notice and this permission notice appear in all copies. │ ++│ │ ++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ ++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ ++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ ++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ ++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ ++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ ++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ ++│ PERFORMANCE OF THIS SOFTWARE. │ ++╚─────────────────────────────────────────────────────────────────────────────*/ ++#include "c-family/ifswitch.h" ++#include "c-family/initstruct.h" ++ ++tree check_usage(tree *tp, int *check_subtree, void *data) { ++ SubContext *ctx = (SubContext *)(data); ++ tree t = *tp; ++ tree z; ++ subu_node *use = NULL; ++ location_t loc = EXPR_LOCATION(t); ++ source_range rng = EXPR_LOCATION_RANGE(t); ++ ++ if (ctx->active == 0 || ctx->mods->count == 0) { ++ /* DEBUGF("substitutions complete\n"); */ ++ *check_subtree = 0; ++ return NULL_TREE; ++ } ++ ++ if (LOCATION_AFTER2(loc, rng.m_start)) { ++ loc = rng.m_start; ++ } else { ++ rng.m_start = loc; ++ } ++ ++ if (ctx->prev && LOCATION_BEFORE2(ctx->mods->start, rng.m_start)) { ++ auto vloc = DECL_SOURCE_LOCATION(DECL_EXPR_DECL(*(ctx->prev))); ++ /* below inequality holds inside this if condition: ++ * vloc <= ctx->mods->start <= rng.m_start ++ * this means that there was a macro substitution ++ * between vloc and rng.m_start, which was not ++ * eliminated when we went through the other parts ++ * of the parse tree earlier. thus, the decl_expr ++ * that we have stored in ctx->prev needs to be ++ * checked for possible macro substitutions */ ++ DEBUGF( ++ "did we miss a decl? vloc=%u,%u, loc=%u,%u, rng.mstart=%u,%u, " ++ "start=%u,%u\n", ++ LOCATION_LINE(vloc), LOCATION_COLUMN(vloc), // ++ LOCATION_LINE(loc), LOCATION_COLUMN(loc), // ++ LOCATION_LINE(rng.m_start), LOCATION_COLUMN(rng.m_start), ++ LOCATION_LINE(ctx->mods->start), LOCATION_COLUMN(ctx->mods->start)); ++ auto z = ctx->initcount; ++ build_modded_declaration(ctx->prev, ctx, rng.m_start); ++ if (z != ctx->initcount) { ++ ctx->prev = NULL; ++ check_context_clear(ctx, loc); ++ } ++ } ++ ++ if (TREE_CODE(t) == DECL_EXPR && TREE_STATIC(DECL_EXPR_DECL(t))) { ++ INFORM(loc, "should we mod this?\n"); ++ ctx->prev = tp; ++ } ++ ++ if (TREE_CODE(t) == SWITCH_STMT) { ++ rng = get_switch_bounds(t); ++ if (valid_subu_bounds(ctx->mods, rng.m_start, rng.m_finish) && ++ count_mods_in_switch(t, ctx->mods) > 0) { ++ /* this is one of the switch statements ++ * where we modified a case label */ ++ DEBUGF("modding the switch \n"); ++ *tp = build_modded_switch_stmt(t, ctx); ++ DEBUGF("we modded it??\n"); ++ walk_tree_without_duplicates(tp, check_usage, ctx); ++ /* due to the above call, I don't need to check ++ * any subtrees from this current location */ ++ *check_subtree = 0; ++ ctx->switchcount += 1; ++ return NULL_TREE; ++ } ++ } ++ ++ return NULL_TREE; ++} ++ ++void handle_pre_genericize(void *gcc_data, void *user_data) { ++ tree t = (tree)gcc_data; ++ SubContext *ctx = (SubContext *)user_data; ++ tree t2; ++ if (ctx->active && TREE_CODE(t) == FUNCTION_DECL && ++ DECL_INITIAL(t) != NULL && TREE_STATIC(t)) { ++ /* this function is defined within the file I'm processing */ ++ if (ctx->mods->count == 0) { ++ // DEBUGF("no substitutions were made in %s\n", IDENTIFIER_NAME(t)); ++ return; ++ } ++ t2 = DECL_SAVED_TREE(t); ++ ctx->prev = NULL; ++ walk_tree_without_duplicates(&t2, check_usage, ctx); ++ /* now at this stage, all uses of our macros have been ++ * fixed, INCLUDING case labels. Let's confirm that: */ ++ check_context_clear(ctx, MAX_LOCATION_T); ++ } ++} ++ ++void portcosmo_pre_genericize(void *gcc_data) { ++ handle_pre_genericize(gcc_data, (void *)(&cosmo_ctx)); ++} +diff --git a/gcc/c-family/unpatch_int.cc b/gcc/c-family/unpatch_int.cc +new file mode 100644 +index 000000000..31a2cebb0 +--- /dev/null ++++ b/gcc/c-family/unpatch_int.cc +@@ -0,0 +1,66 @@ ++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ ++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ++╞══════════════════════════════════════════════════════════════════════════════╡ ++│ Copyright © 2022, Gautham Venkatasubramanian │ ++│ │ ++│ Permission to use, copy, modify, and/or distribute this software for │ ++│ any purpose with or without fee is hereby granted, provided that the │ ++│ above copyright notice and this permission notice appear in all copies. │ ++│ │ ++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ ++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ ++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ ++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ ++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ ++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ ++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ ++│ PERFORMANCE OF THIS SOFTWARE. │ ++╚─────────────────────────────────────────────────────────────────────────────*/ ++#include "c-family/subcontext.h" ++ ++int arg_should_be_unpatched(tree arg, const subu_node *use, tree *rep_ptr) { ++ /* if we are returning 1, rep_ptr has been set. ++ * if we are returning 0, rep_ptr is unchanged. ++ * use is not affected! */ ++ if (TREE_CODE(arg) == INTEGER_CST) { ++ tree vx = maybe_get_tmpconst_value(use->name); ++ if (vx == NULL_TREE) { ++ return 0; ++ } ++ if (tree_int_cst_equal(arg, vx)) { ++ /* if this is an integer constant, AND its ++ * value is equal to the macro we substituted, ++ * then we replace the correct variable here */ ++ *rep_ptr = ++ build1(NOP_EXPR, integer_type_node, VAR_NAME_AS_TREE(use->name)); ++ INFORM(use->loc, "unpatched an integer here with %s\n", use->name); ++ return 1; ++ } ++ /* here you might want to handle some ++ * minimal constant folding algebra, ++ * like -VAR or ~VAR */ ++ if (tree_fits_poly_int64_p(vx) && tree_fits_poly_int64_p(arg)) { ++ auto v1 = tree_to_poly_int64(vx); ++ auto v2 = tree_to_poly_int64(arg); ++ ++ /* handle the -VAR case */ ++ if (known_eq(v1, -v2)) { ++ INFORM(use->loc, "unpatched an integer here with -%s\n", use->name); ++ *rep_ptr = ++ build1(NEGATE_EXPR, integer_type_node, VAR_NAME_AS_TREE(use->name)); ++ return 1; ++ } ++ ++ /* handle the ~VAR case */ ++ if (known_eq(v1, ~v2)) { ++ INFORM(use->loc, "unpatched an integer here with ~%s\n", use->name); ++ *rep_ptr = build1(BIT_NOT_EXPR, integer_type_node, ++ VAR_NAME_AS_TREE(use->name)); ++ return 1; ++ } ++ } ++ return 0; ++ } ++ ++ return 0; ++} +diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in +index a1cdee872..ce57e8a27 100644 +--- a/gcc/c/Make-lang.in ++++ b/gcc/c/Make-lang.in +@@ -55,8 +55,10 @@ C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \ + c/c-fold.o c/gimple-parser.o \ + $(C_COMMON_OBJS) $(C_TARGET_OBJS) + ++PORTCOSMO_C_OBJS = c/portcosmo_bcref.o ++ + # Language-specific object files for C. +-C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS) ++C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS) $(PORTCOSMO_C_OBJS) + c_OBJS = $(C_OBJS) cc1-checksum.o c/gccspec.o + + # Use strict warnings for this front end. +diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c +index 53b2b5b63..51f3a72e5 100644 +--- a/gcc/c/c-decl.c ++++ b/gcc/c/c-decl.c +@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3. If not see + #include "c-family/name-hint.h" + #include "c-family/known-headers.h" + #include "c-family/c-spellcheck.h" ++#include "c-family/portcosmo.h" + #include "context.h" /* For 'g'. */ + #include "omp-general.h" + #include "omp-offload.h" /* For offload_vars. */ +@@ -5685,6 +5686,9 @@ finish_decl (tree decl, location_t init_loc, tree init, + && !DECL_HARD_REGISTER (decl)) + targetm.lower_local_decl_alignment (decl); + ++ if(flag_portcosmo) { ++ portcosmo_finish_decl(decl); ++ } + invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); + } + +@@ -10277,6 +10281,10 @@ finish_function (location_t end_loc) + { + if (!decl_function_context (fndecl)) + { ++ if (flag_portcosmo) ++ { ++ portcosmo_pre_genericize(fndecl); ++ } + invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl); + c_genericize (fndecl); + +diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c +index b5d139e5d..45be3af80 100644 +--- a/gcc/c/c-typeck.c ++++ b/gcc/c/c-typeck.c +@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see + #include "omp-general.h" + #include "c-family/c-objc.h" + #include "c-family/c-ubsan.h" ++#include "c-family/portcosmo.h" + #include "gomp-constants.h" + #include "spellcheck-tree.h" + #include "gcc-rich-location.h" +@@ -8159,10 +8160,10 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, + = valid_compound_expr_initializer (inside_init, + TREE_TYPE (inside_init)); + if (inside_init == error_mark_node) +- error_init (init_loc, "initializer element is not constant"); ++ error_init (init_loc, "initializer element is not constant 8163"); + else + pedwarn_init (init_loc, OPT_Wpedantic, +- "initializer element is not constant"); ++ "initializer element is not constant 8166"); + if (flag_pedantic_errors) + inside_init = error_mark_node; + } +@@ -8170,8 +8171,17 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, + && !initializer_constant_valid_p (inside_init, + TREE_TYPE (inside_init))) + { +- error_init (init_loc, "initializer element is not constant"); +- inside_init = error_mark_node; ++ if (flag_portcosmo) { ++ inside_init = patch_init_nonconst(init_loc, inside_init); ++ if (inside_init == NULL_TREE) { ++ error_init (init_loc, "initializer element is not constant 8177"); ++ inside_init = error_mark_node; ++ } ++ } ++ else { ++ error_init (init_loc, "initializer element is not constant 8183"); ++ inside_init = error_mark_node; ++ } + } + else if (require_constant && !maybe_const) + pedwarn_init (init_loc, OPT_Wpedantic, +@@ -8210,8 +8220,17 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, + ; + else if (require_constant && !TREE_CONSTANT (inside_init)) + { +- error_init (init_loc, "initializer element is not constant"); +- inside_init = error_mark_node; ++ if (flag_portcosmo) { ++ inside_init = patch_init_nonconst(init_loc, inside_init); ++ if (inside_init == NULL_TREE) { ++ error_init (init_loc, "initializer element is not constant 8226"); ++ inside_init = error_mark_node; ++ } ++ } ++ else { ++ error_init (init_loc, "initializer element is not constant 8183"); ++ inside_init = error_mark_node; ++ } + } + else if (require_constant + && !initializer_constant_valid_p (inside_init, +@@ -9740,7 +9759,7 @@ output_init_element (location_t loc, tree value, tree origtype, + the brace enclosed list they contain). */ + if (flag_isoc99) + pedwarn_init (loc, OPT_Wpedantic, "initializer element is not " +- "constant"); ++ "constant 9754"); + tree decl = COMPOUND_LITERAL_EXPR_DECL (value); + value = DECL_INITIAL (decl); + } +@@ -9787,9 +9806,9 @@ output_init_element (location_t loc, tree value, tree origtype, + /* Proceed to check the constness of the original initializer. */ + if (!initializer_constant_valid_p (value, TREE_TYPE (value))) + { +- if (require_constant_value) ++ if (require_constant_value && !flag_portcosmo) + { +- error_init (loc, "initializer element is not constant"); ++ error_init (loc, "initializer element is not constant 9803"); + value = error_mark_node; + } + else if (require_constant_elements) +diff --git a/gcc/c/portcosmo_bcref.cc b/gcc/c/portcosmo_bcref.cc +new file mode 100644 +index 000000000..2c6a58296 +--- /dev/null ++++ b/gcc/c/portcosmo_bcref.cc +@@ -0,0 +1,30 @@ ++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ ++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ++╞══════════════════════════════════════════════════════════════════════════════╡ ++│ Copyright © 2022, Gautham Venkatasubramanian │ ++│ │ ++│ Permission to use, copy, modify, and/or distribute this software for │ ++│ any purpose with or without fee is hereby granted, provided that the │ ++│ above copyright notice and this permission notice appear in all copies. │ ++│ │ ++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ ++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ ++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ ++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ ++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ ++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ ++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ ++│ PERFORMANCE OF THIS SOFTWARE. │ ++╚─────────────────────────────────────────────────────────────────────────────*/ ++#include "c-family/initstruct.h" ++ ++/* initstruct/common.cc */ ++ ++tree access_at(tree obj, tree ind) { ++ if (TREE_CODE(TREE_TYPE(obj)) == ARRAY_TYPE) { ++ return build_array_ref(input_location, obj, ind); ++ } ++ return build_component_ref(input_location, obj, ++ get_identifier(IDENTIFIER_NAME(ind)), ++ DECL_SOURCE_LOCATION(ind)); ++} +diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in +index 155be74ef..2fe9484ff 100644 +--- a/gcc/cp/Make-lang.in ++++ b/gcc/cp/Make-lang.in +@@ -84,6 +84,10 @@ g++-cross$(exeext): xg++$(exeext) + CXX_C_OBJS = attribs.o incpath.o \ + $(C_COMMON_OBJS) $(CXX_TARGET_OBJS) + ++# initstruct has some issues building with cc1plus, ++# so we provide nothing for now ++PORTCOSMO_CXX_OBJS = cp/portcosmo_bcref_cp.o ++ + # Language-specific object files for C++ and Objective C++. + CXX_AND_OBJCXX_OBJS = \ + cp/call.o cp/class.o cp/constexpr.o cp/constraint.o \ +@@ -101,7 +105,7 @@ CXX_AND_OBJCXX_OBJS = \ + cp/rtti.o \ + cp/search.o cp/semantics.o \ + cp/tree.o cp/typeck.o cp/typeck2.o \ +- cp/vtable-class-hierarchy.o $(CXX_C_OBJS) ++ cp/vtable-class-hierarchy.o $(CXX_C_OBJS) $(PORTCOSMO_CXX_OBJS) + + ifeq ($(if $(wildcard ../stage_current),$(shell cat \ + ../stage_current)),stageautofeedback) +diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c +index 5e101ffb8..1f68dddbf 100644 +--- a/gcc/cp/decl.c ++++ b/gcc/cp/decl.c +@@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see + #include "context.h" /* For 'g'. */ + #include "omp-general.h" + #include "omp-offload.h" /* For offload_vars. */ ++#include "c-family/portcosmo.h" + + /* Possible cases of bad specifiers type used by bad_specifiers. */ + enum bad_spec_place { +@@ -8246,6 +8247,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, + && !DECL_HARD_REGISTER (decl)) + targetm.lower_local_decl_alignment (decl); + ++ if (flag_portcosmo) { ++ portcosmo_finish_decl(decl); ++ } + invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); + } + +@@ -17459,8 +17463,13 @@ finish_function (bool inline_p) + maybe_save_constexpr_fundef (fndecl); + + /* Invoke the pre-genericize plugin before we start munging things. */ +- if (!processing_template_decl) ++ if (!processing_template_decl) { ++ if (flag_portcosmo) ++ { ++ portcosmo_pre_genericize(fndecl); ++ } + invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl); ++ } + + /* Perform delayed folding before NRV transformation. */ + if (!processing_template_decl +diff --git a/gcc/cp/portcosmo_bcref_cp.cc b/gcc/cp/portcosmo_bcref_cp.cc +new file mode 100644 +index 000000000..bf01d9aeb +--- /dev/null ++++ b/gcc/cp/portcosmo_bcref_cp.cc +@@ -0,0 +1,42 @@ ++/*- mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ ++│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ++╞══════════════════════════════════════════════════════════════════════════════╡ ++│ Copyright © 2022, Gautham Venkatasubramanian │ ++│ │ ++│ Permission to use, copy, modify, and/or distribute this software for │ ++│ any purpose with or without fee is hereby granted, provided that the │ ++│ above copyright notice and this permission notice appear in all copies. │ ++│ │ ++│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ ++│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ ++│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ ++│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ ++│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ ++│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ ++│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ ++│ PERFORMANCE OF THIS SOFTWARE. │ ++╚─────────────────────────────────────────────────────────────────────────────*/ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "target.h" ++#include "c-family/c-target.h" ++#include "cp-tree.h" ++#include "tree.h" ++#include "stringpool.h" ++ ++#define IDENTIFIER_NAME(z) IDENTIFIER_POINTER(DECL_NAME((z))) ++ ++/* initstruct/common.cc */ ++ ++tree access_at(tree obj, tree ind) { ++ return cp_build_addr_expr(ind, 0); ++ /* ++ if (TREE_CODE(TREE_TYPE(obj)) == ARRAY_TYPE) { ++ return build_array_ref(input_location, obj, ind); ++ } ++ return build_component_ref(input_location, obj, ++ get_identifier(IDENTIFIER_NAME(ind)), ++ DECL_SOURCE_LOCATION(ind)); ++ */ ++}