Skip to content

Commit 378c691

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 3ce9b6d commit 378c691

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;
@@ -1250,10 +1251,6 @@ void read_full_var_decl(var_t *vd, int anon, int is_param)
12501251

12511252
vd->type = type;
12521253

1253-
/* Inherit pointer level from typedef */
1254-
if (type->ptr_level > 0)
1255-
vd->is_ptr = type->ptr_level;
1256-
12571254
read_inner_var_decl(vd, anon, is_param);
12581255
}
12591256

@@ -1528,8 +1525,28 @@ void handle_single_dereference(block_t *parent, basic_block_t **bb)
15281525
vd = require_deref_var(parent, var->type, var->is_ptr);
15291526
if (lvalue.is_ptr > 1)
15301527
sz = PTR_SIZE;
1531-
else
1532-
sz = lvalue.type->size;
1528+
else {
1529+
/* For typedef pointers, get the size of the pointed-to type */
1530+
if (lvalue.type && lvalue.type->ptr_level > 0) {
1531+
/* This is a typedef pointer */
1532+
switch (lvalue.type->base_type) {
1533+
case TYPE_char:
1534+
sz = TY_char->size;
1535+
break;
1536+
case TYPE_int:
1537+
sz = TY_int->size;
1538+
break;
1539+
case TYPE_void:
1540+
sz = 1;
1541+
break;
1542+
default:
1543+
sz = lvalue.type->size;
1544+
break;
1545+
}
1546+
} else {
1547+
sz = lvalue.type->size;
1548+
}
1549+
}
15331550
gen_name_to(vd->var_name);
15341551
opstack_push(vd);
15351552
add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL);
@@ -1587,8 +1604,29 @@ void handle_multiple_dereference(block_t *parent, basic_block_t **bb)
15871604
lvalue.is_ptr > i ? lvalue.is_ptr - i - 1 : 0);
15881605
if (lvalue.is_ptr > i + 1)
15891606
sz = PTR_SIZE;
1590-
else
1591-
sz = lvalue.type->size;
1607+
else {
1608+
/* For typedef pointers, get the size of the pointed-to type */
1609+
if (lvalue.type && lvalue.type->ptr_level > 0 &&
1610+
i == deref_count - 1) {
1611+
/* This is a typedef pointer on the final dereference */
1612+
switch (lvalue.type->base_type) {
1613+
case TYPE_char:
1614+
sz = TY_char->size;
1615+
break;
1616+
case TYPE_int:
1617+
sz = TY_int->size;
1618+
break;
1619+
case TYPE_void:
1620+
sz = 1;
1621+
break;
1622+
default:
1623+
sz = lvalue.type->size;
1624+
break;
1625+
}
1626+
} else {
1627+
sz = lvalue.type->size;
1628+
}
1629+
}
15921630
gen_name_to(vd->var_name);
15931631
opstack_push(vd);
15941632
add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL);
@@ -2156,6 +2194,99 @@ void read_expr(block_t *parent, basic_block_t **bb)
21562194
if (get_operator_prio(top_op) >= get_operator_prio(op)) {
21572195
rs2 = opstack_pop();
21582196
rs1 = opstack_pop();
2197+
2198+
/* Handle pointer arithmetic for addition and subtraction */
2199+
if ((top_op == OP_add || top_op == OP_sub) &&
2200+
(rs1->is_ptr ||
2201+
(rs1->type && rs1->type->ptr_level > 0) ||
2202+
rs2->is_ptr ||
2203+
(rs2->type && rs2->type->ptr_level > 0))) {
2204+
var_t *ptr_var = NULL;
2205+
var_t *int_var = NULL;
2206+
int element_size = 0;
2207+
2208+
/* Determine which operand is the pointer */
2209+
if (rs1->is_ptr ||
2210+
(rs1->type && rs1->type->ptr_level > 0)) {
2211+
ptr_var = rs1;
2212+
int_var = rs2;
2213+
2214+
/* Calculate element size */
2215+
if (rs1->is_ptr && rs1->type) {
2216+
element_size = rs1->type->size;
2217+
} else if (rs1->type && rs1->type->ptr_level > 0) {
2218+
/* Typedef pointer */
2219+
switch (rs1->type->base_type) {
2220+
case TYPE_char:
2221+
element_size = TY_char->size;
2222+
break;
2223+
case TYPE_int:
2224+
element_size = TY_int->size;
2225+
break;
2226+
case TYPE_void:
2227+
element_size = 1;
2228+
break;
2229+
default:
2230+
element_size =
2231+
rs1->type ? rs1->type->size : PTR_SIZE;
2232+
break;
2233+
}
2234+
}
2235+
} else if (rs2->is_ptr ||
2236+
(rs2->type && rs2->type->ptr_level > 0)) {
2237+
/* Only for addition (p + n == n + p) */
2238+
if (top_op == OP_add) {
2239+
ptr_var = rs2;
2240+
int_var = rs1;
2241+
2242+
/* Calculate element size */
2243+
if (rs2->is_ptr && rs2->type) {
2244+
element_size = rs2->type->size;
2245+
} else if (rs2->type &&
2246+
rs2->type->ptr_level > 0) {
2247+
/* Typedef pointer */
2248+
switch (rs2->type->base_type) {
2249+
case TYPE_char:
2250+
element_size = TY_char->size;
2251+
break;
2252+
case TYPE_int:
2253+
element_size = TY_int->size;
2254+
break;
2255+
case TYPE_void:
2256+
element_size = 1;
2257+
break;
2258+
default:
2259+
element_size = rs2->type
2260+
? rs2->type->size
2261+
: PTR_SIZE;
2262+
break;
2263+
}
2264+
}
2265+
/* Swap operands so pointer is rs1 */
2266+
rs1 = ptr_var;
2267+
rs2 = int_var;
2268+
}
2269+
}
2270+
2271+
/* If we need to scale the integer operand */
2272+
if (ptr_var && element_size > 1) {
2273+
/* Create multiplication by element size */
2274+
var_t *size_const = require_var(parent);
2275+
gen_name_to(size_const->var_name);
2276+
size_const->init_val = element_size;
2277+
add_insn(parent, *bb, OP_load_constant, size_const,
2278+
NULL, NULL, 0, NULL);
2279+
2280+
var_t *scaled = require_var(parent);
2281+
gen_name_to(scaled->var_name);
2282+
add_insn(parent, *bb, OP_mul, scaled, int_var,
2283+
size_const, 0, NULL);
2284+
2285+
/* Use scaled value as rs2 */
2286+
rs2 = scaled;
2287+
}
2288+
}
2289+
21592290
vd = require_var(parent);
21602291
gen_name_to(vd->var_name);
21612292
opstack_push(vd);
@@ -2271,6 +2402,91 @@ void read_expr(block_t *parent, basic_block_t **bb)
22712402
rs2 = opstack_pop();
22722403
rs1 = opstack_pop();
22732404

2405+
/* Handle pointer arithmetic for addition and subtraction */
2406+
if ((top_op == OP_add || top_op == OP_sub) &&
2407+
(rs1->is_ptr || (rs1->type && rs1->type->ptr_level > 0) ||
2408+
rs2->is_ptr || (rs2->type && rs2->type->ptr_level > 0))) {
2409+
var_t *ptr_var = NULL;
2410+
var_t *int_var = NULL;
2411+
int element_size = 0;
2412+
2413+
/* Determine which operand is the pointer */
2414+
if (rs1->is_ptr || (rs1->type && rs1->type->ptr_level > 0)) {
2415+
ptr_var = rs1;
2416+
int_var = rs2;
2417+
2418+
/* Calculate element size */
2419+
if (rs1->is_ptr && rs1->type) {
2420+
element_size = rs1->type->size;
2421+
} else if (rs1->type && rs1->type->ptr_level > 0) {
2422+
/* Typedef pointer */
2423+
switch (rs1->type->base_type) {
2424+
case TYPE_char:
2425+
element_size = TY_char->size;
2426+
break;
2427+
case TYPE_int:
2428+
element_size = TY_int->size;
2429+
break;
2430+
case TYPE_void:
2431+
element_size = 1;
2432+
break;
2433+
default:
2434+
element_size = rs1->type ? rs1->type->size : PTR_SIZE;
2435+
break;
2436+
}
2437+
}
2438+
} else if (rs2->is_ptr || (rs2->type && rs2->type->ptr_level > 0)) {
2439+
/* Only for addition (p + n == n + p) */
2440+
if (top_op == OP_add) {
2441+
ptr_var = rs2;
2442+
int_var = rs1;
2443+
2444+
/* Calculate element size */
2445+
if (rs2->is_ptr && rs2->type) {
2446+
element_size = rs2->type->size;
2447+
} else if (rs2->type && rs2->type->ptr_level > 0) {
2448+
/* Typedef pointer */
2449+
switch (rs2->type->base_type) {
2450+
case TYPE_char:
2451+
element_size = TY_char->size;
2452+
break;
2453+
case TYPE_int:
2454+
element_size = TY_int->size;
2455+
break;
2456+
case TYPE_void:
2457+
element_size = 1;
2458+
break;
2459+
default:
2460+
element_size =
2461+
rs2->type ? rs2->type->size : PTR_SIZE;
2462+
break;
2463+
}
2464+
}
2465+
/* Swap operands so pointer is rs1 */
2466+
rs1 = ptr_var;
2467+
rs2 = int_var;
2468+
}
2469+
}
2470+
2471+
/* If we need to scale the integer operand */
2472+
if (ptr_var && element_size > 1) {
2473+
/* Create multiplication by element size */
2474+
var_t *size_const = require_var(parent);
2475+
gen_name_to(size_const->var_name);
2476+
size_const->init_val = element_size;
2477+
add_insn(parent, *bb, OP_load_constant, size_const, NULL, NULL,
2478+
0, NULL);
2479+
2480+
var_t *scaled = require_var(parent);
2481+
gen_name_to(scaled->var_name);
2482+
add_insn(parent, *bb, OP_mul, scaled, int_var, size_const, 0,
2483+
NULL);
2484+
2485+
/* Use scaled value as rs2 */
2486+
rs2 = scaled;
2487+
}
2488+
}
2489+
22742490
/* Constant folding for binary operations */
22752491
if (rs1 && rs2 && rs1->init_val && !rs1->is_ptr && !rs1->is_global &&
22762492
rs2->init_val && !rs2->is_ptr && !rs2->is_global) {
@@ -2421,11 +2637,15 @@ void read_lvalue(lvalue_t *lvalue,
24212637
}
24222638

24232639
/* var must be either a pointer or an array of some type */
2424-
if (var->is_ptr == 0 && var->array_size == 0)
2640+
/* For typedef pointers, check the type's ptr_level */
2641+
bool is_typedef_pointer = (var->type && var->type->ptr_level > 0);
2642+
if (var->is_ptr == 0 && var->array_size == 0 && !is_typedef_pointer)
24252643
error("Cannot apply square operator to non-pointer");
24262644

24272645
/* if nested pointer, still pointer */
2428-
if (var->is_ptr <= 1 && var->array_size == 0) {
2646+
/* Also handle typedef pointers which have is_ptr == 0 */
2647+
if ((var->is_ptr <= 1 || is_typedef_pointer) &&
2648+
var->array_size == 0) {
24292649
/* For typedef pointers, get the size of the base type that the
24302650
* pointer points to
24312651
*/
@@ -2645,7 +2865,31 @@ void read_lvalue(lvalue_t *lvalue,
26452865
side_effect[se_idx].opcode = OP_load_constant;
26462866
vd = require_var(parent);
26472867
gen_name_to(vd->var_name);
2648-
vd->init_val = 1;
2868+
2869+
/* Calculate increment size based on pointer type */
2870+
int increment_size = 1;
2871+
if (lvalue->is_ptr && !lvalue->is_reference) {
2872+
increment_size = lvalue->type->size;
2873+
} else if (!lvalue->is_reference && lvalue->type &&
2874+
lvalue->type->ptr_level > 0) {
2875+
/* This is a typedef pointer */
2876+
switch (lvalue->type->base_type) {
2877+
case TYPE_char:
2878+
increment_size = TY_char->size;
2879+
break;
2880+
case TYPE_int:
2881+
increment_size = TY_int->size;
2882+
break;
2883+
case TYPE_void:
2884+
increment_size = 1;
2885+
break;
2886+
default:
2887+
increment_size = lvalue->type->size;
2888+
break;
2889+
}
2890+
}
2891+
vd->init_val = increment_size;
2892+
26492893
side_effect[se_idx].rd = vd;
26502894
side_effect[se_idx].rs1 = NULL;
26512895
side_effect[se_idx].rs2 = NULL;
@@ -2960,6 +3204,27 @@ bool read_body_assignment(char *token,
29603204
*/
29613205
if (lvalue.is_ptr && !lvalue.is_reference)
29623206
increment_size = lvalue.type->size;
3207+
/* Also check for typedef pointers which have is_ptr == 0 */
3208+
else if (!lvalue.is_reference && lvalue.type &&
3209+
lvalue.type->ptr_level > 0) {
3210+
/* This is a typedef pointer, get the base type size */
3211+
switch (lvalue.type->base_type) {
3212+
case TYPE_char:
3213+
increment_size = TY_char->size;
3214+
break;
3215+
case TYPE_int:
3216+
increment_size = TY_int->size;
3217+
break;
3218+
case TYPE_void:
3219+
/* void pointers treated as byte pointers */
3220+
increment_size = 1;
3221+
break;
3222+
default:
3223+
/* For struct pointers and other types */
3224+
increment_size = lvalue.type->size;
3225+
break;
3226+
}
3227+
}
29633228

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

0 commit comments

Comments
 (0)