Skip to content

Commit e791a2b

Browse files
committed
Implement pointer difference arithmetic
This commit adds comprehensive pointer difference support (ptr1 - ptr2) that was missing from the existing pointer arithmetic implementation: - Pointer difference calculation: It computes element count by dividing byte difference by element size (char=1, int=4, etc.) - Expression support: Enables complex expressions like *(p + (q - r)) - Unified element size detection: Consistent logic for both regular and typedef pointers across all arithmetic operations
1 parent 3ce9b6d commit e791a2b

File tree

2 files changed

+481
-3
lines changed

2 files changed

+481
-3
lines changed

src/parser.c

Lines changed: 351 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,7 +2159,164 @@ void read_expr(block_t *parent, basic_block_t **bb)
21592159
vd = require_var(parent);
21602160
gen_name_to(vd->var_name);
21612161
opstack_push(vd);
2162-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2162+
2163+
/* Handle pointer arithmetic:
2164+
* - If both operands are pointers (subtraction), divide by
2165+
* element size
2166+
* - If one operand is a pointer, handle scaling
2167+
* appropriately
2168+
*/
2169+
if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) {
2170+
/* Subtracting two pointers - divide by element size */
2171+
var_t *diff = require_var(parent);
2172+
gen_name_to(diff->var_name);
2173+
add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL);
2174+
2175+
/* Get the element size */
2176+
int elem_size = 4; /* Default to int size */
2177+
if (rs1->type) {
2178+
/* For pointers, check what they point to */
2179+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2180+
switch (rs1->type->base_type) {
2181+
case TYPE_char:
2182+
elem_size = 1;
2183+
break;
2184+
case TYPE_int:
2185+
elem_size = 4;
2186+
break;
2187+
default:
2188+
elem_size = 4;
2189+
break;
2190+
}
2191+
} else {
2192+
/* For non-pointers, use the type size */
2193+
if (rs1->type->size > 0) {
2194+
elem_size = rs1->type->size;
2195+
} else {
2196+
elem_size = 4;
2197+
}
2198+
}
2199+
}
2200+
2201+
/* Divide by element size */
2202+
if (elem_size > 1) {
2203+
var_t *size_const = require_var(parent);
2204+
size_const->init_val = elem_size;
2205+
gen_name_to(size_const->var_name);
2206+
add_insn(parent, *bb, OP_load_constant, size_const,
2207+
NULL, NULL, 0, NULL);
2208+
add_insn(parent, *bb, OP_div, vd, diff, size_const,
2209+
0, NULL);
2210+
} else {
2211+
/* If element size is 1, no division needed - use
2212+
* assignment */
2213+
add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0,
2214+
NULL);
2215+
}
2216+
} else if ((top_op == OP_add || top_op == OP_sub) &&
2217+
(rs1->is_ptr ||
2218+
(rs1->type && rs1->type->ptr_level > 0)) &&
2219+
!rs2->is_ptr) {
2220+
/* Pointer +/- integer: scale the integer by element
2221+
* size */
2222+
int elem_size = 4;
2223+
if (rs1->type) {
2224+
/* For pointers, check what they point to */
2225+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2226+
switch (rs1->type->base_type) {
2227+
case TYPE_char:
2228+
elem_size = 1;
2229+
break;
2230+
case TYPE_int:
2231+
elem_size = 4;
2232+
break;
2233+
default:
2234+
elem_size = 4;
2235+
break;
2236+
}
2237+
} else {
2238+
/* For non-pointers, use the type size */
2239+
if (rs1->type->size > 0) {
2240+
elem_size = rs1->type->size;
2241+
} else {
2242+
elem_size = 4;
2243+
}
2244+
}
2245+
}
2246+
2247+
/* Scale the integer operand if needed */
2248+
if (elem_size > 1) {
2249+
var_t *scaled = require_var(parent);
2250+
gen_name_to(scaled->var_name);
2251+
var_t *size_const = require_var(parent);
2252+
size_const->init_val = elem_size;
2253+
gen_name_to(size_const->var_name);
2254+
add_insn(parent, *bb, OP_load_constant, size_const,
2255+
NULL, NULL, 0, NULL);
2256+
add_insn(parent, *bb, OP_mul, scaled, rs2,
2257+
size_const, 0, NULL);
2258+
add_insn(parent, *bb, top_op, vd, rs1, scaled, 0,
2259+
NULL);
2260+
} else {
2261+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0,
2262+
NULL);
2263+
}
2264+
/* Result is still a pointer */
2265+
vd->is_ptr = rs1->is_ptr;
2266+
vd->type = rs1->type;
2267+
} else if ((top_op == OP_add) && !rs1->is_ptr &&
2268+
(rs2->is_ptr ||
2269+
(rs2->type && rs2->type->ptr_level > 0))) {
2270+
/* Integer + pointer: scale the integer by element size
2271+
*/
2272+
int elem_size = 4;
2273+
if (rs2->type) {
2274+
/* For pointers, check what they point to */
2275+
if (rs2->is_ptr || rs2->type->ptr_level > 0) {
2276+
switch (rs2->type->base_type) {
2277+
case TYPE_char:
2278+
elem_size = 1;
2279+
break;
2280+
case TYPE_int:
2281+
elem_size = 4;
2282+
break;
2283+
default:
2284+
elem_size = 4;
2285+
break;
2286+
}
2287+
} else {
2288+
/* For non-pointers, use the type size */
2289+
if (rs2->type->size > 0) {
2290+
elem_size = rs2->type->size;
2291+
} else {
2292+
elem_size = 4;
2293+
}
2294+
}
2295+
}
2296+
2297+
/* Scale the integer operand if needed */
2298+
if (elem_size > 1) {
2299+
var_t *scaled = require_var(parent);
2300+
gen_name_to(scaled->var_name);
2301+
var_t *size_const = require_var(parent);
2302+
size_const->init_val = elem_size;
2303+
gen_name_to(size_const->var_name);
2304+
add_insn(parent, *bb, OP_load_constant, size_const,
2305+
NULL, NULL, 0, NULL);
2306+
add_insn(parent, *bb, OP_mul, scaled, rs1,
2307+
size_const, 0, NULL);
2308+
add_insn(parent, *bb, top_op, vd, scaled, rs2, 0,
2309+
NULL);
2310+
} else {
2311+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0,
2312+
NULL);
2313+
}
2314+
/* Result is a pointer */
2315+
vd->is_ptr = rs2->is_ptr;
2316+
vd->type = rs2->type;
2317+
} else {
2318+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2319+
}
21632320

