WIP DW_OP_piece

This commit is contained in:
Nikita Smith
2025-12-17 17:32:03 -08:00
parent 43cb8b7b1a
commit ce4d09d431
4 changed files with 128 additions and 34 deletions
+2 -2
View File
@@ -1548,7 +1548,7 @@ typedef enum
X(RegX, 0x90, 1, 0, 1, ULEB128, Null) \
X(FBReg, 0x91, 1, 0, 1, SLEB128, Null) \
X(BRegX, 0x92, 2, 0, 1, ULEB128, SLEB128) \
X(Piece, 0x93, 1, 0, 0, ULEB128, Null) \
X(Piece, 0x93, 1, 1, 0, ULEB128, Null) \
X(DerefSize, 0x94, 1, 1, 1, U8, Null) \
X(XDerefSize, 0x95, 1, 2, 1, U8, Null) \
X(Nop, 0x96, 0, 0, 0, Null, Null) \
@@ -1558,7 +1558,7 @@ typedef enum
X(CallRef, 0x9a, 1, 0, 0, DwarfUInt,Null) \
X(FormTlsAddress, 0x9b, 0, 0, 1, Null, Null) \
X(CallFrameCfa, 0x9c, 0, 0, 1, Null, Null) \
X(BitPiece, 0x9d, 2, 0, 0, ULEB128, ULEB128)
X(BitPiece, 0x9d, 2, 1, 0, ULEB128, ULEB128)
#define DW_Expr_V4_XList \
X(ImplicitValue, 0x9e, 2, 0, 1, Block, Null) \
+83 -16
View File
@@ -1269,29 +1269,44 @@ dw_eval_expr(Arena *arena,
} break;
case DW_ExprOp_Piece: {
if (stack->count) {
String8 value = dw_string_from_expr_value(arena, arch, dw_expr_stack_pop(stack));
if (inst->operands[0].u64 <= value.size) {
dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .value = { .ptr = value.str, .bit_size = inst->operands[0].u64 * 8 }});
B32 is_undefined = stack->count == 0 || (inst->prev && inst->prev->opcode == DW_ExprOp_Piece);
if (is_undefined) {
dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .bit_size = inst->operands[0].u64 * 8 });
} else {
Assert(0 && "out of bounds size in the piece opcode");
goto exit;
DW_ExprValue top = dw_expr_stack_pop(stack);
String8 value;
// piece is a memory reference
if (top.type == DW_ExprValueType_Addr) {
U64 value_size = inst->operands[0].u64;
U8 *value_buffer = push_array(arena, U8, value_size);
MachineOpResult read_result = mem_read(top.addr, value_buffer, value_size, mem_read_ud);
if (read_result != MachineOpResult_Ok) { Assert(0 && "failed to read piece memory referece"); goto exit; }
}
} else {
dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .undef_bit_size = inst->operands[0].u64 * 8 });
// piece is a value
else {
value = dw_string_from_expr_value(arena, arch, top);
}
if (inst->operands[0].u64 > value.size) { Assert(0 && "out of bounds size in the piece opcode"); goto exit; }
dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .bit_size = inst->operands[0].u64 * 8, .value = value.str });
}
} break;
case DW_ExprOp_BitPiece: {
if (stack->count) {
String8 value = dw_string_from_expr_value(arena, arch, dw_expr_stack_pop(stack));
if (inst->operands[0].u64 <= value.size * 8) {
dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .value = { .ptr = value.str, .bit_size = inst->operands[0].u64 }});
B32 is_undefined = stack->count == 0 || (inst->prev && inst->prev->opcode == DW_ExprOp_Piece);
if (is_undefined) {
dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .bit_size = inst->operands[0].u64 });
} else {
Assert(0 && "out of bounds size in the bit piece opcode");
goto exit;
String8 value;
if (dw_expr_stack_peek(stack).type == DW_ExprValueType_Addr) {
NotImplemented;
} else {
value = dw_string_from_expr_value(arena, arch, dw_expr_stack_pop(stack));
}
} else {
dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .undef_bit_size = inst->operands[0].u64 });
if (inst->operands[0].u64 > value.size * 8) { Assert(0 && "out of bounds size in piece opcode"); goto exit; }
dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .bit_size = inst->operands[0].u64, .value = value.str });
}
} break;
@@ -1485,8 +1500,60 @@ dw_eval_expr(Arena *arena,
}
}
// composite value
if (pieces.count > 0) {
#if 0
U64 total_bit_size = 0;
for EachNode (n, DW_PieceNode, pieces.first) {
total_bit_size += n->v.bit_size;
}
U64 value_size = CeilIntegerDiv(total_bit_size, 8);
U8 *value = push_array(arena, U8, value_size);
Rng1U64 *ranges = push_array(arena, Rng1U64, pieces.count);
U64 *offsets = push_array(arena, U64, pieces.count);
U64 value_idx = 0;
U64 value_cursor = 0;
U64 piece_cursor = 0;
for EachNode(n, DW_PieceNode, pieces.first) {
if (n->v.kind == DW_PieceKind_Value) {
ranges[value_idx] = r1u64(piece_cursor, piece_cursor + n->v.bit_size);
offsets[value_idx] = value_cursor;
for (U64 i = 0; i < n->v.bit_size; i += 8) {
U64 to_copy = Min(8, n->v.bit_size - i);
if (value_cursor % 8 == 0) {
value[value_cursor / 8] = n->v.value[i];
} else {
value[value_cursor / 8] |= n->v.value[i] << (value_cursor % 8);
value[AlignPow2(value_cursor / 8, 8)] |= n->v.value[i] >> (value_cursor % 8);
}
value_cursor += to_copy;
}
value_idx += 1;
}
piece_cursor += n->v.bit_size;
}
value_out->type = DW_ExprValueType_Generic;
value_out->ranges = (Rng1U64Array){ .count = pieces.count, .v = ranges };
value_out->offsets = offsets;
value_out->generic = str8(value, value_size);
#else
NotImplemented;
#endif
}
// scalar
else {
if (stack->top) {
*value_out = stack->top->v;
Rng1U64 *range = push_array(arena, Rng1U64, 1);
*range = r1u64(0, max_U64);
value_out->ranges = (Rng1U64Array){ .count = 1, .v = range };
value_out->offsets = push_array(arena, U64, 1);
} else {
MemoryZeroStruct(value_out);
}
}
result = DW_ExprEvalResult_Ok;
+3 -11
View File
@@ -40,6 +40,8 @@ typedef S8 DW_ExprBool;
typedef struct DW_ExprValue
{
DW_ExprValueType type;
Rng1U64Array ranges;
U64 *offsets;
union {
U8 u8;
U16 u16;
@@ -77,13 +79,8 @@ typedef enum
typedef struct DW_Piece
{
DW_PieceKind kind;
union {
U64 undef_bit_size;
struct {
U64 bit_size;
void *ptr;
} value;
};
U8 *value;
} DW_Piece;
typedef struct DW_PieceNode
@@ -105,11 +102,6 @@ typedef struct DW_ExprStack
DW_ExprValueNode *top;
} DW_ExprStack;
typedef struct DW_ExprResult
{
int x;
} DW_ExprResult;
typedef enum
{
DW_ExprEvalResult_Fail,
+35
View File
@@ -5163,6 +5163,40 @@ t_plus_uconst(void)
return result;
}
internal T_Result
t_reg_split_spill(void)
{
Temp scratch = scratch_begin(0, 0);
T_Result result = T_Result_Fail;
// setup register context
REGS_RegBlockX64 regs = {0};
{
REGS_RegCode reg_code = reg_code_from_dw_reg(Arch_x64, DW_ExprOp_BReg3 - DW_ExprOp_BReg0);
Rng1U64 reg_range = regs_range_from_code(Arch_x64, 0, reg_code);
U64 value = 0xaaaa;
MemoryCopy((U8 *)&regs + reg_range.min, &value, sizeof(value));
}
{
REGS_RegCode reg_code = reg_code_from_dw_reg(Arch_x64, DW_ExprOp_BReg10 - DW_ExprOp_BReg0);
Rng1U64 reg_range = regs_range_from_code(Arch_x64, 0, reg_code);
U64 value = 0xbbbb;
MemoryCopy((U8 *)&regs + reg_range.min, &value, sizeof(value));
}
DW_ExprEnc expr_encs[] = { DW_ExprEnc_Op(Reg3), DW_ExprEnc_Op(Piece), DW_ExprEnc_ULEB128(4), DW_ExprEnc_Op(Reg10), DW_ExprEnc_Op(Piece), DW_ExprEnc_ULEB128(2) };
String8 expr_data = dw_encode_expr(scratch.arena, Arch_x64, DW_Format_64Bit, expr_encs, ArrayCount(expr_encs));
DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_64Bit, byte_size_from_arch(Arch_x64), expr_data);
DW_ExprValue expr_value;
DW_ExprEvalResult expr_eval = dw_eval_expr(scratch.arena, Arch_x64, DW_Format_64Bit, 0, 0, 0, max_U64, expr, regs_read_dwarf_x64, &regs, 0, 0, &expr_value);
result = T_Result_Pass;
exit:;
scratch_end(scratch);
return result;
}
////////////////////////////////////////////////////////////////
internal void
@@ -5251,6 +5285,7 @@ entry_point(CmdLine *cmdline)
T(frame_relative_variable),
T(call_by_reference),
T(plus_uconst),
//T(reg_split_spill),
#undef T
};