863 lines
48 KiB
Python
863 lines
48 KiB
Python
from __future__ import annotations
|
|
from typing import TYPE_CHECKING
|
|
if TYPE_CHECKING:
|
|
from lib.core.translator import Translator
|
|
from lib.core.Handles.HandlesBase import BaseHandle
|
|
import ast
|
|
import llvmlite.ir as ir
|
|
|
|
|
|
class ExprBuiltinHandle(BaseHandle):
|
|
_C_LIB_FUNCS = {
|
|
'strlen': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
|
'strlength': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
|
'memset': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]),
|
|
'memcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
|
'memmove': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
|
'memcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
|
'strcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
|
|
'strncmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
|
'strcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
|
|
'strncpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
|
'strcat': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
|
|
'puts': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
|
|
'atoi': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
|
|
'atol': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
|
'abs': lambda: (ir.IntType(32), [ir.IntType(32)]),
|
|
'labs': lambda: (ir.IntType(64), [ir.IntType(64)]),
|
|
}
|
|
|
|
def _HandleBuiltinCallLlvm(self, Node):
|
|
Gen = self.Trans.LlvmGen
|
|
if not isinstance(Node.func, ast.Name):
|
|
return None
|
|
FuncName = Node.func.id
|
|
|
|
if FuncName == 'print':
|
|
return self._HandlePrintLlvm(Node)
|
|
elif FuncName == 'len':
|
|
if Node.args:
|
|
return self._HandleLenLlvm(Node.args[0])
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
elif FuncName == 'sizeof':
|
|
if Node.args:
|
|
return self._HandleSizeofLlvm(Node.args[0])
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
elif FuncName == 'abs':
|
|
if Node.args:
|
|
return self._HandleAbsLlvm(Node.args[0])
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
elif FuncName == 'arg':
|
|
return self._HandleArgLlvm(Node.args)
|
|
elif FuncName == 'bool':
|
|
if Node.args:
|
|
Val = self.HandleExprLlvm(Node.args[0])
|
|
if Val:
|
|
if isinstance(Val.type, ir.IntType):
|
|
if Val.type.width == 1:
|
|
return Val
|
|
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
|
|
elif isinstance(Val.type, ir.PointerType):
|
|
return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result")
|
|
return Val
|
|
return ir.Constant(ir.IntType(1), 0)
|
|
elif FuncName == 'int':
|
|
if Node.args:
|
|
Val = self.HandleExprLlvm(Node.args[0])
|
|
if Val:
|
|
if isinstance(Val.type, ir.IntType):
|
|
if Val.type.width < 32:
|
|
return Gen.builder.zext(Val, ir.IntType(32), name="cast_int")
|
|
elif Val.type.width > 32:
|
|
return Gen.builder.trunc(Val, ir.IntType(32), name="trunc_int")
|
|
return Val
|
|
elif isinstance(Val.type, ir.PointerType):
|
|
if isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8:
|
|
result = self._HandleAtoiLlvm(Val)
|
|
if result:
|
|
return result
|
|
elif isinstance(Val.type, (ir.FloatType, ir.DoubleType)):
|
|
return Gen.builder.fptosi(Val, ir.IntType(32), name="float_to_int")
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
elif FuncName == 'float' or FuncName == 'double':
|
|
if Node.args:
|
|
Val = self.HandleExprLlvm(Node.args[0])
|
|
if Val:
|
|
target_type = ir.DoubleType() if FuncName == 'double' else ir.FloatType()
|
|
if isinstance(Val.type, (ir.FloatType, ir.DoubleType)):
|
|
if Val.type != target_type:
|
|
if isinstance(target_type, ir.DoubleType):
|
|
return Gen.builder.fpext(Val, target_type, name="fpext_double")
|
|
return Gen.builder.fptrunc(Val, target_type, name="fptrunc_float")
|
|
return Val
|
|
elif isinstance(Val.type, ir.IntType):
|
|
if Val.type.width == 1:
|
|
return Gen.builder.uitofp(Val, target_type, name="uitofp")
|
|
return Gen.builder.sitofp(Val, target_type, name="sitofp")
|
|
return ir.Constant(ir.DoubleType() if FuncName == 'double' else ir.FloatType(), 0.0)
|
|
elif FuncName == 'min':
|
|
if len(Node.args) >= 2:
|
|
a = self.HandleExprLlvm(Node.args[0])
|
|
b = self.HandleExprLlvm(Node.args[1])
|
|
if a and b:
|
|
is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType))
|
|
if is_float:
|
|
fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="min_int2float")
|
|
fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="min_int2float")
|
|
cmp = Gen.builder.fcmp_ordered('olt', fa, fb, name="min_cmp")
|
|
return Gen.builder.select(cmp, fa, fb, name="min_val")
|
|
else:
|
|
cmp = Gen.builder.icmp_signed('<', a, b, name="min_cmp")
|
|
return Gen.builder.select(cmp, a, b, name="min_val")
|
|
elif len(Node.args) == 1:
|
|
return self.HandleExprLlvm(Node.args[0])
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
elif FuncName == 'max':
|
|
if len(Node.args) >= 2:
|
|
a = self.HandleExprLlvm(Node.args[0])
|
|
b = self.HandleExprLlvm(Node.args[1])
|
|
if a and b:
|
|
is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType))
|
|
if is_float:
|
|
fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="max_int2float")
|
|
fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="max_int2float")
|
|
cmp = Gen.builder.fcmp_ordered('ogt', fa, fb, name="max_cmp")
|
|
return Gen.builder.select(cmp, fa, fb, name="max_val")
|
|
else:
|
|
cmp = Gen.builder.icmp_signed('>', a, b, name="max_cmp")
|
|
return Gen.builder.select(cmp, a, b, name="max_val")
|
|
elif len(Node.args) == 1:
|
|
return self.HandleExprLlvm(Node.args[0])
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
elif FuncName == 'str':
|
|
if Node.args:
|
|
arg_node = Node.args[0]
|
|
arg_val = self.HandleExprLlvm(arg_node)
|
|
if arg_val:
|
|
if isinstance(arg_val.type, ir.PointerType):
|
|
ClassName = self.Trans.ExprHandler._get_var_class(arg_node, Gen)
|
|
if ClassName and Gen._has_function(f'{ClassName}.__str__'):
|
|
if isinstance(arg_val.type, ir.PointerType) and isinstance(arg_val.type.pointee, ir.IntType) and arg_val.type.pointee.width == 8:
|
|
if ClassName in Gen.structs:
|
|
arg_val = Gen.builder.bitcast(arg_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_str")
|
|
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [arg_val], name=f"call_{ClassName}.__str__")
|
|
return str_val
|
|
return arg_val
|
|
return self._EmitStringFromValue(arg_val)
|
|
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
|
elif FuncName == 'input':
|
|
return self._HandleInputLlvm(Node)
|
|
elif FuncName == 'ord':
|
|
if Node.args:
|
|
return self._HandleOrdLlvm(Node.args[0])
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
elif FuncName == 'chr':
|
|
if Node.args:
|
|
return self._HandleChrLlvm(Node.args[0])
|
|
return ir.Constant(ir.IntType(8), 0)
|
|
elif FuncName == 'malloc':
|
|
return self._HandleMallocLlvm(Node.args)
|
|
elif FuncName == 'realloc':
|
|
return self._HandleReallocLlvm(Node.args)
|
|
elif FuncName == 'free':
|
|
return self._HandleFreeLlvm(Node.args)
|
|
elif FuncName == 'memcpy':
|
|
return self._HandleMemcpyLlvm(Node.args)
|
|
elif FuncName == 'memset':
|
|
return self._HandleMemsetLlvm(Node.args)
|
|
elif FuncName == 'va_start':
|
|
return self._HandleVaStartLlvm(Node.args)
|
|
elif FuncName == 'va_end':
|
|
return self._HandleVaEndLlvm(Node.args)
|
|
elif FuncName == 'va_arg':
|
|
return self._HandleVaArgLlvm(Node.args)
|
|
elif FuncName == 'dir':
|
|
return self._HandleDirLlvm(Node)
|
|
elif FuncName == 'type':
|
|
return self._HandleTypeLlvm(Node)
|
|
return None
|
|
|
|
def _HandlePrintLlvm(self, Node):
|
|
Gen = self.Trans.LlvmGen
|
|
printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
|
args = Node.args
|
|
end_arg = None
|
|
sep_arg = None
|
|
if Node.keywords:
|
|
for kw in Node.keywords:
|
|
if kw.arg == 'end':
|
|
end_arg = kw.value
|
|
elif kw.arg == 'sep':
|
|
sep_arg = kw.value
|
|
sep_str = ' '
|
|
if sep_arg and isinstance(sep_arg, ast.Constant) and isinstance(sep_arg.value, str):
|
|
sep_str = sep_arg.value
|
|
end_str = '\n'
|
|
if end_arg:
|
|
if isinstance(end_arg, ast.Constant) and isinstance(end_arg.value, str):
|
|
end_str = end_arg.value
|
|
elif isinstance(end_arg, ast.Constant) and end_arg.value is None:
|
|
end_str = ''
|
|
if not args:
|
|
if end_str:
|
|
nl_fmt = Gen.emit_constant(end_str, 'string')
|
|
Gen.builder.call(printf_func, [nl_fmt], name="print_nl")
|
|
return
|
|
has_fstring = any(isinstance(arg, ast.JoinedStr) for arg in args)
|
|
if has_fstring:
|
|
self._HandlePrintWithFString(Node, printf_func, args, sep_str, end_str)
|
|
return
|
|
fmt_parts = []
|
|
fmt_args = []
|
|
for i, arg in enumerate(args):
|
|
if i > 0:
|
|
fmt_parts.append(sep_str)
|
|
val = self.HandleExprLlvm(arg)
|
|
if not val:
|
|
fmt_parts.append('(null)')
|
|
continue
|
|
if isinstance(val, ir.Constant) and isinstance(val.type, ir.PointerType) and val.constant is None:
|
|
fmt_parts.append('nil')
|
|
continue
|
|
if isinstance(val.type, ir.PointerType):
|
|
pointee = val.type.pointee
|
|
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
|
fmt_parts.append('%s')
|
|
fmt_args.append(val)
|
|
elif isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8:
|
|
elem_ptr = Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="print_arr_to_ptr")
|
|
fmt_parts.append('%s')
|
|
fmt_args.append(elem_ptr)
|
|
elif isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
|
ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen)
|
|
if not ClassName and isinstance(arg, ast.Name):
|
|
ClassName = Gen.var_struct_class.get(arg.id)
|
|
if ClassName and Gen._has_function(f'{ClassName}.__str__'):
|
|
if isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8:
|
|
if ClassName in Gen.structs:
|
|
val = Gen.builder.bitcast(val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
|
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [val], name=f"call_{ClassName}.__str__")
|
|
fmt_parts.append('%s')
|
|
fmt_args.append(str_val)
|
|
else:
|
|
int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int")
|
|
fmt_parts.append('0x%llx')
|
|
fmt_args.append(int_val)
|
|
else:
|
|
int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int")
|
|
fmt_parts.append('%lld')
|
|
fmt_args.append(int_val)
|
|
elif isinstance(val.type, ir.IntType):
|
|
is_unsigned = self._is_val_unsigned(arg, val)
|
|
if val.type.width == 1:
|
|
fmt_parts.append('%d')
|
|
val = Gen.builder.zext(val, ir.IntType(32), name="zext_bool_print")
|
|
elif val.type.width == 8:
|
|
if self._is_char_type(arg):
|
|
char_var = Gen._allocaEntry(ir.IntType(8), name="print_char_buf")
|
|
Gen.builder.store(val, char_var)
|
|
fmt_parts.append('%c')
|
|
fmt_args.append(char_var)
|
|
continue
|
|
fmt_parts.append('%d')
|
|
if is_unsigned:
|
|
val = Gen.builder.zext(val, ir.IntType(32), name="zext_i8_print")
|
|
else:
|
|
val = Gen.builder.sext(val, ir.IntType(32), name="sext_i8_print")
|
|
elif val.type.width == 16:
|
|
fmt_parts.append('%u' if is_unsigned else '%d')
|
|
if is_unsigned:
|
|
val = Gen.builder.zext(val, ir.IntType(32), name="zext_i16_print")
|
|
else:
|
|
val = Gen.builder.sext(val, ir.IntType(32), name="sext_i16_print")
|
|
elif val.type.width == 32:
|
|
fmt_parts.append('%u' if is_unsigned else '%d')
|
|
elif val.type.width == 64:
|
|
fmt_parts.append('%llu' if is_unsigned else '%lld')
|
|
else:
|
|
fmt_parts.append('%d')
|
|
val = Gen.builder.zext(val, ir.IntType(32), name="zext_int_print")
|
|
fmt_args.append(val)
|
|
elif isinstance(val.type, ir.FloatType):
|
|
fmt_parts.append('%f')
|
|
fmt_args.append(Gen.builder.fpext(val, ir.DoubleType(), name="fpext_printf_float"))
|
|
elif isinstance(val.type, ir.DoubleType):
|
|
fmt_parts.append('%f')
|
|
fmt_args.append(val)
|
|
else:
|
|
fmt_parts.append('(unknown)')
|
|
fmt_parts.append(end_str)
|
|
fmt_str = ''.join(fmt_parts)
|
|
fmt_bytes = fmt_str.encode('utf-8') + b'\x00'
|
|
fmt_type = ir.ArrayType(ir.IntType(8), len(fmt_bytes))
|
|
fmt_const = ir.Constant(fmt_type, bytearray(fmt_bytes))
|
|
fmt_gvar = ir.GlobalVariable(Gen.module, fmt_type, name=f"str_const_{Gen.string_const_counter}")
|
|
Gen.string_const_counter += 1
|
|
fmt_gvar.initializer = fmt_const
|
|
fmt_gvar.linkage = 'internal'
|
|
fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name="print_fmt")
|
|
call_args = [fmt_ptr] + fmt_args
|
|
return Gen.builder.call(printf_func, call_args, name="print_call")
|
|
|
|
def _HandlePrintWithFString(self, Node, printf_func, args, sep_str, end_str):
|
|
Gen = self.Trans.LlvmGen
|
|
for i, arg in enumerate(args):
|
|
if i > 0:
|
|
sep_const = Gen.emit_constant(sep_str, 'string')
|
|
Gen.builder.call(printf_func, [sep_const], name="print_sep")
|
|
if isinstance(arg, ast.JoinedStr):
|
|
self.HandleExprLlvm(arg)
|
|
else:
|
|
ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen)
|
|
if ClassName and Gen._has_function(f'{ClassName}.__str__'):
|
|
obj_val = self.HandleExprLlvm(arg)
|
|
if obj_val:
|
|
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
|
if ClassName in Gen.structs:
|
|
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
|
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [obj_val], name=f"call_{ClassName}.__str__")
|
|
Gen._RegisterTempPtr(str_val)
|
|
Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None)
|
|
else:
|
|
val = self.HandleExprLlvm(arg)
|
|
if val:
|
|
if isinstance(val.type, ir.PointerType):
|
|
pointee = val.type.pointee
|
|
if not (isinstance(pointee, ir.IntType) and pointee.width == 8):
|
|
try:
|
|
val = Gen._load(val, name="print_Load")
|
|
except Exception as _e:
|
|
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
|
|
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
|
is_u = Gen._check_node_unsigned(arg)
|
|
if not is_u and id(val) in Gen._unsigned_results:
|
|
is_u = True
|
|
Gen._emit_printf([val], unsigned_flags=[is_u], sep=None, end=None)
|
|
if end_str:
|
|
end_const = Gen.emit_constant(end_str, 'string')
|
|
Gen.builder.call(printf_func, [end_const], name="print_end")
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
|
|
def _is_char_type(self, arg_node):
|
|
if isinstance(arg_node, ast.Call):
|
|
if isinstance(arg_node.func, ast.Name):
|
|
return arg_node.func.id in ('CChar', 'CUInt8T', 'CInt8T')
|
|
if isinstance(arg_node.func, ast.Attribute):
|
|
return arg_node.func.attr in ('CChar', 'CUInt8T', 'CInt8T')
|
|
return False
|
|
|
|
def _is_val_unsigned(self, arg_node, val):
|
|
Gen = self.Trans.LlvmGen
|
|
if isinstance(arg_node, ast.Name):
|
|
var_name = arg_node.id
|
|
signedness = Gen.var_signedness.get(var_name)
|
|
if signedness:
|
|
if isinstance(signedness, bool):
|
|
return signedness
|
|
return 'unsigned' in signedness
|
|
if isinstance(val.type, ir.IntType):
|
|
return False
|
|
return False
|
|
|
|
def _try_declare_c_lib_func(self, func_name, Gen):
|
|
if func_name not in self._C_LIB_FUNCS:
|
|
return None
|
|
ret_type, param_types = self._C_LIB_FUNCS[func_name]()
|
|
func_type = ir.FunctionType(ret_type, param_types)
|
|
func = ir.Function(Gen.module, func_type, name=func_name)
|
|
Gen.functions[func_name] = func
|
|
return func
|
|
|
|
def _HandleLenLlvm(self, arg_node):
|
|
Gen = self.Trans.LlvmGen
|
|
if isinstance(arg_node, ast.Attribute) and isinstance(arg_node.value, ast.Name) and arg_node.value.id == 'self':
|
|
attr_name = arg_node.attr
|
|
len_member = f'{attr_name}__len'
|
|
current_class = self.Trans._CurrentCpythonObjectClass
|
|
if current_class and current_class in Gen.class_members:
|
|
for m_name, m_type in Gen.class_members[current_class]:
|
|
if m_name == len_member:
|
|
self_val = Gen._get_var_ptr('self')
|
|
if self_val:
|
|
self_ptr = Gen._load(self_val, name="self_for_len")
|
|
offset = Gen._get_member_offset(len_member, current_class)
|
|
len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr")
|
|
return Gen._load(len_ptr, name=f"self_{len_member}")
|
|
val = self.HandleExprLlvm(arg_node)
|
|
if not val:
|
|
return None
|
|
if isinstance(val.type, ir.PointerType):
|
|
pointee = val.type.pointee
|
|
if isinstance(pointee, ir.PointerType):
|
|
val = Gen._load(val, name="len_deref")
|
|
pointee = val.type.pointee
|
|
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
|
for CN, ST in Gen.structs.items():
|
|
if pointee == ST:
|
|
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen)
|
|
if result is not None:
|
|
return result
|
|
break
|
|
if isinstance(pointee, ir.ArrayType):
|
|
return ir.Constant(ir.IntType(64), pointee.count)
|
|
if isinstance(pointee, (ir.FloatType, ir.DoubleType, ir.IntType)) and pointee.width != 8:
|
|
return ir.Constant(ir.IntType(64), 0)
|
|
if val.type != ir.PointerType(ir.IntType(8)):
|
|
val = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name="str_ptr_cast")
|
|
correct_strlen_type = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))])
|
|
strlen_func = None
|
|
if 'strlen' in Gen.functions:
|
|
existing = Gen.functions['strlen']
|
|
if existing.ftype == correct_strlen_type:
|
|
strlen_func = existing
|
|
if not strlen_func:
|
|
try:
|
|
strlen_func = ir.Function(Gen.module, correct_strlen_type, name='strlen')
|
|
Gen.functions['strlen'] = strlen_func
|
|
except Exception as _e:
|
|
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
|
|
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
|
if strlen_func:
|
|
result = Gen.builder.call(strlen_func, [val], name="strlen_call")
|
|
return result
|
|
elif isinstance(val.type, ir.ArrayType):
|
|
return ir.Constant(ir.IntType(64), val.type.count)
|
|
return ir.Constant(ir.IntType(64), 0)
|
|
|
|
def _HandleSizeofLlvm(self, Node):
|
|
Gen = self.Trans.LlvmGen
|
|
if isinstance(Node, ast.Name):
|
|
type_name = Node.id
|
|
elif isinstance(Node, ast.Attribute):
|
|
type_name = Node.attr
|
|
else:
|
|
return ir.Constant(ir.IntType(64), 0)
|
|
|
|
if type_name not in Gen.structs:
|
|
from lib.includes.t import CTypeRegistry
|
|
ctype_cls = CTypeRegistry.GetClassByName(type_name)
|
|
if ctype_cls is not None:
|
|
try:
|
|
ctype_inst = ctype_cls()
|
|
size_bits = getattr(ctype_inst, 'Size', 0) or 0
|
|
size_bytes = size_bits // 8
|
|
return ir.Constant(ir.IntType(64), size_bytes)
|
|
except Exception as _e:
|
|
from lib.core.VLogger import get_logger as _vlog
|
|
from lib.constants.config import mode as _config_mode
|
|
if _config_mode == "strict":
|
|
raise
|
|
_vlog().warning(f"解析类型失败: {_e}", "Exception")
|
|
resolved = CTypeRegistry.ResolveName(type_name)
|
|
if resolved:
|
|
ctype_cls, ptr_level = resolved
|
|
try:
|
|
ctype_inst = ctype_cls()
|
|
size_bits = getattr(ctype_inst, 'Size', 0) or 0
|
|
size_bytes = size_bits // 8
|
|
if ptr_level > 0:
|
|
size_bytes = 8
|
|
return ir.Constant(ir.IntType(64), size_bytes)
|
|
except Exception as _e:
|
|
from lib.core.VLogger import get_logger as _vlog
|
|
from lib.constants.config import mode as _config_mode
|
|
if _config_mode == "strict":
|
|
raise
|
|
_vlog().warning(f"解析类型失败: {_e}", "Exception")
|
|
return ir.Constant(ir.IntType(64), 0)
|
|
|
|
struct_type = Gen.structs[type_name]
|
|
if isinstance(struct_type, ir.PointerType):
|
|
struct_type = struct_type.pointee
|
|
if isinstance(struct_type, ir.IdentifiedStructType) and (struct_type.elements is None or len(struct_type.elements) == 0):
|
|
self.Trans.ImportHandler._TryLoadStructFromStub(type_name, Gen)
|
|
struct_type = Gen.structs.get(type_name, struct_type)
|
|
size = Gen._get_struct_size(struct_type)
|
|
if size > 0:
|
|
return ir.Constant(ir.IntType(64), size)
|
|
return ir.Constant(ir.IntType(64), 0)
|
|
|
|
def _HandleAbsLlvm(self, arg_node):
|
|
Gen = self.Trans.LlvmGen
|
|
val = self.HandleExprLlvm(arg_node)
|
|
if not val:
|
|
return None
|
|
if isinstance(val.type, ir.PointerType):
|
|
pointee = val.type.pointee
|
|
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
|
for CN, ST in Gen.structs.items():
|
|
if pointee == ST:
|
|
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen)
|
|
if result is not None:
|
|
return result
|
|
break
|
|
if isinstance(val.type, ir.IntType):
|
|
neg_val = Gen.builder.neg(val, name="abs_neg")
|
|
is_neg = Gen.builder.icmp_signed('<', val, ir.Constant(val.type, 0), name="is_neg")
|
|
return Gen.builder.select(is_neg, neg_val, val, name="abs_result")
|
|
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
|
zero = ir.Constant(val.type, 0.0)
|
|
neg_val = Gen.builder.fneg(val, name="fabs_neg")
|
|
is_neg = Gen.builder.fcmp_ordered('<', val, zero, name="f_is_neg")
|
|
return Gen.builder.select(is_neg, neg_val, val, name="fabs_result")
|
|
return None
|
|
|
|
def _HandleDirLlvm(self, Node):
|
|
Gen = self.Trans.LlvmGen
|
|
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
|
|
|
def _HandleTypeLlvm(self, Node):
|
|
Gen = self.Trans.LlvmGen
|
|
if not Node.args:
|
|
type_str = "<class 'unknown' size=0 signed=false, ptr=false>"
|
|
else:
|
|
arg = Node.args[0]
|
|
enum_type_name = None
|
|
|
|
def _get_attr_path(node):
|
|
if isinstance(node, ast.Name):
|
|
return node.id
|
|
elif isinstance(node, ast.Attribute):
|
|
return f"{_get_attr_path(node.value)}.{node.attr}"
|
|
return None
|
|
|
|
if isinstance(arg, ast.Name):
|
|
arg_name = arg.id
|
|
Gen = self.Trans.LlvmGen
|
|
if arg_name in Gen.var_type_info:
|
|
type_info = Gen.var_type_info[arg_name]
|
|
if isinstance(type_info, dict) and type_info.get('type') == 'enum':
|
|
enum_type_name = type_info.get('name')
|
|
if not enum_type_name and self.Trans.SymbolTable.has(arg_name):
|
|
TypeInfo = self.Trans.SymbolTable[arg_name]
|
|
if TypeInfo.IsEnum:
|
|
enum_type_name = arg_name
|
|
elif isinstance(arg, ast.Attribute):
|
|
LastPart = None
|
|
enum_class_name = None
|
|
if isinstance(arg.value, ast.Name):
|
|
LastPart = arg.attr
|
|
if self.Trans.SymbolTable.has(LastPart):
|
|
AttrInfo = self.Trans.SymbolTable[LastPart]
|
|
if AttrInfo.IsEnumMember and AttrInfo.EnumName:
|
|
enum_type_name = AttrInfo.EnumName
|
|
elif isinstance(arg.value, ast.Attribute):
|
|
attr_path = _get_attr_path(arg)
|
|
if attr_path:
|
|
parts = attr_path.split('.')
|
|
if len(parts) >= 2:
|
|
enum_class_name = parts[-2]
|
|
LastPart = parts[-1]
|
|
qualified_name_dot = f"{enum_class_name}.{LastPart}"
|
|
qualified_name_under = f"{enum_class_name}_{LastPart}"
|
|
enum_member_found = None
|
|
for qname in (qualified_name_dot, qualified_name_under):
|
|
if self.Trans.SymbolTable.has(qname):
|
|
info = self.Trans.SymbolTable[qname]
|
|
if info.IsEnumMember and info.EnumName == enum_class_name:
|
|
enum_member_found = info
|
|
break
|
|
if not enum_member_found:
|
|
for key in self.Trans.SymbolTable:
|
|
if key == LastPart:
|
|
info = self.Trans.SymbolTable[key]
|
|
if info.IsEnumMember and info.EnumName == enum_class_name:
|
|
enum_member_found = info
|
|
break
|
|
if enum_member_found:
|
|
enum_type_name = enum_class_name
|
|
if enum_type_name:
|
|
type_str = f"<enum '{enum_type_name}' size=4 signed=true, ptr=false>"
|
|
else:
|
|
llvm_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(arg)
|
|
if isinstance(llvm_type, ir.PointerType):
|
|
pointee = llvm_type.pointee
|
|
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
|
llvm_type = pointee
|
|
type_info = self.Trans.ExprUtils._llvm_type_to_detailed_string(llvm_type)
|
|
type_str = f"<class '{type_info['name']}' size={type_info['size']} signed={str(type_info['signed']).lower()}, ptr={str(type_info['ptr']).lower()}>"
|
|
return Gen.emit_constant(type_str, 'string')
|
|
|
|
def _HandleInputLlvm(self, Node):
|
|
Gen = self.Trans.LlvmGen
|
|
if Node.args and isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, str):
|
|
prompt = Node.args[0].value
|
|
prompt_ptr = Gen.emit_constant(prompt, 'string')
|
|
printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
|
Gen.builder.call(printf_func, [prompt_ptr])
|
|
scanf_func = Gen.get_or_declare_c_func('scanf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
|
input_buffer = Gen._alloca(ir.ArrayType(ir.IntType(8), 256), name="input_buffer")
|
|
result = Gen.builder.call(scanf_func, [Gen.emit_constant("%255s", 'string'), input_buffer])
|
|
return Gen.builder.gep(input_buffer, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="input_result")
|
|
|
|
def _HandleAtoiLlvm(self, str_ptr):
|
|
Gen = self.Trans.LlvmGen
|
|
atoi_func = Gen.get_or_declare_c_func('atoi', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))]))
|
|
return Gen.builder.call(atoi_func, [str_ptr], name="atoi_result")
|
|
|
|
def _HandleOrdLlvm(self, expr_node):
|
|
Gen = self.Trans.LlvmGen
|
|
val = self.HandleExprLlvm(expr_node)
|
|
if val and isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8:
|
|
return Gen._load(val, name="ord_result")
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
|
|
def _HandleChrLlvm(self, expr_node):
|
|
Gen = self.Trans.LlvmGen
|
|
val = self.HandleExprLlvm(expr_node)
|
|
if val:
|
|
char_ptr = Gen._alloca(ir.IntType(8), name="chr_char")
|
|
Gen.builder.store(Gen.builder.trunc(val, ir.IntType(8), name="trunc_chr"), char_ptr)
|
|
return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result")
|
|
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
|
|
|
def _EmitStringFromValue(self, val):
|
|
Gen = self.Trans.LlvmGen
|
|
if isinstance(val.type, ir.IntType):
|
|
if val.type.width == 8:
|
|
buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 2))
|
|
null_ptr = Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 1)], name="null_byte")
|
|
Gen.builder.store(ir.Constant(ir.IntType(8), 0), null_ptr)
|
|
Gen.builder.store(val, buf)
|
|
return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
|
|
buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32))
|
|
snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [
|
|
ir.PointerType(ir.IntType(8)),
|
|
ir.IntType(64),
|
|
ir.PointerType(ir.IntType(8))
|
|
], var_arg=True))
|
|
fmt_ptr = Gen.emit_constant("%d", 'string')
|
|
Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(64), 32), fmt_ptr, val])
|
|
return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
|
|
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
|
|
|
def _HandleMallocLlvm(self, args):
|
|
Gen = self.Trans.LlvmGen
|
|
malloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
|
malloc_func = Gen._get_or_declare_func('malloc', malloc_type)
|
|
param_type = malloc_func.type.pointee.args[0]
|
|
size_val = None
|
|
if args:
|
|
size_val = self.HandleExprLlvm(args[0])
|
|
if size_val and isinstance(size_val.type, ir.IntType):
|
|
if isinstance(param_type, ir.IntType) and size_val.type.width != param_type.width:
|
|
if size_val.type.width < param_type.width:
|
|
size_val = Gen.builder.zext(size_val, param_type, name="zext_malloc_size")
|
|
else:
|
|
size_val = Gen.builder.trunc(size_val, param_type, name="trunc_malloc_size")
|
|
if not size_val:
|
|
size_val = ir.Constant(param_type, 1)
|
|
result = Gen.builder.call(malloc_func, [size_val], name="malloc_result")
|
|
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="malloc_cast")
|
|
|
|
def _HandleReallocLlvm(self, args):
|
|
Gen = self.Trans.LlvmGen
|
|
realloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)])
|
|
realloc_func = Gen._get_or_declare_func('realloc', realloc_type)
|
|
size_param_type = realloc_func.type.pointee.args[1]
|
|
ptr_val = None
|
|
size_val = None
|
|
if len(args) >= 2:
|
|
ptr_val = self.HandleExprLlvm(args[0])
|
|
size_val = self.HandleExprLlvm(args[1])
|
|
elif len(args) == 1:
|
|
size_val = self.HandleExprLlvm(args[0])
|
|
if not ptr_val:
|
|
ptr_val = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
|
if isinstance(ptr_val.type, ir.PointerType) and not (isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8):
|
|
ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="realloc_cast_ptr")
|
|
if size_val and isinstance(size_val.type, ir.IntType):
|
|
if isinstance(size_param_type, ir.IntType) and size_val.type.width != size_param_type.width:
|
|
if size_val.type.width < size_param_type.width:
|
|
size_val = Gen.builder.zext(size_val, size_param_type, name="zext_realloc_size")
|
|
else:
|
|
size_val = Gen.builder.trunc(size_val, size_param_type, name="trunc_realloc_size")
|
|
if not size_val:
|
|
size_val = ir.Constant(size_param_type, 0)
|
|
result = Gen.builder.call(realloc_func, [ptr_val, size_val], name="realloc_result")
|
|
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="realloc_cast")
|
|
|
|
def _HandleFreeLlvm(self, args):
|
|
Gen = self.Trans.LlvmGen
|
|
free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])
|
|
free_func = Gen._get_or_declare_func('free', free_type)
|
|
if args:
|
|
var_name = None
|
|
if isinstance(args[0], ast.Name):
|
|
var_name = args[0].id
|
|
ptr_val = self.HandleExprLlvm(args[0])
|
|
if ptr_val is not None:
|
|
if var_name and hasattr(Gen, '_var_to_heap_ptr') and var_name in Gen._var_to_heap_ptr:
|
|
registered_val = Gen._var_to_heap_ptr[var_name]
|
|
Gen._unregister_local_heap_ptr(registered_val)
|
|
del Gen._var_to_heap_ptr[var_name]
|
|
if isinstance(ptr_val.type, ir.PointerType):
|
|
if isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8:
|
|
pass
|
|
else:
|
|
ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="free_cast_ptr")
|
|
elif isinstance(ptr_val.type, ir.IntType):
|
|
ptr_val = Gen.builder.inttoptr(ptr_val, ir.PointerType(ir.IntType(8)), name="free_inttoptr")
|
|
Gen.builder.call(free_func, [ptr_val], name="free_call")
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
|
|
def _HandleMemcpyLlvm(self, args):
|
|
Gen = self.Trans.LlvmGen
|
|
if 'llvm.memcpy' not in Gen.functions:
|
|
memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)])
|
|
Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy')
|
|
if len(args) >= 3:
|
|
dst = self.HandleExprLlvm(args[0])
|
|
src = self.HandleExprLlvm(args[1])
|
|
size = self.HandleExprLlvm(args[2])
|
|
if dst and src and size:
|
|
i8ptr = ir.PointerType(ir.IntType(8))
|
|
if isinstance(dst.type, ir.PointerType) and dst.type != i8ptr:
|
|
dst = Gen.builder.bitcast(dst, i8ptr, name="memcpy_dst_cast")
|
|
elif isinstance(dst.type, ir.IntType):
|
|
if dst.type.width < 64:
|
|
dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_dst_ptr")
|
|
dst = Gen.builder.inttoptr(dst, i8ptr, name="dst_int2ptr")
|
|
if isinstance(src.type, ir.PointerType) and src.type != i8ptr:
|
|
src = Gen.builder.bitcast(src, i8ptr, name="memcpy_src_cast")
|
|
elif isinstance(src.type, ir.IntType):
|
|
if src.type.width < 64:
|
|
src = Gen.builder.zext(src, ir.IntType(64), name="zext_src_ptr")
|
|
src = Gen.builder.inttoptr(src, i8ptr, name="src_int2ptr")
|
|
if isinstance(size.type, ir.IntType) and size.type.width < 64:
|
|
size = Gen.builder.zext(size, ir.IntType(64), name="zext_memcpy_size")
|
|
isvolatile = ir.Constant(ir.IntType(1), 0)
|
|
Gen.builder.call(Gen.functions['llvm.memcpy'], [dst, src, size, isvolatile], name="memcpy_call")
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
|
|
def _HandleMemsetLlvm(self, args):
|
|
Gen = self.Trans.LlvmGen
|
|
memset_func = Gen.get_or_declare_c_func('memset', ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]))
|
|
if len(args) >= 3:
|
|
dst = self.HandleExprLlvm(args[0])
|
|
val = self.HandleExprLlvm(args[1])
|
|
size = self.HandleExprLlvm(args[2])
|
|
if dst and val is not None and size:
|
|
if isinstance(dst.type, ir.PointerType) and not (isinstance(dst.type.pointee, ir.IntType) and dst.type.pointee.width == 8):
|
|
dst = Gen.builder.bitcast(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_cast")
|
|
elif isinstance(dst.type, ir.IntType):
|
|
if dst.type.width < 64:
|
|
dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_memset_dst")
|
|
elif dst.type.width > 64:
|
|
dst = Gen.builder.trunc(dst, ir.IntType(64), name="trunc_memset_dst")
|
|
dst = Gen.builder.inttoptr(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_int2ptr")
|
|
if isinstance(val.type, ir.IntType) and val.type.width != 32:
|
|
if val.type.width < 32:
|
|
val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val")
|
|
else:
|
|
val = Gen.builder.trunc(val, ir.IntType(32), name="trunc_memset_val")
|
|
if isinstance(size.type, ir.IntType) and size.type.width < 64:
|
|
size = Gen.builder.zext(size, ir.IntType(64), name="zext_memset_size")
|
|
elif isinstance(size.type, ir.IntType) and size.type.width > 64:
|
|
size = Gen.builder.trunc(size, ir.IntType(64), name="trunc_memset_size")
|
|
Gen.builder.call(memset_func, [dst, val, size], name="memset_call")
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
|
|
def _HandleVaStartLlvm(self, args):
|
|
Gen = self.Trans.LlvmGen
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
|
|
def _HandleVaEndLlvm(self, args):
|
|
Gen = self.Trans.LlvmGen
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
|
|
def _HandleArgLlvm(self, args, CallNode=None):
|
|
Gen = self.Trans.LlvmGen
|
|
va_list_ptr = None
|
|
variadic_info = getattr(Gen, '_va_arg_info', None)
|
|
if not variadic_info:
|
|
variadic_info = getattr(Gen, '_variadic_info', None)
|
|
if variadic_info:
|
|
va_list_ptr = variadic_info.get('va_list_ptr')
|
|
if not va_list_ptr:
|
|
vararg_name = variadic_info.get('vararg_name', 'args') if variadic_info else 'args'
|
|
if vararg_name in Gen.variables:
|
|
va_list_ptr = Gen.variables[vararg_name]
|
|
if not va_list_ptr:
|
|
return ir.Constant(ir.IntType(32), 0)
|
|
target_type = ir.IntType(32)
|
|
if args:
|
|
type_arg = args[0]
|
|
if isinstance(type_arg, ast.Name):
|
|
type_name = type_arg.id
|
|
from lib.includes.t import CTypeRegistry
|
|
if type_name in ('str', 'bytes'):
|
|
target_type = ir.PointerType(ir.IntType(8))
|
|
elif type_name == 'CPtr':
|
|
target_type = ir.PointerType(ir.IntType(8))
|
|
elif type_name in Gen.structs:
|
|
target_type = ir.PointerType(Gen.structs[type_name])
|
|
else:
|
|
ctype_cls = CTypeRegistry.GetClassByName(type_name)
|
|
if ctype_cls is not None:
|
|
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
|
resolved = Gen._type_str_to_llvm(llvm_str)
|
|
if resolved:
|
|
target_type = resolved
|
|
else:
|
|
resolved = CTypeRegistry.ResolveName(type_name)
|
|
if resolved is not None:
|
|
ctype_cls, ptr_level = resolved
|
|
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
|
if llvm_str:
|
|
base = Gen._type_str_to_llvm(llvm_str)
|
|
if base is not None:
|
|
for _ in range(ptr_level):
|
|
if isinstance(base, ir.VoidType):
|
|
base = ir.IntType(8).as_pointer()
|
|
else:
|
|
base = ir.PointerType(base)
|
|
target_type = base
|
|
elif isinstance(type_arg, ast.Attribute):
|
|
if isinstance(type_arg.value, ast.Name) and type_arg.value.id == 't':
|
|
attr_name = type_arg.attr
|
|
from lib.includes.t import CTypeRegistry
|
|
ctype_cls = CTypeRegistry.GetClassByName(attr_name)
|
|
if ctype_cls is not None:
|
|
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
|
resolved = Gen._type_str_to_llvm(llvm_str)
|
|
if resolved:
|
|
target_type = resolved
|
|
else:
|
|
assign_node = getattr(self.Trans, '_current_assign_node', None)
|
|
if assign_node:
|
|
ann = getattr(assign_node, 'annotation', None)
|
|
if ann:
|
|
ann_name = None
|
|
if isinstance(ann, ast.Name):
|
|
ann_name = ann.id
|
|
elif isinstance(ann, ast.Attribute):
|
|
ann_name = ann.attr
|
|
elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
|
|
left = ann.left
|
|
if isinstance(left, ast.Name):
|
|
ann_name = left.id
|
|
elif isinstance(left, ast.Attribute):
|
|
ann_name = left.attr
|
|
if ann_name:
|
|
from lib.includes.t import CTypeRegistry
|
|
ctype_cls = CTypeRegistry.GetClassByName(ann_name)
|
|
if ctype_cls is not None:
|
|
llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
|
resolved = Gen._type_str_to_llvm(llvm_str)
|
|
if resolved:
|
|
target_type = resolved
|
|
elif ann_name in Gen.structs:
|
|
target_type = ir.PointerType(Gen.structs[ann_name])
|
|
if not getattr(Gen, '_va_arg_counter', None):
|
|
Gen._va_arg_counter = 0
|
|
Gen._va_arg_counter += 1
|
|
result = Gen.emit_va_arg(va_list_ptr, target_type)
|
|
if result is not None and getattr(result, 'name', None):
|
|
result.name = f"va_arg_result_{Gen._va_arg_counter}"
|
|
return result
|
|
|
|
def _HandleVaArgLlvm(self, args):
|
|
Gen = self.Trans.LlvmGen
|
|
return ir.Constant(ir.IntType(32), 0)
|