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)); + */ +}