Skip to content

Commit add8849

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 ee97fef commit add8849

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
@@ -2198,7 +2198,164 @@ void read_expr(block_t *parent, basic_block_t **bb)
21982198
vd = require_var(parent);
21992199
gen_name_to(vd->var_name);
22002200
opstack_push(vd);
2201-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2201+
2202+
/* Handle pointer arithmetic:
2203+
* - If both operands are pointers (subtraction), divide by
2204+
* element size
2205+
* - If one operand is a pointer, handle scaling
2206+
* appropriately
2207+
*/
2208+
if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) {
2209+
/* Subtracting two pointers - divide by element size */
2210+
var_t *diff = require_var(parent);
2211+
gen_name_to(diff->var_name);
2212+
add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL);
2213+
2214+
/* Get the element size */
2215+
int elem_size = 4; /* Default to int size */
2216+
if (rs1->type) {
2217+
/* For pointers, check what they point to */
2218+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2219+
switch (rs1->type->base_type) {
2220+
case TYPE_char:
2221+
elem_size = 1;
2222+
break;
2223+
case TYPE_int:
2224+
elem_size = 4;
2225+
break;
2226+
default:
2227+
elem_size = 4;
2228+
break;
2229+
}
2230+
} else {
2231+
/* For non-pointers, use the type size */
2232+
if (rs1->type->size > 0) {
2233+
elem_size = rs1->type->size;
2234+
} else {
2235+
elem_size = 4;
2236+
}
2237+
}
2238+
}
2239+
2240+
/* Divide by element size */
2241+
if (elem_size > 1) {
2242+
var_t *size_const = require_var(parent);
2243+
size_const->init_val = elem_size;
2244+
gen_name_to(size_const->var_name);
2245+
add_insn(parent, *bb, OP_load_constant, size_const,
2246+
NULL, NULL, 0, NULL);
2247+
add_insn(parent, *bb, OP_div, vd, diff, size_const,
2248+
0, NULL);
2249+
} else {
2250+
/* If element size is 1, no division needed - use
2251+
* assignment */
2252+
add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0,
2253+
NULL);
2254+
}
2255+
} else if ((top_op == OP_add || top_op == OP_sub) &&
2256+
(rs1->is_ptr ||
2257+
(rs1->type && rs1->type->ptr_level > 0)) &&
2258+
!rs2->is_ptr) {
2259+
/* Pointer +/- integer: scale the integer by element
2260+
* size */
2261+
int elem_size = 4;
2262+
if (rs1->type) {
2263+
/* For pointers, check what they point to */
2264+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2265+
switch (rs1->type->base_type) {
2266+
case TYPE_char:
2267+
elem_size = 1;
2268+
break;
2269+
case TYPE_int:
2270+
elem_size = 4;
2271+
break;
2272+
default:
2273+
elem_size = 4;
2274+
break;
2275+
}
2276+
} else {
2277+
/* For non-pointers, use the type size */
2278+
if (rs1->type->size > 0) {
2279+
elem_size = rs1->type->size;
2280+
} else {
2281+
elem_size = 4;
2282+
}
2283+
}
2284+
}
2285+
2286+
/* Scale the integer operand if needed */
2287+
if (elem_size > 1) {
2288+
var_t *scaled = require_var(parent);
2289+
gen_name_to(scaled->var_name);
2290+
var_t *size_const = require_var(parent);
2291+
size_const->init_val = elem_size;
2292+
gen_name_to(size_const->var_name);
2293+
add_insn(parent, *bb, OP_load_constant, size_const,
2294+
NULL, NULL, 0, NULL);
2295+
add_insn(parent, *bb, OP_mul, scaled, rs2,
2296+
size_const, 0, NULL);
2297+
add_insn(parent, *bb, top_op, vd, rs1, scaled, 0,
2298+
NULL);
2299+
} else {
2300+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0,
2301+
NULL);
2302+
}
2303+
/* Result is still a pointer */
2304+
vd->is_ptr = rs1->is_ptr;
2305+
vd->type = rs1->type;
2306+
} else if ((top_op == OP_add) && !rs1->is_ptr &&
2307+
(rs2->is_ptr ||
2308+
(rs2->type && rs2->type->ptr_level > 0))) {
2309+
/* Integer + pointer: scale the integer by element size
2310+
*/
2311+
int elem_size = 4;
2312+
if (rs2->type) {
2313+
/* For pointers, check what they point to */
2314+
if (rs2->is_ptr || rs2->type->ptr_level > 0) {
2315+
switch (rs2->type->base_type) {
2316+
case TYPE_char:
2317+
elem_size = 1;
2318+
break;
2319+
case TYPE_int:
2320+
elem_size = 4;
2321+
break;
2322+
default:
2323+
elem_size = 4;
2324+
break;
2325+
}
2326+
} else {
2327+
/* For non-pointers, use the type size */
2328+
if (rs2->type->size > 0) {
2329+
elem_size = rs2->type->size;
2330+
} else {
2331+
elem_size = 4;
2332+
}
2333+
}
2334+
}
2335+
2336+
/* Scale the integer operand if needed */
2337+
if (elem_size > 1) {
2338+
var_t *scaled = require_var(parent);
2339+
gen_name_to(scaled->var_name);
2340+
var_t *size_const = require_var(parent);
2341+
size_const->init_val = elem_size;
2342+
gen_name_to(size_const->var_name);
2343+
add_insn(parent, *bb, OP_load_constant, size_const,
2344+
NULL, NULL, 0, NULL);
2345+
add_insn(parent, *bb, OP_mul, scaled, rs1,
2346+
size_const, 0, NULL);
2347+
add_insn(parent, *bb, top_op, vd, scaled, rs2, 0,
2348+
NULL);
2349+
} else {
2350+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0,
2351+
NULL);
2352+
}
2353+
/* Result is a pointer */
2354+
vd->is_ptr = rs2->is_ptr;
2355+
vd->type = rs2->type;
2356+
} else {
2357+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2358+
}
22022359

