From 58a54f520084cc9fc5e764fd16b795a0b2d363e2 Mon Sep 17 00:00:00 2001 From: York Jasper Niebuhr Date: Tue, 28 Oct 2025 21:05:36 +0100 Subject: [PATCH] Deleted deprecated stuff --- deprecated/plugin/CMakeLists.txt | 9 - deprecated/plugin/access_discover.cpp | 72 ------ deprecated/plugin/access_discover.h | 11 - deprecated/plugin/attrib.cpp | 37 --- deprecated/plugin/attrib.h | 6 - deprecated/plugin/gcc_includes.h | 25 -- deprecated/plugin/main.cpp | 25 -- deprecated/plugin/pattern.cpp | 85 ------- deprecated/plugin/pattern.h | 7 - playground/commands.txt | 27 -- playground/plugin.cpp | 291 ---------------------- playground/spslr_pinpoint.cpp | 344 -------------------------- 12 files changed, 939 deletions(-) delete mode 100644 deprecated/plugin/CMakeLists.txt delete mode 100644 deprecated/plugin/access_discover.cpp delete mode 100644 deprecated/plugin/access_discover.h delete mode 100644 deprecated/plugin/attrib.cpp delete mode 100644 deprecated/plugin/attrib.h delete mode 100644 deprecated/plugin/gcc_includes.h delete mode 100644 deprecated/plugin/main.cpp delete mode 100644 deprecated/plugin/pattern.cpp delete mode 100644 deprecated/plugin/pattern.h delete mode 100644 playground/commands.txt delete mode 100644 playground/plugin.cpp delete mode 100644 playground/spslr_pinpoint.cpp diff --git a/deprecated/plugin/CMakeLists.txt b/deprecated/plugin/CMakeLists.txt deleted file mode 100644 index bb02e15..0000000 --- a/deprecated/plugin/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -add_library(selfpatch-slr SHARED main.cpp attrib.cpp access_discover.cpp pattern.cpp) - -set_target_properties(selfpatch-slr PROPERTIES PREFIX "") -target_compile_definitions(selfpatch-slr PRIVATE _GNU_SOURCE) -target_compile_options(selfpatch-slr PRIVATE -fno-rtti -fno-exceptions) - -execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=plugin OUTPUT_VARIABLE GCC_PLUGIN_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) -message(STATUS "GCC plugin path: ${GCC_PLUGIN_PATH}") -target_include_directories(selfpatch-slr PRIVATE ${GCC_PLUGIN_PATH}/include) diff --git a/deprecated/plugin/access_discover.cpp b/deprecated/plugin/access_discover.cpp deleted file mode 100644 index 0829c9f..0000000 --- a/deprecated/plugin/access_discover.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "access_discover.h" -#include "pattern.h" - -#include - -static void print_gimple_tree(tree t, int depth, int indent = 2) { - if (!t) - return; - - for (int i = 0; i < depth; ++i) - std::cout << " "; - - std::cout << get_tree_code_name(TREE_CODE(t)); - - if (TREE_CODE(t) == FIELD_DECL && DECL_NAME(t)) - std::cout << " <" << IDENTIFIER_POINTER(DECL_NAME(t)) << ">"; - else if (TREE_CODE(t) == SSA_NAME && SSA_NAME_VAR(t) && DECL_NAME(SSA_NAME_VAR(t))) - std::cout << " "; - - std::cout << std::endl; - - for (int i = 0; i < TREE_CODE_LENGTH(TREE_CODE(t)); ++i) - print_gimple_tree(TREE_OPERAND(t, i), depth + indent, indent); -} - -static void print_gimple_statement(gimple* stmt) { - if (!stmt) - return; - - print_gimple_stmt(stdout, stmt, 0, TDF_NONE); - - for (unsigned i = 0; i < gimple_num_ops(stmt); ++i) { - tree operand = gimple_op(stmt, i); - print_gimple_tree(operand, 2, 2); - } -} - -static int scan_gimple_statement(const char* funcname, gimple_stmt_iterator* gsi) { - print_gimple_statement(gsi_stmt(*gsi)); - //return register_gimple_statement_pattern(gsi); - return 0; -} - -static const pass_data access_discover_pass_data = { - GIMPLE_PASS, - "access_discover", - OPTGROUP_NONE, - TV_NONE, - 0,0,0,0, - TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il -}; - -access_discover_pass::access_discover_pass(gcc::context *ctxt) : gimple_opt_pass(access_discover_pass_data, ctxt) {} - -unsigned int access_discover_pass::execute(function* fun) { - const char* funcname = fun->decl && DECL_NAME(fun->decl) - ? IDENTIFIER_POINTER(DECL_NAME(fun->decl)) - : ""; - - basic_block bb; - FOR_EACH_BB_FN(bb, fun) { - for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { - if (scan_gimple_statement(funcname, &gsi) != 0) { - internal_error("fatal error in spslr plugin: %s", "failed to scan gimple statement"); - return 0; - } - } - } - - clean_unnecessary_patterns(); - return 0; -} diff --git a/deprecated/plugin/access_discover.h b/deprecated/plugin/access_discover.h deleted file mode 100644 index 22a14b9..0000000 --- a/deprecated/plugin/access_discover.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "gcc_includes.h" - -struct access_discover_pass : gimple_opt_pass { - access_discover_pass(gcc::context *ctxt); - unsigned int execute(function* fun) override; -}; - -#define ACCESS_DISCOVER_PASS_REFPASS "optimized" -#define ACCESS_DISCOVER_PASS_POSOP PASS_POS_INSERT_AFTER - diff --git a/deprecated/plugin/attrib.cpp b/deprecated/plugin/attrib.cpp deleted file mode 100644 index e518eaf..0000000 --- a/deprecated/plugin/attrib.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "attrib.h" - -#include "gcc_includes.h" - -#include -#include - -static std::unordered_set targets; - -static tree handle_spslr_attribute(tree* node, tree name, tree args, int flags, bool* no_add_attrs) { - if (!node) - return NULL_TREE; - - if (TREE_CODE(*node) != RECORD_TYPE) - return *node; // Only allowed on structs - - tree type_name_tree = TYPE_IDENTIFIER(*node); - if (type_name_tree == NULL_TREE) - return *node; - - std::string name_str{ IDENTIFIER_POINTER(type_name_tree) }; - targets.insert(name_str); - return *node; -} - -static struct attribute_spec spslr_attribute = { - SPSRL_ATTRIBUTE, 0, 0, false, false, false, false, handle_spslr_attribute, NULL -}; - -void register_attributes(void* event_data, void* data) { - register_attribute(&spslr_attribute); -} - -bool is_target(const char* name) { - std::string str{ name }; - return targets.find(str) != targets.end(); -} diff --git a/deprecated/plugin/attrib.h b/deprecated/plugin/attrib.h deleted file mode 100644 index 68fe706..0000000 --- a/deprecated/plugin/attrib.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#define SPSRL_ATTRIBUTE "slr" - -void register_attributes(void* event_data, void* data); -bool is_target(const char* name); diff --git a/deprecated/plugin/gcc_includes.h b/deprecated/plugin/gcc_includes.h deleted file mode 100644 index 2257c79..0000000 --- a/deprecated/plugin/gcc_includes.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef GCC_PLUGIN_INCLUDES_H -#define GCC_PLUGIN_INCLUDES_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif diff --git a/deprecated/plugin/main.cpp b/deprecated/plugin/main.cpp deleted file mode 100644 index 36f3dae..0000000 --- a/deprecated/plugin/main.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include - -#include "gcc_includes.h" -#include "attrib.h" -#include "access_discover.h" - -int plugin_is_GPL_compatible; - -int plugin_init(plugin_name_args *plugin_info, plugin_gcc_version *version) { - if (!plugin_default_version_check(version, &gcc_version)) { - std::cerr << "GCC version mismatch!" << std::endl; - return 1; - } - - register_callback(plugin_info->base_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); - - struct register_pass_info access_discover_pass_info; - access_discover_pass_info.pass = new access_discover_pass(nullptr); - access_discover_pass_info.ref_pass_instance_number = 1; - access_discover_pass_info.reference_pass_name = ACCESS_DISCOVER_PASS_REFPASS; - access_discover_pass_info.pos_op = ACCESS_DISCOVER_PASS_POSOP; - register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &access_discover_pass_info); - - return 0; -} diff --git a/deprecated/plugin/pattern.cpp b/deprecated/plugin/pattern.cpp deleted file mode 100644 index ab0dc31..0000000 --- a/deprecated/plugin/pattern.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "pattern.h" - -#include - -class PatternNode { -public: - enum OP { NOP /* just move */, ADD, SUB, NEG, CALL, MEMREF }; -private: - OP m_op; -public: - // ... -}; - -class PatternEdge { -public: - enum DATATYPE { VAR, CONST, FIELDOFF /* field offset is specialization of CONST */ }; -private: - DATATYPE m_datatype; - // std::size_t m_datasize; -public: - // ... -}; - -// TODO -> build pattern tree from output root to input leafs - -class LocationPattern { - // ... -public: - LocationPattern() {} - ~LocationPattern() {} -}; - -static std::unordered_map locations; - -int register_gimple_statement_pattern(gimple_stmt_iterator* gsi) { - gimple* stmt = gsi_stmt(*gsi); - enum gimple_code stmt_code = gimple_code(stmt); - location_t stmt_location = gimple_location(stmt); - - auto lp_it = locations.find(stmt_location); - if (lp_it == locations.end()) { - auto [new_it, success] = locations.emplace(stmt_location, LocationPattern{}); - if (!success) - return 1; - - lp_it = new_it; - } - - LocationPattern& pattern = lp_it->second; - - /* - for (unsigned i = 0; i < gimple_num_ops(stmt); ++i) { - tree op = gimple_op(stmt, i); - scan_tree_for_components(op, funcname, &gsi); - } - */ - - switch (stmt_code) { - case GIMPLE_CALL: - // check for offsetof, then fall through to operand scanning - case GIMPLE_ASSIGN: - case GIMPLE_COND: - case GIMPLE_LABEL: - case GIMPLE_RETURN: - return 0; - default: - return 1; - } - - return 0; -} - -void clean_unnecessary_patterns() { - // TODO -> erase all that do not contain a single member offset -} - -int register_rtl_instruction_pattern(rtx_insn* i) { - // TODO - return 0; -} - -int annotate_rtl() { - // TODO - return 0; -} diff --git a/deprecated/plugin/pattern.h b/deprecated/plugin/pattern.h deleted file mode 100644 index 53a027d..0000000 --- a/deprecated/plugin/pattern.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "gcc_includes.h" - -int register_gimple_statement_pattern(gimple_stmt_iterator* gsi); // 1 -void clean_unnecessary_patterns(); // 2 -int register_rtl_instruction_pattern(rtx_insn* i); // 3 -int annotate_rtl(); // 4 diff --git a/playground/commands.txt b/playground/commands.txt deleted file mode 100644 index 112b9c7..0000000 --- a/playground/commands.txt +++ /dev/null @@ -1,27 +0,0 @@ -../gcc/configure --enable-host-shared --disable-multilib --enable-languages=c,c++ --enable-plugin --disable-werror -make all-gcc -j8 -make all-target-libgcc -j8 -make all-target-libstdc++-v3 -j8 - -./gcc/xg++ -B./gcc/ -shared -fPIC -fno-rtti -I ../gcc/include -I ../gcc/gcc plugin.cpp -I ./gcc -I ./x86_64-pc-linux-gnu/libstdc++-v3/include -I ./x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu -I ../gcc/libstdc++-v3/include -I ../gcc/libstdc++-v3/libsupc++ -I ../gcc/libcpp/include -L ./x86_64-pc-linux-gnu/libstdc++-v3/src/.libs -o myplugin.so - -./gcc/xgcc -B./gcc -fplugin=./myplugin.so -fdump-tree-original test.c -o test - -git log -git format-patch -1 -python3 contrib/check_GNU_style.py gcc_component_ref.patch - - - - - - -Build and install: - -../gcc/configure --enable-host-shared --prefix=/usr/local/gcc-16 --program-suffix=16 --enable-languages=c,c++ --enable-plugin --disable-multilib --disable-werror --disable-bootstrap --disable-libsanitizer --disable-libquadmath --disable-libvtv - -make -j8 -sudo make install - -sudo ln -s /usr/local/gcc-16/bin/gcc16 /usr/local/bin/gcc-16 -sudo ln -s /usr/local/gcc-16/bin/g++16 /usr/local/bin/g++-16 diff --git a/playground/plugin.cpp b/playground/plugin.cpp deleted file mode 100644 index 99e14ec..0000000 --- a/playground/plugin.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int plugin_is_GPL_compatible; - -struct MemberOffset { - using UID = unsigned long; - - std::string type; - std::string member; - unsigned long offset; -}; - -static MemberOffset::UID next_moffset_uid = 0; -static std::unordered_map member_offset_occasions; - -static void print_gimple_tree(tree t, int depth, int indent = 2) { - if (!t) - return; - - for (int i = 0; i < depth; ++i) - std::cout << " "; - - std::cout << get_tree_code_name(TREE_CODE(t)); - - if (TREE_CODE(t) == FIELD_DECL && DECL_NAME(t)) - std::cout << " <" << IDENTIFIER_POINTER(DECL_NAME(t)) << ">"; - else if (TREE_CODE(t) == SSA_NAME && SSA_NAME_VAR(t) && DECL_NAME(SSA_NAME_VAR(t))) - std::cout << " "; - - std::cout << std::endl; - - for (int i = 0; i < TREE_CODE_LENGTH(TREE_CODE(t)); ++i) - print_gimple_tree(TREE_OPERAND(t, i), depth + indent, indent); -} - -static void print_gimple_statement(gimple* stmt) { - if (!stmt) - return; - - print_gimple_stmt(stdout, stmt, 0, TDF_NONE); - - for (unsigned i = 0; i < gimple_num_ops(stmt); ++i) { - tree operand = gimple_op(stmt, i); - print_gimple_tree(operand, 2, 2); - } -} - -static bool is_member_offset(gimple* stmt, MemberOffset::UID& uid) { - if (!is_gimple_call(stmt)) - return false; - - tree fndecl = gimple_call_fndecl(stmt); - if (!fndecl || !DECL_NAME(fndecl)) - return false; - - const char *fname = IDENTIFIER_POINTER(DECL_NAME(fndecl)); - if (!fname || strcmp(fname, "__get_member_offset") != 0) - return false; - - if (gimple_call_num_args(stmt) != 1) - return false; - - tree farg0 = gimple_call_arg(stmt, 0); - if (!farg0 || TREE_CODE(farg0) != INTEGER_CST) - return false; - - uid = (MemberOffset::UID) tree_to_uhwi(farg0); - return true; -} - -static int scan_gimple_statement(const char* funcname, gimple_stmt_iterator* gsi) { - print_gimple_statement(gsi_stmt(*gsi)); - - // Replace calls (later do it in RTL with UNSPECs) - MemberOffset::UID moffset_uid; - if (is_member_offset(gsi_stmt(*gsi), moffset_uid)) { - auto moit = member_offset_occasions.find(moffset_uid); - if (moit == member_offset_occasions.end()) { - std::cout << "Failed to find member offset occasion data!" << std::endl; - return 1; - } - - const MemberOffset& mo = moit->second; - - tree lhs = gimple_get_lhs(gsi_stmt(*gsi)); - tree ctype = lhs ? TREE_TYPE(lhs) : size_type_node; - - tree cst = build_int_cst(ctype, mo.offset); - - if (lhs) { - gimple *assign = gimple_build_assign(lhs, cst); - gsi_replace(gsi, assign, true); - std::cout << "REPLACED MOFF " << moffset_uid << " -> offsetof(" << mo.type << ", " << mo.member << ")" << std::endl; - print_gimple_statement(gsi_stmt(*gsi)); - } else { - gsi_remove(gsi, true); - std::cout << "REMOVED MOFF " << moffset_uid << " -> offsetof(" << mo.type << ", " << mo.member << ")" << std::endl; - } - } - - return 0; -} - -static const pass_data access_discover_pass_data = { - GIMPLE_PASS, - "access_discover", - OPTGROUP_NONE, - TV_NONE, - 0,0,0,0, - TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il -}; - -struct access_discover_pass : gimple_opt_pass { - access_discover_pass(gcc::context *ctxt); - unsigned int execute(function* fun) override; -}; - -access_discover_pass::access_discover_pass(gcc::context *ctxt) : gimple_opt_pass(access_discover_pass_data, ctxt) {} - -unsigned int access_discover_pass::execute(function* fun) { - const char* funcname = fun->decl && DECL_NAME(fun->decl) - ? IDENTIFIER_POINTER(DECL_NAME(fun->decl)) - : ""; - - basic_block bb; - FOR_EACH_BB_FN(bb, fun) { - for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { - if (scan_gimple_statement(funcname, &gsi) != 0) { - internal_error("fatal error in spslr plugin: %s", "failed to scan gimple statement"); - return 0; - } - } - } - - return 0; -} - -static tree my_component_ref_cb (tree ref) -{ - tree base = TREE_OPERAND (ref, 0); /* p */ - tree field = TREE_OPERAND (ref, 1); /* FIELD_DECL */ - tree basetype = TREE_TYPE (base); /* struct type */ - - if (!basetype || TREE_CODE (basetype) != RECORD_TYPE) - return NULL_TREE; /* Not a struct, leave alone. */ - - /* Choose which structs you care about. */ - const char *name = NULL; - if (TYPE_NAME (basetype)) - { - tree tn = TYPE_NAME (basetype); - if (TREE_CODE (tn) == TYPE_DECL && DECL_NAME (tn)) - name = IDENTIFIER_POINTER (DECL_NAME (tn)); - else if (TREE_CODE (tn) == IDENTIFIER_NODE) - name = IDENTIFIER_POINTER (tn); - } - - if (!name || strcmp (name, "task_struct") != 0) - return NULL_TREE; /* Only modify struct Tracked. */ - - location_t loc = EXPR_LOCATION (ref); - tree result_type = TREE_TYPE (ref); /* type of the field access */ - - /* 1. Build the __get_member_offset call. TODO -> Do not redo it every time... */ - tree param_types = - tree_cons (NULL_TREE, long_unsigned_type_node, NULL_TREE); - tree fntype = build_function_type (sizetype, param_types); - - tree fn = build_fn_decl ("__get_member_offset", fntype); - DECL_EXTERNAL (fn) = 1; - TREE_PUBLIC (fn) = 1; - DECL_ARTIFICIAL (fn) = 1; - - // Prevent VOP problems later when removing calls (VOPs manage memory effects, which these calls have none of) - DECL_PURE_P(fn) = 1; - DECL_IS_NOVOPS(fn) = 1; - - tree off_tree = byte_position(field); - if (!off_tree || TREE_CODE(off_tree) != INTEGER_CST) { - std::cout << "Failed to get member offset!" << std::endl; - return NULL_TREE; - } - - unsigned long member_offset = (unsigned long) tree_to_uhwi(off_tree); - - std::string member_name; - - tree member_name_id = DECL_NAME(field); - if (!member_name_id) - member_name = std::string{ "" }; // e.g. unnamed bitfields - - member_name = std::string{ IDENTIFIER_POINTER(member_name_id) }; - - unsigned long next_uid = next_moffset_uid++; - - MemberOffset moffset; - moffset.type = std::string{ name }; - moffset.member = member_name; - moffset.offset = member_offset; - - member_offset_occasions.emplace(next_uid, moffset); - - tree moffset_uid = build_int_cst (long_unsigned_type_node, next_uid); - - tree offset_call = build_call_expr_loc (loc, fn, 1, moffset_uid); - // TREE_SIDE_EFFECTS (offset_call) = 1; // Maybe not - - /* 2. Get a (char *) pointer to the base. */ - tree char_ptr_type = build_pointer_type (char_type_node); - tree base_ptr = NULL_TREE; - - if (POINTER_TYPE_P (TREE_TYPE (base))) - { - // TODO -> Is it actually a pointer? INDIRECT_REF is used, so it is dereferenced already! - /* Case: p->member, base is already a pointer. */ - base_ptr = build1_loc (loc, NOP_EXPR, char_ptr_type, - build1_loc (loc, NOP_EXPR, - TREE_TYPE (char_ptr_type), base)); - } - else - { - /* Case: T.member, take its address. */ - tree base_addr = build1_loc (loc, ADDR_EXPR, - build_pointer_type (TREE_TYPE (base)), - base); - // TODO -> case of INDIRECT_REF is 2 blocks that cancel each other out -> &*ptr - base_ptr = build1_loc (loc, NOP_EXPR, char_ptr_type, base_addr); - } - - /* 3. Add offset and cast back to field pointer, then dereference. */ - tree plus = build2_loc (loc, POINTER_PLUS_EXPR, char_ptr_type, - base_ptr, offset_call); - - tree field_ptr_type = build_pointer_type (result_type); - tree cast_back = build1_loc (loc, NOP_EXPR, field_ptr_type, plus); - - tree new_ref = build1_loc (loc, INDIRECT_REF, result_type, cast_back); - - /* Optional: mark to suppress further folding. */ - // TREE_SIDE_EFFECTS (new_ref) = 1; - - return new_ref; // ALWAYS an INDIRECT_REF, directly to the member (same type as COMPONENT_REF!) -} - -static void build_component_ref_cb(void* event_data, void* user_data) { - tree* component_ref_node = (tree*)event_data; - if (!component_ref_node) - return; - - tree repl = my_component_ref_cb(*component_ref_node); - if (repl) - *component_ref_node = repl; -} - -int plugin_init (struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) { - if (!plugin_default_version_check(version, &gcc_version)) { - std::cerr << "GCC version mismatch!" << std::endl; - return 1; - } - - register_callback(plugin_info->base_name, PLUGIN_BUILD_COMPONENT_REF, build_component_ref_cb, NULL); - - struct register_pass_info access_discover_pass_info; - access_discover_pass_info.pass = new access_discover_pass(nullptr); - access_discover_pass_info.ref_pass_instance_number = 1; - access_discover_pass_info.reference_pass_name = "optimized"; - access_discover_pass_info.pos_op = PASS_POS_INSERT_AFTER; - register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &access_discover_pass_info); - - return 0; -} - diff --git a/playground/spslr_pinpoint.cpp b/playground/spslr_pinpoint.cpp deleted file mode 100644 index 12cd9d0..0000000 --- a/playground/spslr_pinpoint.cpp +++ /dev/null @@ -1,344 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int plugin_is_GPL_compatible; - -#ifndef SPSLR_OFFSETOF -#define SPSLR_OFFSETOF "__spslr_offsetof_" /* with suffix */ -#endif - -#ifndef UNSPEC_SPSLR_OFFSETOF -#define UNSPEC_SPSLR_OFFSETOF 1042 -#endif - -// At early RTL, replace __spslr_offsetof_ with UNSPECs to avoid ABI and clobbering "problems" - -static bool extract_callee_symbol (rtx call_rtx, const char** out_name) { - if (!call_rtx || GET_CODE(call_rtx) != CALL) - return false; - - rtx op0 = XEXP(call_rtx, 0); - if (!op0) - return false; - - rtx addr = XEXP(op0, 0); - if (addr && GET_CODE(addr) == SYMBOL_REF) { - *out_name = XSTR(addr, 0); - return true; - } - - return false; -} - -static bool parse_uid_from_name(const char* name, unsigned long* out_uid) { - if (!name || !out_uid) - return false; - - if (strncmp(name, SPSLR_OFFSETOF, strlen(SPSLR_OFFSETOF)) != 0) - return false; - - const char *p = name + strlen(SPSLR_OFFSETOF); - if (*p == 0) - return false; - - char *endp = nullptr; - unsigned long v = strtoul(p, &endp, 10); - if (endp == p) - return false; - - *out_uid = v; - return true; -} - -static bool extract_dest_and_call (rtx pat, rtx* out_dest, rtx* out_call) { - if (!pat) - return false; - - if (GET_CODE(pat) == SET) { - rtx src = SET_SRC(pat); - if (GET_CODE(src) == CALL) { - *out_dest = SET_DEST(pat); - *out_call = src; - return true; - } - return false; - } - - if (GET_CODE(pat) == PARALLEL) { - // Look for a SET whose src is CALL - int n = XVECLEN(pat, 0); - for (int i = 0; i < n; ++i) { - rtx elt = XVECEXP(pat, 0, i); - if (GET_CODE(elt) == SET && GET_CODE(SET_SRC(elt)) == CALL) { - *out_dest = SET_DEST(elt); - *out_call = SET_SRC(elt); - return true; - } - } - } - - return false; -} - -static void call_to_unspec(function* fn) { - if (!fn) - return; - - unsigned replaced = 0; - - basic_block bb; - FOR_EACH_BB_FN(bb, fn) { - for (rtx_insn* insn = BB_HEAD(bb); insn != NEXT_INSN(BB_END(bb)); insn = NEXT_INSN(insn)) { - if (!INSN_P(insn) || !CALL_P(insn)) - continue; - - rtx pat = PATTERN(insn); - rtx dest = NULL_RTX; - rtx call = NULL_RTX; - if (!extract_dest_and_call(pat, &dest, &call)) - continue; - - const char *name = nullptr; - if (!extract_callee_symbol(call, &name)) - continue; - - unsigned long uid = 0; - if (!parse_uid_from_name(name, &uid)) - continue; - - // We expect a returning call (assigned to dest) - if (!dest || !REG_P(dest) || GET_MODE(dest) == VOIDmode) - continue; - - machine_mode mode = GET_MODE(dest); - - // Build: (set dest (unspec:mode [(const_int uid)] UNSPEC_SPSLR_OFFSETOF)) - rtvec vec = gen_rtvec(1, GEN_INT((HOST_WIDE_INT) uid)); - rtx uns = gen_rtx_UNSPEC(mode, vec, UNSPEC_SPSLR_OFFSETOF); // Note -> maybe volatile - rtx set = gen_rtx_SET(dest, uns); - - emit_insn_before(set, insn); - delete_insn(insn); - replaced++; - } - } - - if (replaced) { - df_set_bb_dirty(ENTRY_BLOCK_PTR_FOR_FN(fn)); - df_set_bb_dirty(EXIT_BLOCK_PTR_FOR_FN(fn)); - } -} - -const pass_data call_to_unspec_pass_data = { - RTL_PASS, - "call_to_unspec", - OPTGROUP_NONE, - TV_NONE, - PROP_rtl, - 0, 0, 0, 0 -}; - -struct call_to_unspec_pass : rtl_opt_pass { - call_to_unspec_pass(gcc::context* ctxt) - : rtl_opt_pass(call_to_unspec_pass_data, ctxt) {} - - unsigned int execute(function* fn) override { - call_to_unspec(fn); - return 0; - } -}; - -// Late RTL pass replaces UNSPECs with labeled constants (must happen before vregs, no optimizations afterwards) - -static bool lookup_initial_member_offset(SPSLROffsetofCallData::UID uid, Member::OFF& ioff) { - auto call_data_it = spslr_offsetof_calls.find(uid); - if (call_data_it == spslr_offsetof_calls.end()) - return false; - - const SPSLROffsetofCallData& call_data = call_data_it->second; - - // call_data.target, call_data.member - - ioff = call_data.member; - return true; -} - -static void emit_named_asm_label_before(SPSLROffsetofCallData::UID uid, rtx_insn* before) { - char name[128]; - snprintf(name, sizeof(name), "%s%lu:\n", SPSLR_OFFSETOF, uid); - - rtvec no_out = rtvec_alloc(0); - rtvec no_in = rtvec_alloc(0); - rtvec no_cl = rtvec_alloc(0); - const char* empty_constraints = ""; - - location_t loc = INSN_LOCATION(before); - - rtx asmops = gen_rtx_ASM_OPERANDS (VOIDmode, ggc_strdup(name), empty_constraints, 1, no_out, no_in, no_cl, loc); - emit_insn_before (asmops, before); -} - -static rtx labeled_cst_mov(SPSLROffsetofCallData::UID uid, rtx dest, Member::OFF ioff, location_t loc) { - char asm_str[128]; - snprintf(asm_str, sizeof(asm_str), "%s%lu:\nmov %1, %0\n", SPSLR_OFFSETOF, uid); - - // rtl.def - // -> DEF_RTL_EXPR(ASM_INPUT, "asm_input", "sL", RTX_EXTRA) -> only string+location in ASM_INPUT - // -> DEF_RTL_EXPR(ASM_OPERANDS, "asm_operands", "ssiEEEL", RTX_EXTRA) - - rtx desc_in1 = gen_rtx_ASM_INPUT(SImode, ggc_strdup("i")); - rtvec desc_inputs = gen_rtvec(1, desc_in1); - rtvec inputs = gen_rtvec(1, GEN_INT(ioff)); - - const char* desc_outputs = "=r"; - rtvec outputs = gen_rtvec(1, dest); - - rtvec labels = rtvec_alloc(0); - - rtx asmops = gen_rtx_ASM_OPERANDS(GET_MODE(dest), - ggc_strdup(asm_str), /* template */ - ggc_strdup(desc_outputs), /* output constraint */ - 0, /* output number */ - inputs, /* vector of input RTXs */ - desc_inputs, /* vector of input descriptors */ - labels, /* labels (empty) */ - loc); /* source location */ - - rtx cc_clob = gen_rtx_CLOBBER(VOIDmode, gen_rtx_REG(CCmode, 17)); - - rtvec vec = gen_rtvec (2, gen_rtx_SET(dest, asmops), cc_clob); - rtx parallel = gen_rtx_PARALLEL(VOIDmode, vec); - - return parallel; -} - -static void unspec_to_labeled_const(function* fn) { - basic_block bb; - FOR_EACH_BB_FN(bb, fn) { - for (rtx_insn *insn = BB_HEAD(bb); insn != NEXT_INSN(BB_END(bb)); insn = NEXT_INSN(insn)) { - if (!INSN_P(insn)) - continue; - - rtx pat = PATTERN(insn); - if (GET_CODE(pat) != SET) - continue; - - rtx src = SET_SRC(pat); - if (GET_CODE(src) != UNSPEC) - continue; - - if (XINT(src, 1) != UNSPEC_SPSLR_OFFSETOF) - continue; - - /* Extract UID from UNSPEC operands. */ - if (XVEC(src, 0) == NULL || XVECLEN(src, 0) < 1) - continue; - - rtx arg = XVECEXP(src, 0, 0); - if (!CONST_INT_P(arg)) - continue; - - SPSLROffsetofCallData::UID uid = (SPSLROffsetofCallData::UID)INTVAL(arg); - rtx dest = SET_DEST(pat); - - Member::OFF initial_offset = uid; // TODO -> Use value that forces 32 bit (currently uses 32 bit anyways)? - if (!lookup_initial_member_offset(uid, initial_offset)) { - std::cerr << "Failed to query initial member offset for access uid " << uid << "!" << std::endl; - return; - } - - // TODO - - PATTERN(insn) = labeled_cst_mov(uid, dest, initial_offset, INSN_LOCATION(insn)); - INSN_CODE(insn) = -1; - df_insn_rescan(insn); - - /* - // Generate asm label - emit_named_asm_label_before(uid, insn); - - rtx new_set = gen_rtx_SET(dest, GEN_INT(initial_offset)); - PATTERN(insn) = new_set; - INSN_CODE(insn) = -1; // force re-recognition - */ - - std::cout << "Inserted labeled initial member offset " << initial_offset - << " for access uid " << uid << "!" << std::endl; - } - } -} - -const pass_data unspec_to_lconst_pass_data = { - RTL_PASS, - "unspec_to_lconst", - OPTGROUP_NONE, - TV_NONE, - PROP_rtl, - 0, 0, 0, 0 -}; - -struct unspec_to_lconst_pass : rtl_opt_pass { - unspec_to_lconst_pass (gcc::context *ctxt) - : rtl_opt_pass(unspec_to_lconst_pass_data, ctxt) {} - - unsigned int execute(function* fn) override { - unspec_to_labeled_const(fn); - return 0; - } -}; - - -// Hook everything up in plugin_init - -int plugin_init (struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) { - if (!plugin_default_version_check(version, &gcc_version)) { - fprintf(stderr, "GCC version mismatch!\n"); - std::cerr << "spslr_pinpoint -> GCC version mismatch" << std::endl; - return 1; - } - - /* - TODO - vregs is almost immediately after expand (maybe the first one) - optimizations happen afterwards (e.g. forward propagation in rtl-fwprop1) - */ - - struct register_pass_info call_to_unspec_pass_info; - call_to_unspec_pass_info.pass = new call_to_unspec_pass(nullptr); - call_to_unspec_pass_info.reference_pass_name = "vregs"; // "expand"; - call_to_unspec_pass_info.ref_pass_instance_number = 1; - call_to_unspec_pass_info.pos_op = PASS_POS_INSERT_AFTER; - register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &call_to_unspec_pass_info); - - struct register_pass_info unspec_to_lconst_pass_info; - unspec_to_lconst_pass_info.pass = new unspec_to_lconst_pass(nullptr); - unspec_to_lconst_pass_info.reference_pass_name = "call_to_unspec"; // "vregs"; - unspec_to_lconst_pass_info.ref_pass_instance_number = 1; - unspec_to_lconst_pass_info.pos_op = PASS_POS_INSERT_AFTER; // PASS_POS_INSERT_BEFORE; - register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &unspec_to_lconst_pass_info); - - return 0; -}