|
|
|
|
@@ -4,6 +4,16 @@
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
// Debug assert that prints location before aborting.
|
|
|
|
|
#undef assert
|
|
|
|
|
#define assert(cond) \
|
|
|
|
|
do { \
|
|
|
|
|
if (!(cond)) { \
|
|
|
|
|
fprintf(stderr, "ASSERT FAIL: %s:%d: %s\n", __FILE__, __LINE__, \
|
|
|
|
|
#cond); \
|
|
|
|
|
abort(); \
|
|
|
|
|
} \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
// Simple djb2 hash for enum literal names.
|
|
|
|
|
static uint32_t simpleStringHash(const char* s) {
|
|
|
|
|
@@ -347,8 +357,9 @@ static uint32_t semaAppendAirString(Sema* sema, const char* str) {
|
|
|
|
|
// Ported from src/Sema.zig zirDbgVar.
|
|
|
|
|
static void zirDbgVar(
|
|
|
|
|
Sema* sema, SemaBlock* block, uint32_t inst, AirInstTag air_tag) {
|
|
|
|
|
if (block->is_comptime)
|
|
|
|
|
if (block->is_comptime) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t str_idx = sema->code.inst_datas[inst].str_op.str;
|
|
|
|
|
ZirInstRef operand_ref = sema->code.inst_datas[inst].str_op.operand;
|
|
|
|
|
@@ -677,8 +688,23 @@ static AirInstRef semaCoerce(
|
|
|
|
|
TypeIndex src_ty = semaTypeOf(sema, ref);
|
|
|
|
|
if (src_ty == target_ty)
|
|
|
|
|
return ref;
|
|
|
|
|
if (src_ty == TYPE_NONE || target_ty == TYPE_NONE)
|
|
|
|
|
return ref;
|
|
|
|
|
if (src_ty == IP_INDEX_COMPTIME_INT_TYPE)
|
|
|
|
|
return semaCoerceIntRef(sema, ref, target_ty);
|
|
|
|
|
// Comptime float → concrete float: re-intern with target type.
|
|
|
|
|
// Ported from src/Sema.zig coerce comptime_float → float.
|
|
|
|
|
if (src_ty == IP_INDEX_COMPTIME_FLOAT_TYPE && AIR_REF_IS_IP(ref)) {
|
|
|
|
|
InternPoolKey src_key = ipIndexToKey(sema->ip, AIR_REF_TO_IP(ref));
|
|
|
|
|
if (src_key.tag == IP_KEY_FLOAT) {
|
|
|
|
|
InternPoolKey key;
|
|
|
|
|
memset(&key, 0, sizeof(key));
|
|
|
|
|
key.tag = IP_KEY_FLOAT;
|
|
|
|
|
key.data.float_val.ty = target_ty;
|
|
|
|
|
key.data.float_val.val = src_key.data.float_val.val;
|
|
|
|
|
return AIR_REF_FROM_IP(ipIntern(sema->ip, key));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Undefined coercion: re-intern undefined with the target type.
|
|
|
|
|
// Ported from src/Sema.zig coerceInMemory → getCoerced.
|
|
|
|
|
if (src_ty == IP_INDEX_UNDEFINED_TYPE) {
|
|
|
|
|
@@ -1474,6 +1500,26 @@ static AirInstRef zirShl(
|
|
|
|
|
return semaAddInst(block, air_tag, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// tryResolveInst: like resolveInst, but returns AIR_REF_NONE without
|
|
|
|
|
// setting has_compile_errors when the instruction is not in the inst_map.
|
|
|
|
|
// Ported from upstream Zig's GenericPoison handling: callers that can
|
|
|
|
|
// gracefully handle unresolved references (e.g. zirAs in generic arg
|
|
|
|
|
// bodies) use this to avoid cascading failures.
|
|
|
|
|
static AirInstRef tryResolveInst(Sema* sema, ZirInstRef zir_ref) {
|
|
|
|
|
assert(zir_ref != ZIR_REF_NONE);
|
|
|
|
|
if (zir_ref >= ZIR_REF_START_INDEX) {
|
|
|
|
|
uint32_t zir_inst = zir_ref - ZIR_REF_START_INDEX;
|
|
|
|
|
// Return AIR_REF_NONE if the instruction is not in the map range.
|
|
|
|
|
if (sema->inst_map.items_len == 0)
|
|
|
|
|
return AIR_REF_NONE;
|
|
|
|
|
if (zir_inst < sema->inst_map.start
|
|
|
|
|
|| zir_inst >= sema->inst_map.start + sema->inst_map.items_len)
|
|
|
|
|
return AIR_REF_NONE;
|
|
|
|
|
return sema->inst_map.items[zir_inst - sema->inst_map.start];
|
|
|
|
|
}
|
|
|
|
|
return AIR_REF_FROM_IP(zir_ref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// zirAsNode: handle @as ZIR instruction.
|
|
|
|
|
// Ported from src/Sema.zig zirAs / zirAsNode.
|
|
|
|
|
static AirInstRef zirAsNode(Sema* sema, SemaBlock* block, uint32_t inst) {
|
|
|
|
|
@@ -1484,8 +1530,16 @@ static AirInstRef zirAsNode(Sema* sema, SemaBlock* block, uint32_t inst) {
|
|
|
|
|
if (dest_ty_ref < ZIR_REF_START_INDEX) {
|
|
|
|
|
dest_ty = dest_ty_ref;
|
|
|
|
|
} else {
|
|
|
|
|
// Resolve through inst_map (comptime-evaluated type).
|
|
|
|
|
AirInstRef resolved = resolveInst(sema, dest_ty_ref);
|
|
|
|
|
// Ported from src/Sema.zig zirAs: when the destination type
|
|
|
|
|
// references a not-yet-resolved instruction (GenericPoison),
|
|
|
|
|
// skip the coercion and pass through the operand. This
|
|
|
|
|
// happens in arg bodies of generic calls where the result
|
|
|
|
|
// type references the call instruction itself.
|
|
|
|
|
AirInstRef resolved = tryResolveInst(sema, dest_ty_ref);
|
|
|
|
|
if (resolved == AIR_REF_NONE) {
|
|
|
|
|
// GenericPoison: skip coercion.
|
|
|
|
|
return resolveInst(sema, operand_ref);
|
|
|
|
|
}
|
|
|
|
|
if (!AIR_REF_IS_IP(resolved)) {
|
|
|
|
|
return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
|
|
|
|
|
}
|
|
|
|
|
@@ -1587,6 +1641,9 @@ static FuncZirInfo parseFuncZir(Sema* sema, uint32_t inst) {
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Forward declaration (defined later, used by findDeclImportPath et al).
|
|
|
|
|
static uint32_t findDeclInstByNameInZir(const Zir* zir, const char* decl_name);
|
|
|
|
|
|
|
|
|
|
// findDeclImportPath: given a declaration name index, check if the
|
|
|
|
|
// declaration's value body contains a ZIR_INST_IMPORT. If so, return
|
|
|
|
|
// the import path string (from string_bytes). Returns NULL if not found.
|
|
|
|
|
@@ -1598,6 +1655,11 @@ static const char* findDeclImportPath(Sema* sema, uint32_t name_idx) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Fallback: search current ZIR by name (cross-module inline).
|
|
|
|
|
if (decl_inst == UINT32_MAX && name_idx != 0) {
|
|
|
|
|
const char* nm = (const char*)&sema->code.string_bytes[name_idx];
|
|
|
|
|
decl_inst = findDeclInstByNameInZir(&sema->code, nm);
|
|
|
|
|
}
|
|
|
|
|
if (decl_inst == UINT32_MAX)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
@@ -1634,6 +1696,11 @@ static bool findDeclImportFieldVal(Sema* sema, uint32_t name_idx,
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Fallback: search current ZIR by name (cross-module inline).
|
|
|
|
|
if (decl_inst == UINT32_MAX && name_idx != 0) {
|
|
|
|
|
const char* nm = (const char*)&sema->code.string_bytes[name_idx];
|
|
|
|
|
decl_inst = findDeclInstByNameInZir(&sema->code, nm);
|
|
|
|
|
}
|
|
|
|
|
if (decl_inst == UINT32_MAX)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
@@ -1947,18 +2014,26 @@ static bool findDeclImportFieldValInZir(const Zir* zir, const char* decl_name,
|
|
|
|
|
// resolves to <module_root>/lib/<name>.
|
|
|
|
|
static void computeSourceDir(const char* module_root, const char* source_dir,
|
|
|
|
|
const char* import_path, char* out_dir, size_t out_size) {
|
|
|
|
|
if (import_path[0] == '.' && import_path[1] == '/') {
|
|
|
|
|
// Relative import: source_dir + dirname(import_path)
|
|
|
|
|
const char* rel = import_path + 2;
|
|
|
|
|
const char* last_slash = strrchr(rel, '/');
|
|
|
|
|
if (last_slash) {
|
|
|
|
|
const char* last_slash = strrchr(import_path, '/');
|
|
|
|
|
if (import_path[0] == '.'
|
|
|
|
|
&& (import_path[1] == '/'
|
|
|
|
|
|| (import_path[1] == '.' && import_path[2] == '/'))) {
|
|
|
|
|
// Relative import (./foo.zig or ../foo.zig):
|
|
|
|
|
// source_dir + dirname(import_path)
|
|
|
|
|
if (last_slash && last_slash != import_path) {
|
|
|
|
|
snprintf(out_dir, out_size, "%s/%.*s", source_dir,
|
|
|
|
|
(int)(last_slash - rel), rel);
|
|
|
|
|
(int)(last_slash - import_path), import_path);
|
|
|
|
|
} else {
|
|
|
|
|
snprintf(out_dir, out_size, "%s", source_dir);
|
|
|
|
|
}
|
|
|
|
|
} else if (module_root) {
|
|
|
|
|
// Non-relative (e.g. "std") → <module_root>/lib/<name>
|
|
|
|
|
} else if (last_slash) {
|
|
|
|
|
// Path with subdirectory (e.g. "math/isinf.zig"):
|
|
|
|
|
// source_dir + dirname(import_path)
|
|
|
|
|
snprintf(out_dir, out_size, "%s/%.*s", source_dir,
|
|
|
|
|
(int)(last_slash - import_path), import_path);
|
|
|
|
|
} else if (module_root && import_path[0] != '.') {
|
|
|
|
|
// Non-relative bare module name (e.g. "std"):
|
|
|
|
|
// <module_root>/lib/<name>
|
|
|
|
|
snprintf(out_dir, out_size, "%s/lib/%s", module_root, import_path);
|
|
|
|
|
} else {
|
|
|
|
|
snprintf(out_dir, out_size, "%s", source_dir);
|
|
|
|
|
@@ -2054,6 +2129,74 @@ static void populateDeclTableFromZir(Sema* sema, const Zir* zir) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// findDeclInstByNameInZir: find a declaration instruction by name in a ZIR.
|
|
|
|
|
// Scans the ZIR's struct_decl (inst 0) for a declaration with the given name.
|
|
|
|
|
// Returns the declaration instruction index, or UINT32_MAX if not found.
|
|
|
|
|
// Used as fallback during cross-module inline expansion where sema->decl_names
|
|
|
|
|
// contains indices from a different module's string table.
|
|
|
|
|
static uint32_t findDeclInstByNameInZir(
|
|
|
|
|
const Zir* zir, const char* decl_name) {
|
|
|
|
|
if (zir->inst_len == 0)
|
|
|
|
|
return UINT32_MAX;
|
|
|
|
|
if (zir->inst_tags[0] != ZIR_INST_EXTENDED)
|
|
|
|
|
return UINT32_MAX;
|
|
|
|
|
if (zir->inst_datas[0].extended.opcode != ZIR_EXT_STRUCT_DECL)
|
|
|
|
|
return UINT32_MAX;
|
|
|
|
|
|
|
|
|
|
uint16_t small = zir->inst_datas[0].extended.small;
|
|
|
|
|
uint32_t operand = zir->inst_datas[0].extended.operand;
|
|
|
|
|
uint32_t extra_index = operand + 6;
|
|
|
|
|
|
|
|
|
|
bool has_captures_len = (small & (1 << 0)) != 0;
|
|
|
|
|
bool has_fields_len = (small & (1 << 1)) != 0;
|
|
|
|
|
bool has_decls_len = (small & (1 << 2)) != 0;
|
|
|
|
|
bool has_backing_int = (small & (1 << 3)) != 0;
|
|
|
|
|
|
|
|
|
|
uint32_t captures_len = 0;
|
|
|
|
|
if (has_captures_len) {
|
|
|
|
|
captures_len = zir->extra[extra_index];
|
|
|
|
|
extra_index++;
|
|
|
|
|
}
|
|
|
|
|
if (has_fields_len)
|
|
|
|
|
extra_index++;
|
|
|
|
|
|
|
|
|
|
uint32_t decls_len = 0;
|
|
|
|
|
if (has_decls_len) {
|
|
|
|
|
decls_len = zir->extra[extra_index];
|
|
|
|
|
extra_index++;
|
|
|
|
|
}
|
|
|
|
|
extra_index += captures_len * 2;
|
|
|
|
|
if (has_backing_int) {
|
|
|
|
|
uint32_t backing_int_body_len = zir->extra[extra_index];
|
|
|
|
|
extra_index++;
|
|
|
|
|
if (backing_int_body_len == 0)
|
|
|
|
|
extra_index++;
|
|
|
|
|
else
|
|
|
|
|
extra_index += backing_int_body_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (uint32_t d = 0; d < decls_len; d++) {
|
|
|
|
|
uint32_t di_inst = zir->extra[extra_index + d];
|
|
|
|
|
if (zir->inst_tags[di_inst] != ZIR_INST_DECLARATION)
|
|
|
|
|
continue;
|
|
|
|
|
uint32_t payload = zir->inst_datas[di_inst].declaration.payload_index;
|
|
|
|
|
uint32_t flags_1 = zir->extra[payload + 5];
|
|
|
|
|
uint32_t id = (flags_1 >> 27) & 0x1F;
|
|
|
|
|
uint32_t di = payload + 6;
|
|
|
|
|
uint32_t name_idx = 0;
|
|
|
|
|
if (declIdHasName(id)) {
|
|
|
|
|
name_idx = zir->extra[di];
|
|
|
|
|
di++;
|
|
|
|
|
}
|
|
|
|
|
if (name_idx == 0)
|
|
|
|
|
continue;
|
|
|
|
|
const char* name = (const char*)&zir->string_bytes[name_idx];
|
|
|
|
|
if (strcmp(name, decl_name) == 0)
|
|
|
|
|
return di_inst;
|
|
|
|
|
}
|
|
|
|
|
return UINT32_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// findFuncInstInZir: find a func/func_fancy instruction by name in a ZIR.
|
|
|
|
|
// Scans the ZIR's struct_decl (inst 0) for a declaration matching the
|
|
|
|
|
// given name, then searches its value body for a func instruction.
|
|
|
|
|
@@ -2577,8 +2720,10 @@ static InternPoolIndex registerStructTypeFromZir(
|
|
|
|
|
// source_dir is the directory containing the module.
|
|
|
|
|
// On success, returns func_inst and may replace *zir/*ast with the target
|
|
|
|
|
// module (freeing the old ones). On failure, returns UINT32_MAX.
|
|
|
|
|
static uint32_t findFuncInModuleZir(
|
|
|
|
|
const char* source_dir, Zir* zir, Ast* ast, const char* func_name) {
|
|
|
|
|
// If out_resolved_dir is non-NULL and a re-export was followed, writes
|
|
|
|
|
// the resolved target module's source directory there.
|
|
|
|
|
static uint32_t findFuncInModuleZir(const char* source_dir, Zir* zir, Ast* ast,
|
|
|
|
|
const char* func_name, char* out_resolved_dir, size_t resolved_dir_size) {
|
|
|
|
|
uint32_t func_inst = findFuncInstInZir(zir, func_name);
|
|
|
|
|
if (func_inst != UINT32_MAX)
|
|
|
|
|
return func_inst;
|
|
|
|
|
@@ -2603,6 +2748,10 @@ static uint32_t findFuncInModuleZir(
|
|
|
|
|
astDeinit(ast);
|
|
|
|
|
*zir = target_zir;
|
|
|
|
|
*ast = target_ast;
|
|
|
|
|
// Report the resolved directory if requested.
|
|
|
|
|
if (out_resolved_dir)
|
|
|
|
|
computeSourceDir(NULL, source_dir, reexport_import, out_resolved_dir,
|
|
|
|
|
resolved_dir_size);
|
|
|
|
|
return func_inst;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2697,8 +2846,29 @@ static AirInstRef zirCall(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Debug: save callee name before chain resolution changes sema->code.
|
|
|
|
|
char dbg_callee[64] = "?";
|
|
|
|
|
if (callee_name_idx) {
|
|
|
|
|
const char* nm
|
|
|
|
|
= (const char*)&sema->code.string_bytes[callee_name_idx];
|
|
|
|
|
size_t nl = strlen(nm);
|
|
|
|
|
if (nl > 63)
|
|
|
|
|
nl = 63;
|
|
|
|
|
memcpy(dbg_callee, nm, nl);
|
|
|
|
|
dbg_callee[nl] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the inline function's ZIR instruction.
|
|
|
|
|
uint32_t func_inst = findDeclFuncInst(sema, callee_name_idx);
|
|
|
|
|
// Fallback: during cross-module inline expansion, sema->decl_names
|
|
|
|
|
// contains indices from the main module's string table, but
|
|
|
|
|
// callee_name_idx is from the inlined module's string table.
|
|
|
|
|
// Search the current ZIR directly by name.
|
|
|
|
|
if (func_inst == UINT32_MAX && callee_name_idx != 0) {
|
|
|
|
|
const char* cn
|
|
|
|
|
= (const char*)&sema->code.string_bytes[callee_name_idx];
|
|
|
|
|
func_inst = findFuncInstInZir(&sema->code, cn);
|
|
|
|
|
}
|
|
|
|
|
// For cross-module field_call: if local lookup fails, check if
|
|
|
|
|
// the callee object is an import and load the imported module.
|
|
|
|
|
Ast import_ast;
|
|
|
|
|
@@ -2706,9 +2876,11 @@ static AirInstRef zirCall(
|
|
|
|
|
Zir saved_code;
|
|
|
|
|
bool is_cross_module = false;
|
|
|
|
|
InternPoolIndex struct_ret_type = IP_INDEX_VOID_TYPE;
|
|
|
|
|
char import_source_dir[1024];
|
|
|
|
|
memset(&import_ast, 0, sizeof(import_ast));
|
|
|
|
|
memset(&import_zir, 0, sizeof(import_zir));
|
|
|
|
|
memset(&saved_code, 0, sizeof(saved_code));
|
|
|
|
|
import_source_dir[0] = 0;
|
|
|
|
|
|
|
|
|
|
// For non-field calls to imported function aliases:
|
|
|
|
|
// e.g. `const isNan = std.math.isNan;` then `isNan(x)`.
|
|
|
|
|
@@ -2726,6 +2898,12 @@ static AirInstRef zirCall(
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Fallback: search current ZIR by name (cross-module inline).
|
|
|
|
|
if (decl_inst_val == UINT32_MAX) {
|
|
|
|
|
const char* cn
|
|
|
|
|
= (const char*)&sema->code.string_bytes[callee_name_idx];
|
|
|
|
|
decl_inst_val = findDeclInstByNameInZir(&sema->code, cn);
|
|
|
|
|
}
|
|
|
|
|
if (decl_inst_val != UINT32_MAX) {
|
|
|
|
|
const uint32_t* vb;
|
|
|
|
|
uint32_t vb_len;
|
|
|
|
|
@@ -2786,6 +2964,8 @@ static AirInstRef zirCall(
|
|
|
|
|
import_zir = cur_zir;
|
|
|
|
|
import_ast = cur_ast;
|
|
|
|
|
is_cross_module = true;
|
|
|
|
|
snprintf(import_source_dir,
|
|
|
|
|
sizeof(import_source_dir), "%s", cur_dir);
|
|
|
|
|
} else {
|
|
|
|
|
zirDeinit(&cur_zir);
|
|
|
|
|
astDeinit(&cur_ast);
|
|
|
|
|
@@ -2834,6 +3014,9 @@ static AirInstRef zirCall(
|
|
|
|
|
import_zir = fn_zir;
|
|
|
|
|
import_ast = fn_ast;
|
|
|
|
|
is_cross_module = true;
|
|
|
|
|
computeSourceDir(NULL, cur_dir, fn_import,
|
|
|
|
|
import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
} else {
|
|
|
|
|
zirDeinit(&fn_zir);
|
|
|
|
|
astDeinit(&fn_ast);
|
|
|
|
|
@@ -2847,6 +3030,8 @@ static AirInstRef zirCall(
|
|
|
|
|
import_zir = cur_zir;
|
|
|
|
|
import_ast = cur_ast;
|
|
|
|
|
is_cross_module = true;
|
|
|
|
|
snprintf(import_source_dir,
|
|
|
|
|
sizeof(import_source_dir), "%s", cur_dir);
|
|
|
|
|
} else {
|
|
|
|
|
zirDeinit(&cur_zir);
|
|
|
|
|
astDeinit(&cur_ast);
|
|
|
|
|
@@ -2870,6 +3055,9 @@ static AirInstRef zirCall(
|
|
|
|
|
import_zir = base_zir;
|
|
|
|
|
import_ast = base_ast;
|
|
|
|
|
is_cross_module = true;
|
|
|
|
|
computeSourceDir(sema->module_root, sema->source_dir,
|
|
|
|
|
base_import, import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
} else {
|
|
|
|
|
zirDeinit(&base_zir);
|
|
|
|
|
astDeinit(&base_ast);
|
|
|
|
|
@@ -2897,8 +3085,12 @@ static AirInstRef zirCall(
|
|
|
|
|
import_zir = loadImportZir(
|
|
|
|
|
sema->source_dir, import_path, &import_ast);
|
|
|
|
|
if (import_zir.inst_len > 0) {
|
|
|
|
|
func_inst = findFuncInModuleZir(sema->source_dir,
|
|
|
|
|
&import_zir, &import_ast, field_name);
|
|
|
|
|
computeSourceDir(sema->module_root, sema->source_dir,
|
|
|
|
|
import_path, import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
func_inst = findFuncInModuleZir(import_source_dir,
|
|
|
|
|
&import_zir, &import_ast, field_name,
|
|
|
|
|
import_source_dir, sizeof(import_source_dir));
|
|
|
|
|
if (func_inst != UINT32_MAX) {
|
|
|
|
|
// Swap to imported module's ZIR.
|
|
|
|
|
saved_code = sema->code;
|
|
|
|
|
@@ -2948,8 +3140,13 @@ static AirInstRef zirCall(
|
|
|
|
|
const char* field_name
|
|
|
|
|
= (const char*)&sema->code
|
|
|
|
|
.string_bytes[callee_name_idx];
|
|
|
|
|
func_inst = findFuncInModuleZir(base_dir,
|
|
|
|
|
&import_zir, &import_ast, field_name);
|
|
|
|
|
computeSourceDir(NULL, base_dir, sub_import,
|
|
|
|
|
import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
func_inst = findFuncInModuleZir(
|
|
|
|
|
import_source_dir, &import_zir,
|
|
|
|
|
&import_ast, field_name, import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
if (func_inst != UINT32_MAX) {
|
|
|
|
|
saved_code = sema->code;
|
|
|
|
|
sema->code = import_zir;
|
|
|
|
|
@@ -2969,6 +3166,10 @@ static AirInstRef zirCall(
|
|
|
|
|
import_zir = base_zir;
|
|
|
|
|
import_ast = base_ast;
|
|
|
|
|
is_cross_module = true;
|
|
|
|
|
computeSourceDir(sema->module_root,
|
|
|
|
|
sema->source_dir, chain_import,
|
|
|
|
|
import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
} else {
|
|
|
|
|
zirDeinit(&base_zir);
|
|
|
|
|
astDeinit(&base_ast);
|
|
|
|
|
@@ -3032,9 +3233,14 @@ static AirInstRef zirCall(
|
|
|
|
|
zirDeinit(&alias_zir);
|
|
|
|
|
astDeinit(&alias_ast);
|
|
|
|
|
if (import_zir.inst_len > 0) {
|
|
|
|
|
computeSourceDir(NULL, alias_dir,
|
|
|
|
|
sub_path, import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
func_inst = findFuncInModuleZir(
|
|
|
|
|
alias_dir, &import_zir,
|
|
|
|
|
&import_ast, fn_field);
|
|
|
|
|
import_source_dir, &import_zir,
|
|
|
|
|
&import_ast, fn_field,
|
|
|
|
|
import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
if (func_inst != UINT32_MAX) {
|
|
|
|
|
saved_code = sema->code;
|
|
|
|
|
sema->code = import_zir;
|
|
|
|
|
@@ -3073,9 +3279,14 @@ static AirInstRef zirCall(
|
|
|
|
|
.string_bytes
|
|
|
|
|
[callee_name_idx]
|
|
|
|
|
: fn_field;
|
|
|
|
|
computeSourceDir(NULL, base_dir,
|
|
|
|
|
sub_import, import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
func_inst = findFuncInModuleZir(
|
|
|
|
|
base_dir, &import_zir, &import_ast,
|
|
|
|
|
fn_name);
|
|
|
|
|
import_source_dir, &import_zir,
|
|
|
|
|
&import_ast, fn_name,
|
|
|
|
|
import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
if (func_inst != UINT32_MAX) {
|
|
|
|
|
saved_code = sema->code;
|
|
|
|
|
sema->code = import_zir;
|
|
|
|
|
@@ -3151,6 +3362,10 @@ static AirInstRef zirCall(
|
|
|
|
|
saved_code = sema->code;
|
|
|
|
|
sema->code = import_zir;
|
|
|
|
|
is_cross_module = true;
|
|
|
|
|
computeSourceDir(NULL, bd,
|
|
|
|
|
sp, import_source_dir,
|
|
|
|
|
sizeof(
|
|
|
|
|
import_source_dir));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
@@ -3179,8 +3394,11 @@ static AirInstRef zirCall(
|
|
|
|
|
import_zir
|
|
|
|
|
= loadImportZir(sema->source_dir, import_path, &import_ast);
|
|
|
|
|
if (import_zir.inst_len > 0) {
|
|
|
|
|
func_inst = findFuncInModuleZir(
|
|
|
|
|
sema->source_dir, &import_zir, &import_ast, field_name);
|
|
|
|
|
computeSourceDir(sema->module_root, sema->source_dir,
|
|
|
|
|
import_path, import_source_dir, sizeof(import_source_dir));
|
|
|
|
|
func_inst = findFuncInModuleZir(import_source_dir, &import_zir,
|
|
|
|
|
&import_ast, field_name, import_source_dir,
|
|
|
|
|
sizeof(import_source_dir));
|
|
|
|
|
if (func_inst != UINT32_MAX) {
|
|
|
|
|
saved_code = sema->code;
|
|
|
|
|
sema->code = import_zir;
|
|
|
|
|
@@ -3398,7 +3616,8 @@ static AirInstRef zirCall(
|
|
|
|
|
&& (strcmp(type_fn_name, "Int") == 0
|
|
|
|
|
|| strcmp(type_fn_name, "Log2Int") == 0
|
|
|
|
|
|| strcmp(type_fn_name, "PowerOfTwoSignificandZ") == 0
|
|
|
|
|
|| strcmp(type_fn_name, "F16T") == 0)) {
|
|
|
|
|
|| strcmp(type_fn_name, "F16T") == 0
|
|
|
|
|
|| strcmp(type_fn_name, "Complex") == 0)) {
|
|
|
|
|
returns_type = true;
|
|
|
|
|
} else {
|
|
|
|
|
if (is_cross_module) {
|
|
|
|
|
@@ -3438,6 +3657,13 @@ static AirInstRef zirCall(
|
|
|
|
|
if (ptag == ZIR_INST_PARAM_COMPTIME
|
|
|
|
|
|| ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) {
|
|
|
|
|
is_ct_param[pi] = true;
|
|
|
|
|
}
|
|
|
|
|
// Ported from upstream: anytype and comptime params both
|
|
|
|
|
// make the function generic. Used for dummy alloc emission
|
|
|
|
|
// in the non-inline CALL path (Sema.zig:7394-7399).
|
|
|
|
|
if (ptag == ZIR_INST_PARAM_COMPTIME
|
|
|
|
|
|| ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME
|
|
|
|
|
|| ptag == ZIR_INST_PARAM_ANYTYPE) {
|
|
|
|
|
is_generic = true;
|
|
|
|
|
}
|
|
|
|
|
// Check if param type is generic (refers to previous params).
|
|
|
|
|
@@ -3639,6 +3865,42 @@ static AirInstRef zirCall(
|
|
|
|
|
// returns_type functions return `type` which is comptime-only.
|
|
|
|
|
// Upstream evaluates these in comptime context, so
|
|
|
|
|
// need_debug_scope is always false → BLOCK tag.
|
|
|
|
|
// Upstream (Sema.zig:7247) sets block to comptime for
|
|
|
|
|
// comptime-only ret types, enabling memoization (line 7724).
|
|
|
|
|
// Memoized calls return BEFORE block pre-allocation, so
|
|
|
|
|
// repeated calls with same args don't create dead blocks.
|
|
|
|
|
// Check memo first to match upstream behavior.
|
|
|
|
|
if (!block->is_comptime) {
|
|
|
|
|
bool all_ct = (args_len > 0);
|
|
|
|
|
for (uint32_t a = 0; a < args_len && all_ct; a++) {
|
|
|
|
|
if (!AIR_REF_IS_IP(arg_refs[a]))
|
|
|
|
|
all_ct = false;
|
|
|
|
|
}
|
|
|
|
|
if (all_ct) {
|
|
|
|
|
for (uint32_t mi = 0; mi < sema->num_memo; mi++) {
|
|
|
|
|
if (sema->memo_func_inst[mi] != func_inst)
|
|
|
|
|
continue;
|
|
|
|
|
if (sema->memo_args_len[mi] != args_len)
|
|
|
|
|
continue;
|
|
|
|
|
bool match = true;
|
|
|
|
|
for (uint32_t a = 0; a < args_len && a < 4; a++) {
|
|
|
|
|
if (sema->memo_args[mi][a] != arg_refs[a]) {
|
|
|
|
|
match = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (match) {
|
|
|
|
|
AirInstRef mr = sema->memo_result[mi];
|
|
|
|
|
if (is_cross_module) {
|
|
|
|
|
sema->code = saved_code;
|
|
|
|
|
zirDeinit(&import_zir);
|
|
|
|
|
astDeinit(&import_ast);
|
|
|
|
|
}
|
|
|
|
|
return mr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Check if this function's dead block was pre-emitted during
|
|
|
|
|
// generic param type resolution.
|
|
|
|
|
{
|
|
|
|
|
@@ -3661,7 +3923,7 @@ static AirInstRef zirCall(
|
|
|
|
|
(void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, rt_dead);
|
|
|
|
|
}
|
|
|
|
|
// Track that this function has had its dead block created.
|
|
|
|
|
if (!block->is_comptime && type_fn_name
|
|
|
|
|
if (!skip_block && !block->is_comptime && type_fn_name
|
|
|
|
|
&& sema->num_type_fn_created < 16)
|
|
|
|
|
sema->type_fn_created[sema->num_type_fn_created++]
|
|
|
|
|
= type_fn_name;
|
|
|
|
|
@@ -3840,6 +4102,53 @@ static AirInstRef zirCall(
|
|
|
|
|
// F16T(T): returns u16 on wasm32-wasi (test target).
|
|
|
|
|
// Ported from lib/compiler_rt/common.zig F16T.
|
|
|
|
|
result_type = IP_INDEX_U16_TYPE;
|
|
|
|
|
} else if (type_fn_name && strcmp(type_fn_name, "Complex") == 0) {
|
|
|
|
|
// Complex(T): returns extern struct { real: T, imag: T }.
|
|
|
|
|
// Ported from lib/compiler_rt/mulc3.zig Complex.
|
|
|
|
|
if (args_len >= 1 && AIR_REF_IS_IP(arg_refs[0])) {
|
|
|
|
|
InternPoolIndex elem_ty = AIR_REF_TO_IP(arg_refs[0]);
|
|
|
|
|
// Use unique struct ID based on element type.
|
|
|
|
|
uint32_t struct_id = 0xC0A100 + (uint32_t)elem_ty;
|
|
|
|
|
// Check if already registered.
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (uint32_t si = 0; si < sema->num_struct_info; si++) {
|
|
|
|
|
if (sema->struct_info[si].num_fields == 2
|
|
|
|
|
&& strcmp(sema->struct_info[si].fields[0].name, "real")
|
|
|
|
|
== 0
|
|
|
|
|
&& sema->struct_info[si].fields[0].type == elem_ty) {
|
|
|
|
|
result_type = sema->struct_info[si].struct_type;
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found) {
|
|
|
|
|
InternPoolKey skey;
|
|
|
|
|
memset(&skey, 0, sizeof(skey));
|
|
|
|
|
skey.tag = IP_KEY_STRUCT_TYPE;
|
|
|
|
|
skey.data.struct_type = struct_id;
|
|
|
|
|
InternPoolIndex struct_ip = ipIntern(sema->ip, skey);
|
|
|
|
|
|
|
|
|
|
InternPoolKey pkey;
|
|
|
|
|
memset(&pkey, 0, sizeof(pkey));
|
|
|
|
|
pkey.tag = IP_KEY_PTR_TYPE;
|
|
|
|
|
pkey.data.ptr_type.child = struct_ip;
|
|
|
|
|
pkey.data.ptr_type.flags = 0;
|
|
|
|
|
InternPoolIndex ptr_ip = ipIntern(sema->ip, pkey);
|
|
|
|
|
|
|
|
|
|
if (sema->num_struct_info < 32) {
|
|
|
|
|
StructFieldInfo* info
|
|
|
|
|
= &sema->struct_info[sema->num_struct_info++];
|
|
|
|
|
info->struct_type = struct_ip;
|
|
|
|
|
info->ptr_type = ptr_ip;
|
|
|
|
|
info->num_fields = 2;
|
|
|
|
|
info->fields[0].name = "real";
|
|
|
|
|
info->fields[0].type = elem_ty;
|
|
|
|
|
info->fields[1].name = "imag";
|
|
|
|
|
info->fields[1].type = elem_ty;
|
|
|
|
|
}
|
|
|
|
|
result_type = struct_ip;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_cross_module) {
|
|
|
|
|
@@ -3847,6 +4156,24 @@ static AirInstRef zirCall(
|
|
|
|
|
zirDeinit(&import_zir);
|
|
|
|
|
astDeinit(&import_ast);
|
|
|
|
|
}
|
|
|
|
|
// Memoize type function result for future calls with same args.
|
|
|
|
|
// Matches upstream behavior where memoized calls skip block
|
|
|
|
|
// pre-allocation (Sema.zig:7724-7744, 7891-7896).
|
|
|
|
|
if (result_type != IP_INDEX_NONE && !block->is_comptime) {
|
|
|
|
|
bool all_ct = (args_len > 0);
|
|
|
|
|
for (uint32_t a = 0; a < args_len && all_ct; a++) {
|
|
|
|
|
if (!AIR_REF_IS_IP(arg_refs[a]))
|
|
|
|
|
all_ct = false;
|
|
|
|
|
}
|
|
|
|
|
if (all_ct && sema->num_memo < 32) {
|
|
|
|
|
uint32_t mi = sema->num_memo++;
|
|
|
|
|
sema->memo_func_inst[mi] = func_inst;
|
|
|
|
|
sema->memo_args_len[mi] = args_len;
|
|
|
|
|
for (uint32_t a = 0; a < args_len && a < 4; a++)
|
|
|
|
|
sema->memo_args[mi][a] = arg_refs[a];
|
|
|
|
|
sema->memo_result[mi] = AIR_REF_FROM_IP(result_type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (result_type != IP_INDEX_NONE)
|
|
|
|
|
return AIR_REF_FROM_IP(result_type);
|
|
|
|
|
return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
|
|
|
|
|
@@ -3871,10 +4198,44 @@ static AirInstRef zirCall(
|
|
|
|
|
&& struct_ret_type != IP_INDEX_VOID_TYPE) {
|
|
|
|
|
ret_ty = struct_ret_type;
|
|
|
|
|
}
|
|
|
|
|
// Resolve multi-instruction return type body (e.g. Complex(f64)).
|
|
|
|
|
// We cannot call analyzeBodyInner here because the inst_map
|
|
|
|
|
// doesn't cover the ret_ty body instructions. Instead, check if
|
|
|
|
|
// the return type was already resolved by zirFunc's pre_resolved
|
|
|
|
|
// pass (which populated struct_info for Complex).
|
|
|
|
|
// Look for a matching struct_info entry based on element type.
|
|
|
|
|
if (ret_ty == IP_INDEX_VOID_TYPE && func_info.ret_ty_body_len > 2
|
|
|
|
|
&& args_len > 0) {
|
|
|
|
|
// Check if any registered struct matches as a return type.
|
|
|
|
|
// For Complex(T): struct with {real: T, imag: T} where T is
|
|
|
|
|
// the first arg's element type.
|
|
|
|
|
for (uint32_t si = 0; si < sema->num_struct_info; si++) {
|
|
|
|
|
if (sema->struct_info[si].num_fields == 2
|
|
|
|
|
&& strcmp(sema->struct_info[si].fields[0].name, "real") == 0) {
|
|
|
|
|
// Found Complex struct — use its type as return type.
|
|
|
|
|
ret_ty = sema->struct_info[si].struct_type;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ret_ty == IP_INDEX_VOID_TYPE && is_cross_module && args_len > 0
|
|
|
|
|
&& func_info.ret_ty_body_len > 1) {
|
|
|
|
|
// Assume return type = first argument's type (covers @TypeOf(a)).
|
|
|
|
|
ret_ty = semaTypeOf(sema, arg_refs[0]);
|
|
|
|
|
// Assume return type = argument's type (covers @TypeOf(a)).
|
|
|
|
|
// Try each arg until we find one with a concrete (non-comptime-only)
|
|
|
|
|
// type. This handles GenericPoison where the first arg's type
|
|
|
|
|
// might not be resolved (e.g. copysign's first arg in generic
|
|
|
|
|
// context).
|
|
|
|
|
for (uint32_t a = 0; a < args_len; a++) {
|
|
|
|
|
TypeIndex candidate = semaTypeOf(sema, arg_refs[a]);
|
|
|
|
|
if (candidate != IP_INDEX_TYPE_TYPE
|
|
|
|
|
&& candidate != IP_INDEX_COMPTIME_INT_TYPE
|
|
|
|
|
&& candidate != IP_INDEX_COMPTIME_FLOAT_TYPE
|
|
|
|
|
&& candidate != IP_INDEX_ENUM_LITERAL_TYPE
|
|
|
|
|
&& candidate != TYPE_NONE) {
|
|
|
|
|
ret_ty = candidate;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Handle case where return type is a param ref (e.g. `fn absv(comptime
|
|
|
|
|
// ST: type, a: ST) ST`). The ret_ty_ref points to a param instruction;
|
|
|
|
|
@@ -3909,13 +4270,20 @@ static AirInstRef zirCall(
|
|
|
|
|
// Upstream (Sema.zig:7247): if the return type is comptime-only
|
|
|
|
|
// (e.g. comptime_int, type), the block is set to comptime, making
|
|
|
|
|
// is_inline_call = true. Upstream (Sema.zig:7482):
|
|
|
|
|
// is_inline_call = block.isComptime() or inline_requested;
|
|
|
|
|
// is_inline_call = block.isComptime() or func_type.isGeneric()
|
|
|
|
|
// or inline_requested;
|
|
|
|
|
bool is_comptime_only_ret
|
|
|
|
|
= (ret_ty == IP_INDEX_TYPE_TYPE || ret_ty == IP_INDEX_COMPTIME_INT_TYPE
|
|
|
|
|
|| ret_ty == IP_INDEX_COMPTIME_FLOAT_TYPE
|
|
|
|
|
|| ret_ty == IP_INDEX_ENUM_LITERAL_TYPE);
|
|
|
|
|
bool is_inline_call
|
|
|
|
|
= func_info.is_inline || block->is_comptime || is_comptime_only_ret;
|
|
|
|
|
if (strcmp(dbg_callee, "copysign") == 0)
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
" COPYSIGN_PATH: is_inline=%d is_comptime=%d ct_only_ret=%d"
|
|
|
|
|
" ret_ty=%u is_generic=%d\n",
|
|
|
|
|
func_info.is_inline, block->is_comptime, is_comptime_only_ret,
|
|
|
|
|
ret_ty, is_generic);
|
|
|
|
|
if (!is_inline_call) {
|
|
|
|
|
// Dummy allocs for generic runtime params are now emitted
|
|
|
|
|
// interleaved in the arg evaluation loop above (Fix A).
|
|
|
|
|
@@ -4171,9 +4539,12 @@ static AirInstRef zirCall(
|
|
|
|
|
// For cross-module calls, populate decl table from imported ZIR
|
|
|
|
|
// so that decl_val/decl_ref can resolve the imported module's
|
|
|
|
|
// declarations (e.g. `const std = @import("std")`).
|
|
|
|
|
// Also set source_dir to the imported module's directory so that
|
|
|
|
|
// nested cross-module calls resolve relative imports correctly.
|
|
|
|
|
uint32_t saved_decl_names[64];
|
|
|
|
|
uint32_t saved_decl_insts[64];
|
|
|
|
|
uint32_t saved_num_decls = 0;
|
|
|
|
|
const char* saved_source_dir = NULL;
|
|
|
|
|
if (is_cross_module) {
|
|
|
|
|
saved_num_decls = sema->num_decls;
|
|
|
|
|
memcpy(saved_decl_names, sema->decl_names,
|
|
|
|
|
@@ -4181,6 +4552,10 @@ static AirInstRef zirCall(
|
|
|
|
|
memcpy(saved_decl_insts, sema->decl_insts,
|
|
|
|
|
saved_num_decls * sizeof(uint32_t));
|
|
|
|
|
populateDeclTableFromZir(sema, &import_zir);
|
|
|
|
|
if (import_source_dir[0]) {
|
|
|
|
|
saved_source_dir = sema->source_dir;
|
|
|
|
|
sema->source_dir = import_source_dir;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Analyze the inline function body.
|
|
|
|
|
@@ -4188,13 +4563,15 @@ static AirInstRef zirCall(
|
|
|
|
|
|
|
|
|
|
(void)analyzeBodyInner(sema, &child_block, func_body, func_info.body_len);
|
|
|
|
|
|
|
|
|
|
// Restore decl table for cross-module calls.
|
|
|
|
|
// Restore decl table and source_dir for cross-module calls.
|
|
|
|
|
if (is_cross_module) {
|
|
|
|
|
memcpy(sema->decl_names, saved_decl_names,
|
|
|
|
|
saved_num_decls * sizeof(uint32_t));
|
|
|
|
|
memcpy(sema->decl_insts, saved_decl_insts,
|
|
|
|
|
saved_num_decls * sizeof(uint32_t));
|
|
|
|
|
sema->num_decls = saved_num_decls;
|
|
|
|
|
if (saved_source_dir)
|
|
|
|
|
sema->source_dir = saved_source_dir;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sema->fn_ret_ty = saved_fn_ret_ty;
|
|
|
|
|
@@ -4580,7 +4957,6 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
|
|
|
|
|
// Multi-instruction return type body resolved before state save.
|
|
|
|
|
sema->fn_ret_ty = pre_resolved_ret_ty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Set up block for function body ---
|
|
|
|
|
SemaBlock fn_block;
|
|
|
|
|
semaBlockInit(&fn_block, sema, NULL);
|
|
|
|
|
@@ -5846,6 +6222,67 @@ static bool analyzeBodyInner(
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ret_load: return by loading from the return pointer.
|
|
|
|
|
// Ported from src/Sema.zig zirRetLoad / analyzeRet.
|
|
|
|
|
case ZIR_INST_RET_LOAD: {
|
|
|
|
|
ZirInstRef operand_ref
|
|
|
|
|
= sema->code.inst_datas[inst].un_node.operand;
|
|
|
|
|
AirInstRef ret_ptr = resolveInst(sema, operand_ref);
|
|
|
|
|
|
|
|
|
|
if (block->is_comptime || block->inlining) {
|
|
|
|
|
// Load from the return pointer.
|
|
|
|
|
TypeIndex ptr_ty = semaTypeOf(sema, ret_ptr);
|
|
|
|
|
TypeIndex elem_ty = ptrChildType(sema->ip, ptr_ty);
|
|
|
|
|
AirInstData load_data;
|
|
|
|
|
memset(&load_data, 0, sizeof(load_data));
|
|
|
|
|
load_data.ty_op.ty_ref = AIR_REF_FROM_IP(elem_ty);
|
|
|
|
|
load_data.ty_op.operand = ret_ptr;
|
|
|
|
|
AirInstRef operand
|
|
|
|
|
= semaAddInst(block, AIR_INST_LOAD, load_data);
|
|
|
|
|
|
|
|
|
|
if (block->inlining) {
|
|
|
|
|
SemaBlockInlining* inl = block->inlining;
|
|
|
|
|
if (block->is_comptime) {
|
|
|
|
|
inl->comptime_result = operand;
|
|
|
|
|
inl->comptime_returned = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Runtime inlining: rewrite ret as br.
|
|
|
|
|
AirInstData br_data;
|
|
|
|
|
memset(&br_data, 0, sizeof(br_data));
|
|
|
|
|
br_data.br.block_inst = inl->merges.block_inst;
|
|
|
|
|
br_data.br.operand = operand;
|
|
|
|
|
AirInstRef br_ref
|
|
|
|
|
= semaAddInst(block, AIR_INST_BR, br_data);
|
|
|
|
|
if (inl->merges.results_len >= inl->merges.results_cap) {
|
|
|
|
|
uint32_t new_cap = (inl->merges.results_cap == 0)
|
|
|
|
|
? 4
|
|
|
|
|
: inl->merges.results_cap * 2;
|
|
|
|
|
inl->merges.results = realloc(
|
|
|
|
|
inl->merges.results, new_cap * sizeof(AirInstRef));
|
|
|
|
|
inl->merges.br_list = realloc(
|
|
|
|
|
inl->merges.br_list, new_cap * sizeof(uint32_t));
|
|
|
|
|
if (!inl->merges.results || !inl->merges.br_list)
|
|
|
|
|
exit(1);
|
|
|
|
|
inl->merges.results_cap = new_cap;
|
|
|
|
|
inl->merges.br_list_cap = new_cap;
|
|
|
|
|
}
|
|
|
|
|
inl->merges.results[inl->merges.results_len++] = operand;
|
|
|
|
|
inl->merges.br_list[inl->merges.br_list_len++]
|
|
|
|
|
= AIR_REF_TO_INST(br_ref);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Non-inlining runtime: emit AIR ret_load.
|
|
|
|
|
AirInstData ret_data;
|
|
|
|
|
memset(&ret_data, 0, sizeof(ret_data));
|
|
|
|
|
ret_data.un_op.operand = ret_ptr;
|
|
|
|
|
(void)semaAddInst(block, AIR_INST_RET_LOAD, ret_data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// func/func_inferred/func_fancy: function declaration.
|
|
|
|
|
// Ported from src/Sema.zig zirFunc / zirFuncFancy.
|
|
|
|
|
case ZIR_INST_FUNC:
|
|
|
|
|
@@ -5916,6 +6353,21 @@ static bool analyzeBodyInner(
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// float: comptime float literal (fits in f64).
|
|
|
|
|
// Ported from src/Sema.zig zirFloat.
|
|
|
|
|
case ZIR_INST_FLOAT: {
|
|
|
|
|
double val = sema->code.inst_datas[inst].float_val;
|
|
|
|
|
InternPoolKey key;
|
|
|
|
|
memset(&key, 0, sizeof(key));
|
|
|
|
|
key.tag = IP_KEY_FLOAT;
|
|
|
|
|
key.data.float_val.ty = IP_INDEX_COMPTIME_FLOAT_TYPE;
|
|
|
|
|
key.data.float_val.val = val;
|
|
|
|
|
instMapPut(&sema->inst_map, inst,
|
|
|
|
|
AIR_REF_FROM_IP(ipIntern(sema->ip, key)));
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// extended: handle extended opcodes.
|
|
|
|
|
case ZIR_INST_EXTENDED: {
|
|
|
|
|
uint16_t opcode = sema->code.inst_datas[inst].extended.opcode;
|
|
|
|
|
@@ -6596,8 +7048,22 @@ static bool analyzeBodyInner(
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// field_ptr: runtime struct field pointer access.
|
|
|
|
|
// opt_eu_base_ptr_init: pass-through for struct init.
|
|
|
|
|
// Ported from Sema.zig zirOptEuBasePtrInit: resolves to the
|
|
|
|
|
// alloc pointer unchanged (for non-error-union/optional types).
|
|
|
|
|
case ZIR_INST_OPT_EU_BASE_PTR_INIT: {
|
|
|
|
|
ZirInstRef operand = sema->code.inst_datas[inst].un_node.operand;
|
|
|
|
|
AirInstRef resolved_op = resolveInst(sema, operand);
|
|
|
|
|
instMapPut(&sema->inst_map, inst, resolved_op);
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// field_ptr / struct_init_field_ptr: runtime struct field pointer
|
|
|
|
|
// access. struct_init_field_ptr uses the same pl_node + Field format
|
|
|
|
|
// as field_ptr. Upstream calls sema.fieldPtr for both.
|
|
|
|
|
case ZIR_INST_FIELD_PTR:
|
|
|
|
|
case ZIR_INST_STRUCT_INIT_FIELD_PTR:
|
|
|
|
|
instMapPut(&sema->inst_map, inst, zirFieldPtr(sema, block, inst));
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
@@ -6607,7 +7073,6 @@ static bool analyzeBodyInner(
|
|
|
|
|
case ZIR_INST_VALIDATE_STRUCT_INIT_RESULT_TY:
|
|
|
|
|
case ZIR_INST_VALIDATE_PTR_STRUCT_INIT:
|
|
|
|
|
case ZIR_INST_STRUCT_INIT_FIELD_TYPE:
|
|
|
|
|
case ZIR_INST_STRUCT_INIT_FIELD_PTR:
|
|
|
|
|
instMapPut(
|
|
|
|
|
&sema->inst_map, inst, AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE));
|
|
|
|
|
i++;
|
|
|
|
|
@@ -7084,13 +7549,10 @@ static bool analyzeBodyInner(
|
|
|
|
|
// Ported from src/Sema.zig resolveAnalyzedBlock.
|
|
|
|
|
uint32_t last_inst_idx = child_block.instructions_len - 1;
|
|
|
|
|
uint32_t last_inst = child_block.instructions[last_inst_idx];
|
|
|
|
|
bool elide = false;
|
|
|
|
|
if (!need_debug_scope
|
|
|
|
|
bool elide = !need_debug_scope
|
|
|
|
|
&& sema->air_inst_tags[last_inst] == AIR_INST_BR
|
|
|
|
|
&& sema->air_inst_datas[last_inst].br.block_inst
|
|
|
|
|
== block_inst_idx) {
|
|
|
|
|
elide = true;
|
|
|
|
|
}
|
|
|
|
|
== block_inst_idx;
|
|
|
|
|
if (elide) {
|
|
|
|
|
// Elide the block: copy instructions (excluding
|
|
|
|
|
// trailing br) to parent.
|
|
|
|
|
@@ -7214,6 +7676,8 @@ static bool analyzeBodyInner(
|
|
|
|
|
}
|
|
|
|
|
semaAddExtra(sema, sub_br_idx);
|
|
|
|
|
sema->air_inst_tags[br] = AIR_INST_BLOCK;
|
|
|
|
|
fprintf(
|
|
|
|
|
stderr, " REWRITE_BR_BLOCK: air_idx=%u\n", br);
|
|
|
|
|
sema->air_inst_datas[br].ty_pl.ty_ref
|
|
|
|
|
= AIR_REF_FROM_IP(resolved_ty);
|
|
|
|
|
sema->air_inst_datas[br].ty_pl.payload = sub_extra;
|
|
|
|
|
@@ -7472,7 +7936,6 @@ static bool analyzeBodyInner(
|
|
|
|
|
if (cond == AIR_REF_FROM_IP(IP_INDEX_BOOL_FALSE)) {
|
|
|
|
|
return analyzeBodyInner(sema, block, else_body, else_body_len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Analyze then-body in a sub-block, collecting branch hint.
|
|
|
|
|
// Upstream (Sema.zig line 18364): need_debug_scope = null
|
|
|
|
|
// because this body is emitted regardless.
|
|
|
|
|
@@ -7645,9 +8108,26 @@ static bool analyzeBodyInner(
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// coerce_ptr_elem_ty: coerce a value so that a reference to it
|
|
|
|
|
// would be coercible to a given pointer type.
|
|
|
|
|
// Ported from src/Sema.zig zirCoercePtrElemTy.
|
|
|
|
|
// Uses pl_node with Bin payload: lhs=pointer type, rhs=value.
|
|
|
|
|
case ZIR_INST_COERCE_PTR_ELEM_TY: {
|
|
|
|
|
uint32_t payload_index
|
|
|
|
|
= sema->code.inst_datas[inst].pl_node.payload_index;
|
|
|
|
|
ZirInstRef val_ref = sema->code.extra[payload_index + 1];
|
|
|
|
|
AirInstRef val = resolveInst(sema, val_ref);
|
|
|
|
|
// For single pointers with matching types (the common case
|
|
|
|
|
// in our bootstrap), the coercion is a no-op.
|
|
|
|
|
instMapPut(&sema->inst_map, inst, val);
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For all other instructions, produce a void mapping and skip.
|
|
|
|
|
// As handlers are implemented, they will replace this default.
|
|
|
|
|
default: {
|
|
|
|
|
fprintf(stderr, " UNHANDLED: inst=%u tag=%u\n", inst, inst_tag);
|
|
|
|
|
AirInstRef air_ref = AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE);
|
|
|
|
|
instMapPut(&sema->inst_map, inst, air_ref);
|
|
|
|
|
i++;
|
|
|
|
|
|