22032360
oper_stack_idx--;
22042361
} else
@@ -2390,14 +2547,205 @@ void read_expr(block_t *parent, basic_block_t **bb)
23902547
vd = require_var(parent);
23912548
gen_name_to(vd->var_name);
23922549
opstack_push(vd);
2393-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2550+
2551+
/* Handle pointer subtraction */
2552+
if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) {
2553+
var_t *diff = require_var(parent);
2554+
gen_name_to(diff->var_name);
2555+
add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL);
2556+
2557+
int elem_size = 4;
2558+
if (rs1->type) {
2559+
/* For pointers, check what they point to */
2560+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2561+
switch (rs1->type->base_type) {
2562+
case TYPE_char:
2563+
elem_size = 1;
2564+
break;
2565+
case TYPE_int:
2566+
elem_size = 4;
2567+
break;
2568+
default:
2569+
elem_size = 4;
2570+
break;
2571+
}
2572+
} else {
2573+
/* For non-pointers, use the type size */
2574+
if (rs1->type->size > 0) {
2575+
elem_size = rs1->type->size;
2576+
} else {
2577+
elem_size = 4;
2578+
}
2579+
}
2580+
}
2581+
2582+
if (elem_size > 1) {
2583+
var_t *size_const = require_var(parent);
2584+
size_const->init_val = elem_size;
2585+
gen_name_to(size_const->var_name);
2586+
add_insn(parent, *bb, OP_load_constant, size_const,
2587+
NULL, NULL, 0, NULL);
2588+
add_insn(parent, *bb, OP_div, vd, diff, size_const, 0,
2589+
NULL);
2590+
} else {
2591+
/* If element size is 1, no division needed - use
2592+
* assignment */
2593+
add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0,
2594+
NULL);
2595+
}
2596+
} else if ((top_op == OP_add || top_op == OP_sub) &&
2597+
(rs1->is_ptr ||
2598+
(rs1->type && rs1->type->ptr_level > 0)) &&
2599+
!rs2->is_ptr) {
2600+
/* Pointer +/- integer: scale the integer by element size */
2601+
int elem_size = 4;
2602+
if (rs1->type) {
2603+
/* For pointers, check what they point to */
2604+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2605+
switch (rs1->type->base_type) {
2606+
case TYPE_char:
2607+
elem_size = 1;
2608+
break;
2609+
case TYPE_int:
2610+
elem_size = 4;
2611+
break;
2612+
default:
2613+
elem_size = 4;
2614+
break;
2615+
}
2616+
} else {
2617+
/* For non-pointers, use the type size */
2618+
if (rs1->type->size > 0) {
2619+
elem_size = rs1->type->size;
2620+
} else {
2621+
elem_size = 4;
2622+
}
2623+
}
2624+
}
2625+
2626+
/* Scale the integer operand if needed */
2627+
if (elem_size > 1) {
2628+
var_t *scaled = require_var(parent);
2629+
gen_name_to(scaled->var_name);
2630+
var_t *size_const = require_var(parent);
2631+
size_const->init_val = elem_size;
2632+
gen_name_to(size_const->var_name);
2633+
add_insn(parent, *bb, OP_load_constant, size_const,
2634+
NULL, NULL, 0, NULL);
2635+
add_insn(parent, *bb, OP_mul, scaled, rs2, size_const,
2636+
0, NULL);
2637+
add_insn(parent, *bb, top_op, vd, rs1, scaled, 0, NULL);
2638+
} else {
2639+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2640+
}
2641+
/* Result is still a pointer */
2642+
vd->is_ptr = rs1->is_ptr;
2643+
vd->type = rs1->type;
2644+
} else {
2645+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2646+
}
23942647
}
23952648
} else {
23962649
/* Normal operation */
23972650
vd = require_var(parent);
23982651
gen_name_to(vd->var_name);
23992652
opstack_push(vd);
2400-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2653+
2654+
/* Handle pointer subtraction */
2655+
if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) {
2656+
var_t *diff = require_var(parent);
2657+
gen_name_to(diff->var_name);
2658+
add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL);
2659+
2660+
int elem_size = 4;
2661+
if (rs1->type) {
2662+
/* For pointers, check what they point to */
2663+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2664+
switch (rs1->type->base_type) {
2665+
case TYPE_char:
2666+
elem_size = 1;
2667+
break;
2668+
case TYPE_int:
2669+
elem_size = 4;
2670+
break;
2671+
default:
2672+
elem_size = 4;
2673+
break;
2674+
}
2675+
} else {
2676+
/* For non-pointers, use the type size */
2677+
if (rs1->type->size > 0) {
2678+
elem_size = rs1->type->size;
2679+
} else {
2680+
elem_size = 4;
2681+
}
2682+
}
2683+
}
2684+
2685+
if (elem_size > 1) {
2686+
var_t *size_const = require_var(parent);
2687+
size_const->init_val = elem_size;
2688+
gen_name_to(size_const->var_name);
2689+
add_insn(parent, *bb, OP_load_constant, size_const, NULL,
2690+
NULL, 0, NULL);
2691+
add_insn(parent, *bb, OP_div, vd, diff, size_const, 0,
2692+
NULL);
2693+
} else {
2694+
/* If element size is 1, no division needed - use assignment
2695+
*/
2696+
add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0, NULL);
2697+
}
2698+
} else if ((top_op == OP_add || top_op == OP_sub) &&
2699+
(rs1->is_ptr ||
2700+
(rs1->type && rs1->type->ptr_level > 0)) &&
2701+
!rs2->is_ptr) {
2702+
/* Pointer +/- integer: scale the integer by element size */
2703+
int elem_size = 4;
2704+
if (rs1->type) {
2705+
/* For pointers, check what they point to */
2706+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2707+
switch (rs1->type->base_type) {
2708+
case TYPE_char:
2709+
elem_size = 1;
2710+
break;
2711+
case TYPE_int:
2712+
elem_size = 4;
2713+
break;
2714+
default:
2715+
elem_size = 4;
2716+
break;
2717+
}
2718+
} else {
2719+
/* For non-pointers, use the type size */
2720+
if (rs1->type->size > 0) {
2721+
elem_size = rs1->type->size;
2722+
} else {
2723+
elem_size = 4;
2724+
}
2725+
}
2726+
}
2727+
2728+
/* Scale the integer operand if needed */
2729+
if (elem_size > 1) {
2730+
var_t *scaled = require_var(parent);
2731+
gen_name_to(scaled->var_name);
2732+
var_t *size_const = require_var(parent);
2733+
size_const->init_val = elem_size;
2734+
gen_name_to(size_const->var_name);
2735+
add_insn(parent, *bb, OP_load_constant, size_const, NULL,
2736+
NULL, 0, NULL);
2737+
add_insn(parent, *bb, OP_mul, scaled, rs2, size_const, 0,
2738+
NULL);
2739+
add_insn(parent, *bb, top_op, vd, rs1, scaled, 0, NULL);
2740+
} else {
2741+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2742+
}
2743+
/* Result is still a pointer */
2744+
vd->is_ptr = rs1->is_ptr;
2745+
vd->type = rs1->type;
2746+
} else {
2747+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2748+
}
24012749
}
24022750
}
24032751
while (has_prev_log_op) {

0 commit comments

Comments
 (0)