Implemented array handling
This commit is contained in:
parent
7e85fadccf
commit
e7851641a1
@ -36,6 +36,37 @@ static bool compile_datapin(tree type, DataPin& pin, std::size_t offset = 0, std
|
|||||||
res = true;
|
res = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TREE_CODE(type) == ARRAY_TYPE) {
|
||||||
|
tree elem_type = TREE_TYPE(type);
|
||||||
|
tree domain = TYPE_DOMAIN(type);
|
||||||
|
if (!elem_type || !domain)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
tree min_t = TYPE_MIN_VALUE(domain);
|
||||||
|
tree max_t = TYPE_MAX_VALUE(domain);
|
||||||
|
if (!min_t || !max_t ||
|
||||||
|
TREE_CODE(min_t) != INTEGER_CST ||
|
||||||
|
TREE_CODE(max_t) != INTEGER_CST)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
HOST_WIDE_INT min_i = tree_to_shwi(min_t);
|
||||||
|
HOST_WIDE_INT max_i = tree_to_shwi(max_t);
|
||||||
|
std::size_t elem_size = tree_to_uhwi(TYPE_SIZE_UNIT(elem_type));
|
||||||
|
|
||||||
|
for (HOST_WIDE_INT i = min_i; i <= max_i; ++i) {
|
||||||
|
bool sub_res = compile_datapin(
|
||||||
|
elem_type,
|
||||||
|
pin,
|
||||||
|
offset + (std::size_t)(i - min_i) * elem_size,
|
||||||
|
level + 1
|
||||||
|
);
|
||||||
|
res = res || sub_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note -> should probably make sure that randomized structs are never used in unions!
|
||||||
if (TREE_CODE(type) != RECORD_TYPE /* && TREE_CODE(type) != UNION_TYPE */)
|
if (TREE_CODE(type) != RECORD_TYPE /* && TREE_CODE(type) != UNION_TYPE */)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
|||||||
@ -4,16 +4,23 @@
|
|||||||
|
|
||||||
#include <pinpoint_error.h>
|
#include <pinpoint_error.h>
|
||||||
|
|
||||||
struct ComponentRefChain {
|
struct AccessChain {
|
||||||
struct Link {
|
struct Step {
|
||||||
|
enum Kind {
|
||||||
|
STEP_COMPONENT,
|
||||||
|
STEP_ARRAY
|
||||||
|
} kind = STEP_COMPONENT;
|
||||||
|
|
||||||
tree t = NULL_TREE;
|
tree t = NULL_TREE;
|
||||||
|
|
||||||
|
/* COMPONENT_REF data */
|
||||||
bool relevant = false;
|
bool relevant = false;
|
||||||
UID target;
|
UID target = UID_INVALID;
|
||||||
std::size_t offset;
|
std::size_t offset = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool relevant = false;
|
bool relevant = false;
|
||||||
std::list<Link> links;
|
std::list<Step> steps;
|
||||||
tree base = NULL_TREE;
|
tree base = NULL_TREE;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,100 +42,109 @@ static bool tree_contains_component_ref(tree ref) {
|
|||||||
return found_flag != 0;
|
return found_flag != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool component_ref_chain(tree ref, ComponentRefChain& chain) {
|
static bool access_chain(tree ref, AccessChain& chain) {
|
||||||
if (!ref)
|
if (!ref)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (TREE_CODE(ref) != COMPONENT_REF) {
|
switch (TREE_CODE(ref)) {
|
||||||
if (chain.links.empty())
|
case COMPONENT_REF: {
|
||||||
return false;
|
AccessChain::Step step;
|
||||||
|
step.kind = AccessChain::Step::STEP_COMPONENT;
|
||||||
|
step.t = ref;
|
||||||
|
step.relevant = TargetType::reference(ref, step.target, step.offset);
|
||||||
|
if (step.relevant)
|
||||||
|
chain.relevant = true;
|
||||||
|
chain.steps.push_front(step);
|
||||||
|
return access_chain(TREE_OPERAND(ref, 0), chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
case ARRAY_REF:
|
||||||
|
case ARRAY_RANGE_REF: {
|
||||||
|
AccessChain::Step step;
|
||||||
|
step.kind = AccessChain::Step::STEP_ARRAY;
|
||||||
|
step.t = ref;
|
||||||
|
chain.steps.push_front(step);
|
||||||
|
return access_chain(TREE_OPERAND(ref, 0), chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
if (tree_contains_component_ref(ref))
|
if (tree_contains_component_ref(ref))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
chain.base = ref;
|
chain.base = ref;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentRefChain::Link link;
|
|
||||||
link.t = ref;
|
|
||||||
link.relevant = TargetType::reference(ref, link.target, link.offset);
|
|
||||||
|
|
||||||
if (link.relevant)
|
|
||||||
chain.relevant = true;
|
|
||||||
|
|
||||||
chain.links.push_front(link);
|
|
||||||
return component_ref_chain(TREE_OPERAND(ref, 0), chain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static tree separate_offset_chain_maybe(tree ref, gimple_stmt_iterator* gsi) {
|
static tree separate_offset_chain_maybe(tree ref, gimple_stmt_iterator* gsi) {
|
||||||
ComponentRefChain crc;
|
AccessChain chain;
|
||||||
if (!component_ref_chain(ref, crc))
|
if (!access_chain(ref, chain)) {
|
||||||
pinpoint_fatal("separate_offset_chain_maybe encountered invalid COMPONENT_REF chain");
|
pinpoint_fatal("separate_offset_chain_maybe encountered invalid access chain: top=%s base=%s",
|
||||||
|
get_tree_code_name(TREE_CODE(ref)),
|
||||||
|
TREE_OPERAND(ref, 0) ? get_tree_code_name(TREE_CODE(TREE_OPERAND(ref, 0))) : "<null>");
|
||||||
|
}
|
||||||
|
|
||||||
if (!crc.relevant)
|
if (!chain.relevant)
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
|
|
||||||
// Get base pointer
|
tree cur_expr = chain.base;
|
||||||
|
|
||||||
tree base_tmp = NULL_TREE;
|
// NOTE -> Could fold into single call here (needs to track what offsets contribute, +irrelevant combined)
|
||||||
|
|
||||||
if (TREE_CODE(crc.base) == ADDR_EXPR)
|
for (const AccessChain::Step& step : chain.steps) {
|
||||||
|
if (step.kind == AccessChain::Step::STEP_COMPONENT) {
|
||||||
|
if (TREE_CODE(cur_expr) == ADDR_EXPR)
|
||||||
pinpoint_fatal("separate_offset_chain_maybe encountered ADDR_EXPR as base of COMPONENT_REF");
|
pinpoint_fatal("separate_offset_chain_maybe encountered ADDR_EXPR as base of COMPONENT_REF");
|
||||||
|
|
||||||
base_tmp = build_fold_addr_expr(crc.base);
|
tree cur_ptr = build_fold_addr_expr(cur_expr);
|
||||||
|
|
||||||
// For each component ref in chain, add the member offset to the pointer
|
tree field_ptr_type = build_pointer_type(TREE_TYPE(step.t));
|
||||||
|
tree field_ptr;
|
||||||
|
|
||||||
for (const ComponentRefChain::Link& cr : crc.links) {
|
if (step.relevant) {
|
||||||
// NOTE -> Could fold into single call here (needs to track what offsets contribute, +irrelevant combined)
|
|
||||||
if (cr.relevant) {
|
|
||||||
// Call is a separate statement, the result is added to the base pointer
|
|
||||||
tree return_tmp = create_tmp_var(size_type_node, NULL);
|
tree return_tmp = create_tmp_var(size_type_node, NULL);
|
||||||
|
gimple* call_stmt =
|
||||||
gimple* call_stmt = make_stage0_gimple_separator(return_tmp, cr.target, cr.offset);
|
make_stage0_gimple_separator(return_tmp, step.target, step.offset);
|
||||||
if (!call_stmt)
|
if (!call_stmt)
|
||||||
pinpoint_fatal("separate_offset_chain_maybe failed to make gimple separator for target %u at offset %u",
|
pinpoint_fatal("separate_offset_chain_maybe failed to make gimple separator");
|
||||||
(unsigned)cr.target, (unsigned)cr.offset);
|
|
||||||
|
|
||||||
gsi_insert_before(gsi, call_stmt, GSI_SAME_STMT);
|
gsi_insert_before(gsi, call_stmt, GSI_SAME_STMT);
|
||||||
|
field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type, cur_ptr, return_tmp);
|
||||||
// Add call return value to current base pointer (result is field pointer)
|
|
||||||
tree field_ptr_type = build_pointer_type(TREE_TYPE(cr.t));
|
|
||||||
tree field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type, base_tmp, return_tmp);
|
|
||||||
|
|
||||||
base_tmp = create_tmp_var(field_ptr_type, NULL);
|
|
||||||
gimple* field_ptr_assignment = gimple_build_assign(base_tmp, field_ptr);
|
|
||||||
gsi_insert_before(gsi, field_ptr_assignment, GSI_SAME_STMT);
|
|
||||||
} else {
|
} else {
|
||||||
// Add offsetof contant
|
tree field_decl = TREE_OPERAND(step.t, 1);
|
||||||
tree field_decl = TREE_OPERAND(cr.t, 1);
|
|
||||||
|
|
||||||
std::size_t field_offset;
|
std::size_t field_offset;
|
||||||
bool field_bitfield;
|
bool field_bitfield;
|
||||||
|
|
||||||
if (!field_info(field_decl, &field_offset, nullptr, nullptr, &field_bitfield))
|
if (!field_info(field_decl, &field_offset, nullptr, nullptr, &field_bitfield))
|
||||||
pinpoint_fatal("separate_offset_chain_maybe failed to get field info of non-target access");
|
pinpoint_fatal("separate_offset_chain_maybe failed to get field info of non-target access");
|
||||||
|
|
||||||
if (field_bitfield)
|
if (field_bitfield)
|
||||||
pinpoint_fatal("separate_offset_chain_maybe encountered bitfield access in relevant COMPONENT_REF chain");
|
pinpoint_fatal("separate_offset_chain_maybe encountered bitfield access in relevant COMPONENT_REF chain");
|
||||||
|
|
||||||
// Add constant offset to current base pointer (result is field pointer)
|
field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type,
|
||||||
tree field_ptr_type = build_pointer_type(TREE_TYPE(cr.t));
|
cur_ptr, build_int_cst(sizetype, field_offset));
|
||||||
tree field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type, base_tmp, build_int_cst(sizetype, field_offset));
|
}
|
||||||
|
|
||||||
base_tmp = create_tmp_var(field_ptr_type, NULL);
|
tree ptr_tmp = create_tmp_var(field_ptr_type, NULL);
|
||||||
gimple* field_ptr_assignment = gimple_build_assign(base_tmp, field_ptr);
|
gimple* ptr_assign = gimple_build_assign(ptr_tmp, field_ptr);
|
||||||
gsi_insert_before(gsi, field_ptr_assignment, GSI_SAME_STMT);
|
gsi_insert_before(gsi, ptr_assign, GSI_SAME_STMT);
|
||||||
|
|
||||||
|
// Dereference constructed pointer expression
|
||||||
|
|
||||||
|
tree offset0 = fold_convert(TREE_TYPE(ptr_tmp), build_int_cst(sizetype, 0));
|
||||||
|
cur_expr = build2(MEM_REF, TREE_TYPE(step.t), ptr_tmp, offset0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.kind == AccessChain::Step::STEP_ARRAY) {
|
||||||
|
tree idx = TREE_OPERAND(step.t, 1);
|
||||||
|
tree low = TREE_OPERAND(step.t, 2);
|
||||||
|
tree elts = TREE_OPERAND(step.t, 3);
|
||||||
|
|
||||||
|
cur_expr = build4(TREE_CODE(step.t), TREE_TYPE(step.t), cur_expr, idx, low, elts);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current pointer is a field pointer -> dereference
|
return cur_expr;
|
||||||
|
|
||||||
tree offset0 = fold_convert(TREE_TYPE(base_tmp), build_int_cst(sizetype, 0));
|
|
||||||
tree result_ref = build2(MEM_REF, TREE_TYPE(ref), base_tmp, offset0);
|
|
||||||
|
|
||||||
return result_ref;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatch_separation_maybe(const std::list<tree*>& path, gimple_stmt_iterator* gsi, unsigned& cancel_levels) {
|
static void dispatch_separation_maybe(const std::list<tree*>& path, gimple_stmt_iterator* gsi, unsigned& cancel_levels) {
|
||||||
|
|||||||
@ -7,7 +7,13 @@ const char* second_comm();
|
|||||||
int subsecond_pid();
|
int subsecond_pid();
|
||||||
const char* subsecond_comm();
|
const char* subsecond_comm();
|
||||||
|
|
||||||
struct task_struct global = { .pid = 42, .comm = "main_global" };
|
struct task_struct global = { .pid = 42, .comm = "main_global", .arrfun = {
|
||||||
|
{ .a = 1, .b = 2, .c = 3, .d = 4.0 },
|
||||||
|
{ .a = 5, .b = 6, .c = 7, .d = 8.0 },
|
||||||
|
{ .a = 9, .b = 10, .c = 11, .d = 12.0 },
|
||||||
|
{ .a = 13, .b = 14, .c = 15, .d = 16.0 },
|
||||||
|
{ .a = 17, .b = 18, .c = 19, .d = 20.0 }
|
||||||
|
} };
|
||||||
|
|
||||||
static void print_layout() {
|
static void print_layout() {
|
||||||
// TODO -> Make builtin __spslr_initial_offsetof(type, field) that is not patched
|
// TODO -> Make builtin __spslr_initial_offsetof(type, field) that is not patched
|
||||||
@ -15,9 +21,14 @@ static void print_layout() {
|
|||||||
printf(" stuck0 (int) : %2llu -> %2llu\n", 0, offsetof(struct task_struct, stuck0));
|
printf(" stuck0 (int) : %2llu -> %2llu\n", 0, offsetof(struct task_struct, stuck0));
|
||||||
printf(" pid (int) : %2llu -> %2llu\n", 8, offsetof(struct task_struct, pid));
|
printf(" pid (int) : %2llu -> %2llu\n", 8, offsetof(struct task_struct, pid));
|
||||||
printf(" comm (const char*) : %2llu -> %2llu\n", 16, offsetof(struct task_struct, comm));
|
printf(" comm (const char*) : %2llu -> %2llu\n", 16, offsetof(struct task_struct, comm));
|
||||||
printf(" tasks (struct list_head) : %2llu -> %2llu\n", 24, offsetof(struct task_struct, tasks));
|
printf(" arrfun (struct ArrayFun [5]) : %2llu -> %2llu\n", 24, offsetof(struct task_struct, arrfun));
|
||||||
printf(" stuck1 (int) : %2llu -> %2llu\n", 40, offsetof(struct task_struct, stuck1));
|
printf(" tasks (struct list_head) : %2llu -> %2llu\n", 144, offsetof(struct task_struct, tasks));
|
||||||
printf(" stuck2 (int) : %2llu -> %2llu\n", 44, offsetof(struct task_struct, stuck2));
|
printf(" stuck1 (int) : %2llu -> %2llu\n", 160, offsetof(struct task_struct, stuck1));
|
||||||
|
printf(" stuck2 (int) : %2llu -> %2llu\n", 166, offsetof(struct task_struct, stuck2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void arr_test() {
|
||||||
|
printf("Global arrfun[3].b: %d (should be 14)\n", global.arrfun[3].b);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
@ -55,6 +66,8 @@ int main(void)
|
|||||||
printf("Second global: pid=%d comm=\"%s\"\n", second_pid(), second_comm());
|
printf("Second global: pid=%d comm=\"%s\"\n", second_pid(), second_comm());
|
||||||
printf("Subsecond global: pid=%d comm=\"%s\"\n", subsecond_pid(), subsecond_comm());
|
printf("Subsecond global: pid=%d comm=\"%s\"\n", subsecond_pid(), subsecond_comm());
|
||||||
|
|
||||||
|
arr_test();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,7 +43,13 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
|||||||
#define list_for_each(pos, head) \
|
#define list_for_each(pos, head) \
|
||||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||||
|
|
||||||
|
struct ArrayFun {
|
||||||
|
int a, b, c;
|
||||||
|
double d;
|
||||||
|
} __attribute__((spslr));
|
||||||
|
|
||||||
// A small struct like the Linux kernel's task_struct
|
// A small struct like the Linux kernel's task_struct
|
||||||
|
|
||||||
struct task_struct {
|
struct task_struct {
|
||||||
int stuck0;
|
int stuck0;
|
||||||
|
|
||||||
@ -54,6 +60,8 @@ struct task_struct {
|
|||||||
int pid;
|
int pid;
|
||||||
const char *comm;
|
const char *comm;
|
||||||
|
|
||||||
|
struct ArrayFun arrfun[5];
|
||||||
|
|
||||||
randomized_struct_fields_end
|
randomized_struct_fields_end
|
||||||
|
|
||||||
struct list_head tasks; // linkage for global task list
|
struct list_head tasks; // linkage for global task list
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user