Skip to content

Commit 9ff47b9

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 9ff47b9

File tree

2 files changed

+356
-208
lines changed

2 files changed

+356
-208
lines changed

src/parser.c

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

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

0 commit comments

Comments
 (0)