diff --git a/playground/spslr_pinpoint.cpp b/playground/spslr_pinpoint.cpp index b7963a4..3e96394 100644 --- a/playground/spslr_pinpoint.cpp +++ b/playground/spslr_pinpoint.cpp @@ -358,6 +358,11 @@ struct log_component_refs_pass : gimple_opt_pass { log_component_refs_pass::log_component_refs_pass(gcc::context *ctxt) : gimple_opt_pass(log_component_refs_pass_data, ctxt) {} static tree gimple_instrument_offsetof_maybe(tree ref, gimple_stmt_iterator* gsi) { + // TODO -> nested COMPONENT_REFs! + + if (!ref || TREE_CODE(ref) != COMPONENT_REF) + return NULL_TREE; + SPSLROffsetofCallData call_data; if (!is_relevant_offsetof(ref, call_data.target, call_data.member)) return NULL_TREE; @@ -421,30 +426,85 @@ static tree gimple_instrument_offsetof_maybe(tree ref, gimple_stmt_iterator* gsi return new_ref; } -static tree log_gimple_operand_component_refs(tree *tp, int *walk_subtrees, void *data) { - gimple_stmt_iterator* gsi = (gimple_stmt_iterator*)data; - *walk_subtrees = 1; +static void instrument_tree(const std::list& path, gimple_stmt_iterator* gsi, unsigned& cancel_levels) { + if (path.empty() || !gsi) + return; - if (!tp || !*tp) - return NULL_TREE; - - if (TREE_CODE(*tp) != COMPONENT_REF) - return NULL_TREE; - - tree repl = gimple_instrument_offsetof_maybe(*tp, gsi); - if (!repl) - return NULL_TREE; - - // TODO -> Recursively do sub-component-refs - // After top level split, the base is in a separate stmt! - - *tp = repl; - *walk_subtrees = 0; + tree instrumented_ref = gimple_instrument_offsetof_maybe(*path.back(), gsi); + if (!instrumented_ref) + return; gimple_set_modified(gsi_stmt(*gsi), true); - walk_tree(tp, log_gimple_operand_component_refs, data, NULL); - return NULL_TREE; + *path.back() = instrumented_ref; + cancel_levels = 1; + + // At this point, instrumented_ref is a MEM_REF node (off=0). A wrapping ADDR_EXPR cancels it out. + + if (path.size() < 2) + return; + + tree* parent = *(++path.rbegin()); + + if (TREE_CODE(*parent) == ADDR_EXPR) { + // Note -> the base of the MEM_REF is expected to have the same type as the ADDR_EXPR + *parent = TREE_OPERAND(instrumented_ref, 0); + cancel_levels++; + } +} + +struct TreeWalkData { + std::list path; + gimple_stmt_iterator* gsi; + unsigned cancel_levels; +}; + +static tree walk_tree_level(tree* tp, int* walk_subtrees, void* data) { + TreeWalkData* twd = (TreeWalkData*)data; + if (!twd) + return NULL_TREE; + + if (!twd->path.empty() && twd->path.back() == tp) + return NULL_TREE; // root of this level + + if (walk_subtrees) + *walk_subtrees = 0; + + twd->cancel_levels = 0; + twd->path.push_back(tp); + + instrument_tree(twd->path, twd->gsi, twd->cancel_levels); + + if (twd->cancel_levels == 0) + walk_tree(tp, walk_tree_level, data, NULL); + + twd->path.pop_back(); + + if (twd->cancel_levels > 0) + twd->cancel_levels--; + + // Cancel current level if there are still cancel_levels due + return twd->cancel_levels == 0 ? NULL_TREE : *tp; +} + +static bool walk_gimple_stmt(gimple_stmt_iterator* gsi) { + if (!gsi || gsi_end_p(*gsi)) + return false; + + gimple* stmt = gsi_stmt(*gsi); + + for (int i = 0; i < gimple_num_ops(stmt); i++) { + tree* op = gimple_op_ptr(stmt, i); + if (!op || !*op) + continue; + + TreeWalkData twd; + twd.gsi = gsi; + + walk_tree_level(op, NULL, &twd); + } + + return true; } unsigned int log_component_refs_pass::execute(function* fun) { @@ -457,17 +517,7 @@ unsigned int log_component_refs_pass::execute(function* fun) { return 0; gimple_seq body = gimple_body(fndecl); - for (gimple_stmt_iterator gsi = gsi_start(body); !gsi_end_p(gsi); gsi_next(&gsi)) { - gimple* stmt = gsi_stmt(gsi); - - for (int i = 0; i < gimple_num_ops(stmt); i++) { - tree* op = gimple_op_ptr(stmt, i); - if (!op || !*op) - continue; - - walk_tree(op, log_gimple_operand_component_refs, &gsi, NULL); - } - } + for (gimple_stmt_iterator gsi = gsi_start(body); walk_gimple_stmt(&gsi); gsi_next(&gsi)); // print_gimple_seq(stderr, gimple_body(fun->decl), 0, TDF_NONE); return 0; @@ -519,7 +569,7 @@ int plugin_init (struct plugin_name_args *plugin_info, struct plugin_gcc_version register_callback(plugin_info->base_name, PLUGIN_ATTRIBUTES, on_register_attributes, NULL); register_callback(plugin_info->base_name, PLUGIN_FINISH_TYPE, on_type_complete, NULL); - register_callback(plugin_info->base_name, PLUGIN_BUILD_COMPONENT_REF, on_build_component_ref, NULL); + // TODO register_callback(plugin_info->base_name, PLUGIN_BUILD_COMPONENT_REF, on_build_component_ref, NULL); struct register_pass_info log_component_refs_pass_info; log_component_refs_pass_info.pass = new log_component_refs_pass(nullptr);