Deleted deprecated stuff
This commit is contained in:
parent
989aa63881
commit
58a54f5200
@ -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)
|
||||
@ -1,72 +0,0 @@
|
||||
#include "access_discover.h"
|
||||
#include "pattern.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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 << " <ssa " << IDENTIFIER_POINTER(DECL_NAME(SSA_NAME_VAR(t))) << ">";
|
||||
|
||||
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))
|
||||
: "<anonymous>";
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
#include "attrib.h"
|
||||
|
||||
#include "gcc_includes.h"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
|
||||
static std::unordered_set<std::string> 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();
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define SPSRL_ATTRIBUTE "slr"
|
||||
|
||||
void register_attributes(void* event_data, void* data);
|
||||
bool is_target(const char* name);
|
||||
@ -1,25 +0,0 @@
|
||||
#ifndef GCC_PLUGIN_INCLUDES_H
|
||||
#define GCC_PLUGIN_INCLUDES_H
|
||||
|
||||
#include <gcc-plugin.h>
|
||||
#include <plugin-version.h>
|
||||
#include <tree.h>
|
||||
#include <gimple.h>
|
||||
#include <gimplify.h>
|
||||
#include <gimple-iterator.h>
|
||||
#include <rtl.h>
|
||||
#include <rtl-iter.h>
|
||||
#include <basic-block.h>
|
||||
#include <gimple-ssa.h>
|
||||
#include <tree-pass.h>
|
||||
#include <pretty-print.h>
|
||||
#include <tree-pretty-print.h>
|
||||
#include <diagnostic.h>
|
||||
#include <gimple-pretty-print.h>
|
||||
#include <obstack.h>
|
||||
#include <cgraph.h>
|
||||
#include <context.h>
|
||||
#include <function.h>
|
||||
#include <builtins.h>
|
||||
|
||||
#endif
|
||||
@ -1,25 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
#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;
|
||||
}
|
||||
@ -1,85 +0,0 @@
|
||||
#include "pattern.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
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<location_t, LocationPattern> 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;
|
||||
}
|
||||
@ -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
|
||||
@ -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 <hash>
|
||||
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
|
||||
@ -1,291 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <gcc-plugin.h>
|
||||
#include <plugin-version.h>
|
||||
#include <tree.h>
|
||||
#include <gimple.h>
|
||||
#include <gimplify.h>
|
||||
#include <gimple-iterator.h>
|
||||
#include <basic-block.h>
|
||||
#include <gimple-ssa.h>
|
||||
#include <tree-pass.h>
|
||||
#include <pretty-print.h>
|
||||
#include <tree-pretty-print.h>
|
||||
#include <diagnostic.h>
|
||||
#include <gimple-pretty-print.h>
|
||||
#include <obstack.h>
|
||||
#include <cgraph.h>
|
||||
#include <context.h>
|
||||
#include <function.h>
|
||||
#include <builtins.h>
|
||||
#include <unordered_map>
|
||||
|
||||
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<MemberOffset::UID, MemberOffset> 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 << " <ssa " << IDENTIFIER_POINTER(DECL_NAME(SSA_NAME_VAR(t))) << ">";
|
||||
|
||||
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))
|
||||
: "<anonymous>";
|
||||
|
||||
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{ "<anonymous>" }; // 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;
|
||||
}
|
||||
|
||||
@ -1,344 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#include <gcc-plugin.h>
|
||||
#include <plugin-version.h>
|
||||
#include <tree.h>
|
||||
#include <langhooks.h>
|
||||
#include <gimple.h>
|
||||
#include <gimplify.h>
|
||||
#include <stringpool.h>
|
||||
#include <tree-pass.h>
|
||||
#include <gimple-iterator.h>
|
||||
#include <gimple-pretty-print.h>
|
||||
#include <tree-pretty-print.h>
|
||||
#include <tree-dump.h>
|
||||
#include <print-tree.h>
|
||||
#include <tree-iterator.h>
|
||||
#include <rtl.h>
|
||||
#include <memmodel.h>
|
||||
#include <emit-rtl.h>
|
||||
#include <df.h>
|
||||
|
||||
int plugin_is_GPL_compatible;
|
||||
|
||||
#ifndef SPSLR_OFFSETOF
|
||||
#define SPSLR_OFFSETOF "__spslr_offsetof_" /* with suffix <uid> */
|
||||
#endif
|
||||
|
||||
#ifndef UNSPEC_SPSLR_OFFSETOF
|
||||
#define UNSPEC_SPSLR_OFFSETOF 1042
|
||||
#endif
|
||||
|
||||
// At early RTL, replace __spslr_offsetof_<uid> 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;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user