407 lines
22 KiB
Plaintext
407 lines
22 KiB
Plaintext
from stdint import *
|
|
import ast
|
|
import mlirlite
|
|
import memhub
|
|
import string
|
|
import lib.core.Gen.Translator as HT
|
|
|
|
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
|
|
|
# f-string translation constants (local copy of ExprGenMixin's to avoid a cross-module
|
|
# CDefine lookup bug: ExprGenFstr compiles before ExprGenMixin, so the table is unregistered).
|
|
define FSTR_BUF_SIZE = 1024
|
|
define FSTR_SPEC_MAX = 64
|
|
define FSTR_FMT_MAX = 64
|
|
|
|
# ExprGenFstr - ExprGenMixin split (stage D): f-string/formatted-value translation
|
|
novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
|
"""f-string and formatted-value translation."""
|
|
|
|
# translate_joined_str - f-string translation (aligned with TPC _HandleJoinedStrLlvm):
|
|
# join literals and format specs, snprintf into a per-site i8* stack buffer (no escape).
|
|
def translate_joined_str(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, trans: HT.Translator* = None) -> mlirlite.Value*:
|
|
"""Lower an f-string to snprintf into a per-site i8* stack buffer."""
|
|
if node is None or builder is None or trans is None: return None
|
|
js: ast.JoinedStr* = ast.JoinedStr*(node)
|
|
if js is None or js.values is None: return None
|
|
|
|
parts: list[ast.AST*]* = js.values
|
|
pn: sizet = len(parts)
|
|
|
|
# Size the format buffer from the actual parts: each literal may double ('%' -> '%%') and
|
|
# each conversion contributes a short spec. A fixed 1024 silently dropped trailing
|
|
# literals/converters while their arguments were still appended -> wrong runtime output.
|
|
fmt_cap: sizet = 16
|
|
for pi0 in range(int(pn)):
|
|
part0: ast.AST* = parts.get(pi0)
|
|
if part0 is None: continue
|
|
if part0.kind() == ast.ASTKind.Constant:
|
|
pc0: ast.Constant* = ast.Constant*(part0)
|
|
if pc0.const_kind == ast.CONST_STR and pc0.str_val is not None:
|
|
fmt_cap = fmt_cap + string.strlen(pc0.str_val) * 2
|
|
elif part0.kind() == ast.ASTKind.FormattedValue:
|
|
fmt_cap = fmt_cap + FSTR_SPEC_MAX + 16
|
|
|
|
# Compile-time format string buffer (pool-allocated)
|
|
fmt_buf: str = pool.alloc(fmt_cap)
|
|
if fmt_buf is None: return None
|
|
fmt_buf[0] = '\0'
|
|
|
|
# Runtime argument list (linked by Value.Next, matching the printf call)
|
|
arg_head: mlirlite.Value* = None
|
|
arg_tail: mlirlite.Value* = None
|
|
arg_count: int = 0
|
|
|
|
for pi in range(int(pn)):
|
|
part: ast.AST* = parts.get(pi)
|
|
if part is None: continue
|
|
if part.kind() == ast.ASTKind.Constant:
|
|
pcn: ast.Constant* = ast.Constant*(part)
|
|
if pcn.const_kind == ast.CONST_STR and pcn.str_val is not None:
|
|
self._fstr_append_literal(fmt_buf, fmt_cap, pcn.str_val)
|
|
continue
|
|
if part.kind() != ast.ASTKind.FormattedValue: continue
|
|
fv: ast.FormattedValue* = ast.FormattedValue*(part)
|
|
if fv.value is None: continue
|
|
val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fv.value, None, 0, trans)
|
|
if val is None:
|
|
# fail-fast: a failed formatted-value translation must abort compilation
|
|
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string formatted value translation failed (expression returned None)", "TypeError")
|
|
continue
|
|
# Object defines __str__ and no format is given -> use its returned string (like TPC)
|
|
if fv.format_spec is None:
|
|
str_ov_fs: mlirlite.Value* = self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, val, "__str__", trans)
|
|
if str_ov_fs is not None: val = str_ov_fs
|
|
# Determine the C format specifier (format_spec first, else infer from the value type)
|
|
c_fmt: str = None
|
|
if fv.format_spec is not None: c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value)
|
|
if c_fmt is None: c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
|
|
if c_fmt is None:
|
|
# fail-fast: cannot infer the f-string format (missing value type); abort
|
|
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string format cannot be inferred (value type missing)", "TypeError")
|
|
# Append the format specifier
|
|
self._fstr_append_raw(fmt_buf, fmt_cap, c_fmt)
|
|
# Convert the argument type (i8/i16->i32, bool->i32, f32->f64)
|
|
cast_val: mlirlite.Value* = self._fstr_cast_value(builder, pool, val, c_fmt, fv.value, trans)
|
|
if cast_val is None: cast_val = val
|
|
cast_val.Next = None
|
|
if arg_head is None: arg_head = cast_val
|
|
else: arg_tail.Next = cast_val
|
|
arg_tail = cast_val
|
|
arg_count += 1
|
|
|
|
return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans)
|
|
def translate_formatted_value(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, trans: HT.Translator* = None) -> mlirlite.Value*:
|
|
"""Translate a bare FormattedValue without any literal parts."""
|
|
if node is None or builder is None or trans is None: return None
|
|
fv: ast.FormattedValue* = ast.FormattedValue*(node)
|
|
if fv is None or fv.value is None: return None
|
|
# A bare FormattedValue contributes exactly one conversion spec (bounded by FSTR_SPEC_MAX
|
|
# plus the C prefix/width); size the buffer from that instead of the fixed 1024.
|
|
fmt_cap: sizet = FSTR_SPEC_MAX + 64
|
|
fmt_buf: str = pool.alloc(fmt_cap)
|
|
if fmt_buf is None: return None
|
|
fmt_buf[0] = '\0'
|
|
arg_head: mlirlite.Value* = None
|
|
arg_tail: mlirlite.Value* = None
|
|
arg_count: int = 0
|
|
val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fv.value, None, 0, trans)
|
|
if val is None:
|
|
# fail-fast: a failed bare FormattedValue translation must abort compilation
|
|
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string formatted value translation failed (expression returned None)", "TypeError")
|
|
else:
|
|
# Object defines __str__ and no format is given -> use its returned string (like TPC)
|
|
if fv.format_spec is None:
|
|
str_ov_sf: mlirlite.Value* = self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, val, "__str__", trans)
|
|
if str_ov_sf is not None: val = str_ov_sf
|
|
c_fmt: str = None
|
|
if fv.format_spec is not None: c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value)
|
|
if c_fmt is None: c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
|
|
if c_fmt is None:
|
|
# fail-fast: cannot infer the f-string format (missing value type); abort
|
|
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string format cannot be inferred (value type missing)", "TypeError")
|
|
self._fstr_append_raw(fmt_buf, fmt_cap, c_fmt)
|
|
cast_val: mlirlite.Value* = self._fstr_cast_value(builder, pool, val, c_fmt, fv.value, trans)
|
|
if cast_val is None: cast_val = val
|
|
cast_val.Next = None
|
|
arg_head = cast_val
|
|
arg_tail = cast_val
|
|
arg_count = 1
|
|
return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans)
|
|
def _fstr_finalize(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, fmt_buf: str, arg_head: mlirlite.Value*, arg_tail: mlirlite.Value*, arg_count: int, trans: HT.Translator*) -> mlirlite.Value*:
|
|
"""Emit the final snprintf over the global format and per-site buffer."""
|
|
i32_ty: mlirlite.LLVMType* = mlirlite.Int32(pool)
|
|
i8_ty: mlirlite.LLVMType* = mlirlite.Int8(pool)
|
|
if fmt_buf is None or fmt_buf[0] == '\0':
|
|
# Empty f-string (f"") -> empty string constant
|
|
return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, "", trans)
|
|
# Format string -> global string constant (i8*)
|
|
fmt_ptr: mlirlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fmt_buf, trans)
|
|
if fmt_ptr is None: return None
|
|
# Result buffer: a per-site entry alloca (thread-safe, no runtime dependency), so the
|
|
# f-string result is a function-local temporary that must not escape; copy to escape.
|
|
buf_ty: mlirlite.LLVMType* = mlirlite.Array(pool, i8_ty, FSTR_BUF_SIZE)
|
|
buf_alloca: mlirlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, buf_ty)
|
|
if buf_alloca is None: return None
|
|
zero_i32: mlirlite.Value* = mlirlite.const_int32(pool, 0)
|
|
buf_ptr: mlirlite.Value* = mlirlite.build_gep_array(builder, buf_ty, i8_ty, buf_alloca, zero_i32)
|
|
if buf_ptr is None: return None
|
|
# f-string lowers to snprintf, declared in includes/stdio.vp. If the source imports no
|
|
# module declaring it, add the declare here (implicit-provide); i8*, i64, i8* + varargs.
|
|
if self.Gen.CallGenBase.find_func_in_module(mod, "snprintf") is None:
|
|
snprintf_decl: mlirlite.Function* = mlirlite.create_declare(pool, mod, "snprintf", i32_ty)
|
|
if snprintf_decl is not None:
|
|
snprintf_decl.IsVarArg = 1
|
|
# buf/fmt are pointer params (i8*), not the element type i8: a bare i8 declare
|
|
# would cause an MLIR 'llvm.call' operand type mismatch ('!llvm.ptr' != 'i8').
|
|
i8_ptr_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, i8_ty)
|
|
mlirlite.add_param(pool, snprintf_decl, i8_ptr_ty, "buf")
|
|
mlirlite.add_param(pool, snprintf_decl, mlirlite.Int64(pool), "size")
|
|
mlirlite.add_param(pool, snprintf_decl, i8_ptr_ty, "fmt")
|
|
# snprintf(buf, FSTR_BUF_SIZE, fmt, args...)
|
|
size_val: mlirlite.Value* = mlirlite.const_int64(pool, FSTR_BUF_SIZE)
|
|
buf_ptr.Next = size_val
|
|
size_val.Next = fmt_ptr
|
|
fmt_ptr.Next = arg_head
|
|
if arg_tail is not None: arg_tail.Next = None
|
|
mlirlite.build_call(builder, "snprintf", buf_ptr, 3 + arg_count, i32_ty, 1)
|
|
return buf_ptr
|
|
def _fstr_append_literal(self, fmt_buf: str, cap: sizet, lit: str) -> None:
|
|
"""Append a literal to the format string, escaping percent signs; fail-fast on overflow."""
|
|
if fmt_buf is None or lit is None: return
|
|
cur_len: sizet = string.strlen(fmt_buf)
|
|
src_len: sizet = string.strlen(lit)
|
|
# Worst case: every character expands to "%%".
|
|
if cur_len + src_len * 2 + 1 > cap:
|
|
self.Gen.TypeGenErr.fatal_error(None, f"f-string format text exceeds its {cap}-byte buffer ({cur_len} used + up to {src_len * 2} escaped + 1 NUL); shorten the literal", "OverflowError")
|
|
si: sizet = 0
|
|
while si < src_len:
|
|
ch: char = lit[si]
|
|
if ch == '%':
|
|
fmt_buf[cur_len] = '%'
|
|
fmt_buf[cur_len + 1] = '%'
|
|
cur_len += 2
|
|
else:
|
|
fmt_buf[cur_len] = ch
|
|
cur_len += 1
|
|
si += 1
|
|
fmt_buf[cur_len] = '\0'
|
|
def _fstr_append_raw(self, fmt_buf: str, cap: sizet, s: str) -> None:
|
|
"""Append a raw string without percent escaping; fail-fast on overflow."""
|
|
if fmt_buf is None or s is None: return
|
|
cur_len: sizet = string.strlen(fmt_buf)
|
|
src_len: sizet = string.strlen(s)
|
|
if cur_len + src_len + 1 > cap:
|
|
self.Gen.TypeGenErr.fatal_error(None, f"f-string format text exceeds its {cap}-byte buffer ({cur_len} used + {src_len} to append + 1 NUL); shorten the format spec", "OverflowError")
|
|
i: sizet = 0
|
|
while i < src_len:
|
|
fmt_buf[cur_len + i] = s[i]
|
|
i += 1
|
|
fmt_buf[cur_len + src_len] = '\0'
|
|
def _fstr_parse_format_spec(self, pool: memhub.MemBuddy*, spec_node: ast.AST*, val: mlirlite.Value*, arg_node: ast.AST*) -> str:
|
|
"""Convert a Python format_spec into a C printf format string."""
|
|
if spec_node is None or pool is None or val is None: return None
|
|
# 1. Extract the spec string (JoinedStr with constants only)
|
|
spec: str = pool.alloc(FSTR_SPEC_MAX)
|
|
if spec is None: return None
|
|
spec[0] = '\0'
|
|
sk: int = spec_node.kind()
|
|
if sk == ast.ASTKind.JoinedStr:
|
|
jss: ast.JoinedStr* = ast.JoinedStr*(spec_node)
|
|
if jss.values is None: return None
|
|
vn: sizet = len(jss.values)
|
|
for vi in range(int(vn)):
|
|
vpart: ast.AST* = jss.values.get(vi)
|
|
if vpart is None: continue
|
|
if vpart.kind() != ast.ASTKind.Constant: return None
|
|
vcn: ast.Constant* = ast.Constant*(vpart)
|
|
if vcn.const_kind != ast.CONST_STR or vcn.str_val is None: return None
|
|
# fail-fast: a truncated spec can still look valid (e.g. ">10.5f" cut to ">10."),
|
|
# which silently changes the output format.
|
|
if string.strlen(spec) + string.strlen(vcn.str_val) >= FSTR_SPEC_MAX - 1:
|
|
self.Gen.TypeGenErr.fatal_error(arg_node, f"f-string format spec exceeds {FSTR_SPEC_MAX - 1} characters; shorten it", "OverflowError")
|
|
string.strcat(spec, vcn.str_val)
|
|
elif sk == ast.ASTKind.Constant:
|
|
cn: ast.Constant* = ast.Constant*(spec_node)
|
|
if cn.const_kind != ast.CONST_STR or cn.str_val is None: return None
|
|
if string.strlen(cn.str_val) >= FSTR_SPEC_MAX - 1:
|
|
self.Gen.TypeGenErr.fatal_error(arg_node, f"f-string format spec exceeds {FSTR_SPEC_MAX - 1} characters; shorten it", "OverflowError")
|
|
string.strncpy(spec, cn.str_val, FSTR_SPEC_MAX - 1)
|
|
else: return None
|
|
slen: sizet = string.strlen(spec)
|
|
if slen == 0: return None
|
|
|
|
# 2. Parse segment by segment: [fill]align / sign / # / 0 / width / , / .precision / type
|
|
pos: sizet = 0
|
|
align_char: char = 0
|
|
if pos < slen:
|
|
ch0: char = spec[pos]
|
|
if ch0 == '<' or ch0 == '>' or ch0 == '^' or ch0 == '=':
|
|
align_char = ch0
|
|
pos += 1
|
|
elif pos + 1 < slen:
|
|
ch1: char = spec[pos + 1]
|
|
if ch1 == '<' or ch1 == '>' or ch1 == '^' or ch1 == '=':
|
|
align_char = ch1
|
|
pos += 2
|
|
c_flags: str = pool.alloc(FSTR_FMT_MAX)
|
|
c_width: str = pool.alloc(32)
|
|
c_prec: str = pool.alloc(32)
|
|
if c_flags is None or c_width is None or c_prec is None: return None
|
|
c_flags[0] = '\0'
|
|
c_width[0] = '\0'
|
|
c_prec[0] = '\0'
|
|
# sign
|
|
if pos < slen and (spec[pos] == '+' or spec[pos] == '-' or spec[pos] == ' '):
|
|
if spec[pos] == '+': string.strcat(c_flags, "+")
|
|
elif spec[pos] == ' ': string.strcat(c_flags, " ")
|
|
pos += 1
|
|
# alt '#'
|
|
if pos < slen and spec[pos] == '#':
|
|
string.strcat(c_flags, "#")
|
|
pos += 1
|
|
# zero '0'
|
|
if pos < slen and spec[pos] == '0':
|
|
string.strcat(c_flags, "0")
|
|
pos += 1
|
|
# Left align '<'/'^' -> '-' (C semantics give '-' priority over '0')
|
|
if align_char == '<' or align_char == '^': string.strcat(c_flags, "-")
|
|
# width digits
|
|
while pos < slen and spec[pos] >= '0' and spec[pos] <= '9':
|
|
wl: sizet = string.strlen(c_width)
|
|
if wl < 30:
|
|
c_width[wl] = spec[pos]
|
|
c_width[wl + 1] = '\0'
|
|
pos += 1
|
|
# comma ',' -> C printf has no thousands separator, ignore
|
|
if pos < slen and spec[pos] == ',': pos += 1
|
|
# .precision
|
|
if pos < slen and spec[pos] == '.':
|
|
string.strcat(c_prec, ".")
|
|
pos += 1
|
|
while pos < slen and spec[pos] >= '0' and spec[pos] <= '9':
|
|
pl: sizet = string.strlen(c_prec)
|
|
if pl < 30:
|
|
c_prec[pl] = spec[pos]
|
|
c_prec[pl + 1] = '\0'
|
|
pos += 1
|
|
if string.strlen(c_prec) == 1:
|
|
return None # a lone '.' is invalid
|
|
# type char
|
|
fmt_type: char = 0
|
|
if pos < slen:
|
|
fmt_type = spec[pos]
|
|
pos += 1
|
|
if pos != slen: return None # extra characters cannot be parsed
|
|
|
|
# 3. Length modifier (by value type bit width)
|
|
len_mod: str = pool.alloc(4)
|
|
if len_mod is None: return None
|
|
len_mod[0] = '\0'
|
|
ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
|
# Do not write a length modifier for 32-bit (N14): `{x:08X}` passes an i32, but `l`
|
|
# would make %08lX (long) mismatch on LP64 and misread the varargs.
|
|
if ibits == 64: string.strcpy(len_mod, "ll")
|
|
elif ibits == 16: string.strcpy(len_mod, "h")
|
|
elif ibits == 8: string.strcpy(len_mod, "hh")
|
|
|
|
# 4. Assemble the C format string
|
|
out: str = pool.alloc(FSTR_FMT_MAX)
|
|
if out is None: return None
|
|
out[0] = '\0'
|
|
string.strcat(out, "%")
|
|
string.strcat(out, c_flags)
|
|
string.strcat(out, c_width)
|
|
string.strcat(out, c_prec)
|
|
if fmt_type == 0:
|
|
# No type: infer from the value type
|
|
fbits2: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty)
|
|
if ibits != 0:
|
|
if ibits == 8: string.strcat(out, "c")
|
|
elif ibits == 1: string.strcat(out, "d")
|
|
else:
|
|
string.strcat(out, len_mod)
|
|
string.strcat(out, "d")
|
|
elif fbits2 != 0: string.strcat(out, "f")
|
|
elif self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0: string.strcat(out, "s")
|
|
else: string.strcat(out, "d")
|
|
elif fmt_type == 'c': string.strcat(out, "c")
|
|
elif fmt_type == 'f' or fmt_type == 'F': string.strcat(out, "f")
|
|
elif fmt_type == 'e' or fmt_type == 'E' or fmt_type == 'g' or fmt_type == 'G':
|
|
tmp_ch: str = pool.alloc(2)
|
|
if tmp_ch is None: return None
|
|
tmp_ch[0] = fmt_type
|
|
tmp_ch[1] = '\0'
|
|
string.strcat(out, tmp_ch)
|
|
elif fmt_type == 's': string.strcat(out, "s")
|
|
elif fmt_type == '%': string.strcat(out, "%")
|
|
elif fmt_type == 'b':
|
|
return None # binary is unsupported
|
|
elif fmt_type == 'd' or fmt_type == 'i':
|
|
string.strcat(out, len_mod)
|
|
string.strcat(out, "d")
|
|
elif fmt_type == 'x' or fmt_type == 'X' or fmt_type == 'o' or fmt_type == 'u':
|
|
string.strcat(out, len_mod)
|
|
tmp_ch2: str = pool.alloc(2)
|
|
if tmp_ch2 is None: return None
|
|
tmp_ch2[0] = fmt_type
|
|
tmp_ch2[1] = '\0'
|
|
string.strcat(out, tmp_ch2)
|
|
else: return None
|
|
return out
|
|
def _fstr_infer_c_fmt(self, pool: memhub.MemBuddy*, val: mlirlite.Value*, arg_node: ast.AST*, trans: HT.Translator*) -> str:
|
|
"""Infer the C printf format from the value type when no format_spec is given."""
|
|
if val is None or pool is None: return None
|
|
out: str = pool.alloc(16)
|
|
if out is None: return None
|
|
out[0] = '\0'
|
|
ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
|
fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty)
|
|
if ibits == 1: return "%d" # bool
|
|
if ibits == 8: return "%c" # character
|
|
if ibits != 0:
|
|
if self.Gen.ExprGenOps._node_type_unsigned(pool, arg_node, trans) != 0:
|
|
if ibits == 64: string.strcpy(out, "%llu")
|
|
else: string.strcpy(out, "%u")
|
|
else:
|
|
if ibits == 64: string.strcpy(out, "%lld")
|
|
else: string.strcpy(out, "%d")
|
|
return out
|
|
if fbits != 0: return "%f"
|
|
if self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0: return "%s"
|
|
# fail-fast: missing value type (not int/float/pointer); cannot infer the C format
|
|
self.Gen.TypeGenErr.fatal_error(arg_node, "f-string format cannot be inferred (value type missing)", "TypeError")
|
|
return None
|
|
def _fstr_cast_value(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, val: mlirlite.Value*, c_fmt: str, arg_node: ast.AST*, trans: HT.Translator*) -> mlirlite.Value*:
|
|
"""Cast the value to the type required by the C format specifier."""
|
|
if val is None or c_fmt is None: return None
|
|
# Find the format type char (last letter, ignoring l/h length modifiers)
|
|
fmt_char: char = 0
|
|
flen: sizet = string.strlen(c_fmt)
|
|
fi: sizet = flen
|
|
while fi > 0:
|
|
fi -= 1
|
|
ch: char = c_fmt[fi]
|
|
if ch == '%': break
|
|
if (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z'):
|
|
if ch != 'l' and ch != 'h':
|
|
fmt_char = ch
|
|
break
|
|
i32_ty: mlirlite.LLVMType* = mlirlite.Int32(pool)
|
|
if fmt_char == 's': return val
|
|
if fmt_char == 'c':
|
|
ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
|
if ibits != 0 and ibits < 32: return mlirlite.build_zext(builder, val, i32_ty)
|
|
return val
|
|
if fmt_char == 'd' or fmt_char == 'i' or fmt_char == 'x' or fmt_char == 'X' or fmt_char == 'o' or fmt_char == 'u':
|
|
ibits = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
|
if ibits == 1: return mlirlite.build_zext(builder, val, i32_ty)
|
|
if ibits == 8 or ibits == 16:
|
|
if self.Gen.ExprGenOps._node_type_unsigned(pool, arg_node, trans) != 0: return mlirlite.build_zext(builder, val, i32_ty)
|
|
return mlirlite.build_sext(builder, val, i32_ty)
|
|
return val
|
|
if fmt_char == 'f' or fmt_char == 'e' or fmt_char == 'E' or fmt_char == 'g' or fmt_char == 'G':
|
|
fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty)
|
|
if fbits == 32: return mlirlite.build_fpext(builder, val, mlirlite.Double(pool))
|
|
return val
|
|
return val |