Skip to content

Commit bb34a74

Browse files
committed
Fix typedef pointer arithmetic and array ops
This commit fixes multiple issues with typedef pointer handling: 1. Remove incorrect pointer level inheritance in read_full_var_decl() - Previously caused double indirection bugs with typedef pointers - Variables now maintain separate pointer levels from their types 2. Implement proper pointer arithmetic for typedef pointers - Add scaling for binary addition/subtraction (p+n, p-n, n+p) - Fix increment/decrement operators (++p, p++, --p, p--) - Calculate element size based on base type (int=4, char=1, etc.) 3. Enable array indexing for typedef pointers - Recognize typedef pointers in square bracket operations - Properly calculate element sizes for array access
1 parent ee97fef commit bb34a74

File tree

2 files changed

+483
-12
lines changed

2 files changed

+483
-12
lines changed

src/parser.c

Lines changed: 277 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ var_t *truncate_unchecked(block_t *block,
280280
var_t *resize_var(block_t *block, basic_block_t **bb, var_t *from, var_t *to)
281281
{
282282
bool is_from_ptr = from->is_ptr || from->array_size,
283-
is_to_ptr = to->is_ptr || to->array_size;
283+
is_to_ptr = to->is_ptr || to->array_size ||
284+
(to->type && to->type->ptr_level > 0);
284285

285286
if (is_from_ptr && is_to_ptr)
286287
return from;
@@ -1289,10 +1290,6 @@ void read_full_var_decl(var_t *vd, int anon, int is_param)
12891290

12901291
vd->type = type;
12911292

1292-
/* Inherit pointer level from typedef */
1293-
if (type->ptr_level > 0)
1294-
vd->is_ptr = type->ptr_level;
1295-
12961293
read_inner_var_decl(vd, anon, is_param);
12971294
}
12981295

@@ -1567,8 +1564,28 @@ void handle_single_dereference(block_t *parent, basic_block_t **bb)
15671564
vd = require_deref_var(parent, var->type, var->is_ptr);
15681565
if (lvalue.is_ptr > 1)
15691566
sz = PTR_SIZE;
1570-
else
1571-
sz = lvalue.type->size;
1567+
else {
1568+
/* For typedef pointers, get the size of the pointed-to type */
1569+
if (lvalue.type && lvalue.type->ptr_level > 0) {
1570+
/* This is a typedef pointer */
1571+
switch (lvalue.type->base_type) {
1572+
case TYPE_char:
1573+
sz = TY_char->size;
1574+
break;
1575+
case TYPE_int:
1576+
sz = TY_int->size;
1577+
break;
1578+
case TYPE_void:
1579+
sz = 1;
1580+
break;
1581+
default:
1582+
sz = lvalue.type->size;
1583+
break;
1584+
}
1585+
} else {
1586+
sz = lvalue.type->size;
1587+
}
1588+
}
15721589
gen_name_to(vd->var_name);
15731590
opstack_push(vd);
15741591
add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL);
@@ -1626,8 +1643,29 @@ void handle_multiple_dereference(block_t *parent, basic_block_t **bb)
16261643
lvalue.is_ptr > i ? lvalue.is_ptr - i - 1 : 0);
16271644
if (lvalue.is_ptr > i + 1)
16281645
sz = PTR_SIZE;
1629-
else
1630-
sz = lvalue.type->size;
1646+
else {
1647+
/* For typedef pointers, get the size of the pointed-to type */
1648+
if (lvalue.type && lvalue.type->ptr_level > 0 &&
1649+
i == deref_count - 1) {
1650+
/* This is a typedef pointer on the final dereference */
1651+
switch (lvalue.type->base_type) {
1652+
case TYPE_char:
1653+
sz = TY_char->size;
1654+
break;
1655+
case TYPE_int:
1656+
sz = TY_int->size;
1657+
break;
1658+
case TYPE_void:
1659+
sz = 1;
1660+
break;
1661+
default:
1662+
sz = lvalue.type->size;
1663+
break;
1664+
}
1665+
} else {
1666+
sz = lvalue.type->size;
1667+
}
1668+
}
16311669
gen_name_to(vd->var_name);
16321670
opstack_push(vd);
16331671
add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL);
@@ -2195,6 +2233,99 @@ void read_expr(block_t *parent, basic_block_t **bb)
21952233
if (get_operator_prio(top_op) >= get_operator_prio(op)) {
21962234
rs2 = opstack_pop();
21972235
rs1 = opstack_pop();
2236+
2237+
/* Handle pointer arithmetic for addition and subtraction */
2238+
if ((top_op == OP_add || top_op == OP_sub) &&
2239+
(rs1->is_ptr ||
2240+
(rs1->type && rs1->type->ptr_level > 0) ||
2241+
rs2->is_ptr ||
2242+
(rs2->type && rs2->type->ptr_level > 0))) {
2243+
var_t *ptr_var = NULL;
2244+
var_t *int_var = NULL;
2245+
int element_size = 0;
2246+
2247+
/* Determine which operand is the pointer */
2248+
if (rs1->is_ptr ||
2249+
(rs1->type && rs1->type->ptr_level > 0)) {
2250+
ptr_var = rs1;
2251+
int_var = rs2;
2252+
2253+
/* Calculate element size */
2254+
if (rs1->is_ptr && rs1->type) {
2255+
element_size = rs1->type->size;
2256+
} else if (rs1->type && rs1->type->ptr_level > 0) {
2257+
/* Typedef pointer */
2258+
switch (rs1->type->base_type) {
2259+
case TYPE_char:
2260+
element_size = TY_char->size;
2261+
break;
2262+
case TYPE_int:
2263+
element_size = TY_int->size;
2264+
break;
2265+
case TYPE_void:
2266+
element_size = 1;
2267+
break;
2268+
default:
2269+
element_size =
2270+
rs1->type ? rs1->type->size : PTR_SIZE;
2271+
break;
2272+
}
2273+
}
2274+
} else if (rs2->is_ptr ||
2275+
(rs2->type && rs2->type->ptr_level > 0)) {
2276+
/* Only for addition (p + n == n + p) */
2277+
if (top_op == OP_add) {
2278+
ptr_var = rs2;
2279+
int_var = rs1;
2280+
2281+
/* Calculate element size */
2282+
if (rs2->is_ptr && rs2->type) {
2283+
element_size = rs2->type->size;
2284+
} else if (rs2->type &&
2285+
rs2->type->ptr_level > 0) {
2286+
/* Typedef pointer */
2287+
switch (rs2->type->base_type) {
2288+
case TYPE_char:
2289+
element_size = TY_char->size;
2290+
break;
2291+
case TYPE_int:
2292+
element_size = TY_int->size;
2293+
break;
2294+
case TYPE_void:
2295+
element_size = 1;
2296+
break;
2297+
default:
2298+
element_size = rs2->type
2299+
? rs2->type->size
2300+
: PTR_SIZE;
2301+
break;
2302+
}
2303+
}
2304+
/* Swap operands so pointer is rs1 */
2305+
rs1 = ptr_var;
2306+
rs2 = int_var;
2307+
}
2308+
}
2309+
2310+
/* If we need to scale the integer operand */
2311+
if (ptr_var && element_size > 1) {
2312+
/* Create multiplication by element size */
2313+
var_t *size_const = require_var(parent);
2314+
gen_name_to(size_const->var_name);
2315+
size_const->init_val = element_size;
2316+
add_insn(parent, *bb, OP_load_constant, size_const,
2317+
NULL, NULL, 0, NULL);
2318+
2319+
var_t *scaled = require_var(parent);
2320+
gen_name_to(scaled->var_name);
2321+
add_insn(parent, *bb, OP_mul, scaled, int_var,
2322+
size_const, 0, NULL);
2323+
2324+
/* Use scaled value as rs2 */
2325+
rs2 = scaled;
2326+
}
2327+
}
2328+
21982329
vd = require_var(parent);
21992330
gen_name_to(vd->var_name);
22002331
opstack_push(vd);
@@ -2310,6 +2441,91 @@ void read_expr(block_t *parent, basic_block_t **bb)
23102441
rs2 = opstack_pop();
23112442
rs1 = opstack_pop();
23122443

2444+
/* Handle pointer arithmetic for addition and subtraction */
2445+
if ((top_op == OP_add || top_op == OP_sub) &&
2446+
(rs1->is_ptr || (rs1->type && rs1->type->ptr_level > 0) ||
2447+
rs2->is_ptr || (rs2->type && rs2->type->ptr_level > 0))) {
2448+
var_t *ptr_var = NULL;
2449+
var_t *int_var = NULL;
2450+
int element_size = 0;
2451+
2452+
/* Determine which operand is the pointer */
2453+
if (rs1->is_ptr || (rs1->type && rs1->type->ptr_level > 0)) {
2454+
ptr_var = rs1;
2455+
int_var = rs2;
2456+
2457+
/* Calculate element size */
2458+
if (rs1->is_ptr && rs1->type) {
2459+
element_size = rs1->type->size;
2460+
} else if (rs1->type && rs1->type->ptr_level > 0) {
2461+
/* Typedef pointer */
2462+
switch (rs1->type->base_type) {
2463+
case TYPE_char:
2464+
element_size = TY_char->size;
2465+
break;
2466+
case TYPE_int:
2467+
element_size = TY_int->size;
2468+
break;
2469+
case TYPE_void:
2470+
element_size = 1;
2471+
break;
2472+
default:
2473+
element_size = rs1->type ? rs1->type->size : PTR_SIZE;
2474+
break;
2475+
}
2476+
}
2477+
} else if (rs2->is_ptr || (rs2->type && rs2->type->ptr_level > 0)) {
2478+
/* Only for addition (p + n == n + p) */
2479+
if (top_op == OP_add) {
2480+
ptr_var = rs2;
2481+
int_var = rs1;
2482+
2483+
/* Calculate element size */
2484+
if (rs2->is_ptr && rs2->type) {
2485+
element_size = rs2->type->size;
2486+
} else if (rs2->type && rs2->type->ptr_level > 0) {
2487+
/* Typedef pointer */
2488+
switch (rs2->type->base_type) {
2489+
case TYPE_char:
2490+
element_size = TY_char->size;
2491+
break;
2492+
case TYPE_int:
2493+
element_size = TY_int->size;
2494+
break;
2495+
case TYPE_void:
2496+
element_size = 1;
2497+
break;
2498+
default:
2499+
element_size =
2500+
rs2->type ? rs2->type->size : PTR_SIZE;
2501+
break;
2502+
}
2503+
}
2504+
/* Swap operands so pointer is rs1 */
2505+
rs1 = ptr_var;
2506+
rs2 = int_var;
2507+
}
2508+
}
2509+
2510+
/* If we need to scale the integer operand */
2511+
if (ptr_var && element_size > 1) {
2512+
/* Create multiplication by element size */
2513+
var_t *size_const = require_var(parent);
2514+
gen_name_to(size_const->var_name);
2515+
size_const->init_val = element_size;
2516+
add_insn(parent, *bb, OP_load_constant, size_const, NULL, NULL,
2517+
0, NULL);
2518+
2519+
var_t *scaled = require_var(parent);
2520+
gen_name_to(scaled->var_name);
2521+
add_insn(parent, *bb, OP_mul, scaled, int_var, size_const, 0,
2522+
NULL);
2523+
2524+
/* Use scaled value as rs2 */
2525+
rs2 = scaled;
2526+
}
2527+
}
2528+
23132529
/* Constant folding for binary operations */
23142530
if (rs1 && rs2 && rs1->init_val && !rs1->is_ptr && !rs1->is_global &&
23152531
rs2->init_val && !rs2->is_ptr && !rs2->is_global) {
@@ -2460,11 +2676,15 @@ void read_lvalue(lvalue_t *lvalue,
24602676
}
24612677

24622678
/* var must be either a pointer or an array of some type */
2463-
if (var->is_ptr == 0 && var->array_size == 0)
2679+
/* For typedef pointers, check the type's ptr_level */
2680+
bool is_typedef_pointer = (var->type && var->type->ptr_level > 0);
2681+
if (var->is_ptr == 0 && var->array_size == 0 && !is_typedef_pointer)
24642682
error("Cannot apply square operator to non-pointer");
24652683

24662684
/* if nested pointer, still pointer */
2467-
if (var->is_ptr <= 1 && var->array_size == 0) {
2685+
/* Also handle typedef pointers which have is_ptr == 0 */
2686+
if ((var->is_ptr <= 1 || is_typedef_pointer) &&
2687+
var->array_size == 0) {
24682688
/* For typedef pointers, get the size of the base type that the
24692689
* pointer points to
24702690
*/
@@ -2693,7 +2913,31 @@ void read_lvalue(lvalue_t *lvalue,
26932913
side_effect[se_idx].opcode = OP_load_constant;
26942914
vd = require_var(parent);
26952915
gen_name_to(vd->var_name);
2696-
vd->init_val = 1;
2916+
2917+
/* Calculate increment size based on pointer type */
2918+
int increment_size = 1;
2919+
if (lvalue->is_ptr && !lvalue->is_reference) {
2920+
increment_size = lvalue->type->size;
2921+
} else if (!lvalue->is_reference && lvalue->type &&
2922+
lvalue->type->ptr_level > 0) {
2923+
/* This is a typedef pointer */
2924+
switch (lvalue->type->base_type) {
2925+
case TYPE_char:
2926+
increment_size = TY_char->size;
2927+
break;
2928+
case TYPE_int:
2929+
increment_size = TY_int->size;
2930+
break;
2931+
case TYPE_void:
2932+
increment_size = 1;
2933+
break;
2934+
default:
2935+
increment_size = lvalue->type->size;
2936+
break;
2937+
}
2938+
}
2939+
vd->init_val = increment_size;
2940+
26972941
side_effect[se_idx].rd = vd;
26982942
side_effect[se_idx].rs1 = NULL;
26992943
side_effect[se_idx].rs2 = NULL;
@@ -3008,6 +3252,27 @@ bool read_body_assignment(char *token,
30083252
*/
30093253
if (lvalue.is_ptr && !lvalue.is_reference)
30103254
increment_size = lvalue.type->size;
3255+
/* Also check for typedef pointers which have is_ptr == 0 */
3256+
else if (!lvalue.is_reference && lvalue.type &&
3257+
lvalue.type->ptr_level > 0) {
3258+
/* This is a typedef pointer, get the base type size */
3259+
switch (lvalue.type->base_type) {
3260+
case TYPE_char:
3261+
increment_size = TY_char->size;
3262+
break;
3263+
case TYPE_int:
3264+
increment_size = TY_int->size;
3265+
break;
3266+
case TYPE_void:
3267+
/* void pointers treated as byte pointers */
3268+
increment_size = 1;
3269+
break;
3270+
default:
3271+
/* For struct pointers and other types */
3272+
increment_size = lvalue.type->size;
3273+
break;
3274+
}
3275+
}
30113276

30123277
/* If operand is a reference, read the value and push to stack for
30133278
* the incoming addition/subtraction. Otherwise, use the top element

0 commit comments

Comments
 (0)