Implemented array handling

This commit is contained in:
York Jasper Niebuhr 2026-04-05 10:55:34 +02:00
parent 7e85fadccf
commit e7851641a1
4 changed files with 143 additions and 75 deletions

View File

@ -36,6 +36,37 @@ static bool compile_datapin(tree type, DataPin& pin, std::size_t offset = 0, std
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 */)
return res;

View File

@ -4,16 +4,23 @@
#include <pinpoint_error.h>
struct ComponentRefChain {
struct Link {
struct AccessChain {
struct Step {
enum Kind {
STEP_COMPONENT,
STEP_ARRAY
} kind = STEP_COMPONENT;
tree t = NULL_TREE;
/* COMPONENT_REF data */
bool relevant = false;
UID target;
std::size_t offset;
UID target = UID_INVALID;
std::size_t offset = 0;
};
bool relevant = false;
std::list<Link> links;
std::list<Step> steps;
tree base = NULL_TREE;
};
@ -35,100 +42,109 @@ static bool tree_contains_component_ref(tree ref) {
return found_flag != 0;
}
static bool component_ref_chain(tree ref, ComponentRefChain& chain) {
static bool access_chain(tree ref, AccessChain& chain) {
if (!ref)
return false;
if (TREE_CODE(ref) != COMPONENT_REF) {
if (chain.links.empty())
return false;
switch (TREE_CODE(ref)) {
case COMPONENT_REF: {
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))
return false;
chain.base = ref;
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) {
ComponentRefChain crc;
if (!component_ref_chain(ref, crc))
pinpoint_fatal("separate_offset_chain_maybe encountered invalid COMPONENT_REF chain");
AccessChain chain;
if (!access_chain(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;
// 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)
pinpoint_fatal("separate_offset_chain_maybe encountered ADDR_EXPR as base of COMPONENT_REF");
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");
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) {
// 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);
if (step.relevant) {
tree return_tmp = create_tmp_var(size_type_node, NULL);
gimple* call_stmt =
make_stage0_gimple_separator(return_tmp, step.target, step.offset);
if (!call_stmt)
pinpoint_fatal("separate_offset_chain_maybe failed to make gimple separator");
gimple* call_stmt = make_stage0_gimple_separator(return_tmp, cr.target, cr.offset);
if (!call_stmt)
pinpoint_fatal("separate_offset_chain_maybe failed to make gimple separator for target %u at offset %u",
(unsigned)cr.target, (unsigned)cr.offset);
gsi_insert_before(gsi, call_stmt, GSI_SAME_STMT);
field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type, cur_ptr, return_tmp);
} else {
tree field_decl = TREE_OPERAND(step.t, 1);
gsi_insert_before(gsi, call_stmt, GSI_SAME_STMT);
std::size_t field_offset;
bool 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");
if (field_bitfield)
pinpoint_fatal("separate_offset_chain_maybe encountered bitfield access in relevant COMPONENT_REF chain");
// 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);
field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type,
cur_ptr, build_int_cst(sizetype, field_offset));
}
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 {
// Add offsetof contant
tree field_decl = TREE_OPERAND(cr.t, 1);
tree ptr_tmp = create_tmp_var(field_ptr_type, NULL);
gimple* ptr_assign = gimple_build_assign(ptr_tmp, field_ptr);
gsi_insert_before(gsi, ptr_assign, GSI_SAME_STMT);
std::size_t field_offset;
bool field_bitfield;
// Dereference constructed pointer expression
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");
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 (field_bitfield)
pinpoint_fatal("separate_offset_chain_maybe encountered bitfield access in relevant COMPONENT_REF chain");
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);
// Add constant offset 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, build_int_cst(sizetype, field_offset));
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);
cur_expr = build4(TREE_CODE(step.t), TREE_TYPE(step.t), cur_expr, idx, low, elts);
continue;
}
}
// Current pointer is a field pointer -> dereference
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;
return cur_expr;
}
static void dispatch_separation_maybe(const std::list<tree*>& path, gimple_stmt_iterator* gsi, unsigned& cancel_levels) {

View File

@ -7,17 +7,28 @@ const char* second_comm();
int subsecond_pid();
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() {
// TODO -> Make builtin __spslr_initial_offsetof(type, field) that is not patched
printf("Current task_struct layout:\n");
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(" 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(" stuck1 (int) : %2llu -> %2llu\n", 40, offsetof(struct task_struct, stuck1));
printf(" stuck2 (int) : %2llu -> %2llu\n", 44, offsetof(struct task_struct, stuck2));
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(" comm (const char*) : %2llu -> %2llu\n", 16, offsetof(struct task_struct, comm));
printf(" arrfun (struct ArrayFun [5]) : %2llu -> %2llu\n", 24, offsetof(struct task_struct, arrfun));
printf(" tasks (struct list_head) : %2llu -> %2llu\n", 144, offsetof(struct task_struct, tasks));
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)
@ -55,6 +66,8 @@ int main(void)
printf("Second global: pid=%d comm=\"%s\"\n", second_pid(), second_comm());
printf("Subsecond global: pid=%d comm=\"%s\"\n", subsecond_pid(), subsecond_comm());
arr_test();
return 0;
}

View File

@ -43,7 +43,13 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head)
#define list_for_each(pos, head) \
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
struct task_struct {
int stuck0;
@ -54,6 +60,8 @@ struct task_struct {
int pid;
const char *comm;
struct ArrayFun arrfun[5];
randomized_struct_fields_end
struct list_head tasks; // linkage for global task list