21642321
oper_stack_idx--;
21652322
} else
@@ -2351,14 +2508,205 @@ void read_expr(block_t *parent, basic_block_t **bb)
23512508
vd = require_var(parent);
23522509
gen_name_to(vd->var_name);
23532510
opstack_push(vd);
2354-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2511+
2512+
/* Handle pointer subtraction */
2513+
if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) {
2514+
var_t *diff = require_var(parent);
2515+
gen_name_to(diff->var_name);
2516+
add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL);
2517+
2518+
int elem_size = 4;
2519+
if (rs1->type) {
2520+
/* For pointers, check what they point to */
2521+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2522+
switch (rs1->type->base_type) {
2523+
case TYPE_char:
2524+
elem_size = 1;
2525+
break;
2526+
case TYPE_int:
2527+
elem_size = 4;
2528+
break;
2529+
default:
2530+
elem_size = 4;
2531+
break;
2532+
}
2533+
} else {
2534+
/* For non-pointers, use the type size */
2535+
if (rs1->type->size > 0) {
2536+
elem_size = rs1->type->size;
2537+
} else {
2538+
elem_size = 4;
2539+
}
2540+
}
2541+
}
2542+
2543+
if (elem_size > 1) {
2544+
var_t *size_const = require_var(parent);
2545+
size_const->init_val = elem_size;
2546+
gen_name_to(size_const->var_name);
2547+
add_insn(parent, *bb, OP_load_constant, size_const,
2548+
NULL, NULL, 0, NULL);
2549+
add_insn(parent, *bb, OP_div, vd, diff, size_const, 0,
2550+
NULL);
2551+
} else {
2552+
/* If element size is 1, no division needed - use
2553+
* assignment */
2554+
add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0,
2555+
NULL);
2556+
}
2557+
} else if ((top_op == OP_add || top_op == OP_sub) &&
2558+
(rs1->is_ptr ||
2559+
(rs1->type && rs1->type->ptr_level > 0)) &&
2560+
!rs2->is_ptr) {
2561+
/* Pointer +/- integer: scale the integer by element size */
2562+
int elem_size = 4;
2563+
if (rs1->type) {
2564+
/* For pointers, check what they point to */
2565+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2566+
switch (rs1->type->base_type) {
2567+
case TYPE_char:
2568+
elem_size = 1;
2569+
break;
2570+
case TYPE_int:
2571+
elem_size = 4;
2572+
break;
2573+
default:
2574+
elem_size = 4;
2575+
break;
2576+
}
2577+
} else {
2578+
/* For non-pointers, use the type size */
2579+
if (rs1->type->size > 0) {
2580+
elem_size = rs1->type->size;
2581+
} else {
2582+
elem_size = 4;
2583+
}
2584+
}
2585+
}
2586+
2587+
/* Scale the integer operand if needed */
2588+
if (elem_size > 1) {
2589+
var_t *scaled = require_var(parent);
2590+
gen_name_to(scaled->var_name);
2591+
var_t *size_const = require_var(parent);
2592+
size_const->init_val = elem_size;
2593+
gen_name_to(size_const->var_name);
2594+
add_insn(parent, *bb, OP_load_constant, size_const,
2595+
NULL, NULL, 0, NULL);
2596+
add_insn(parent, *bb, OP_mul, scaled, rs2, size_const,
2597+
0, NULL);
2598+
add_insn(parent, *bb, top_op, vd, rs1, scaled, 0, NULL);
2599+
} else {
2600+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2601+
}
2602+
/* Result is still a pointer */
2603+
vd->is_ptr = rs1->is_ptr;
2604+
vd->type = rs1->type;
2605+
} else {
2606+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2607+
}
23552608
}
23562609
} else {
23572610
/* Normal operation */
23582611
vd = require_var(parent);
23592612
gen_name_to(vd->var_name);
23602613
opstack_push(vd);
2361-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2614+
2615+
/* Handle pointer subtraction */
2616+
if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) {
2617+
var_t *diff = require_var(parent);
2618+
gen_name_to(diff->var_name);
2619+
add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL);
2620+
2621+
int elem_size = 4;
2622+
if (rs1->type) {
2623+
/* For pointers, check what they point to */
2624+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2625+
switch (rs1->type->base_type) {
2626+
case TYPE_char:
2627+
elem_size = 1;
2628+
break;
2629+
case TYPE_int:
2630+
elem_size = 4;
2631+
break;
2632+
default:
2633+
elem_size = 4;
2634+
break;
2635+
}
2636+
} else {
2637+
/* For non-pointers, use the type size */
2638+
if (rs1->type->size > 0) {
2639+
elem_size = rs1->type->size;
2640+
} else {
2641+
elem_size = 4;
2642+
}
2643+
}
2644+
}
2645+
2646+
if (elem_size > 1) {
2647+
var_t *size_const = require_var(parent);
2648+
size_const->init_val = elem_size;
2649+
gen_name_to(size_const->var_name);
2650+
add_insn(parent, *bb, OP_load_constant, size_const, NULL,
2651+
NULL, 0, NULL);
2652+
add_insn(parent, *bb, OP_div, vd, diff, size_const, 0,
2653+
NULL);
2654+
} else {
2655+
/* If element size is 1, no division needed - use assignment
2656+
*/
2657+
add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0, NULL);
2658+
}
2659+
} else if ((top_op == OP_add || top_op == OP_sub) &&
2660+
(rs1->is_ptr ||
2661+
(rs1->type && rs1->type->ptr_level > 0)) &&
2662+
!rs2->is_ptr) {
2663+
/* Pointer +/- integer: scale the integer by element size */
2664+
int elem_size = 4;
2665+
if (rs1->type) {
2666+
/* For pointers, check what they point to */
2667+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2668+
switch (rs1->type->base_type) {
2669+
case TYPE_char:
2670+
elem_size = 1;
2671+
break;
2672+
case TYPE_int:
2673+
elem_size = 4;
2674+
break;
2675+
default:
2676+
elem_size = 4;
2677+
break;
2678+
}
2679+
} else {
2680+
/* For non-pointers, use the type size */
2681+
if (rs1->type->size > 0) {
2682+
elem_size = rs1->type->size;
2683+
} else {
2684+
elem_size = 4;
2685+
}
2686+
}
2687+
}
2688+
2689+
/* Scale the integer operand if needed */
2690+
if (elem_size > 1) {
2691+
var_t *scaled = require_var(parent);
2692+
gen_name_to(scaled->var_name);
2693+
var_t *size_const = require_var(parent);
2694+
size_const->init_val = elem_size;
2695+
gen_name_to(size_const->var_name);
2696+
add_insn(parent, *bb, OP_load_constant, size_const, NULL,
2697+
NULL, 0, NULL);
2698+
add_insn(parent, *bb, OP_mul, scaled, rs2, size_const, 0,
2699+
NULL);
2700+
add_insn(parent, *bb, top_op, vd, rs1, scaled, 0, NULL);
2701+
} else {
2702+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2703+
}
2704+
/* Result is still a pointer */
2705+
vd->is_ptr = rs1->is_ptr;
2706+
vd->type = rs1->type;
2707+
} else {
2708+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2709+
}
23622710
}
23632711
}
23642712
while (has_prev_log_op) {

0 commit comments

Comments
 (0)