Files
TransPyC/lib/core/Handles/HandlesExprOps.py
2026-07-18 19:25:40 +08:00

453 lines
28 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class ExprOpsHandle(BaseHandle):
def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
Gen._set_node_info(Node, "BinOp")
LeftVal: Any = self.HandleExprLlvm(Node.left, VarType)
if not LeftVal:
return None
RightVal: Any = self.HandleExprLlvm(Node.right, VarType)
if not RightVal:
return None
Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if not Op:
return None
OP_OVERLOAD_MAP: dict[str, str] = {
'+': '__add__', '-': '__sub__', '*': '__mul__',
'/': '__truediv__', '//': '__floordiv__', '%': '__mod__',
'**': '__pow__',
}
if Op in OP_OVERLOAD_MAP:
LeftClassName: str | None = None
if isinstance(LeftVal.type, ir.PointerType):
pointee: ir.Type = LeftVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
LeftClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
if LeftClassName and LeftClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName is None and isinstance(Node.left, ast.Name):
LeftClassName = Gen.var_struct_class.get(Node.left.id)
if LeftClassName and LeftClassName in Gen.structs:
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName:
op_name: str = OP_OVERLOAD_MAP[Op]
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
if result is not None:
return result
if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1:
CharVal: Any = Gen._load(LeftVal, name="Load_char_const")
CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int")
result = Gen.builder.add(CharAsInt, RightVal, name="char_add")
TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char")
return TruncResult
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right")
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType):
LeftVal = Gen._load(LeftVal, name="deref_ptr_binop")
if LeftVal.type.width < RightVal.type.width:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left")
elif LeftVal.type.width > RightVal.type.width:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref")
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType):
RightVal = Gen._load(RightVal, name="deref_ptr_binop_r")
if RightVal.type.width < LeftVal.type.width:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right")
elif RightVal.type.width > LeftVal.type.width:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref")
if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name):
vname: str = Node.left.id
if vname in Gen.var_signedness and Gen.var_signedness[vname]:
is_unsigned = True
result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned)
return result
def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
def _to_bool(val: Any, name: str) -> Any:
if isinstance(val.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name)
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name)
return val
values: list[ast.expr] = Node.values
if len(values) < 2:
return self.HandleExprLlvm(values[0]) if values else None
if isinstance(Node.op, ast.And):
phi_incomings: list[tuple[ir.Constant, ir.Block]] = []
end_bb: ir.Block = Gen.func.append_basic_block(name="and.end")
for idx in range(len(values) - 1):
val: Any = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block: ir.Block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"andcond{idx}")
cur_bb: ir.Block = Gen.builder.block
next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}")
Gen.builder.cbranch(val, next_bb, end_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val: Any = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 0)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "andcond_last")
last_bb: ir.Block = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
elif isinstance(Node.op, ast.Or):
phi_incomings = []
end_bb = Gen.func.append_basic_block(name="or.end")
for idx in range(len(values) - 1):
val = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"orcond{idx}")
cur_bb = Gen.builder.block
next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}")
Gen.builder.cbranch(val, end_bb, next_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 1)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "orcond_last")
last_bb = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi = Gen.builder.phi(ir.IntType(1), name="or.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
return None
def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
OperandVal: Any = self.HandleExprLlvm(Node.operand)
if not OperandVal:
return None
OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
if not OpSymbol:
return None
UNARY_OVERLOAD_MAP: dict[str, str] = {
'-': '__neg__',
'+': '__pos__',
'~': '__invert__',
}
if OpSymbol in UNARY_OVERLOAD_MAP:
ClassName: str | None = None
if isinstance(OperandVal.type, ir.PointerType):
pointee: ir.Type = OperandVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
ClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen)
if ClassName and ClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName is None and isinstance(Node.operand, ast.Name):
ClassName = Gen.var_struct_class.get(Node.operand.id)
if ClassName and ClassName in Gen.structs:
if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName:
op_name: str = UNARY_OVERLOAD_MAP[OpSymbol]
result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen)
if result is not None:
return result
if OpSymbol == 'not':
if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1:
return Gen.builder.not_(OperandVal, name="not_result")
if isinstance(OperandVal.type, ir.PointerType):
null_val: ir.Constant = ir.Constant(OperandVal.type, None)
return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
zero: ir.Constant = ir.Constant(OperandVal.type, 0)
return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
elif OpSymbol == '~':
if isinstance(OperandVal.type, ir.IntType):
mask: int = (1 << OperandVal.type.width) - 1
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result")
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result")
elif OpSymbol == '+':
return OperandVal
elif OpSymbol == '-':
if isinstance(OperandVal.type, ir.IntType):
return Gen.builder.neg(OperandVal, name="neg_result")
elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fneg(OperandVal, name="fneg_result")
return None
def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
LeftVal: Any = self.HandleExprLlvm(Node.left)
if not LeftVal:
return None
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False)
if len(Node.ops) == 1:
Op: ast.cmpop = Node.ops[0]
# in/not in: 调用 __contains__
if isinstance(Op, (ast.In, ast.NotIn)):
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
if RightVal:
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen)
if ClassName and Gen._has_function(f'{ClassName}.__contains__'):
# 处理 RightVal 为 i8整数的情况联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8:
RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__')
result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__")
# 归一化为 i1
if isinstance(result.type, ir.IntType) and result.type.width > 1:
zero: ir.Constant = ir.Constant(result.type, 0)
result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool")
if isinstance(Op, ast.NotIn):
result = Gen.builder.not_(result, name="not_in_result")
return result
return ir.Constant(ir.IntType(1), 0)
ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
return None
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
if not RightVal:
return None
if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant):
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
lv: int = LeftVal.constant
rv: int = RightVal.constant
lw: int = LeftVal.type.width
rw: int = RightVal.type.width
if lw < rw:
lv = lv if lv >= 0 else lv + (1 << lw)
elif rw < lw:
rv = rv if rv >= 0 else rv + (1 << rw)
if is_unsigned:
mask_l: int = (1 << max(lw, rw)) - 1
lv = lv & mask_l
rv = rv & mask_l
cmp_map: dict[str, bool] = {
'==': lv == rv, '!=': lv != rv,
'<': lv < rv, '>': lv > rv,
'<=': lv <= rv, '>=': lv >= rv,
}
result: bool = cmp_map.get(ComparatorSymbol, False)
return ir.Constant(ir.IntType(1), 1 if result else 0)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
# 如果宽类型常量值超出窄类型有符号范围则必须用zext
# i8 类型默认使用 zext系统编程中 i8 几乎总是无符号字节)
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp")
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp")
else:
if isinstance(RightVal, ir.Constant) and RightVal.constant == 0:
RightVal = ir.Constant(LeftVal.type, None)
else:
# 不将整数转为指针(避免 strcmp 解引用无效地址),改为将指针转为整数走正常 ==
LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp")
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8:
RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp")
else:
if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0:
LeftVal = ir.Constant(RightVal.type, None)
else:
# 不将整数转为指针(避免 strcmp 解引用无效地址),改为将指针转为整数走正常 ==
RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp")
# is / is not: 地址比较指针或值比较int
if ComparatorSymbol in ('is', 'is not'):
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp")
if ComparatorSymbol == 'is not':
addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result")
return addr_cmp
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp")
if ComparatorSymbol == 'is not':
val_cmp = Gen.builder.not_(val_cmp, name="is_not_result")
return val_cmp
# str/bytes == str/bytes: 值比较(调用 strcmpNone 比较用地址
if ComparatorSymbol in ('==', '!='):
if (isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8
and isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8):
left_is_null: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None
right_is_null: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None
if not (left_is_null or right_is_null):
strcmp_func = Gen.get_or_declare_c_func('strcmp', ir.FunctionType(ir.IntType(32), [ir.IntType(8).as_pointer(), ir.IntType(8).as_pointer()]))
cmp_result = Gen.builder.call(strcmp_func, [LeftVal, RightVal], name="str_eq_cmp")
zero = ir.Constant(ir.IntType(32), 0)
eq_result = Gen.builder.icmp_signed('==', cmp_result, zero, name="str_eq")
if ComparatorSymbol == '!=':
eq_result = Gen.builder.not_(eq_result, name="str_neq")
return eq_result
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp")
result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif is_unsigned:
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
else:
result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
return result
EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end")
phi_incomings: list[tuple[ir.Value, ir.Block]] = []
for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)):
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
continue
RightVal = self.HandleExprLlvm(Comparator)
if not RightVal:
continue
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}")
if is_unsigned:
cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}")
cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
else:
cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
if i < len(Node.ops) - 1:
NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}")
cur_bb: ir.Block = Gen.builder.block
Gen.builder.cbranch(cmp_result, NextBB, EndBB)
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
Gen.builder.position_at_start(NextBB)
LeftVal = RightVal
else:
cur_bb = Gen.builder.block
Gen.builder.branch(EndBB)
phi_incomings.append((cmp_result, cur_bb))
Gen.builder.position_at_start(EndBB)
final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp")
for val, bb in phi_incomings:
final_result.add_incoming(val, bb)
return final_result