Commit 31a59c229c
Changed files (14)
src/codegen/llvm/bindings.zig
@@ -82,6 +82,24 @@ pub const Value = opaque {
pub const setGlobalConstant = LLVMSetGlobalConstant;
extern fn LLVMSetGlobalConstant(GlobalVar: *const Value, IsConstant: Bool) void;
+
+ pub const setLinkage = LLVMSetLinkage;
+ extern fn LLVMSetLinkage(Global: *const Value, Linkage: Linkage) void;
+
+ pub const setUnnamedAddr = LLVMSetUnnamedAddr;
+ extern fn LLVMSetUnnamedAddr(Global: *const Value, HasUnnamedAddr: Bool) void;
+
+ pub const deleteGlobal = LLVMDeleteGlobal;
+ extern fn LLVMDeleteGlobal(GlobalVar: *const Value) void;
+
+ pub const getNextGlobalAlias = LLVMGetNextGlobalAlias;
+ extern fn LLVMGetNextGlobalAlias(GA: *const Value) *const Value;
+
+ pub const getAliasee = LLVMAliasGetAliasee;
+ extern fn LLVMAliasGetAliasee(Alias: *const Value) *const Value;
+
+ pub const setAliasee = LLVMAliasSetAliasee;
+ extern fn LLVMAliasSetAliasee(Alias: *const Value, Aliasee: *const Value) void;
};
pub const Type = opaque {
@@ -145,6 +163,27 @@ pub const Module = opaque {
pub const dump = LLVMDumpModule;
extern fn LLVMDumpModule(M: *const Module) void;
+
+ pub const getFirstGlobalAlias = LLVMGetFirstGlobalAlias;
+ extern fn LLVMGetFirstGlobalAlias(M: *const Module) *const Value;
+
+ pub const getLastGlobalAlias = LLVMGetLastGlobalAlias;
+ extern fn LLVMGetLastGlobalAlias(M: *const Module) *const Value;
+
+ pub const addAlias = LLVMAddAlias;
+ extern fn LLVMAddAlias(
+ M: *const Module,
+ Ty: *const Type,
+ Aliasee: *const Value,
+ Name: [*:0]const u8,
+ ) *const Value;
+
+ pub const getNamedGlobalAlias = LLVMGetNamedGlobalAlias;
+ extern fn LLVMGetNamedGlobalAlias(
+ M: *const Module,
+ Name: [*]const u8,
+ NameLen: usize,
+ ) ?*const Value;
};
pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
@@ -252,18 +291,60 @@ pub const Builder = opaque {
pub const buildNot = LLVMBuildNot;
extern fn LLVMBuildNot(*const Builder, V: *const Value, Name: [*:0]const u8) *const Value;
+ pub const buildFAdd = LLVMBuildFAdd;
+ extern fn LLVMBuildFAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildAdd = LLVMBuildAdd;
+ extern fn LLVMBuildAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
pub const buildNSWAdd = LLVMBuildNSWAdd;
extern fn LLVMBuildNSWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
pub const buildNUWAdd = LLVMBuildNUWAdd;
extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+ pub const buildFSub = LLVMBuildFSub;
+ extern fn LLVMBuildFSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildSub = LLVMBuildSub;
+ extern fn LLVMBuildSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
pub const buildNSWSub = LLVMBuildNSWSub;
extern fn LLVMBuildNSWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
pub const buildNUWSub = LLVMBuildNUWSub;
extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+ pub const buildFMul = LLVMBuildFMul;
+ extern fn LLVMBuildFMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildMul = LLVMBuildMul;
+ extern fn LLVMBuildMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildNSWMul = LLVMBuildNSWMul;
+ extern fn LLVMBuildNSWMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildNUWMul = LLVMBuildNUWMul;
+ extern fn LLVMBuildNUWMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildUDiv = LLVMBuildUDiv;
+ extern fn LLVMBuildUDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildSDiv = LLVMBuildSDiv;
+ extern fn LLVMBuildSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildFDiv = LLVMBuildFDiv;
+ extern fn LLVMBuildFDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildAnd = LLVMBuildAnd;
+ extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildOr = LLVMBuildOr;
+ extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildXor = LLVMBuildXor;
+ extern fn LLVMBuildXor(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
pub const buildIntCast2 = LLVMBuildIntCast2;
extern fn LLVMBuildIntCast2(*const Builder, Val: *const Value, DestTy: *const Type, IsSigned: Bool, Name: [*:0]const u8) *const Value;
@@ -279,6 +360,16 @@ pub const Builder = opaque {
Name: [*:0]const u8,
) *const Value;
+ pub const buildInBoundsGEP2 = LLVMBuildInBoundsGEP2;
+ extern fn LLVMBuildInBoundsGEP2(
+ B: *const Builder,
+ Ty: *const Type,
+ Pointer: *const Value,
+ Indices: [*]const *const Value,
+ NumIndices: c_uint,
+ Name: [*:0]const u8,
+ ) *const Value;
+
pub const buildICmp = LLVMBuildICmp;
extern fn LLVMBuildICmp(*const Builder, Op: IntPredicate, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
@@ -292,10 +383,28 @@ pub const Builder = opaque {
extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value;
pub const buildExtractValue = LLVMBuildExtractValue;
- extern fn LLVMBuildExtractValue(*const Builder, AggVal: *const Value, Index: c_uint, Name: [*:0]const u8) *const Value;
+ extern fn LLVMBuildExtractValue(
+ *const Builder,
+ AggVal: *const Value,
+ Index: c_uint,
+ Name: [*:0]const u8,
+ ) *const Value;
pub const buildPtrToInt = LLVMBuildPtrToInt;
- extern fn LLVMBuildPtrToInt(*const Builder, Val: *const Value, DestTy: *const Type, Name: [*:0]const u8) *const Value;
+ extern fn LLVMBuildPtrToInt(
+ *const Builder,
+ Val: *const Value,
+ DestTy: *const Type,
+ Name: [*:0]const u8,
+ ) *const Value;
+
+ pub const buildStructGEP = LLVMBuildStructGEP;
+ extern fn LLVMBuildStructGEP(
+ B: *const Builder,
+ Pointer: *const Value,
+ Idx: c_uint,
+ Name: [*:0]const u8,
+ ) *const Value;
};
pub const IntPredicate = enum(c_int) {
@@ -715,3 +824,23 @@ extern fn ZigLLVMWriteImportLibrary(
output_lib_path: [*c]const u8,
kill_at: bool,
) bool;
+
+pub const Linkage = enum(c_uint) {
+ External,
+ AvailableExternally,
+ LinkOnceAny,
+ LinkOnceODR,
+ LinkOnceODRAutoHide,
+ WeakAny,
+ WeakODR,
+ Appending,
+ Internal,
+ Private,
+ DLLImport,
+ DLLExport,
+ ExternalWeak,
+ Ghost,
+ Common,
+ LinkerPrivate,
+ LinkerPrivateWeak,
+};
src/codegen/c.zig
@@ -935,6 +935,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
.wrap_optional => try airWrapOptional(o, inst),
.ref => try airRef(o, inst),
.struct_field_ptr => try airStructFieldPtr(o, inst),
+ .struct_field_val => try airStructFieldVal(o, inst),
.varptr => try airVarPtr(o, inst),
.slice_ptr => try airSliceField(o, inst, ".ptr;\n"),
.slice_len => try airSliceField(o, inst, ".len;\n"),
@@ -1660,8 +1661,8 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;
const writer = o.writer();
- const struct_ptr = try o.resolveInst(extra.struct_ptr);
- const struct_ptr_ty = o.air.typeOf(extra.struct_ptr);
+ const struct_ptr = try o.resolveInst(extra.struct_operand);
+ const struct_ptr_ty = o.air.typeOf(extra.struct_operand);
const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data;
const field_name = struct_obj.fields.keys()[extra.field_index];
@@ -1680,6 +1681,26 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
return local;
}
+fn airStructFieldVal(o: *Object, inst: Air.Inst.Index) !CValue {
+ if (o.liveness.isUnused(inst))
+ return CValue.none;
+
+ const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
+ const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;
+ const writer = o.writer();
+ const struct_byval = try o.resolveInst(extra.struct_operand);
+ const struct_ty = o.air.typeOf(extra.struct_operand);
+ const struct_obj = struct_ty.castTag(.@"struct").?.data;
+ const field_name = struct_obj.fields.keys()[extra.field_index];
+
+ const inst_ty = o.air.typeOfIndex(inst);
+ const local = try o.allocLocal(inst_ty, .Const);
+ try writer.writeAll(" = ");
+ try o.writeCValue(writer, struct_byval);
+ try writer.print(".{};\n", .{fmtIdent(field_name)});
+ return local;
+}
+
// *(E!T) -> E NOT *E
fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {
if (o.liveness.isUnused(inst))
src/codegen/llvm.zig
@@ -350,19 +350,21 @@ pub const Object = struct {
air: Air,
liveness: Liveness,
) !void {
+ const decl = func.owner_decl;
+
var dg: DeclGen = .{
.context = self.context,
.object = self,
.module = module,
- .decl = func.owner_decl,
+ .decl = decl,
.err_msg = null,
.gpa = module.gpa,
};
- const llvm_func = try dg.resolveLLVMFunction(func.owner_decl);
+ const llvm_func = try dg.resolveLlvmFunction(decl);
// This gets the LLVM values from the function and stores them in `dg.args`.
- const fn_param_len = func.owner_decl.ty.fnParamLen();
+ const fn_param_len = decl.ty.fnParamLen();
var args = try dg.gpa.alloc(*const llvm.Value, fn_param_len);
for (args) |*arg, i| {
@@ -400,13 +402,16 @@ pub const Object = struct {
fg.genBody(air.getMainBody()) catch |err| switch (err) {
error.CodegenFail => {
- func.owner_decl.analysis = .codegen_failure;
- try module.failed_decls.put(module.gpa, func.owner_decl, dg.err_msg.?);
+ decl.analysis = .codegen_failure;
+ try module.failed_decls.put(module.gpa, decl, dg.err_msg.?);
dg.err_msg = null;
return;
},
else => |e| return e,
};
+
+ const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
+ try self.updateDeclExports(module, decl, decl_exports);
}
pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
@@ -428,6 +433,38 @@ pub const Object = struct {
else => |e| return e,
};
}
+
+ pub fn updateDeclExports(
+ self: *Object,
+ module: *const Module,
+ decl: *const Module.Decl,
+ exports: []const *Module.Export,
+ ) !void {
+ const llvm_fn = self.llvm_module.getNamedFunction(decl.name).?;
+ const is_extern = decl.val.tag() == .extern_fn;
+ if (is_extern or exports.len != 0) {
+ llvm_fn.setLinkage(.External);
+ llvm_fn.setUnnamedAddr(.False);
+ } else {
+ llvm_fn.setLinkage(.Internal);
+ llvm_fn.setUnnamedAddr(.True);
+ }
+ // TODO LLVM C API does not support deleting aliases. We need to
+ // patch it to support this or figure out how to wrap the C++ API ourselves.
+ // Until then we iterate over existing aliases and make them point
+ // to the correct decl, or otherwise add a new alias. Old aliases are leaked.
+ for (exports) |exp| {
+ if (self.llvm_module.getNamedGlobalAlias(exp.options.name.ptr, exp.options.name.len)) |alias| {
+ alias.setAliasee(llvm_fn);
+ } else {
+ const exp_name_z = try module.gpa.dupeZ(u8, exp.options.name);
+ defer module.gpa.free(exp_name_z);
+
+ const alias = self.llvm_module.addAlias(llvm_fn.typeOf(), llvm_fn, exp_name_z);
+ _ = alias;
+ }
+ }
+ }
};
pub const DeclGen = struct {
@@ -461,21 +498,19 @@ pub const DeclGen = struct {
_ = func_payload;
@panic("TODO llvm backend genDecl function pointer");
} else if (decl.val.castTag(.extern_fn)) |extern_fn| {
- _ = try self.resolveLLVMFunction(extern_fn.data);
+ _ = try self.resolveLlvmFunction(extern_fn.data);
} else {
_ = try self.resolveGlobalDecl(decl);
}
}
/// If the llvm function does not exist, create it
- fn resolveLLVMFunction(self: *DeclGen, func: *Module.Decl) !*const llvm.Value {
- // TODO: do we want to store this in our own datastructure?
- if (self.llvmModule().getNamedFunction(func.name)) |llvm_fn| return llvm_fn;
+ fn resolveLlvmFunction(self: *DeclGen, decl: *Module.Decl) !*const llvm.Value {
+ if (self.llvmModule().getNamedFunction(decl.name)) |llvm_fn| return llvm_fn;
- assert(func.has_tv);
- const zig_fn_type = func.ty;
+ assert(decl.has_tv);
+ const zig_fn_type = decl.ty;
const return_type = zig_fn_type.fnReturnType();
-
const fn_param_len = zig_fn_type.fnParamLen();
const fn_param_types = try self.gpa.alloc(Type, fn_param_len);
@@ -495,9 +530,17 @@ pub const DeclGen = struct {
@intCast(c_uint, fn_param_len),
.False,
);
- const llvm_fn = self.llvmModule().addFunction(func.name, fn_type);
+ const llvm_fn = self.llvmModule().addFunction(decl.name, fn_type);
+
+ const is_extern = decl.val.tag() == .extern_fn;
+ if (!is_extern) {
+ llvm_fn.setLinkage(.Internal);
+ llvm_fn.setUnnamedAddr(.True);
+ }
+
+ // TODO: calling convention, linkage, tsan, etc. see codegen.cpp `make_fn_llvm_value`.
- if (return_type.tag() == .noreturn) {
+ if (return_type.isNoReturn()) {
self.addFnAttr(llvm_fn, "noreturn");
}
@@ -505,7 +548,6 @@ pub const DeclGen = struct {
}
fn resolveGlobalDecl(self: *DeclGen, decl: *Module.Decl) error{ OutOfMemory, CodegenFail }!*const llvm.Value {
- // TODO: do we want to store this in our own datastructure?
if (self.llvmModule().getNamedGlobal(decl.name)) |val| return val;
assert(decl.has_tv);
@@ -515,9 +557,11 @@ pub const DeclGen = struct {
const global = self.llvmModule().addGlobal(llvm_type, decl.name);
const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
const variable = payload.data;
- global.setGlobalConstant(.False);
break :init_val variable.init;
- } else decl.val;
+ } else init_val: {
+ global.setGlobalConstant(.True);
+ break :init_val decl.val;
+ };
const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val }, null);
llvm.setInitializer(global, llvm_init);
@@ -602,12 +646,13 @@ pub const DeclGen = struct {
llvm_param.* = try self.llvmType(t.fnParamType(i));
}
const is_var_args = t.fnIsVarArgs();
- return llvm.functionType(
+ const llvm_fn_ty = llvm.functionType(
ret_ty,
llvm_params.ptr,
@intCast(c_uint, llvm_params.len),
llvm.Bool.fromBool(is_var_args),
);
+ return llvm_fn_ty.pointerType(0);
},
.ComptimeInt => unreachable,
.ComptimeFloat => unreachable,
@@ -717,6 +762,42 @@ pub const DeclGen = struct {
return self.todo("implement const of optional pointer", .{});
}
},
+ .Fn => {
+ const fn_decl = if (tv.val.castTag(.extern_fn)) |extern_fn|
+ extern_fn.data
+ else if (tv.val.castTag(.function)) |func_payload|
+ func_payload.data.owner_decl
+ else
+ unreachable;
+
+ return self.resolveLlvmFunction(fn_decl);
+ },
+ .ErrorSet => {
+ const llvm_ty = try self.llvmType(tv.ty);
+ switch (tv.val.tag()) {
+ .@"error" => {
+ const err_name = tv.val.castTag(.@"error").?.data.name;
+ const kv = try self.module.getErrorValue(err_name);
+ return llvm_ty.constInt(kv.value, .False);
+ },
+ else => {
+ // In this case we are rendering an error union which has a 0 bits payload.
+ return llvm_ty.constNull();
+ },
+ }
+ },
+ .ErrorUnion => {
+ const error_type = tv.ty.errorUnionSet();
+ const payload_type = tv.ty.errorUnionPayload();
+ const sub_val = tv.val.castTag(.error_union).?.data;
+
+ if (!payload_type.hasCodeGenBits()) {
+ // We use the error type directly as the type.
+ return self.genTypedValue(.{ .ty = error_type, .val = sub_val }, fg);
+ }
+
+ return self.todo("implement error union const of type '{}'", .{tv.ty});
+ },
else => return self.todo("implement const of type '{}'", .{tv.ty}),
}
}
@@ -801,8 +882,17 @@ pub const FuncGen = struct {
for (body) |inst| {
const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
// zig fmt: off
- .add => try self.airAdd(inst),
- .sub => try self.airSub(inst),
+ .add => try self.airAdd(inst, false),
+ .addwrap => try self.airAdd(inst, true),
+ .sub => try self.airSub(inst, false),
+ .subwrap => try self.airSub(inst, true),
+ .mul => try self.airMul(inst, false),
+ .mulwrap => try self.airMul(inst, true),
+ .div => try self.airDiv(inst),
+
+ .bit_and, .bool_and => try self.airAnd(inst),
+ .bit_or, .bool_or => try self.airOr(inst),
+ .xor => try self.airXor(inst),
.cmp_eq => try self.airCmp(inst, .eq),
.cmp_gt => try self.airCmp(inst, .gt),
@@ -825,10 +915,12 @@ pub const FuncGen = struct {
.bitcast => try self.airBitCast(inst),
.block => try self.airBlock(inst),
.br => try self.airBr(inst),
+ .switch_br => try self.airSwitchBr(inst),
.breakpoint => try self.airBreakpoint(inst),
.call => try self.airCall(inst),
.cond_br => try self.airCondBr(inst),
.intcast => try self.airIntCast(inst),
+ .floatcast => try self.airFloatCast(inst),
.ptrtoint => try self.airPtrToInt(inst),
.load => try self.airLoad(inst),
.loop => try self.airLoop(inst),
@@ -840,6 +932,9 @@ pub const FuncGen = struct {
.slice_ptr => try self.airSliceField(inst, 0),
.slice_len => try self.airSliceField(inst, 1),
+ .struct_field_ptr => try self.airStructFieldPtr(inst),
+ .struct_field_val => try self.airStructFieldVal(inst),
+
.slice_elem_val => try self.airSliceElemVal(inst, false),
.ptr_slice_elem_val => try self.airSliceElemVal(inst, true),
@@ -851,12 +946,18 @@ pub const FuncGen = struct {
.unwrap_errunion_err => try self.airErrUnionErr(inst, false),
.unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
+ .wrap_optional => try self.airWrapOptional(inst),
+ .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
+ .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
+
+ .constant => unreachable,
+ .const_ty => unreachable,
+ .ref => unreachable, // TODO eradicate this instruction
.unreach => self.airUnreach(inst),
.dbg_stmt => blk: {
// TODO: implement debug info
break :blk null;
},
- else => |tag| return self.todo("implement AIR instruction: {}", .{tag}),
// zig fmt: on
};
if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa, inst, val);
@@ -867,47 +968,32 @@ pub const FuncGen = struct {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const extra = self.air.extraData(Air.Call, pl_op.payload);
const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
+ const zig_fn_type = self.air.typeOf(pl_op.operand);
+ const return_type = zig_fn_type.fnReturnType();
+ const llvm_fn = try self.resolveInst(pl_op.operand);
- if (self.air.value(pl_op.operand)) |func_value| {
- const fn_decl = if (func_value.castTag(.extern_fn)) |extern_fn|
- extern_fn.data
- else if (func_value.castTag(.function)) |func_payload|
- func_payload.data.owner_decl
- else
- unreachable;
-
- assert(fn_decl.has_tv);
- const zig_fn_type = fn_decl.ty;
- const llvm_fn = try self.dg.resolveLLVMFunction(fn_decl);
+ const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len);
+ defer self.gpa.free(llvm_param_vals);
- const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len);
- defer self.gpa.free(llvm_param_vals);
+ for (args) |arg, i| {
+ llvm_param_vals[i] = try self.resolveInst(arg);
+ }
- for (args) |arg, i| {
- llvm_param_vals[i] = try self.resolveInst(arg);
- }
+ const call = self.builder.buildCall(
+ llvm_fn,
+ llvm_param_vals.ptr,
+ @intCast(c_uint, args.len),
+ "",
+ );
- // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs
- // Do we need that?
- const call = self.builder.buildCall(
- llvm_fn,
- llvm_param_vals.ptr,
- @intCast(c_uint, args.len),
- "",
- );
-
- const return_type = zig_fn_type.fnReturnType();
- if (return_type.tag() == .noreturn) {
- _ = self.builder.buildUnreachable();
- }
+ if (return_type.isNoReturn()) {
+ _ = self.builder.buildUnreachable();
+ }
- // No need to store the LLVM value if the return type is void or noreturn
- if (!return_type.hasCodeGenBits()) return null;
+ // No need to store the LLVM value if the return type is void or noreturn
+ if (!return_type.hasCodeGenBits()) return null;
- return call;
- } else {
- return self.todo("implement calling runtime known function pointer", .{});
- }
+ return call;
}
fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
@@ -1026,6 +1112,11 @@ pub const FuncGen = struct {
return null;
}
+ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ _ = inst;
+ return self.todo("implement llvm codegen for switch_br", .{});
+ }
+
fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const loop = self.air.extraData(Air.Block, ty_pl.payload);
@@ -1082,10 +1173,32 @@ pub const FuncGen = struct {
};
const indices: [1]*const llvm.Value = .{rhs};
- const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, 1, "");
+ const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
return self.builder.buildLoad(ptr, "");
}
+ fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
+ const struct_ptr = try self.resolveInst(struct_field.struct_operand);
+ const field_index = @intCast(c_uint, struct_field.field_index);
+ return self.builder.buildStructGEP(struct_ptr, field_index, "");
+ }
+
+ fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
+ const struct_byval = try self.resolveInst(struct_field.struct_operand);
+ const field_index = @intCast(c_uint, struct_field.field_index);
+ return self.builder.buildExtractValue(struct_byval, field_index, "");
+ }
+
fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
@@ -1321,7 +1434,7 @@ pub const FuncGen = struct {
_ = operand;
_ = operand_is_ptr;
- return self.todo("implement 'airErrUnionPayload' for type {}", .{self.air.typeOf(ty_op.operand)});
+ return self.todo("implement llvm codegen for 'airErrUnionPayload' for type {}", .{self.air.typeOf(ty_op.operand)});
}
fn airErrUnionErr(
@@ -1332,42 +1445,123 @@ pub const FuncGen = struct {
if (self.liveness.isUnused(inst))
return null;
- _ = operand_is_ptr;
- return self.todo("implement 'airErrUnionErr'", .{});
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand = try self.resolveInst(ty_op.operand);
+ const operand_ty = self.air.typeOf(ty_op.operand);
+
+ const payload_ty = operand_ty.errorUnionPayload();
+ if (!payload_ty.hasCodeGenBits()) {
+ if (!operand_is_ptr) return operand;
+ return self.builder.buildLoad(operand, "");
+ }
+ return self.todo("implement llvm codegen for 'airErrUnionErr'", .{});
+ }
+
+ fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+
+ return self.todo("implement llvm codegen for 'airWrapOptional'", .{});
+ }
+
+ fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+
+ return self.todo("implement llvm codegen for 'airWrapErrUnionPayload'", .{});
+ }
+
+ fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+
+ return self.todo("implement llvm codegen for 'airWrapErrUnionErr'", .{});
}
- fn airAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ fn airAdd(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
+
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
- if (!inst_ty.isInt())
- return self.todo("implement 'airAdd' for type {}", .{inst_ty});
+ if (inst_ty.isFloat()) return self.builder.buildFAdd(lhs, rhs, "");
+ if (wrap) return self.builder.buildAdd(lhs, rhs, "");
+ if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
+ return self.builder.buildNUWAdd(lhs, rhs, "");
+ }
- return if (inst_ty.isSignedInt())
- self.builder.buildNSWAdd(lhs, rhs, "")
- else
- self.builder.buildNUWAdd(lhs, rhs, "");
+ fn airSub(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ const inst_ty = self.air.typeOfIndex(inst);
+
+ if (inst_ty.isFloat()) return self.builder.buildFSub(lhs, rhs, "");
+ if (wrap) return self.builder.buildSub(lhs, rhs, "");
+ if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
+ return self.builder.buildNUWSub(lhs, rhs, "");
}
- fn airSub(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ fn airMul(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
+
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
- if (!inst_ty.isInt())
- return self.todo("implement 'airSub' for type {}", .{inst_ty});
+ if (inst_ty.isFloat()) return self.builder.buildFMul(lhs, rhs, "");
+ if (wrap) return self.builder.buildMul(lhs, rhs, "");
+ if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
+ return self.builder.buildNUWMul(lhs, rhs, "");
+ }
- return if (inst_ty.isSignedInt())
- self.builder.buildNSWSub(lhs, rhs, "")
- else
- self.builder.buildNUWSub(lhs, rhs, "");
+ fn airDiv(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ const inst_ty = self.air.typeOfIndex(inst);
+
+ if (inst_ty.isFloat()) return self.builder.buildFDiv(lhs, rhs, "");
+ if (inst_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
+ return self.builder.buildUDiv(lhs, rhs, "");
+ }
+
+ fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ return self.builder.buildAnd(lhs, rhs, "");
+ }
+
+ fn airOr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ return self.builder.buildOr(lhs, rhs, "");
+ }
+
+ fn airXor(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ return self.builder.buildXor(lhs, rhs, "");
}
fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
@@ -1384,6 +1578,14 @@ pub const FuncGen = struct {
return self.builder.buildIntCast2(operand, try self.dg.llvmType(inst_ty), llvm.Bool.fromBool(signed), "");
}
+ fn airFloatCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+
+ // TODO split floatcast AIR into float_widen and float_shorten
+ return self.todo("implement 'airFloatCast'", .{});
+ }
+
fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
@@ -1474,8 +1676,8 @@ pub const FuncGen = struct {
fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
_ = inst;
- const llvn_fn = self.getIntrinsic("llvm.debugtrap");
- _ = self.builder.buildCall(llvn_fn, undefined, 0, "");
+ const llvm_fn = self.getIntrinsic("llvm.debugtrap");
+ _ = self.builder.buildCall(llvm_fn, undefined, 0, "");
return null;
}
src/codegen/wasm.zig
@@ -1306,7 +1306,7 @@ pub const Context = struct {
fn airStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.StructField, ty_pl.payload);
- const struct_ptr = self.resolveInst(extra.data.struct_ptr);
+ const struct_ptr = self.resolveInst(extra.data.struct_operand);
return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, extra.data.field_index) };
}
src/link/Coff.zig
@@ -777,8 +777,18 @@ pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {
self.offset_table_free_list.append(self.base.allocator, decl.link.coff.offset_table_index) catch {};
}
-pub fn updateDeclExports(self: *Coff, module: *Module, decl: *Module.Decl, exports: []const *Module.Export) !void {
- if (self.llvm_object) |_| return;
+pub fn updateDeclExports(
+ self: *Coff,
+ module: *Module,
+ decl: *Module.Decl,
+ exports: []const *Module.Export,
+) !void {
+ if (build_options.skip_non_native and builtin.object_format != .coff) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl, exports);
+ }
for (exports) |exp| {
if (exp.options.section) |section_name| {
src/link/Elf.zig
@@ -2716,7 +2716,12 @@ pub fn updateDeclExports(
decl: *Module.Decl,
exports: []const *Module.Export,
) !void {
- if (self.llvm_object) |_| return;
+ if (build_options.skip_non_native and builtin.object_format != .elf) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl, exports);
+ }
const tracy = trace(@src());
defer tracy.end();
src/link/MachO.zig
@@ -3785,6 +3785,12 @@ pub fn updateDeclExports(
decl: *Module.Decl,
exports: []const *Module.Export,
) !void {
+ if (build_options.skip_non_native and builtin.object_format != .macho) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl, exports);
+ }
const tracy = trace(@src());
defer tracy.end();
src/link/Wasm.zig
@@ -330,10 +330,12 @@ pub fn updateDeclExports(
decl: *const Module.Decl,
exports: []const *Module.Export,
) !void {
- _ = self;
- _ = module;
- _ = decl;
- _ = exports;
+ if (build_options.skip_non_native and builtin.object_format != .wasm) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl, exports);
+ }
}
pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
src/Air.zig
@@ -247,6 +247,9 @@ pub const Inst = struct {
/// Given a pointer to a struct and a field index, returns a pointer to the field.
/// Uses the `ty_pl` field, payload is `StructField`.
struct_field_ptr,
+ /// Given a byval struct and a field index, returns the field byval.
+ /// Uses the `ty_pl` field, payload is `StructField`.
+ struct_field_val,
/// Given a slice value, return the length.
/// Result type is always usize.
/// Uses the `ty_op` field.
@@ -376,7 +379,8 @@ pub const SwitchBr = struct {
};
pub const StructField = struct {
- struct_ptr: Inst.Ref,
+ /// Whether this is a pointer or byval is determined by the AIR tag.
+ struct_operand: Inst.Ref,
field_index: u32,
};
@@ -448,6 +452,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.constant,
.varptr,
.struct_field_ptr,
+ .struct_field_val,
=> return air.getRefType(datas[inst].ty_pl.ty),
.not,
src/codegen.zig
@@ -851,6 +851,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.ret => try self.airRet(inst),
.store => try self.airStore(inst),
.struct_field_ptr=> try self.airStructFieldPtr(inst),
+ .struct_field_val=> try self.airStructFieldVal(inst),
.switch_br => try self.airSwitch(inst),
.varptr => try self.airVarPtr(inst),
.slice_ptr => try self.airSlicePtr(inst),
@@ -1501,6 +1502,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
//return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
}
+ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
+ _ = extra;
+ return self.fail("TODO implement codegen struct_field_val", .{});
+ //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
+ }
+
fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool {
return switch (mcv) {
.none => unreachable,
src/Liveness.zig
@@ -320,9 +320,9 @@ fn analyzeInst(
}
return extra_tombs.finish();
},
- .struct_field_ptr => {
+ .struct_field_ptr, .struct_field_val => {
const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;
- return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_ptr, .none, .none });
+ return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });
},
.br => {
const br = inst_datas[inst].br;
src/Module.zig
@@ -3702,8 +3702,8 @@ pub fn analyzeExport(
else => return mod.fail(scope, src, "unable to export type '{}'", .{exported_decl.ty}),
}
- try mod.decl_exports.ensureCapacity(mod.gpa, mod.decl_exports.count() + 1);
- try mod.export_owners.ensureCapacity(mod.gpa, mod.export_owners.count() + 1);
+ try mod.decl_exports.ensureUnusedCapacity(mod.gpa, 1);
+ try mod.export_owners.ensureUnusedCapacity(mod.gpa, 1);
const new_export = try mod.gpa.create(Export);
errdefer mod.gpa.destroy(new_export);
src/print_air.zig
@@ -171,7 +171,8 @@ const Writer = struct {
.loop,
=> try w.writeBlock(s, inst),
- .struct_field_ptr => try w.writeStructFieldPtr(s, inst),
+ .struct_field_ptr => try w.writeStructField(s, inst),
+ .struct_field_val => try w.writeStructField(s, inst),
.varptr => try w.writeVarPtr(s, inst),
.constant => try w.writeConstant(s, inst),
.assembly => try w.writeAssembly(s, inst),
@@ -233,11 +234,11 @@ const Writer = struct {
try s.writeAll("}");
}
- fn writeStructFieldPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
const extra = w.air.extraData(Air.StructField, ty_pl.payload);
- try w.writeOperand(s, inst, 0, extra.data.struct_ptr);
+ try w.writeOperand(s, inst, 0, extra.data.struct_operand);
try s.print(", {d}", .{extra.data.field_index});
}
src/Sema.zig
@@ -655,7 +655,7 @@ fn resolveDefinedValue(
src: LazySrcLoc,
air_ref: Air.Inst.Ref,
) CompileError!?Value {
- if (try sema.resolvePossiblyUndefinedValue(block, src, air_ref)) |val| {
+ if (try sema.resolveMaybeUndefVal(block, src, air_ref)) |val| {
if (val.isUndef()) {
return sema.failWithUseOfUndef(block, src);
}
@@ -664,7 +664,7 @@ fn resolveDefinedValue(
return null;
}
-fn resolvePossiblyUndefinedValue(
+fn resolveMaybeUndefVal(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
@@ -1293,7 +1293,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
};
return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
}
- const result_ptr = try sema.namedFieldPtr(block, src, array_ptr, "len", src);
+ const result_ptr = try sema.fieldPtr(block, src, array_ptr, "len", src);
const result_ptr_src = array_ptr_src;
return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
}
@@ -1789,7 +1789,7 @@ fn zirCompileLog(
const arg = sema.resolveInst(arg_ref);
const arg_ty = sema.typeOf(arg);
- if (try sema.resolvePossiblyUndefinedValue(block, src, arg)) |val| {
+ if (try sema.resolveMaybeUndefVal(block, src, arg)) |val| {
try writer.print("@as({}, {})", .{ arg_ty, val });
} else {
try writer.print("@as({}, [runtime value])", .{arg_ty});
@@ -2579,7 +2579,7 @@ fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile
const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src);
const result_ty = Type.initTag(.u16);
- if (try sema.resolvePossiblyUndefinedValue(block, src, op_coerced)) |val| {
+ if (try sema.resolveMaybeUndefVal(block, src, op_coerced)) |val| {
if (val.isUndef()) {
return sema.addConstUndef(result_ty);
}
@@ -2759,7 +2759,7 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
return sema.addConstant(int_tag_ty, opv);
}
- if (try sema.resolvePossiblyUndefinedValue(block, operand_src, enum_tag)) |enum_tag_val| {
+ if (try sema.resolveMaybeUndefVal(block, operand_src, enum_tag)) |enum_tag_val| {
if (enum_tag_val.castTag(.enum_field_index)) |enum_field_payload| {
const field_index = enum_field_payload.data;
switch (enum_tag_ty.tag()) {
@@ -2806,7 +2806,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});
}
- if (try sema.resolvePossiblyUndefinedValue(block, operand_src, operand)) |int_val| {
+ if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |int_val| {
if (dest_ty.isNonexhaustiveEnum()) {
return sema.addConstant(dest_ty, int_val);
}
@@ -3309,16 +3309,16 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
+ const lhs_src: LazySrcLoc = src; // TODO
const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
const field_name = sema.code.nullTerminatedString(extra.field_name_start);
const object = sema.resolveInst(extra.lhs);
- const object_ptr = if (sema.typeOf(object).zigTypeTag() == .Pointer)
- object
- else
- try sema.analyzeRef(block, src, object);
- const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
- const result_ptr_src = src;
- return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
+ if (sema.typeOf(object).isSinglePointer()) {
+ const result_ptr = try sema.fieldPtr(block, src, object, field_name, field_name_src);
+ return sema.analyzeLoad(block, src, result_ptr, lhs_src);
+ } else {
+ return sema.fieldVal(block, src, object, field_name, field_name_src);
+ }
}
fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -3331,7 +3331,7 @@ fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
const field_name = sema.code.nullTerminatedString(extra.field_name_start);
const object_ptr = sema.resolveInst(extra.lhs);
- return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
+ return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src);
}
fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -3344,9 +3344,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp
const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
const object = sema.resolveInst(extra.lhs);
const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
- const object_ptr = try sema.analyzeRef(block, src, object);
- const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
- return sema.analyzeLoad(block, src, result_ptr, src);
+ return sema.fieldVal(block, src, object, field_name, field_name_src);
}
fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -3359,7 +3357,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp
const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
const object_ptr = sema.resolveInst(extra.lhs);
const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
- return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
+ return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src);
}
fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -4691,8 +4689,8 @@ fn zirBitwise(
return sema.mod.fail(&block.base, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });
}
- if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, casted_lhs)) |lhs_val| {
- if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, casted_rhs)) |rhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
if (lhs_val.isUndef() or rhs_val.isUndef()) {
return sema.addConstUndef(resolved_type);
}
@@ -4823,8 +4821,8 @@ fn analyzeArithmetic(
return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });
}
- if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, casted_lhs)) |lhs_val| {
- if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, casted_rhs)) |rhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
if (lhs_val.isUndef() or rhs_val.isUndef()) {
return sema.addConstUndef(resolved_type);
}
@@ -5038,8 +5036,8 @@ fn zirCmp(
if (!is_equality_cmp) {
return mod.fail(&block.base, src, "{s} operator not allowed for errors", .{@tagName(op)});
}
- if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, lhs)) |lval| {
- if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, rhs)) |rval| {
+ if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lval| {
+ if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rval| {
if (lval.isUndef() or rval.isUndef()) {
return sema.addConstUndef(Type.initTag(.bool));
}
@@ -5085,8 +5083,8 @@ fn zirCmp(
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, casted_lhs)) |lhs_val| {
- if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, casted_rhs)) |rhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
if (lhs_val.isUndef() or rhs_val.isUndef()) {
return sema.addConstUndef(resolved_type);
}
@@ -5759,7 +5757,7 @@ fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref:
if (is_comptime) {
const values = try sema.arena.alloc(Value, field_inits.len);
for (field_inits) |field_init, i| {
- values[i] = (sema.resolvePossiblyUndefinedValue(block, src, field_init) catch unreachable).?;
+ values[i] = (sema.resolveMaybeUndefVal(block, src, field_init) catch unreachable).?;
}
return sema.addConstant(struct_ty, try Value.Tag.@"struct".create(sema.arena, values.ptr));
}
@@ -6234,7 +6232,7 @@ fn zirVarExtended(
const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
const init_air_inst = sema.resolveInst(init_ref);
- break :blk (try sema.resolvePossiblyUndefinedValue(block, init_src, init_air_inst)) orelse
+ break :blk (try sema.resolveMaybeUndefVal(block, init_src, init_air_inst)) orelse
return sema.failWithNeededComptime(block, init_src);
} else Value.initTag(.unreachable_value);
@@ -6565,31 +6563,203 @@ fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
}
}
-fn namedFieldPtr(
+fn fieldVal(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
- object_ptr: Air.Inst.Ref,
+ object: Air.Inst.Ref,
field_name: []const u8,
field_name_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ // When editing this function, note that there is corresponding logic to be edited
+ // in `fieldPtr`. This function takes a value and returns a value.
+
const mod = sema.mod;
const arena = sema.arena;
+ const object_src = src; // TODO better source location
+ const object_ty = sema.typeOf(object);
+
+ switch (object_ty.zigTypeTag()) {
+ .Array => {
+ if (mem.eql(u8, field_name, "len")) {
+ return sema.addConstant(
+ Type.initTag(.comptime_int),
+ try Value.Tag.int_u64.create(arena, object_ty.arrayLen()),
+ );
+ } else {
+ return mod.fail(
+ &block.base,
+ field_name_src,
+ "no member named '{s}' in '{}'",
+ .{ field_name, object_ty },
+ );
+ }
+ },
+ .Pointer => switch (object_ty.ptrSize()) {
+ .Slice => {
+ if (mem.eql(u8, field_name, "ptr")) {
+ const buf = try arena.create(Type.Payload.ElemType);
+ const result_ty = object_ty.slicePtrFieldType(buf);
+ if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
+ if (val.isUndef()) return sema.addConstUndef(result_ty);
+ return mod.fail(
+ &block.base,
+ field_name_src,
+ "TODO implement comptime slice ptr",
+ .{},
+ );
+ }
+ try sema.requireRuntimeBlock(block, src);
+ return block.addTyOp(.slice_ptr, result_ty, object);
+ } else if (mem.eql(u8, field_name, "len")) {
+ const result_ty = Type.initTag(.usize);
+ if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
+ if (val.isUndef()) return sema.addConstUndef(result_ty);
+ return sema.addConstant(
+ result_ty,
+ try Value.Tag.int_u64.create(arena, val.sliceLen()),
+ );
+ }
+ try sema.requireRuntimeBlock(block, src);
+ return block.addTyOp(.slice_len, result_ty, object);
+ } else {
+ return mod.fail(
+ &block.base,
+ field_name_src,
+ "no member named '{s}' in '{}'",
+ .{ field_name, object_ty },
+ );
+ }
+ },
+ .One => {
+ const elem_ty = object_ty.elemType();
+ if (elem_ty.zigTypeTag() == .Array) {
+ if (mem.eql(u8, field_name, "len")) {
+ return sema.addConstant(
+ Type.initTag(.comptime_int),
+ try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
+ );
+ } else {
+ return mod.fail(
+ &block.base,
+ field_name_src,
+ "no member named '{s}' in '{}'",
+ .{ field_name, object_ty },
+ );
+ }
+ }
+ },
+ .Many, .C => {},
+ },
+ .Type => {
+ const val = (try sema.resolveDefinedValue(block, object_src, object)).?;
+ const child_type = try val.toType(arena);
+ switch (child_type.zigTypeTag()) {
+ .ErrorSet => {
+ // TODO resolve inferred error sets
+ const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
+ const error_set = payload.data;
+ // TODO this is O(N). I'm putting off solving this until we solve inferred
+ // error sets at the same time.
+ const names = error_set.names_ptr[0..error_set.names_len];
+ for (names) |name| {
+ if (mem.eql(u8, field_name, name)) {
+ break :blk name;
+ }
+ }
+ return mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
+ field_name, child_type,
+ });
+ } else (try mod.getErrorValue(field_name)).key;
+
+ return sema.addConstant(
+ child_type,
+ try Value.Tag.@"error".create(arena, .{ .name = name }),
+ );
+ },
+ .Struct, .Opaque, .Union => {
+ if (child_type.getNamespace()) |namespace| {
+ if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
+ return sema.analyzeLoad(block, src, inst, src);
+ }
+ }
+ // TODO add note: declared here
+ const kw_name = switch (child_type.zigTypeTag()) {
+ .Struct => "struct",
+ .Opaque => "opaque",
+ .Union => "union",
+ else => unreachable,
+ };
+ return mod.fail(&block.base, src, "{s} '{}' has no member named '{s}'", .{
+ kw_name, child_type, field_name,
+ });
+ },
+ .Enum => {
+ if (child_type.getNamespace()) |namespace| {
+ if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
+ return sema.analyzeLoad(block, src, inst, src);
+ }
+ }
+ const field_index = child_type.enumFieldIndex(field_name) orelse {
+ const msg = msg: {
+ const msg = try mod.errMsg(
+ &block.base,
+ src,
+ "enum '{}' has no member named '{s}'",
+ .{ child_type, field_name },
+ );
+ errdefer msg.destroy(sema.gpa);
+ try mod.errNoteNonLazy(
+ child_type.declSrcLoc(),
+ msg,
+ "enum declared here",
+ .{},
+ );
+ break :msg msg;
+ };
+ return mod.failWithOwnedErrorMsg(&block.base, msg);
+ };
+ const field_index_u32 = @intCast(u32, field_index);
+ const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
+ return sema.addConstant(child_type, enum_val);
+ },
+ else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
+ }
+ },
+ .Struct => return sema.structFieldVal(block, src, object, field_name, field_name_src, object_ty),
+ .Union => return sema.unionFieldVal(block, src, object, field_name, field_name_src, object_ty),
+ else => {},
+ }
+ return mod.fail(&block.base, src, "type '{}' does not support field access", .{object_ty});
+}
+fn fieldPtr(
+ sema: *Sema,
+ block: *Scope.Block,
+ src: LazySrcLoc,
+ object_ptr: Air.Inst.Ref,
+ field_name: []const u8,
+ field_name_src: LazySrcLoc,
+) CompileError!Air.Inst.Ref {
+ // When editing this function, note that there is corresponding logic to be edited
+ // in `fieldVal`. This function takes a pointer and returns a pointer.
+
+ const mod = sema.mod;
+ const arena = sema.arena;
const object_ptr_src = src; // TODO better source location
const object_ptr_ty = sema.typeOf(object_ptr);
- const elem_ty = switch (object_ptr_ty.zigTypeTag()) {
+ const object_ty = switch (object_ptr_ty.zigTypeTag()) {
.Pointer => object_ptr_ty.elemType(),
else => return mod.fail(&block.base, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}),
};
- switch (elem_ty.zigTypeTag()) {
+ switch (object_ty.zigTypeTag()) {
.Array => {
if (mem.eql(u8, field_name, "len")) {
return sema.addConstant(
Type.initTag(.single_const_pointer_to_comptime_int),
try Value.Tag.ref_val.create(
arena,
- try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
+ try Value.Tag.int_u64.create(arena, object_ty.arrayLen()),
),
);
} else {
@@ -6597,33 +6767,33 @@ fn namedFieldPtr(
&block.base,
field_name_src,
"no member named '{s}' in '{}'",
- .{ field_name, elem_ty },
+ .{ field_name, object_ty },
);
}
},
.Pointer => {
- const ptr_child = elem_ty.elemType();
+ const ptr_child = object_ty.elemType();
if (ptr_child.isSlice()) {
if (mem.eql(u8, field_name, "ptr")) {
return mod.fail(
&block.base,
field_name_src,
"cannot obtain reference to pointer field of slice '{}'",
- .{elem_ty},
+ .{object_ty},
);
} else if (mem.eql(u8, field_name, "len")) {
return mod.fail(
&block.base,
field_name_src,
"cannot obtain reference to length field of slice '{}'",
- .{elem_ty},
+ .{object_ty},
);
} else {
return mod.fail(
&block.base,
field_name_src,
"no member named '{s}' in '{}'",
- .{ field_name, elem_ty },
+ .{ field_name, object_ty },
);
}
} else switch (ptr_child.zigTypeTag()) {
@@ -6641,7 +6811,7 @@ fn namedFieldPtr(
&block.base,
field_name_src,
"no member named '{s}' in '{}'",
- .{ field_name, elem_ty },
+ .{ field_name, object_ty },
);
}
},
@@ -6684,7 +6854,7 @@ fn namedFieldPtr(
},
.Struct, .Opaque, .Union => {
if (child_type.getNamespace()) |namespace| {
- if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| {
+ if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
return inst;
}
}
@@ -6701,7 +6871,7 @@ fn namedFieldPtr(
},
.Enum => {
if (child_type.getNamespace()) |namespace| {
- if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| {
+ if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
return inst;
}
}
@@ -6734,20 +6904,20 @@ fn namedFieldPtr(
else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
}
},
- .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
- .Union => return sema.analyzeUnionFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
+ .Struct => return sema.structFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty),
+ .Union => return sema.unionFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty),
else => {},
}
- return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
+ return mod.fail(&block.base, src, "type '{}' does not support field access", .{object_ty});
}
-fn analyzeNamespaceLookup(
+fn namespaceLookup(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
namespace: *Scope.Namespace,
decl_name: []const u8,
-) CompileError!?Air.Inst.Ref {
+) CompileError!?*Decl {
const mod = sema.mod;
const gpa = sema.gpa;
if (try sema.lookupInNamespace(namespace, decl_name)) |decl| {
@@ -6762,12 +6932,23 @@ fn analyzeNamespaceLookup(
};
return mod.failWithOwnedErrorMsg(&block.base, msg);
}
- return try sema.analyzeDeclRef(block, src, decl);
+ return decl;
}
return null;
}
-fn analyzeStructFieldPtr(
+fn namespaceLookupRef(
+ sema: *Sema,
+ block: *Scope.Block,
+ src: LazySrcLoc,
+ namespace: *Scope.Namespace,
+ decl_name: []const u8,
+) CompileError!?Air.Inst.Ref {
+ const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
+ return try sema.analyzeDeclRef(block, src, decl);
+}
+
+fn structFieldPtr(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
@@ -6803,14 +6984,52 @@ fn analyzeStructFieldPtr(
.data = .{ .ty_pl = .{
.ty = try sema.addType(ptr_field_ty),
.payload = try sema.addExtra(Air.StructField{
- .struct_ptr = struct_ptr,
+ .struct_operand = struct_ptr,
.field_index = @intCast(u32, field_index),
}),
} },
});
}
-fn analyzeUnionFieldPtr(
+fn structFieldVal(
+ sema: *Sema,
+ block: *Scope.Block,
+ src: LazySrcLoc,
+ struct_byval: Air.Inst.Ref,
+ field_name: []const u8,
+ field_name_src: LazySrcLoc,
+ unresolved_struct_ty: Type,
+) CompileError!Air.Inst.Ref {
+ assert(unresolved_struct_ty.zigTypeTag() == .Struct);
+
+ const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
+ const struct_obj = struct_ty.castTag(.@"struct").?.data;
+
+ const field_index = struct_obj.fields.getIndex(field_name) orelse
+ return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
+ const field = struct_obj.fields.values()[field_index];
+
+ if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {
+ if (struct_val.isUndef()) return sema.addConstUndef(field.ty);
+
+ const field_values = struct_val.castTag(.@"struct").?.data;
+ return sema.addConstant(field.ty, field_values[field_index]);
+ }
+
+ try sema.requireRuntimeBlock(block, src);
+ return block.addInst(.{
+ .tag = .struct_field_val,
+ .data = .{ .ty_pl = .{
+ .ty = try sema.addType(field.ty),
+ .payload = try sema.addExtra(Air.StructField{
+ .struct_operand = struct_byval,
+ .field_index = @intCast(u32, field_index),
+ }),
+ } },
+ });
+}
+
+fn unionFieldPtr(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
@@ -6847,6 +7066,37 @@ fn analyzeUnionFieldPtr(
return mod.fail(&block.base, src, "TODO implement runtime union field access", .{});
}
+fn unionFieldVal(
+ sema: *Sema,
+ block: *Scope.Block,
+ src: LazySrcLoc,
+ union_byval: Air.Inst.Ref,
+ field_name: []const u8,
+ field_name_src: LazySrcLoc,
+ unresolved_union_ty: Type,
+) CompileError!Air.Inst.Ref {
+ assert(unresolved_union_ty.zigTypeTag() == .Union);
+
+ const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
+ const union_obj = union_ty.cast(Type.Payload.Union).?.data;
+
+ const field_index = union_obj.fields.getIndex(field_name) orelse
+ return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);
+
+ const field = union_obj.fields.values()[field_index];
+
+ if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| {
+ if (union_val.isUndef()) return sema.addConstUndef(field.ty);
+
+ // TODO detect inactive union field and emit compile error
+ const active_val = union_val.castTag(.@"union").?.data.val;
+ return sema.addConstant(field.ty, active_val);
+ }
+
+ try sema.requireRuntimeBlock(block, src);
+ return sema.mod.fail(&block.base, src, "TODO implement runtime union field access", .{});
+}
+
fn elemPtr(
sema: *Sema,
block: *Scope.Block,
@@ -6973,7 +7223,7 @@ fn coerce(
const arena = sema.arena;
// undefined to anything
- if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {
+ if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
if (val.isUndef() or inst_ty.zigTypeTag() == .Undefined) {
return sema.addConstant(dest_type, val);
}
@@ -7207,8 +7457,8 @@ fn storePtr(
if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
return;
- if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| blk: {
- const const_val = (try sema.resolvePossiblyUndefinedValue(block, src, value)) orelse
+ if (try sema.resolveMaybeUndefVal(block, src, ptr)) |ptr_val| blk: {
+ const const_val = (try sema.resolveMaybeUndefVal(block, src, value)) orelse
return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});
if (ptr_val.tag() == .int_u64)
@@ -7252,7 +7502,7 @@ fn bitcast(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
- if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {
+ if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
// Keep the comptime Value representation; take the new type.
return sema.addConstant(dest_type, val);
}
@@ -7358,7 +7608,7 @@ fn analyzeRef(
const operand_ty = sema.typeOf(operand);
const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);
- if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |val| {
+ if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
return sema.addConstant(ptr_type, try Value.Tag.ref_val.create(sema.arena, val));
}
@@ -7395,7 +7645,7 @@ fn analyzeSliceLen(
src: LazySrcLoc,
slice_inst: Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
- if (try sema.resolvePossiblyUndefinedValue(block, src, slice_inst)) |slice_val| {
+ if (try sema.resolveMaybeUndefVal(block, src, slice_inst)) |slice_val| {
if (slice_val.isUndef()) {
return sema.addConstUndef(Type.initTag(.usize));
}
@@ -7413,7 +7663,7 @@ fn analyzeIsNull(
invert_logic: bool,
) CompileError!Air.Inst.Ref {
const result_ty = Type.initTag(.bool);
- if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |opt_val| {
+ if (try sema.resolveMaybeUndefVal(block, src, operand)) |opt_val| {
if (opt_val.isUndef()) {
return sema.addConstUndef(result_ty);
}
@@ -7442,7 +7692,7 @@ fn analyzeIsNonErr(
if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
assert(ot == .ErrorUnion);
const result_ty = Type.initTag(.bool);
- if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |err_union| {
+ if (try sema.resolveMaybeUndefVal(block, src, operand)) |err_union| {
if (err_union.isUndef()) {
return sema.addConstUndef(result_ty);
}
@@ -7567,8 +7817,8 @@ fn cmpNumeric(
});
}
- if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, lhs)) |lhs_val| {
- if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, rhs)) |rhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
if (lhs_val.isUndef() or rhs_val.isUndef()) {
return sema.addConstUndef(Type.initTag(.bool));
}
@@ -7635,7 +7885,7 @@ fn cmpNumeric(
var dest_float_type: ?Type = null;
var lhs_bits: usize = undefined;
- if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, lhs)) |lhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
if (lhs_val.isUndef())
return sema.addConstUndef(Type.initTag(.bool));
const is_unsigned = if (lhs_is_float) x: {
@@ -7670,7 +7920,7 @@ fn cmpNumeric(
}
var rhs_bits: usize = undefined;
- if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, rhs)) |rhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
if (rhs_val.isUndef())
return sema.addConstUndef(Type.initTag(.bool));
const is_unsigned = if (rhs_is_float) x: {
@@ -7725,7 +7975,7 @@ fn wrapOptional(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
- if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {
+ if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
return sema.addConstant(dest_type, val);
}
@@ -7743,7 +7993,7 @@ fn wrapErrorUnion(
const inst_ty = sema.typeOf(inst);
const dest_err_set_ty = dest_type.errorUnionSet();
const dest_payload_ty = dest_type.errorUnionPayload();
- if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {
+ if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
if (inst_ty.zigTypeTag() != .ErrorSet) {
_ = try sema.coerce(block, dest_payload_ty, inst, inst_src);
} else switch (dest_err_set_ty.tag()) {
@@ -7956,7 +8206,7 @@ fn getBuiltin(
const mod = sema.mod;
const std_pkg = mod.main_pkg.table.get("std").?;
const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
- const opt_builtin_inst = try sema.analyzeNamespaceLookup(
+ const opt_builtin_inst = try sema.namespaceLookupRef(
block,
src,
std_file.root_decl.?.namespace,
@@ -7964,7 +8214,7 @@ fn getBuiltin(
);
const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst.?, src);
const builtin_ty = try sema.analyzeAsType(block, src, builtin_inst);
- const opt_ty_inst = try sema.analyzeNamespaceLookup(
+ const opt_ty_inst = try sema.namespaceLookupRef(
block,
src,
builtin_ty.getNamespace().?,
@@ -8320,5 +8570,5 @@ fn isComptimeKnown(
src: LazySrcLoc,
inst: Air.Inst.Ref,
) !bool {
- return (try sema.resolvePossiblyUndefinedValue(block, src, inst)) != null;
+ return (try sema.resolveMaybeUndefVal(block, src, inst)) != null;
}