Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
WIP coercion from short int to fixed width int
  • Loading branch information
JukkaL committed Jan 15, 2026
commit 4f992c09202cbdd38b6fdcad21a61080733794ec
69 changes: 67 additions & 2 deletions mypyc/irbuild/ll_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,12 +540,77 @@ def coerce_int_to_fixed_width(self, src: Value, target_type: RType, line: int) -
return res

def coerce_short_int_to_fixed_width(self, src: Value, target_type: RType, line: int) -> Value:
# short_int (CPyTagged) is guaranteed to be a tagged value, never a pointer,
# so we don't need the fast/slow path split like coerce_int_to_fixed_width.
# However, we still need range checking when target type is smaller than source.
assert is_fixed_width_rtype(target_type), target_type
assert isinstance(target_type, RPrimitive), target_type

if is_int64_rprimitive(target_type) or (
PLATFORM_SIZE == 4 and is_int32_rprimitive(target_type)
):
# No range check needed - target is same size or larger than source
return self.int_op(target_type, src, Integer(1, target_type), IntOp.RIGHT_SHIFT, line)
# TODO: i32 on 64-bit platform
assert False, (src.type, target_type, PLATFORM_SIZE)

# Target is smaller than source - need range checking
size = target_type.size
assert size < short_int_rprimitive.size, (target_type, size, short_int_rprimitive.size)

res = Register(target_type)
in_range, overflow, end = BasicBlock(), BasicBlock(), BasicBlock()

# Calculate bounds for the target type
upper_bound = 1 << (size * 8 - 1)
if not target_type.is_signed:
upper_bound *= 2

# Check if value < upper_bound
check_upper = self.add(
ComparisonOp(src, Integer(upper_bound, src.type), ComparisonOp.SLT)
)
self.add(Branch(check_upper, in_range, overflow, Branch.BOOL))

self.activate_block(in_range)

# Check if value >= lower_bound
in_range2 = BasicBlock()
if target_type.is_signed:
lower_bound = -upper_bound
else:
lower_bound = 0
check_lower = self.add(
ComparisonOp(src, Integer(lower_bound, src.type), ComparisonOp.SGE)
)
self.add(Branch(check_lower, in_range2, overflow, Branch.BOOL))

self.activate_block(in_range2)

# Value is in range - shift right to remove tag, then truncate
shifted = self.int_op(
c_pyssize_t_rprimitive,
src,
Integer(1, c_pyssize_t_rprimitive),
IntOp.RIGHT_SHIFT,
line,
)
tmp = self.add(Truncate(shifted, target_type))
self.add(Assign(res, tmp))
self.goto(end)

# Value is out of range - raise OverflowError
self.activate_block(overflow)
if is_int32_rprimitive(target_type):
self.call_c(int32_overflow, [], line)
elif is_int16_rprimitive(target_type):
self.call_c(int16_overflow, [], line)
elif is_uint8_rprimitive(target_type):
self.call_c(uint8_overflow, [], line)
else:
assert False, target_type
self.add(Unreachable())

self.activate_block(end)
return res

def coerce_fixed_width_to_int(self, src: Value, line: int) -> Value:
if (
Expand Down
36 changes: 35 additions & 1 deletion mypyc/test-data/irbuild-str.test
Original file line number Diff line number Diff line change
Expand Up @@ -508,11 +508,13 @@ L0:
return r6

[case testOrdOfStrIndex_64bit]
from mypy_extensions import i64
from mypy_extensions import i64, i32
def ord_str_index(s: str, i: int) -> int:
return ord(s[i])
def ord_str_index_i64(s: str, i: i64) -> int:
return ord(s[i])
def ord_str_index_to_i32(s: str, i: i64) -> i32:
return ord(s[i])
[typing fixtures/typing-full.pyi]
[out]
def ord_str_index(s, i):
Expand Down Expand Up @@ -565,6 +567,38 @@ L1:
L2:
r3 = CPyStr_GetItemUnsafeAsInt(s, r0)
return r3
def ord_str_index_to_i32(s, i):
s :: str
i, r0 :: i64
r1, r2 :: bool
r3 :: short_int
r4, r5 :: bit
r6 :: native_int
r7, r8 :: i32
L0:
r0 = CPyStr_AdjustIndex(s, i)
r1 = CPyStr_RangeCheck(s, r0)
if r1 goto L2 else goto L1 :: bool
L1:
r2 = raise IndexError('index out of range')
unreachable
L2:
r3 = CPyStr_GetItemUnsafeAsInt(s, r0)
r4 = r3 < 4294967296 :: signed
if r4 goto L3 else goto L5 :: bool
L3:
r5 = r3 >= -4294967296 :: signed
if r5 goto L4 else goto L5 :: bool
L4:
r6 = r3 >> 1
r7 = truncate r6: native_int to i32
r8 = r7
goto L6
L5:
CPyInt32_Overflow()
unreachable
L6:
return r8

[case testStrip]
from typing import NewType, Union
Expand Down