Skip to content

Commit 1198080

Browse files
committed
Fix OP_sign_ext source size detection by encoding both sizes
- Encode both source and target sizes in OP_sign_ext src1 parameter: * Lower 16 bits: target type size * Upper 16 bits: source type size - Update ARM and RISC-V codegen to decode size information properly - Calculate precise shift amounts using both source and target sizes - Fix short integer overflow behavior (32767 + 2 = -32767) - Update snapshots to reflect new IR encoding format - Maintain IR semantic compatibility without structural changes
1 parent 7929ddc commit 1198080

File tree

7 files changed

+46
-23
lines changed

7 files changed

+46
-23
lines changed

src/arm-codegen.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,13 +451,16 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
451451
fatal("Unsupported truncation operation with invalid target size");
452452
}
453453
return;
454-
case OP_sign_ext:
455-
if (rm == 2) {
454+
case OP_sign_ext: {
455+
/* Decode source size from upper 16 bits */
456+
int source_size = (rm >> 16) & 0xFFFF;
457+
if (source_size == 2) {
456458
emit(__sxth(__AL, rd, rn, 0));
457459
} else {
458460
/* For other cases, use byte extension (original behavior) */
459461
emit(__sxtb(__AL, rd, rn, 0));
460462
}
463+
}
461464
return;
462465
case OP_cast:
463466
/* Generic cast operation - for now, just move the value */

src/parser.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,18 @@ var_t *promote_unchecked(block_t *block,
247247
{
248248
var_t *rd = require_typed_ptr_var(block, target_type, target_ptr);
249249
gen_name_to(rd->var_name);
250-
/* TODO: Use source type size instead of target type size for
251-
* sign extension. The OP_sign_ext instruction may need both
252-
* source and target sizes for proper code generation.
250+
/* Encode both source and target sizes in src1:
251+
* Lower 16 bits: target size
252+
* Upper 16 bits: source size
253+
* This allows codegen to distinguish between different promotion types
254+
* without changing IR semantics.
253255
*/
254-
add_insn(block, *bb, OP_sign_ext, rd, var, NULL,
255-
target_ptr ? PTR_SIZE : var->type->size, NULL);
256+
int encoded_size = ((var->type->size) << 16);
257+
if (target_ptr)
258+
encoded_size |= PTR_SIZE;
259+
else
260+
encoded_size |= target_type->size;
261+
add_insn(block, *bb, OP_sign_ext, rd, var, NULL, encoded_size, NULL);
256262
return rd;
257263
}
258264

src/riscv-codegen.c

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,15 @@ void update_elf_offset(ph2_ir_t *ph2_ir)
100100
else
101101
elf_offset += 4;
102102
return;
103-
case OP_sign_ext:
104-
if (ph2_ir->src1 == 2)
105-
elf_offset += 8;
103+
case OP_sign_ext: {
104+
/* Decode source size from upper 16 bits */
105+
int source_size = (ph2_ir->src1 >> 16) & 0xFFFF;
106+
if (source_size == 2)
107+
elf_offset += 8; /* short extension: 2 instructions */
106108
else
107-
elf_offset += 12;
109+
elf_offset += 12; /* byte extension: 3 instructions */
108110
return;
111+
}
109112
case OP_cast:
110113
elf_offset += 4;
111114
return;
@@ -443,20 +446,31 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
443446
fatal("Unsupported truncation operation with invalid target size");
444447
}
445448
return;
446-
case OP_sign_ext:
447-
if (ph2_ir->src1 == 2) {
448-
/* Sign extend from short to word
449+
case OP_sign_ext: {
450+
/* Decode size information:
451+
* Lower 16 bits: target size
452+
* Upper 16 bits: source size
453+
*/
454+
int target_size = ph2_ir->src1 & 0xFFFF;
455+
int source_size = (ph2_ir->src1 >> 16) & 0xFFFF;
456+
457+
/* Calculate shift amount based on target and source sizes */
458+
int shift_amount = (target_size - source_size) * 8;
459+
460+
if (source_size == 2) {
461+
/* Sign extend from short to word (16-bit shift)
449462
* For 16-bit sign extension, use only shift operations
450463
* since 0xFFFF is too large for RISC-V immediate field
451464
*/
452-
emit(__slli(rd, rs1, 16));
453-
emit(__srai(rd, rd, 16));
465+
emit(__slli(rd, rs1, shift_amount));
466+
emit(__srai(rd, rd, shift_amount));
454467
} else {
455-
/* Sign extend from byte to word (src1 == 1) or fallback */
468+
/* Fallback for other sizes */
456469
emit(__andi(rd, rs1, 0xFF));
457-
emit(__slli(rd, rd, 24));
458-
emit(__srai(rd, rd, 24));
470+
emit(__slli(rd, rd, shift_amount));
471+
emit(__srai(rd, rd, shift_amount));
459472
}
473+
}
460474
return;
461475
case OP_cast:
462476
/* Generic cast operation - for now, just move the value */

tests/snapshots/fib-arm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/fib-riscv.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/hello-arm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/hello-riscv.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)