Skip to content

Commit b3d40a4

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 1611d23 commit b3d40a4

File tree

2 files changed

+432
-160
lines changed

2 files changed

+432
-160
lines changed

src/parser.c

Lines changed: 351 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2331,7 +2331,164 @@ void read_expr(block_t *parent, basic_block_t **bb)
23312331
vd = require_var(parent);
23322332
gen_name_to(vd->var_name);
23332333
opstack_push(vd);
2334-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2334+
2335+
/* Handle pointer arithmetic:
2336+
* - If both operands are pointers (subtraction), divide by
2337+
* element size
2338+
* - If one operand is a pointer, handle scaling
2339+
* appropriately
2340+
*/
2341+
if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) {
2342+
/* Subtracting two pointers - divide by element size */
2343+
var_t *diff = require_var(parent);
2344+
gen_name_to(diff->var_name);
2345+
add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL);
2346+
2347+
/* Get the element size */
2348+
int elem_size = 4; /* Default to int size */
2349+
if (rs1->type) {
2350+
/* For pointers, check what they point to */
2351+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2352+
switch (rs1->type->base_type) {
2353+
case TYPE_char:
2354+
elem_size = 1;
2355+
break;
2356+
case TYPE_int:
2357+
elem_size = 4;
2358+
break;
2359+
default:
2360+
elem_size = 4;
2361+
break;
2362+
}
2363+
} else {
2364+
/* For non-pointers, use the type size */
2365+
if (rs1->type->size > 0) {
2366+
elem_size = rs1->type->size;
2367+
} else {
2368+
elem_size = 4;
2369+
}
2370+
}
2371+
}
2372+
2373+
/* Divide by element size */
2374+
if (elem_size > 1) {
2375+
var_t *size_const = require_var(parent);
2376+
size_const->init_val = elem_size;
2377+
gen_name_to(size_const->var_name);
2378+
add_insn(parent, *bb, OP_load_constant, size_const,
2379+
NULL, NULL, 0, NULL);
2380+
add_insn(parent, *bb, OP_div, vd, diff, size_const,
2381+
0, NULL);
2382+
} else {
2383+
/* If element size is 1, no division needed - use
2384+
* assignment */
2385+
add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0,
2386+
NULL);
2387+
}
2388+
} else if ((top_op == OP_add || top_op == OP_sub) &&
2389+
(rs1->is_ptr ||
2390+
(rs1->type && rs1->type->ptr_level > 0)) &&
2391+
!rs2->is_ptr) {
2392+
/* Pointer +/- integer: scale the integer by element
2393+
* size */
2394+
int elem_size = 4;
2395+
if (rs1->type) {
2396+
/* For pointers, check what they point to */
2397+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2398+
switch (rs1->type->base_type) {
2399+
case TYPE_char:
2400+
elem_size = 1;
2401+
break;
2402+
case TYPE_int:
2403+
elem_size = 4;
2404+
break;
2405+
default:
2406+
elem_size = 4;
2407+
break;
2408+
}
2409+
} else {
2410+
/* For non-pointers, use the type size */
2411+
if (rs1->type->size > 0) {
2412+
elem_size = rs1->type->size;
2413+
} else {
2414+
elem_size = 4;
2415+
}
2416+
}
2417+
}
2418+
2419+
/* Scale the integer operand if needed */
2420+
if (elem_size > 1) {
2421+
var_t *scaled = require_var(parent);
2422+
gen_name_to(scaled->var_name);
2423+
var_t *size_const = require_var(parent);
2424+
size_const->init_val = elem_size;
2425+
gen_name_to(size_const->var_name);
2426+
add_insn(parent, *bb, OP_load_constant, size_const,
2427+
NULL, NULL, 0, NULL);
2428+
add_insn(parent, *bb, OP_mul, scaled, rs2,
2429+
size_const, 0, NULL);
2430+
add_insn(parent, *bb, top_op, vd, rs1, scaled, 0,
2431+
NULL);
2432+
} else {
2433+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0,
2434+
NULL);
2435+
}
2436+
/* Result is still a pointer */
2437+
vd->is_ptr = rs1->is_ptr;
2438+
vd->type = rs1->type;
2439+
} else if ((top_op == OP_add) && !rs1->is_ptr &&
2440+
(rs2->is_ptr ||
2441+
(rs2->type && rs2->type->ptr_level > 0))) {
2442+
/* Integer + pointer: scale the integer by element size
2443+
*/
2444+
int elem_size = 4;
2445+
if (rs2->type) {
2446+
/* For pointers, check what they point to */
2447+
if (rs2->is_ptr || rs2->type->ptr_level > 0) {
2448+
switch (rs2->type->base_type) {
2449+
case TYPE_char:
2450+
elem_size = 1;
2451+
break;
2452+
case TYPE_int:
2453+
elem_size = 4;
2454+
break;
2455+
default:
2456+
elem_size = 4;
2457+
break;
2458+
}
2459+
} else {
2460+
/* For non-pointers, use the type size */
2461+
if (rs2->type->size > 0) {
2462+
elem_size = rs2->type->size;
2463+
} else {
2464+
elem_size = 4;
2465+
}
2466+
}
2467+
}
2468+
2469+
/* Scale the integer operand if needed */
2470+
if (elem_size > 1) {
2471+
var_t *scaled = require_var(parent);
2472+
gen_name_to(scaled->var_name);
2473+
var_t *size_const = require_var(parent);
2474+
size_const->init_val = elem_size;
2475+
gen_name_to(size_const->var_name);
2476+
add_insn(parent, *bb, OP_load_constant, size_const,
2477+
NULL, NULL, 0, NULL);
2478+
add_insn(parent, *bb, OP_mul, scaled, rs1,
2479+
size_const, 0, NULL);
2480+
add_insn(parent, *bb, top_op, vd, scaled, rs2, 0,
2481+
NULL);
2482+
} else {
2483+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0,
2484+
NULL);
2485+
}
2486+
/* Result is a pointer */
2487+
vd->is_ptr = rs2->is_ptr;
2488+
vd->type = rs2->type;
2489+
} else {
2490+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2491+
}
23352492

