mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
1910 lines
75 KiB
Diff
1910 lines
75 KiB
Diff
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<tree> *&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<tree> *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 "<unknown>";
|
|
+ }
|
|
+#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 <tree.h>
|
|
+
|
|
+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 <stdio.h>
|
|
+/* now all the plugin headers */
|
|
+#include <gcc-plugin.h>
|
|
+/* first gcc-plugin, then the others */
|
|
+#include <c-family/c-common.h>
|
|
+#include <c-family/c-pragma.h>
|
|
+#include <c/c-tree.h>
|
|
+#include <cgraph.h>
|
|
+#include <cpplib.h>
|
|
+#include <diagnostic.h>
|
|
+#include <print-tree.h>
|
|
+#include <stringpool.h>
|
|
+#include <tree-iterator.h>
|
|
+#include <tree.h>
|
|
+
|
|
+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, "<DEBUG> " __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<false, char, tmpconst, tmpmap_traits>(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<char>, typed_free_remove <char> {
|
|
+ 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<free_string_hash, tmpconst>;
|
|
+using tmpmap = hash_map<char, tmpconst, tmpmap_traits>;
|
|
+
|
|
+/* 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));
|
|
+ */
|
|
+}
|