Skip to content

Commit b3e4cd2

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 b3e4cd2

File tree

2 files changed

+481
-11
lines changed

2 files changed

+481
-11
lines changed

src/parser.c

Lines changed: 275 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,10 +1250,6 @@ void read_full_var_decl(var_t *vd, int anon, int is_param)
12501250

12511251
vd->type = type;
12521252

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

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

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

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

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

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

0 commit comments

Comments
 (0)