23362493
oper_stack_idx--;
23372494
} else
@@ -2609,14 +2766,205 @@ void read_expr(block_t *parent, basic_block_t **bb)
26092766
vd = require_var(parent);
26102767
gen_name_to(vd->var_name);
26112768
opstack_push(vd);
2612-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2769+
2770+
/* Handle pointer subtraction */
2771+
if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) {
2772+
var_t *diff = require_var(parent);
2773+
gen_name_to(diff->var_name);
2774+
add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL);
2775+
2776+
int elem_size = 4;
2777+
if (rs1->type) {
2778+
/* For pointers, check what they point to */
2779+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2780+
switch (rs1->type->base_type) {
2781+
case TYPE_char:
2782+
elem_size = 1;
2783+
break;
2784+
case TYPE_int:
2785+
elem_size = 4;
2786+
break;
2787+
default:
2788+
elem_size = 4;
2789+
break;
2790+
}
2791+
} else {
2792+
/* For non-pointers, use the type size */
2793+
if (rs1->type->size > 0) {
2794+
elem_size = rs1->type->size;
2795+
} else {
2796+
elem_size = 4;
2797+
}
2798+
}
2799+
}
2800+
2801+
if (elem_size > 1) {
2802+
var_t *size_const = require_var(parent);
2803+
size_const->init_val = elem_size;
2804+
gen_name_to(size_const->var_name);
2805+
add_insn(parent, *bb, OP_load_constant, size_const,
2806+
NULL, NULL, 0, NULL);
2807+
add_insn(parent, *bb, OP_div, vd, diff, size_const, 0,
2808+
NULL);
2809+
} else {
2810+
/* If element size is 1, no division needed - use
2811+
* assignment */
2812+
add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0,
2813+
NULL);
2814+
}
2815+
} else if ((top_op == OP_add || top_op == OP_sub) &&
2816+
(rs1->is_ptr ||
2817+
(rs1->type && rs1->type->ptr_level > 0)) &&
2818+
!rs2->is_ptr) {
2819+
/* Pointer +/- integer: scale the integer by element size */
2820+
int elem_size = 4;
2821+
if (rs1->type) {
2822+
/* For pointers, check what they point to */
2823+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2824+
switch (rs1->type->base_type) {
2825+
case TYPE_char:
2826+
elem_size = 1;
2827+
break;
2828+
case TYPE_int:
2829+
elem_size = 4;
2830+
break;
2831+
default:
2832+
elem_size = 4;
2833+
break;
2834+
}
2835+
} else {
2836+
/* For non-pointers, use the type size */
2837+
if (rs1->type->size > 0) {
2838+
elem_size = rs1->type->size;
2839+
} else {
2840+
elem_size = 4;
2841+
}
2842+
}
2843+
}
2844+
2845+
/* Scale the integer operand if needed */
2846+
if (elem_size > 1) {
2847+
var_t *scaled = require_var(parent);
2848+
gen_name_to(scaled->var_name);
2849+
var_t *size_const = require_var(parent);
2850+
size_const->init_val = elem_size;
2851+
gen_name_to(size_const->var_name);
2852+
add_insn(parent, *bb, OP_load_constant, size_const,
2853+
NULL, NULL, 0, NULL);
2854+
add_insn(parent, *bb, OP_mul, scaled, rs2, size_const,
2855+
0, NULL);
2856+
add_insn(parent, *bb, top_op, vd, rs1, scaled, 0, NULL);
2857+
} else {
2858+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2859+
}
2860+
/* Result is still a pointer */
2861+
vd->is_ptr = rs1->is_ptr;
2862+
vd->type = rs1->type;
2863+
} else {
2864+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2865+
}
26132866
}
26142867
} else {
26152868
/* Normal operation */
26162869
vd = require_var(parent);
26172870
gen_name_to(vd->var_name);
26182871
opstack_push(vd);
2619-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2872+
2873+
/* Handle pointer subtraction */
2874+
if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) {
2875+
var_t *diff = require_var(parent);
2876+
gen_name_to(diff->var_name);
2877+
add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL);
2878+
2879+
int elem_size = 4;
2880+
if (rs1->type) {
2881+
/* For pointers, check what they point to */
2882+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2883+
switch (rs1->type->base_type) {
2884+
case TYPE_char:
2885+
elem_size = 1;
2886+
break;
2887+
case TYPE_int:
2888+
elem_size = 4;
2889+
break;
2890+
default:
2891+
elem_size = 4;
2892+
break;
2893+
}
2894+
} else {
2895+
/* For non-pointers, use the type size */
2896+
if (rs1->type->size > 0) {
2897+
elem_size = rs1->type->size;
2898+
} else {
2899+
elem_size = 4;
2900+
}
2901+
}
2902+
}
2903+
2904+
if (elem_size > 1) {
2905+
var_t *size_const = require_var(parent);
2906+
size_const->init_val = elem_size;
2907+
gen_name_to(size_const->var_name);
2908+
add_insn(parent, *bb, OP_load_constant, size_const, NULL,
2909+
NULL, 0, NULL);
2910+
add_insn(parent, *bb, OP_div, vd, diff, size_const, 0,
2911+
NULL);
2912+
} else {
2913+
/* If element size is 1, no division needed - use assignment
2914+
*/
2915+
add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0, NULL);
2916+
}
2917+
} else if ((top_op == OP_add || top_op == OP_sub) &&
2918+
(rs1->is_ptr ||
2919+
(rs1->type && rs1->type->ptr_level > 0)) &&
2920+
!rs2->is_ptr) {
2921+
/* Pointer +/- integer: scale the integer by element size */
2922+
int elem_size = 4;
2923+
if (rs1->type) {
2924+
/* For pointers, check what they point to */
2925+
if (rs1->is_ptr || rs1->type->ptr_level > 0) {
2926+
switch (rs1->type->base_type) {
2927+
case TYPE_char:
2928+
elem_size = 1;
2929+
break;
2930+
case TYPE_int:
2931+
elem_size = 4;
2932+
break;
2933+
default:
2934+
elem_size = 4;
2935+
break;
2936+
}
2937+
} else {
2938+
/* For non-pointers, use the type size */
2939+
if (rs1->type->size > 0) {
2940+
elem_size = rs1->type->size;
2941+
} else {
2942+
elem_size = 4;
2943+
}
2944+
}
2945+
}
2946+
2947+
/* Scale the integer operand if needed */
2948+
if (elem_size > 1) {
2949+
var_t *scaled = require_var(parent);
2950+
gen_name_to(scaled->var_name);
2951+
var_t *size_const = require_var(parent);
2952+
size_const->init_val = elem_size;
2953+
gen_name_to(size_const->var_name);
2954+
add_insn(parent, *bb, OP_load_constant, size_const, NULL,
2955+
NULL, 0, NULL);
2956+
add_insn(parent, *bb, OP_mul, scaled, rs2, size_const, 0,
2957+
NULL);
2958+
add_insn(parent, *bb, top_op, vd, rs1, scaled, 0, NULL);
2959+
} else {
2960+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2961+
}
2962+
/* Result is still a pointer */
2963+
vd->is_ptr = rs1->is_ptr;
2964+
vd->type = rs1->type;
2965+
} else {
2966+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2967+
}
26202968
}
26212969
}
26222970
while (has_prev_log_op) {

0 commit comments

Comments
 (0)