authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-26 19:12:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-26 19:27:49-07:00
log31a59c229cb39b9ffd1ee3397a1ce87c36b91477
treef4074655750f90c6350a8f3070343da9a724ccfd
parentcdeea3b0943b070d49d8d8d0855f9a38843e3ecc

stage2: improvements towards `zig test`

* Add AIR instruction: struct_field_val - This is part of an effort to eliminate the AIR instruction `ref`. - It's implemented for C backend and LLVM backend so far. * Rename `resolvePossiblyUndefinedValue` to `resolveMaybeUndefVal` just to save some columns on long lines. * Sema: add `fieldVal` alongside `fieldPtr` (renamed from `namedFieldPtr`). This is part of an effort to eliminate the AIR instruction `ref`. The idea is to avoid unnecessary loads, stores, stack usage, and IR instructions, by paying a DRY cost. LLVM backend improvements: * internal linkage vs exported linkage is implemented, along with aliases. There is an issue with incremental updates due to missing LLVM API for deleting aliases; see the relevant comment in this commit. - `updateDeclExports` is hooked up to the LLVM backend now. * Fix usage of `Type.tag() == .noreturn` rather than calling `isNoReturn()`. * Properly mark global variables as mutable/constant. * Fix llvm type generation of function pointers * Fix codegen for calls of function pointers * Implement llvm type generation of error unions and error sets. * Implement AIR instructions: addwrap, subwrap, mul, mulwrap, div, bit_and, bool_and, bit_or, bool_or, xor, struct_field_ptr, struct_field_val, unwrap_errunion_err, add for floats, sub for floats. After this commit, `zig test` on a file with `test "example" {}` correctly generates and executes a test binary. However the `test_functions` slice is undefined and just happens to be going into the .bss section, causing the length to be 0. The next step towards `zig test` will be replacing the `test_functions` Decl Value with the set of test function pointers, before it is sent to linker/codegen.

14 files changed, 804 insertions(+), 164 deletions(-)

src/Air.zig+6-1
...@@ -247,6 +247,9 @@ pub const Inst = struct {...@@ -247,6 +247,9 @@ pub const Inst = struct {
247 /// Given a pointer to a struct and a field index, returns a pointer to the field.247 /// Given a pointer to a struct and a field index, returns a pointer to the field.
248 /// Uses the `ty_pl` field, payload is `StructField`.248 /// Uses the `ty_pl` field, payload is `StructField`.
249 struct_field_ptr,249 struct_field_ptr,
250 /// Given a byval struct and a field index, returns the field byval.
251 /// Uses the `ty_pl` field, payload is `StructField`.
252 struct_field_val,
250 /// Given a slice value, return the length.253 /// Given a slice value, return the length.
251 /// Result type is always usize.254 /// Result type is always usize.
252 /// Uses the `ty_op` field.255 /// Uses the `ty_op` field.
...@@ -376,7 +379,8 @@ pub const SwitchBr = struct {...@@ -376,7 +379,8 @@ pub const SwitchBr = struct {
376};379};
377380
378pub const StructField = struct {381pub const StructField = struct {
379 struct_ptr: Inst.Ref,382 /// Whether this is a pointer or byval is determined by the AIR tag.
383 struct_operand: Inst.Ref,
380 field_index: u32,384 field_index: u32,
381};385};
382386
...@@ -448,6 +452,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -448,6 +452,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
448 .constant,452 .constant,
449 .varptr,453 .varptr,
450 .struct_field_ptr,454 .struct_field_ptr,
455 .struct_field_val,
451 => return air.getRefType(datas[inst].ty_pl.ty),456 => return air.getRefType(datas[inst].ty_pl.ty),
452457
453 .not,458 .not,
src/Liveness.zig+2-2
...@@ -320,9 +320,9 @@ fn analyzeInst(...@@ -320,9 +320,9 @@ fn analyzeInst(
320 }320 }
321 return extra_tombs.finish();321 return extra_tombs.finish();
322 },322 },
323 .struct_field_ptr => {323 .struct_field_ptr, .struct_field_val => {
324 const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;324 const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;
325 return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_ptr, .none, .none });325 return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });
326 },326 },
327 .br => {327 .br => {
328 const br = inst_datas[inst].br;328 const br = inst_datas[inst].br;
src/Module.zig+2-2
...@@ -3702,8 +3702,8 @@ pub fn analyzeExport(...@@ -3702,8 +3702,8 @@ pub fn analyzeExport(
3702 else => return mod.fail(scope, src, "unable to export type '{}'", .{exported_decl.ty}),3702 else => return mod.fail(scope, src, "unable to export type '{}'", .{exported_decl.ty}),
3703 }3703 }
37043704
3705 try mod.decl_exports.ensureCapacity(mod.gpa, mod.decl_exports.count() + 1);3705 try mod.decl_exports.ensureUnusedCapacity(mod.gpa, 1);
3706 try mod.export_owners.ensureCapacity(mod.gpa, mod.export_owners.count() + 1);3706 try mod.export_owners.ensureUnusedCapacity(mod.gpa, 1);
37073707
3708 const new_export = try mod.gpa.create(Export);3708 const new_export = try mod.gpa.create(Export);
3709 errdefer mod.gpa.destroy(new_export);3709 errdefer mod.gpa.destroy(new_export);
src/Sema.zig+318-68
...@@ -655,7 +655,7 @@ fn resolveDefinedValue(...@@ -655,7 +655,7 @@ fn resolveDefinedValue(
655 src: LazySrcLoc,655 src: LazySrcLoc,
656 air_ref: Air.Inst.Ref,656 air_ref: Air.Inst.Ref,
657) CompileError!?Value {657) CompileError!?Value {
658 if (try sema.resolvePossiblyUndefinedValue(block, src, air_ref)) |val| {658 if (try sema.resolveMaybeUndefVal(block, src, air_ref)) |val| {
659 if (val.isUndef()) {659 if (val.isUndef()) {
660 return sema.failWithUseOfUndef(block, src);660 return sema.failWithUseOfUndef(block, src);
661 }661 }
...@@ -664,7 +664,7 @@ fn resolveDefinedValue(...@@ -664,7 +664,7 @@ fn resolveDefinedValue(
664 return null;664 return null;
665}665}
666666
667fn resolvePossiblyUndefinedValue(667fn resolveMaybeUndefVal(
668 sema: *Sema,668 sema: *Sema,
669 block: *Scope.Block,669 block: *Scope.Block,
670 src: LazySrcLoc,670 src: LazySrcLoc,
...@@ -1293,7 +1293,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co...@@ -1293,7 +1293,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
1293 };1293 };
1294 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);1294 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
1295 }1295 }
1296 const result_ptr = try sema.namedFieldPtr(block, src, array_ptr, "len", src);1296 const result_ptr = try sema.fieldPtr(block, src, array_ptr, "len", src);
1297 const result_ptr_src = array_ptr_src;1297 const result_ptr_src = array_ptr_src;
1298 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);1298 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
1299}1299}
...@@ -1789,7 +1789,7 @@ fn zirCompileLog(...@@ -1789,7 +1789,7 @@ fn zirCompileLog(
17891789
1790 const arg = sema.resolveInst(arg_ref);1790 const arg = sema.resolveInst(arg_ref);
1791 const arg_ty = sema.typeOf(arg);1791 const arg_ty = sema.typeOf(arg);
1792 if (try sema.resolvePossiblyUndefinedValue(block, src, arg)) |val| {1792 if (try sema.resolveMaybeUndefVal(block, src, arg)) |val| {
1793 try writer.print("@as({}, {})", .{ arg_ty, val });1793 try writer.print("@as({}, {})", .{ arg_ty, val });
1794 } else {1794 } else {
1795 try writer.print("@as({}, [runtime value])", .{arg_ty});1795 try writer.print("@as({}, [runtime value])", .{arg_ty});
...@@ -2579,7 +2579,7 @@ fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile...@@ -2579,7 +2579,7 @@ fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile
2579 const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src);2579 const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src);
2580 const result_ty = Type.initTag(.u16);2580 const result_ty = Type.initTag(.u16);
25812581
2582 if (try sema.resolvePossiblyUndefinedValue(block, src, op_coerced)) |val| {2582 if (try sema.resolveMaybeUndefVal(block, src, op_coerced)) |val| {
2583 if (val.isUndef()) {2583 if (val.isUndef()) {
2584 return sema.addConstUndef(result_ty);2584 return sema.addConstUndef(result_ty);
2585 }2585 }
...@@ -2759,7 +2759,7 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE...@@ -2759,7 +2759,7 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
2759 return sema.addConstant(int_tag_ty, opv);2759 return sema.addConstant(int_tag_ty, opv);
2760 }2760 }
27612761
2762 if (try sema.resolvePossiblyUndefinedValue(block, operand_src, enum_tag)) |enum_tag_val| {2762 if (try sema.resolveMaybeUndefVal(block, operand_src, enum_tag)) |enum_tag_val| {
2763 if (enum_tag_val.castTag(.enum_field_index)) |enum_field_payload| {2763 if (enum_tag_val.castTag(.enum_field_index)) |enum_field_payload| {
2764 const field_index = enum_field_payload.data;2764 const field_index = enum_field_payload.data;
2765 switch (enum_tag_ty.tag()) {2765 switch (enum_tag_ty.tag()) {
...@@ -2806,7 +2806,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE...@@ -2806,7 +2806,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
2806 return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});2806 return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});
2807 }2807 }
28082808
2809 if (try sema.resolvePossiblyUndefinedValue(block, operand_src, operand)) |int_val| {2809 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |int_val| {
2810 if (dest_ty.isNonexhaustiveEnum()) {2810 if (dest_ty.isNonexhaustiveEnum()) {
2811 return sema.addConstant(dest_ty, int_val);2811 return sema.addConstant(dest_ty, int_val);
2812 }2812 }
...@@ -3309,16 +3309,16 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr...@@ -3309,16 +3309,16 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
3309 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;3309 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
3310 const src = inst_data.src();3310 const src = inst_data.src();
3311 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };3311 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
3312 const lhs_src: LazySrcLoc = src; // TODO
3312 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;3313 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
3313 const field_name = sema.code.nullTerminatedString(extra.field_name_start);3314 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
3314 const object = sema.resolveInst(extra.lhs);3315 const object = sema.resolveInst(extra.lhs);
3315 const object_ptr = if (sema.typeOf(object).zigTypeTag() == .Pointer)3316 if (sema.typeOf(object).isSinglePointer()) {
3316 object3317 const result_ptr = try sema.fieldPtr(block, src, object, field_name, field_name_src);
3317 else3318 return sema.analyzeLoad(block, src, result_ptr, lhs_src);
3318 try sema.analyzeRef(block, src, object);3319 } else {
3319 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);3320 return sema.fieldVal(block, src, object, field_name, field_name_src);
3320 const result_ptr_src = src;3321 }
3321 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
3322}3322}
33233323
3324fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3324fn 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...@@ -3331,7 +3331,7 @@ fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
3331 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;3331 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
3332 const field_name = sema.code.nullTerminatedString(extra.field_name_start);3332 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
3333 const object_ptr = sema.resolveInst(extra.lhs);3333 const object_ptr = sema.resolveInst(extra.lhs);
3334 return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);3334 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src);
3335}3335}
33363336
3337fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3337fn 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...@@ -3344,9 +3344,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp
3344 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;3344 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
3345 const object = sema.resolveInst(extra.lhs);3345 const object = sema.resolveInst(extra.lhs);
3346 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);3346 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
3347 const object_ptr = try sema.analyzeRef(block, src, object);3347 return sema.fieldVal(block, src, object, field_name, field_name_src);
3348 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
3349 return sema.analyzeLoad(block, src, result_ptr, src);
3350}3348}
33513349
3352fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3350fn 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...@@ -3359,7 +3357,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp
3359 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;3357 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
3360 const object_ptr = sema.resolveInst(extra.lhs);3358 const object_ptr = sema.resolveInst(extra.lhs);
3361 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);3359 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
3362 return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);3360 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src);
3363}3361}
33643362
3365fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3363fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -4691,8 +4689,8 @@ fn zirBitwise(...@@ -4691,8 +4689,8 @@ fn zirBitwise(
4691 return sema.mod.fail(&block.base, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });4689 return sema.mod.fail(&block.base, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });
4692 }4690 }
46934691
4694 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, casted_lhs)) |lhs_val| {4692 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
4695 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, casted_rhs)) |rhs_val| {4693 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
4696 if (lhs_val.isUndef() or rhs_val.isUndef()) {4694 if (lhs_val.isUndef() or rhs_val.isUndef()) {
4697 return sema.addConstUndef(resolved_type);4695 return sema.addConstUndef(resolved_type);
4698 }4696 }
...@@ -4823,8 +4821,8 @@ fn analyzeArithmetic(...@@ -4823,8 +4821,8 @@ fn analyzeArithmetic(
4823 return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });4821 return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });
4824 }4822 }
48254823
4826 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, casted_lhs)) |lhs_val| {4824 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
4827 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, casted_rhs)) |rhs_val| {4825 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
4828 if (lhs_val.isUndef() or rhs_val.isUndef()) {4826 if (lhs_val.isUndef() or rhs_val.isUndef()) {
4829 return sema.addConstUndef(resolved_type);4827 return sema.addConstUndef(resolved_type);
4830 }4828 }
...@@ -5038,8 +5036,8 @@ fn zirCmp(...@@ -5038,8 +5036,8 @@ fn zirCmp(
5038 if (!is_equality_cmp) {5036 if (!is_equality_cmp) {
5039 return mod.fail(&block.base, src, "{s} operator not allowed for errors", .{@tagName(op)});5037 return mod.fail(&block.base, src, "{s} operator not allowed for errors", .{@tagName(op)});
5040 }5038 }
5041 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, lhs)) |lval| {5039 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lval| {
5042 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, rhs)) |rval| {5040 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rval| {
5043 if (lval.isUndef() or rval.isUndef()) {5041 if (lval.isUndef() or rval.isUndef()) {
5044 return sema.addConstUndef(Type.initTag(.bool));5042 return sema.addConstUndef(Type.initTag(.bool));
5045 }5043 }
...@@ -5085,8 +5083,8 @@ fn zirCmp(...@@ -5085,8 +5083,8 @@ fn zirCmp(
5085 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);5083 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
5086 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);5084 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
50875085
5088 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, casted_lhs)) |lhs_val| {5086 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
5089 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, casted_rhs)) |rhs_val| {5087 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
5090 if (lhs_val.isUndef() or rhs_val.isUndef()) {5088 if (lhs_val.isUndef() or rhs_val.isUndef()) {
5091 return sema.addConstUndef(resolved_type);5089 return sema.addConstUndef(resolved_type);
5092 }5090 }
...@@ -5759,7 +5757,7 @@ fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref:...@@ -5759,7 +5757,7 @@ fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref:
5759 if (is_comptime) {5757 if (is_comptime) {
5760 const values = try sema.arena.alloc(Value, field_inits.len);5758 const values = try sema.arena.alloc(Value, field_inits.len);
5761 for (field_inits) |field_init, i| {5759 for (field_inits) |field_init, i| {
5762 values[i] = (sema.resolvePossiblyUndefinedValue(block, src, field_init) catch unreachable).?;5760 values[i] = (sema.resolveMaybeUndefVal(block, src, field_init) catch unreachable).?;
5763 }5761 }
5764 return sema.addConstant(struct_ty, try Value.Tag.@"struct".create(sema.arena, values.ptr));5762 return sema.addConstant(struct_ty, try Value.Tag.@"struct".create(sema.arena, values.ptr));
5765 }5763 }
...@@ -6234,7 +6232,7 @@ fn zirVarExtended(...@@ -6234,7 +6232,7 @@ fn zirVarExtended(
6234 const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);6232 const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
6235 extra_index += 1;6233 extra_index += 1;
6236 const init_air_inst = sema.resolveInst(init_ref);6234 const init_air_inst = sema.resolveInst(init_ref);
6237 break :blk (try sema.resolvePossiblyUndefinedValue(block, init_src, init_air_inst)) orelse6235 break :blk (try sema.resolveMaybeUndefVal(block, init_src, init_air_inst)) orelse
6238 return sema.failWithNeededComptime(block, init_src);6236 return sema.failWithNeededComptime(block, init_src);
6239 } else Value.initTag(.unreachable_value);6237 } else Value.initTag(.unreachable_value);
62406238
...@@ -6565,31 +6563,203 @@ fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {...@@ -6565,31 +6563,203 @@ fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
6565 }6563 }
6566}6564}
65676565
6568fn namedFieldPtr(6566fn fieldVal(
6569 sema: *Sema,6567 sema: *Sema,
6570 block: *Scope.Block,6568 block: *Scope.Block,
6571 src: LazySrcLoc,6569 src: LazySrcLoc,
6572 object_ptr: Air.Inst.Ref,6570 object: Air.Inst.Ref,
6573 field_name: []const u8,6571 field_name: []const u8,
6574 field_name_src: LazySrcLoc,6572 field_name_src: LazySrcLoc,
6575) CompileError!Air.Inst.Ref {6573) CompileError!Air.Inst.Ref {
6574 // When editing this function, note that there is corresponding logic to be edited
6575 // in `fieldPtr`. This function takes a value and returns a value.
6576
6576 const mod = sema.mod;6577 const mod = sema.mod;
6577 const arena = sema.arena;6578 const arena = sema.arena;
6579 const object_src = src; // TODO better source location
6580 const object_ty = sema.typeOf(object);
6581
6582 switch (object_ty.zigTypeTag()) {
6583 .Array => {
6584 if (mem.eql(u8, field_name, "len")) {
6585 return sema.addConstant(
6586 Type.initTag(.comptime_int),
6587 try Value.Tag.int_u64.create(arena, object_ty.arrayLen()),
6588 );
6589 } else {
6590 return mod.fail(
6591 &block.base,
6592 field_name_src,
6593 "no member named '{s}' in '{}'",
6594 .{ field_name, object_ty },
6595 );
6596 }
6597 },
6598 .Pointer => switch (object_ty.ptrSize()) {
6599 .Slice => {
6600 if (mem.eql(u8, field_name, "ptr")) {
6601 const buf = try arena.create(Type.Payload.ElemType);
6602 const result_ty = object_ty.slicePtrFieldType(buf);
6603 if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
6604 if (val.isUndef()) return sema.addConstUndef(result_ty);
6605 return mod.fail(
6606 &block.base,
6607 field_name_src,
6608 "TODO implement comptime slice ptr",
6609 .{},
6610 );
6611 }
6612 try sema.requireRuntimeBlock(block, src);
6613 return block.addTyOp(.slice_ptr, result_ty, object);
6614 } else if (mem.eql(u8, field_name, "len")) {
6615 const result_ty = Type.initTag(.usize);
6616 if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
6617 if (val.isUndef()) return sema.addConstUndef(result_ty);
6618 return sema.addConstant(
6619 result_ty,
6620 try Value.Tag.int_u64.create(arena, val.sliceLen()),
6621 );
6622 }
6623 try sema.requireRuntimeBlock(block, src);
6624 return block.addTyOp(.slice_len, result_ty, object);
6625 } else {
6626 return mod.fail(
6627 &block.base,
6628 field_name_src,
6629 "no member named '{s}' in '{}'",
6630 .{ field_name, object_ty },
6631 );
6632 }
6633 },
6634 .One => {
6635 const elem_ty = object_ty.elemType();
6636 if (elem_ty.zigTypeTag() == .Array) {
6637 if (mem.eql(u8, field_name, "len")) {
6638 return sema.addConstant(
6639 Type.initTag(.comptime_int),
6640 try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
6641 );
6642 } else {
6643 return mod.fail(
6644 &block.base,
6645 field_name_src,
6646 "no member named '{s}' in '{}'",
6647 .{ field_name, object_ty },
6648 );
6649 }
6650 }
6651 },
6652 .Many, .C => {},
6653 },
6654 .Type => {
6655 const val = (try sema.resolveDefinedValue(block, object_src, object)).?;
6656 const child_type = try val.toType(arena);
6657 switch (child_type.zigTypeTag()) {
6658 .ErrorSet => {
6659 // TODO resolve inferred error sets
6660 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
6661 const error_set = payload.data;
6662 // TODO this is O(N). I'm putting off solving this until we solve inferred
6663 // error sets at the same time.
6664 const names = error_set.names_ptr[0..error_set.names_len];
6665 for (names) |name| {
6666 if (mem.eql(u8, field_name, name)) {
6667 break :blk name;
6668 }
6669 }
6670 return mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
6671 field_name, child_type,
6672 });
6673 } else (try mod.getErrorValue(field_name)).key;
6674
6675 return sema.addConstant(
6676 child_type,
6677 try Value.Tag.@"error".create(arena, .{ .name = name }),
6678 );
6679 },
6680 .Struct, .Opaque, .Union => {
6681 if (child_type.getNamespace()) |namespace| {
6682 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
6683 return sema.analyzeLoad(block, src, inst, src);
6684 }
6685 }
6686 // TODO add note: declared here
6687 const kw_name = switch (child_type.zigTypeTag()) {
6688 .Struct => "struct",
6689 .Opaque => "opaque",
6690 .Union => "union",
6691 else => unreachable,
6692 };
6693 return mod.fail(&block.base, src, "{s} '{}' has no member named '{s}'", .{
6694 kw_name, child_type, field_name,
6695 });
6696 },
6697 .Enum => {
6698 if (child_type.getNamespace()) |namespace| {
6699 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
6700 return sema.analyzeLoad(block, src, inst, src);
6701 }
6702 }
6703 const field_index = child_type.enumFieldIndex(field_name) orelse {
6704 const msg = msg: {
6705 const msg = try mod.errMsg(
6706 &block.base,
6707 src,
6708 "enum '{}' has no member named '{s}'",
6709 .{ child_type, field_name },
6710 );
6711 errdefer msg.destroy(sema.gpa);
6712 try mod.errNoteNonLazy(
6713 child_type.declSrcLoc(),
6714 msg,
6715 "enum declared here",
6716 .{},
6717 );
6718 break :msg msg;
6719 };
6720 return mod.failWithOwnedErrorMsg(&block.base, msg);
6721 };
6722 const field_index_u32 = @intCast(u32, field_index);
6723 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
6724 return sema.addConstant(child_type, enum_val);
6725 },
6726 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
6727 }
6728 },
6729 .Struct => return sema.structFieldVal(block, src, object, field_name, field_name_src, object_ty),
6730 .Union => return sema.unionFieldVal(block, src, object, field_name, field_name_src, object_ty),
6731 else => {},
6732 }
6733 return mod.fail(&block.base, src, "type '{}' does not support field access", .{object_ty});
6734}
65786735
6736fn fieldPtr(
6737 sema: *Sema,
6738 block: *Scope.Block,
6739 src: LazySrcLoc,
6740 object_ptr: Air.Inst.Ref,
6741 field_name: []const u8,
6742 field_name_src: LazySrcLoc,
6743) CompileError!Air.Inst.Ref {
6744 // When editing this function, note that there is corresponding logic to be edited
6745 // in `fieldVal`. This function takes a pointer and returns a pointer.
6746
6747 const mod = sema.mod;
6748 const arena = sema.arena;
6579 const object_ptr_src = src; // TODO better source location6749 const object_ptr_src = src; // TODO better source location
6580 const object_ptr_ty = sema.typeOf(object_ptr);6750 const object_ptr_ty = sema.typeOf(object_ptr);
6581 const elem_ty = switch (object_ptr_ty.zigTypeTag()) {6751 const object_ty = switch (object_ptr_ty.zigTypeTag()) {
6582 .Pointer => object_ptr_ty.elemType(),6752 .Pointer => object_ptr_ty.elemType(),
6583 else => return mod.fail(&block.base, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}),6753 else => return mod.fail(&block.base, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}),
6584 };6754 };
6585 switch (elem_ty.zigTypeTag()) {6755 switch (object_ty.zigTypeTag()) {
6586 .Array => {6756 .Array => {
6587 if (mem.eql(u8, field_name, "len")) {6757 if (mem.eql(u8, field_name, "len")) {
6588 return sema.addConstant(6758 return sema.addConstant(
6589 Type.initTag(.single_const_pointer_to_comptime_int),6759 Type.initTag(.single_const_pointer_to_comptime_int),
6590 try Value.Tag.ref_val.create(6760 try Value.Tag.ref_val.create(
6591 arena,6761 arena,
6592 try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),6762 try Value.Tag.int_u64.create(arena, object_ty.arrayLen()),
6593 ),6763 ),
6594 );6764 );
6595 } else {6765 } else {
...@@ -6597,33 +6767,33 @@ fn namedFieldPtr(...@@ -6597,33 +6767,33 @@ fn namedFieldPtr(
6597 &block.base,6767 &block.base,
6598 field_name_src,6768 field_name_src,
6599 "no member named '{s}' in '{}'",6769 "no member named '{s}' in '{}'",
6600 .{ field_name, elem_ty },6770 .{ field_name, object_ty },
6601 );6771 );
6602 }6772 }
6603 },6773 },
6604 .Pointer => {6774 .Pointer => {
6605 const ptr_child = elem_ty.elemType();6775 const ptr_child = object_ty.elemType();
6606 if (ptr_child.isSlice()) {6776 if (ptr_child.isSlice()) {
6607 if (mem.eql(u8, field_name, "ptr")) {6777 if (mem.eql(u8, field_name, "ptr")) {
6608 return mod.fail(6778 return mod.fail(
6609 &block.base,6779 &block.base,
6610 field_name_src,6780 field_name_src,
6611 "cannot obtain reference to pointer field of slice '{}'",6781 "cannot obtain reference to pointer field of slice '{}'",
6612 .{elem_ty},6782 .{object_ty},
6613 );6783 );
6614 } else if (mem.eql(u8, field_name, "len")) {6784 } else if (mem.eql(u8, field_name, "len")) {
6615 return mod.fail(6785 return mod.fail(
6616 &block.base,6786 &block.base,
6617 field_name_src,6787 field_name_src,
6618 "cannot obtain reference to length field of slice '{}'",6788 "cannot obtain reference to length field of slice '{}'",
6619 .{elem_ty},6789 .{object_ty},
6620 );6790 );
6621 } else {6791 } else {
6622 return mod.fail(6792 return mod.fail(
6623 &block.base,6793 &block.base,
6624 field_name_src,6794 field_name_src,
6625 "no member named '{s}' in '{}'",6795 "no member named '{s}' in '{}'",
6626 .{ field_name, elem_ty },6796 .{ field_name, object_ty },
6627 );6797 );
6628 }6798 }
6629 } else switch (ptr_child.zigTypeTag()) {6799 } else switch (ptr_child.zigTypeTag()) {
...@@ -6641,7 +6811,7 @@ fn namedFieldPtr(...@@ -6641,7 +6811,7 @@ fn namedFieldPtr(
6641 &block.base,6811 &block.base,
6642 field_name_src,6812 field_name_src,
6643 "no member named '{s}' in '{}'",6813 "no member named '{s}' in '{}'",
6644 .{ field_name, elem_ty },6814 .{ field_name, object_ty },
6645 );6815 );
6646 }6816 }
6647 },6817 },
...@@ -6684,7 +6854,7 @@ fn namedFieldPtr(...@@ -6684,7 +6854,7 @@ fn namedFieldPtr(
6684 },6854 },
6685 .Struct, .Opaque, .Union => {6855 .Struct, .Opaque, .Union => {
6686 if (child_type.getNamespace()) |namespace| {6856 if (child_type.getNamespace()) |namespace| {
6687 if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| {6857 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
6688 return inst;6858 return inst;
6689 }6859 }
6690 }6860 }
...@@ -6701,7 +6871,7 @@ fn namedFieldPtr(...@@ -6701,7 +6871,7 @@ fn namedFieldPtr(
6701 },6871 },
6702 .Enum => {6872 .Enum => {
6703 if (child_type.getNamespace()) |namespace| {6873 if (child_type.getNamespace()) |namespace| {
6704 if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| {6874 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
6705 return inst;6875 return inst;
6706 }6876 }
6707 }6877 }
...@@ -6734,20 +6904,20 @@ fn namedFieldPtr(...@@ -6734,20 +6904,20 @@ fn namedFieldPtr(
6734 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),6904 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
6735 }6905 }
6736 },6906 },
6737 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),6907 .Struct => return sema.structFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty),
6738 .Union => return sema.analyzeUnionFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),6908 .Union => return sema.unionFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty),
6739 else => {},6909 else => {},
6740 }6910 }
6741 return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});6911 return mod.fail(&block.base, src, "type '{}' does not support field access", .{object_ty});
6742}6912}
67436913
6744fn analyzeNamespaceLookup(6914fn namespaceLookup(
6745 sema: *Sema,6915 sema: *Sema,
6746 block: *Scope.Block,6916 block: *Scope.Block,
6747 src: LazySrcLoc,6917 src: LazySrcLoc,
6748 namespace: *Scope.Namespace,6918 namespace: *Scope.Namespace,
6749 decl_name: []const u8,6919 decl_name: []const u8,
6750) CompileError!?Air.Inst.Ref {6920) CompileError!?*Decl {
6751 const mod = sema.mod;6921 const mod = sema.mod;
6752 const gpa = sema.gpa;6922 const gpa = sema.gpa;
6753 if (try sema.lookupInNamespace(namespace, decl_name)) |decl| {6923 if (try sema.lookupInNamespace(namespace, decl_name)) |decl| {
...@@ -6762,12 +6932,23 @@ fn analyzeNamespaceLookup(...@@ -6762,12 +6932,23 @@ fn analyzeNamespaceLookup(
6762 };6932 };
6763 return mod.failWithOwnedErrorMsg(&block.base, msg);6933 return mod.failWithOwnedErrorMsg(&block.base, msg);
6764 }6934 }
6765 return try sema.analyzeDeclRef(block, src, decl);6935 return decl;
6766 }6936 }
6767 return null;6937 return null;
6768}6938}
67696939
6770fn analyzeStructFieldPtr(6940fn namespaceLookupRef(
6941 sema: *Sema,
6942 block: *Scope.Block,
6943 src: LazySrcLoc,
6944 namespace: *Scope.Namespace,
6945 decl_name: []const u8,
6946) CompileError!?Air.Inst.Ref {
6947 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
6948 return try sema.analyzeDeclRef(block, src, decl);
6949}
6950
6951fn structFieldPtr(
6771 sema: *Sema,6952 sema: *Sema,
6772 block: *Scope.Block,6953 block: *Scope.Block,
6773 src: LazySrcLoc,6954 src: LazySrcLoc,
...@@ -6803,14 +6984,52 @@ fn analyzeStructFieldPtr(...@@ -6803,14 +6984,52 @@ fn analyzeStructFieldPtr(
6803 .data = .{ .ty_pl = .{6984 .data = .{ .ty_pl = .{
6804 .ty = try sema.addType(ptr_field_ty),6985 .ty = try sema.addType(ptr_field_ty),
6805 .payload = try sema.addExtra(Air.StructField{6986 .payload = try sema.addExtra(Air.StructField{
6806 .struct_ptr = struct_ptr,6987 .struct_operand = struct_ptr,
6807 .field_index = @intCast(u32, field_index),6988 .field_index = @intCast(u32, field_index),
6808 }),6989 }),
6809 } },6990 } },
6810 });6991 });
6811}6992}
68126993
6813fn analyzeUnionFieldPtr(6994fn structFieldVal(
6995 sema: *Sema,
6996 block: *Scope.Block,
6997 src: LazySrcLoc,
6998 struct_byval: Air.Inst.Ref,
6999 field_name: []const u8,
7000 field_name_src: LazySrcLoc,
7001 unresolved_struct_ty: Type,
7002) CompileError!Air.Inst.Ref {
7003 assert(unresolved_struct_ty.zigTypeTag() == .Struct);
7004
7005 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
7006 const struct_obj = struct_ty.castTag(.@"struct").?.data;
7007
7008 const field_index = struct_obj.fields.getIndex(field_name) orelse
7009 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
7010 const field = struct_obj.fields.values()[field_index];
7011
7012 if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {
7013 if (struct_val.isUndef()) return sema.addConstUndef(field.ty);
7014
7015 const field_values = struct_val.castTag(.@"struct").?.data;
7016 return sema.addConstant(field.ty, field_values[field_index]);
7017 }
7018
7019 try sema.requireRuntimeBlock(block, src);
7020 return block.addInst(.{
7021 .tag = .struct_field_val,
7022 .data = .{ .ty_pl = .{
7023 .ty = try sema.addType(field.ty),
7024 .payload = try sema.addExtra(Air.StructField{
7025 .struct_operand = struct_byval,
7026 .field_index = @intCast(u32, field_index),
7027 }),
7028 } },
7029 });
7030}
7031
7032fn unionFieldPtr(
6814 sema: *Sema,7033 sema: *Sema,
6815 block: *Scope.Block,7034 block: *Scope.Block,
6816 src: LazySrcLoc,7035 src: LazySrcLoc,
...@@ -6847,6 +7066,37 @@ fn analyzeUnionFieldPtr(...@@ -6847,6 +7066,37 @@ fn analyzeUnionFieldPtr(
6847 return mod.fail(&block.base, src, "TODO implement runtime union field access", .{});7066 return mod.fail(&block.base, src, "TODO implement runtime union field access", .{});
6848}7067}
68497068
7069fn unionFieldVal(
7070 sema: *Sema,
7071 block: *Scope.Block,
7072 src: LazySrcLoc,
7073 union_byval: Air.Inst.Ref,
7074 field_name: []const u8,
7075 field_name_src: LazySrcLoc,
7076 unresolved_union_ty: Type,
7077) CompileError!Air.Inst.Ref {
7078 assert(unresolved_union_ty.zigTypeTag() == .Union);
7079
7080 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
7081 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
7082
7083 const field_index = union_obj.fields.getIndex(field_name) orelse
7084 return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);
7085
7086 const field = union_obj.fields.values()[field_index];
7087
7088 if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| {
7089 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
7090
7091 // TODO detect inactive union field and emit compile error
7092 const active_val = union_val.castTag(.@"union").?.data.val;
7093 return sema.addConstant(field.ty, active_val);
7094 }
7095
7096 try sema.requireRuntimeBlock(block, src);
7097 return sema.mod.fail(&block.base, src, "TODO implement runtime union field access", .{});
7098}
7099
6850fn elemPtr(7100fn elemPtr(
6851 sema: *Sema,7101 sema: *Sema,
6852 block: *Scope.Block,7102 block: *Scope.Block,
...@@ -6973,7 +7223,7 @@ fn coerce(...@@ -6973,7 +7223,7 @@ fn coerce(
6973 const arena = sema.arena;7223 const arena = sema.arena;
69747224
6975 // undefined to anything7225 // undefined to anything
6976 if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {7226 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
6977 if (val.isUndef() or inst_ty.zigTypeTag() == .Undefined) {7227 if (val.isUndef() or inst_ty.zigTypeTag() == .Undefined) {
6978 return sema.addConstant(dest_type, val);7228 return sema.addConstant(dest_type, val);
6979 }7229 }
...@@ -7207,8 +7457,8 @@ fn storePtr(...@@ -7207,8 +7457,8 @@ fn storePtr(
7207 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)7457 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
7208 return;7458 return;
72097459
7210 if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| blk: {7460 if (try sema.resolveMaybeUndefVal(block, src, ptr)) |ptr_val| blk: {
7211 const const_val = (try sema.resolvePossiblyUndefinedValue(block, src, value)) orelse7461 const const_val = (try sema.resolveMaybeUndefVal(block, src, value)) orelse
7212 return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});7462 return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});
72137463
7214 if (ptr_val.tag() == .int_u64)7464 if (ptr_val.tag() == .int_u64)
...@@ -7252,7 +7502,7 @@ fn bitcast(...@@ -7252,7 +7502,7 @@ fn bitcast(
7252 inst: Air.Inst.Ref,7502 inst: Air.Inst.Ref,
7253 inst_src: LazySrcLoc,7503 inst_src: LazySrcLoc,
7254) CompileError!Air.Inst.Ref {7504) CompileError!Air.Inst.Ref {
7255 if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {7505 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
7256 // Keep the comptime Value representation; take the new type.7506 // Keep the comptime Value representation; take the new type.
7257 return sema.addConstant(dest_type, val);7507 return sema.addConstant(dest_type, val);
7258 }7508 }
...@@ -7358,7 +7608,7 @@ fn analyzeRef(...@@ -7358,7 +7608,7 @@ fn analyzeRef(
7358 const operand_ty = sema.typeOf(operand);7608 const operand_ty = sema.typeOf(operand);
7359 const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);7609 const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);
73607610
7361 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |val| {7611 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
7362 return sema.addConstant(ptr_type, try Value.Tag.ref_val.create(sema.arena, val));7612 return sema.addConstant(ptr_type, try Value.Tag.ref_val.create(sema.arena, val));
7363 }7613 }
73647614
...@@ -7395,7 +7645,7 @@ fn analyzeSliceLen(...@@ -7395,7 +7645,7 @@ fn analyzeSliceLen(
7395 src: LazySrcLoc,7645 src: LazySrcLoc,
7396 slice_inst: Air.Inst.Ref,7646 slice_inst: Air.Inst.Ref,
7397) CompileError!Air.Inst.Ref {7647) CompileError!Air.Inst.Ref {
7398 if (try sema.resolvePossiblyUndefinedValue(block, src, slice_inst)) |slice_val| {7648 if (try sema.resolveMaybeUndefVal(block, src, slice_inst)) |slice_val| {
7399 if (slice_val.isUndef()) {7649 if (slice_val.isUndef()) {
7400 return sema.addConstUndef(Type.initTag(.usize));7650 return sema.addConstUndef(Type.initTag(.usize));
7401 }7651 }
...@@ -7413,7 +7663,7 @@ fn analyzeIsNull(...@@ -7413,7 +7663,7 @@ fn analyzeIsNull(
7413 invert_logic: bool,7663 invert_logic: bool,
7414) CompileError!Air.Inst.Ref {7664) CompileError!Air.Inst.Ref {
7415 const result_ty = Type.initTag(.bool);7665 const result_ty = Type.initTag(.bool);
7416 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |opt_val| {7666 if (try sema.resolveMaybeUndefVal(block, src, operand)) |opt_val| {
7417 if (opt_val.isUndef()) {7667 if (opt_val.isUndef()) {
7418 return sema.addConstUndef(result_ty);7668 return sema.addConstUndef(result_ty);
7419 }7669 }
...@@ -7442,7 +7692,7 @@ fn analyzeIsNonErr(...@@ -7442,7 +7692,7 @@ fn analyzeIsNonErr(
7442 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;7692 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
7443 assert(ot == .ErrorUnion);7693 assert(ot == .ErrorUnion);
7444 const result_ty = Type.initTag(.bool);7694 const result_ty = Type.initTag(.bool);
7445 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |err_union| {7695 if (try sema.resolveMaybeUndefVal(block, src, operand)) |err_union| {
7446 if (err_union.isUndef()) {7696 if (err_union.isUndef()) {
7447 return sema.addConstUndef(result_ty);7697 return sema.addConstUndef(result_ty);
7448 }7698 }
...@@ -7567,8 +7817,8 @@ fn cmpNumeric(...@@ -7567,8 +7817,8 @@ fn cmpNumeric(
7567 });7817 });
7568 }7818 }
75697819
7570 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, lhs)) |lhs_val| {7820 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
7571 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, rhs)) |rhs_val| {7821 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
7572 if (lhs_val.isUndef() or rhs_val.isUndef()) {7822 if (lhs_val.isUndef() or rhs_val.isUndef()) {
7573 return sema.addConstUndef(Type.initTag(.bool));7823 return sema.addConstUndef(Type.initTag(.bool));
7574 }7824 }
...@@ -7635,7 +7885,7 @@ fn cmpNumeric(...@@ -7635,7 +7885,7 @@ fn cmpNumeric(
7635 var dest_float_type: ?Type = null;7885 var dest_float_type: ?Type = null;
76367886
7637 var lhs_bits: usize = undefined;7887 var lhs_bits: usize = undefined;
7638 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, lhs)) |lhs_val| {7888 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
7639 if (lhs_val.isUndef())7889 if (lhs_val.isUndef())
7640 return sema.addConstUndef(Type.initTag(.bool));7890 return sema.addConstUndef(Type.initTag(.bool));
7641 const is_unsigned = if (lhs_is_float) x: {7891 const is_unsigned = if (lhs_is_float) x: {
...@@ -7670,7 +7920,7 @@ fn cmpNumeric(...@@ -7670,7 +7920,7 @@ fn cmpNumeric(
7670 }7920 }
76717921
7672 var rhs_bits: usize = undefined;7922 var rhs_bits: usize = undefined;
7673 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, rhs)) |rhs_val| {7923 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
7674 if (rhs_val.isUndef())7924 if (rhs_val.isUndef())
7675 return sema.addConstUndef(Type.initTag(.bool));7925 return sema.addConstUndef(Type.initTag(.bool));
7676 const is_unsigned = if (rhs_is_float) x: {7926 const is_unsigned = if (rhs_is_float) x: {
...@@ -7725,7 +7975,7 @@ fn wrapOptional(...@@ -7725,7 +7975,7 @@ fn wrapOptional(
7725 inst: Air.Inst.Ref,7975 inst: Air.Inst.Ref,
7726 inst_src: LazySrcLoc,7976 inst_src: LazySrcLoc,
7727) !Air.Inst.Ref {7977) !Air.Inst.Ref {
7728 if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {7978 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
7729 return sema.addConstant(dest_type, val);7979 return sema.addConstant(dest_type, val);
7730 }7980 }
77317981
...@@ -7743,7 +7993,7 @@ fn wrapErrorUnion(...@@ -7743,7 +7993,7 @@ fn wrapErrorUnion(
7743 const inst_ty = sema.typeOf(inst);7993 const inst_ty = sema.typeOf(inst);
7744 const dest_err_set_ty = dest_type.errorUnionSet();7994 const dest_err_set_ty = dest_type.errorUnionSet();
7745 const dest_payload_ty = dest_type.errorUnionPayload();7995 const dest_payload_ty = dest_type.errorUnionPayload();
7746 if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {7996 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
7747 if (inst_ty.zigTypeTag() != .ErrorSet) {7997 if (inst_ty.zigTypeTag() != .ErrorSet) {
7748 _ = try sema.coerce(block, dest_payload_ty, inst, inst_src);7998 _ = try sema.coerce(block, dest_payload_ty, inst, inst_src);
7749 } else switch (dest_err_set_ty.tag()) {7999 } else switch (dest_err_set_ty.tag()) {
...@@ -7956,7 +8206,7 @@ fn getBuiltin(...@@ -7956,7 +8206,7 @@ fn getBuiltin(
7956 const mod = sema.mod;8206 const mod = sema.mod;
7957 const std_pkg = mod.main_pkg.table.get("std").?;8207 const std_pkg = mod.main_pkg.table.get("std").?;
7958 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;8208 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
7959 const opt_builtin_inst = try sema.analyzeNamespaceLookup(8209 const opt_builtin_inst = try sema.namespaceLookupRef(
7960 block,8210 block,
7961 src,8211 src,
7962 std_file.root_decl.?.namespace,8212 std_file.root_decl.?.namespace,
...@@ -7964,7 +8214,7 @@ fn getBuiltin(...@@ -7964,7 +8214,7 @@ fn getBuiltin(
7964 );8214 );
7965 const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst.?, src);8215 const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst.?, src);
7966 const builtin_ty = try sema.analyzeAsType(block, src, builtin_inst);8216 const builtin_ty = try sema.analyzeAsType(block, src, builtin_inst);
7967 const opt_ty_inst = try sema.analyzeNamespaceLookup(8217 const opt_ty_inst = try sema.namespaceLookupRef(
7968 block,8218 block,
7969 src,8219 src,
7970 builtin_ty.getNamespace().?,8220 builtin_ty.getNamespace().?,
...@@ -8320,5 +8570,5 @@ fn isComptimeKnown(...@@ -8320,5 +8570,5 @@ fn isComptimeKnown(
8320 src: LazySrcLoc,8570 src: LazySrcLoc,
8321 inst: Air.Inst.Ref,8571 inst: Air.Inst.Ref,
8322) !bool {8572) !bool {
8323 return (try sema.resolvePossiblyUndefinedValue(block, src, inst)) != null;8573 return (try sema.resolveMaybeUndefVal(block, src, inst)) != null;
8324}8574}
src/codegen.zig+9
...@@ -851,6 +851,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -851,6 +851,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
851 .ret => try self.airRet(inst),851 .ret => try self.airRet(inst),
852 .store => try self.airStore(inst),852 .store => try self.airStore(inst),
853 .struct_field_ptr=> try self.airStructFieldPtr(inst),853 .struct_field_ptr=> try self.airStructFieldPtr(inst),
854 .struct_field_val=> try self.airStructFieldVal(inst),
854 .switch_br => try self.airSwitch(inst),855 .switch_br => try self.airSwitch(inst),
855 .varptr => try self.airVarPtr(inst),856 .varptr => try self.airVarPtr(inst),
856 .slice_ptr => try self.airSlicePtr(inst),857 .slice_ptr => try self.airSlicePtr(inst),
...@@ -1501,6 +1502,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1501,6 +1502,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1501 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });1502 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
1502 }1503 }
15031504
1505 fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
1506 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1507 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
1508 _ = extra;
1509 return self.fail("TODO implement codegen struct_field_val", .{});
1510 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
1511 }
1512
1504 fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool {1513 fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool {
1505 return switch (mcv) {1514 return switch (mcv) {
1506 .none => unreachable,1515 .none => unreachable,
src/codegen/c.zig+23-2
...@@ -935,6 +935,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM...@@ -935,6 +935,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
935 .wrap_optional => try airWrapOptional(o, inst),935 .wrap_optional => try airWrapOptional(o, inst),
936 .ref => try airRef(o, inst),936 .ref => try airRef(o, inst),
937 .struct_field_ptr => try airStructFieldPtr(o, inst),937 .struct_field_ptr => try airStructFieldPtr(o, inst),
938 .struct_field_val => try airStructFieldVal(o, inst),
938 .varptr => try airVarPtr(o, inst),939 .varptr => try airVarPtr(o, inst),
939 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),940 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),
940 .slice_len => try airSliceField(o, inst, ".len;\n"),941 .slice_len => try airSliceField(o, inst, ".len;\n"),
...@@ -1660,8 +1661,8 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1660,8 +1661,8 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
1660 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;1661 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
1661 const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;1662 const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;
1662 const writer = o.writer();1663 const writer = o.writer();
1663 const struct_ptr = try o.resolveInst(extra.struct_ptr);1664 const struct_ptr = try o.resolveInst(extra.struct_operand);
1664 const struct_ptr_ty = o.air.typeOf(extra.struct_ptr);1665 const struct_ptr_ty = o.air.typeOf(extra.struct_operand);
1665 const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data;1666 const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data;
1666 const field_name = struct_obj.fields.keys()[extra.field_index];1667 const field_name = struct_obj.fields.keys()[extra.field_index];
16671668
...@@ -1680,6 +1681,26 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1680,6 +1681,26 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
1680 return local;1681 return local;
1681}1682}
16821683
1684fn airStructFieldVal(o: *Object, inst: Air.Inst.Index) !CValue {
1685 if (o.liveness.isUnused(inst))
1686 return CValue.none;
1687
1688 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
1689 const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;
1690 const writer = o.writer();
1691 const struct_byval = try o.resolveInst(extra.struct_operand);
1692 const struct_ty = o.air.typeOf(extra.struct_operand);
1693 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1694 const field_name = struct_obj.fields.keys()[extra.field_index];
1695
1696 const inst_ty = o.air.typeOfIndex(inst);
1697 const local = try o.allocLocal(inst_ty, .Const);
1698 try writer.writeAll(" = ");
1699 try o.writeCValue(writer, struct_byval);
1700 try writer.print(".{};\n", .{fmtIdent(field_name)});
1701 return local;
1702}
1703
1683// *(E!T) -> E NOT *E1704// *(E!T) -> E NOT *E
1684fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {1705fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {
1685 if (o.liveness.isUnused(inst))1706 if (o.liveness.isUnused(inst))
src/codegen/llvm.zig+278-76
...@@ -350,19 +350,21 @@ pub const Object = struct {...@@ -350,19 +350,21 @@ pub const Object = struct {
350 air: Air,350 air: Air,
351 liveness: Liveness,351 liveness: Liveness,
352 ) !void {352 ) !void {
353 const decl = func.owner_decl;
354
353 var dg: DeclGen = .{355 var dg: DeclGen = .{
354 .context = self.context,356 .context = self.context,
355 .object = self,357 .object = self,
356 .module = module,358 .module = module,
357 .decl = func.owner_decl,359 .decl = decl,
358 .err_msg = null,360 .err_msg = null,
359 .gpa = module.gpa,361 .gpa = module.gpa,
360 };362 };
361363
362 const llvm_func = try dg.resolveLLVMFunction(func.owner_decl);364 const llvm_func = try dg.resolveLlvmFunction(decl);
363365
364 // This gets the LLVM values from the function and stores them in `dg.args`.366 // This gets the LLVM values from the function and stores them in `dg.args`.
365 const fn_param_len = func.owner_decl.ty.fnParamLen();367 const fn_param_len = decl.ty.fnParamLen();
366 var args = try dg.gpa.alloc(*const llvm.Value, fn_param_len);368 var args = try dg.gpa.alloc(*const llvm.Value, fn_param_len);
367369
368 for (args) |*arg, i| {370 for (args) |*arg, i| {
...@@ -400,13 +402,16 @@ pub const Object = struct {...@@ -400,13 +402,16 @@ pub const Object = struct {
400402
401 fg.genBody(air.getMainBody()) catch |err| switch (err) {403 fg.genBody(air.getMainBody()) catch |err| switch (err) {
402 error.CodegenFail => {404 error.CodegenFail => {
403 func.owner_decl.analysis = .codegen_failure;405 decl.analysis = .codegen_failure;
404 try module.failed_decls.put(module.gpa, func.owner_decl, dg.err_msg.?);406 try module.failed_decls.put(module.gpa, decl, dg.err_msg.?);
405 dg.err_msg = null;407 dg.err_msg = null;
406 return;408 return;
407 },409 },
408 else => |e| return e,410 else => |e| return e,
409 };411 };
412
413 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
414 try self.updateDeclExports(module, decl, decl_exports);
410 }415 }
411416
412 pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {417 pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
...@@ -428,6 +433,38 @@ pub const Object = struct {...@@ -428,6 +433,38 @@ pub const Object = struct {
428 else => |e| return e,433 else => |e| return e,
429 };434 };
430 }435 }
436
437 pub fn updateDeclExports(
438 self: *Object,
439 module: *const Module,
440 decl: *const Module.Decl,
441 exports: []const *Module.Export,
442 ) !void {
443 const llvm_fn = self.llvm_module.getNamedFunction(decl.name).?;
444 const is_extern = decl.val.tag() == .extern_fn;
445 if (is_extern or exports.len != 0) {
446 llvm_fn.setLinkage(.External);
447 llvm_fn.setUnnamedAddr(.False);
448 } else {
449 llvm_fn.setLinkage(.Internal);
450 llvm_fn.setUnnamedAddr(.True);
451 }
452 // TODO LLVM C API does not support deleting aliases. We need to
453 // patch it to support this or figure out how to wrap the C++ API ourselves.
454 // Until then we iterate over existing aliases and make them point
455 // to the correct decl, or otherwise add a new alias. Old aliases are leaked.
456 for (exports) |exp| {
457 if (self.llvm_module.getNamedGlobalAlias(exp.options.name.ptr, exp.options.name.len)) |alias| {
458 alias.setAliasee(llvm_fn);
459 } else {
460 const exp_name_z = try module.gpa.dupeZ(u8, exp.options.name);
461 defer module.gpa.free(exp_name_z);
462
463 const alias = self.llvm_module.addAlias(llvm_fn.typeOf(), llvm_fn, exp_name_z);
464 _ = alias;
465 }
466 }
467 }
431};468};
432469
433pub const DeclGen = struct {470pub const DeclGen = struct {
...@@ -461,21 +498,19 @@ pub const DeclGen = struct {...@@ -461,21 +498,19 @@ pub const DeclGen = struct {
461 _ = func_payload;498 _ = func_payload;
462 @panic("TODO llvm backend genDecl function pointer");499 @panic("TODO llvm backend genDecl function pointer");
463 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {500 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {
464 _ = try self.resolveLLVMFunction(extern_fn.data);501 _ = try self.resolveLlvmFunction(extern_fn.data);
465 } else {502 } else {
466 _ = try self.resolveGlobalDecl(decl);503 _ = try self.resolveGlobalDecl(decl);
467 }504 }
468 }505 }
469506
470 /// If the llvm function does not exist, create it507 /// If the llvm function does not exist, create it
471 fn resolveLLVMFunction(self: *DeclGen, func: *Module.Decl) !*const llvm.Value {508 fn resolveLlvmFunction(self: *DeclGen, decl: *Module.Decl) !*const llvm.Value {
472 // TODO: do we want to store this in our own datastructure?509 if (self.llvmModule().getNamedFunction(decl.name)) |llvm_fn| return llvm_fn;
473 if (self.llvmModule().getNamedFunction(func.name)) |llvm_fn| return llvm_fn;
474510
475 assert(func.has_tv);511 assert(decl.has_tv);
476 const zig_fn_type = func.ty;512 const zig_fn_type = decl.ty;
477 const return_type = zig_fn_type.fnReturnType();513 const return_type = zig_fn_type.fnReturnType();
478
479 const fn_param_len = zig_fn_type.fnParamLen();514 const fn_param_len = zig_fn_type.fnParamLen();
480515
481 const fn_param_types = try self.gpa.alloc(Type, fn_param_len);516 const fn_param_types = try self.gpa.alloc(Type, fn_param_len);
...@@ -495,9 +530,17 @@ pub const DeclGen = struct {...@@ -495,9 +530,17 @@ pub const DeclGen = struct {
495 @intCast(c_uint, fn_param_len),530 @intCast(c_uint, fn_param_len),
496 .False,531 .False,
497 );532 );
498 const llvm_fn = self.llvmModule().addFunction(func.name, fn_type);533 const llvm_fn = self.llvmModule().addFunction(decl.name, fn_type);
534
535 const is_extern = decl.val.tag() == .extern_fn;
536 if (!is_extern) {
537 llvm_fn.setLinkage(.Internal);
538 llvm_fn.setUnnamedAddr(.True);
539 }
540
541 // TODO: calling convention, linkage, tsan, etc. see codegen.cpp `make_fn_llvm_value`.
499542
500 if (return_type.tag() == .noreturn) {543 if (return_type.isNoReturn()) {
501 self.addFnAttr(llvm_fn, "noreturn");544 self.addFnAttr(llvm_fn, "noreturn");
502 }545 }
503546
...@@ -505,7 +548,6 @@ pub const DeclGen = struct {...@@ -505,7 +548,6 @@ pub const DeclGen = struct {
505 }548 }
506549
507 fn resolveGlobalDecl(self: *DeclGen, decl: *Module.Decl) error{ OutOfMemory, CodegenFail }!*const llvm.Value {550 fn resolveGlobalDecl(self: *DeclGen, decl: *Module.Decl) error{ OutOfMemory, CodegenFail }!*const llvm.Value {
508 // TODO: do we want to store this in our own datastructure?
509 if (self.llvmModule().getNamedGlobal(decl.name)) |val| return val;551 if (self.llvmModule().getNamedGlobal(decl.name)) |val| return val;
510552
511 assert(decl.has_tv);553 assert(decl.has_tv);
...@@ -515,9 +557,11 @@ pub const DeclGen = struct {...@@ -515,9 +557,11 @@ pub const DeclGen = struct {
515 const global = self.llvmModule().addGlobal(llvm_type, decl.name);557 const global = self.llvmModule().addGlobal(llvm_type, decl.name);
516 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {558 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
517 const variable = payload.data;559 const variable = payload.data;
518 global.setGlobalConstant(.False);
519 break :init_val variable.init;560 break :init_val variable.init;
520 } else decl.val;561 } else init_val: {
562 global.setGlobalConstant(.True);
563 break :init_val decl.val;
564 };
521565
522 const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val }, null);566 const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val }, null);
523 llvm.setInitializer(global, llvm_init);567 llvm.setInitializer(global, llvm_init);
...@@ -602,12 +646,13 @@ pub const DeclGen = struct {...@@ -602,12 +646,13 @@ pub const DeclGen = struct {
602 llvm_param.* = try self.llvmType(t.fnParamType(i));646 llvm_param.* = try self.llvmType(t.fnParamType(i));
603 }647 }
604 const is_var_args = t.fnIsVarArgs();648 const is_var_args = t.fnIsVarArgs();
605 return llvm.functionType(649 const llvm_fn_ty = llvm.functionType(
606 ret_ty,650 ret_ty,
607 llvm_params.ptr,651 llvm_params.ptr,
608 @intCast(c_uint, llvm_params.len),652 @intCast(c_uint, llvm_params.len),
609 llvm.Bool.fromBool(is_var_args),653 llvm.Bool.fromBool(is_var_args),
610 );654 );
655 return llvm_fn_ty.pointerType(0);
611 },656 },
612 .ComptimeInt => unreachable,657 .ComptimeInt => unreachable,
613 .ComptimeFloat => unreachable,658 .ComptimeFloat => unreachable,
...@@ -717,6 +762,42 @@ pub const DeclGen = struct {...@@ -717,6 +762,42 @@ pub const DeclGen = struct {
717 return self.todo("implement const of optional pointer", .{});762 return self.todo("implement const of optional pointer", .{});
718 }763 }
719 },764 },
765 .Fn => {
766 const fn_decl = if (tv.val.castTag(.extern_fn)) |extern_fn|
767 extern_fn.data
768 else if (tv.val.castTag(.function)) |func_payload|
769 func_payload.data.owner_decl
770 else
771 unreachable;
772
773 return self.resolveLlvmFunction(fn_decl);
774 },
775 .ErrorSet => {
776 const llvm_ty = try self.llvmType(tv.ty);
777 switch (tv.val.tag()) {
778 .@"error" => {
779 const err_name = tv.val.castTag(.@"error").?.data.name;
780 const kv = try self.module.getErrorValue(err_name);
781 return llvm_ty.constInt(kv.value, .False);
782 },
783 else => {
784 // In this case we are rendering an error union which has a 0 bits payload.
785 return llvm_ty.constNull();
786 },
787 }
788 },
789 .ErrorUnion => {
790 const error_type = tv.ty.errorUnionSet();
791 const payload_type = tv.ty.errorUnionPayload();
792 const sub_val = tv.val.castTag(.error_union).?.data;
793
794 if (!payload_type.hasCodeGenBits()) {
795 // We use the error type directly as the type.
796 return self.genTypedValue(.{ .ty = error_type, .val = sub_val }, fg);
797 }
798
799 return self.todo("implement error union const of type '{}'", .{tv.ty});
800 },
720 else => return self.todo("implement const of type '{}'", .{tv.ty}),801 else => return self.todo("implement const of type '{}'", .{tv.ty}),
721 }802 }
722 }803 }
...@@ -801,8 +882,17 @@ pub const FuncGen = struct {...@@ -801,8 +882,17 @@ pub const FuncGen = struct {
801 for (body) |inst| {882 for (body) |inst| {
802 const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {883 const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
803 // zig fmt: off884 // zig fmt: off
804 .add => try self.airAdd(inst),885 .add => try self.airAdd(inst, false),
805 .sub => try self.airSub(inst),886 .addwrap => try self.airAdd(inst, true),
887 .sub => try self.airSub(inst, false),
888 .subwrap => try self.airSub(inst, true),
889 .mul => try self.airMul(inst, false),
890 .mulwrap => try self.airMul(inst, true),
891 .div => try self.airDiv(inst),
892
893 .bit_and, .bool_and => try self.airAnd(inst),
894 .bit_or, .bool_or => try self.airOr(inst),
895 .xor => try self.airXor(inst),
806896
807 .cmp_eq => try self.airCmp(inst, .eq),897 .cmp_eq => try self.airCmp(inst, .eq),
808 .cmp_gt => try self.airCmp(inst, .gt),898 .cmp_gt => try self.airCmp(inst, .gt),
...@@ -825,10 +915,12 @@ pub const FuncGen = struct {...@@ -825,10 +915,12 @@ pub const FuncGen = struct {
825 .bitcast => try self.airBitCast(inst),915 .bitcast => try self.airBitCast(inst),
826 .block => try self.airBlock(inst),916 .block => try self.airBlock(inst),
827 .br => try self.airBr(inst),917 .br => try self.airBr(inst),
918 .switch_br => try self.airSwitchBr(inst),
828 .breakpoint => try self.airBreakpoint(inst),919 .breakpoint => try self.airBreakpoint(inst),
829 .call => try self.airCall(inst),920 .call => try self.airCall(inst),
830 .cond_br => try self.airCondBr(inst),921 .cond_br => try self.airCondBr(inst),
831 .intcast => try self.airIntCast(inst),922 .intcast => try self.airIntCast(inst),
923 .floatcast => try self.airFloatCast(inst),
832 .ptrtoint => try self.airPtrToInt(inst),924 .ptrtoint => try self.airPtrToInt(inst),
833 .load => try self.airLoad(inst),925 .load => try self.airLoad(inst),
834 .loop => try self.airLoop(inst),926 .loop => try self.airLoop(inst),
...@@ -840,6 +932,9 @@ pub const FuncGen = struct {...@@ -840,6 +932,9 @@ pub const FuncGen = struct {
840 .slice_ptr => try self.airSliceField(inst, 0),932 .slice_ptr => try self.airSliceField(inst, 0),
841 .slice_len => try self.airSliceField(inst, 1),933 .slice_len => try self.airSliceField(inst, 1),
842934
935 .struct_field_ptr => try self.airStructFieldPtr(inst),
936 .struct_field_val => try self.airStructFieldVal(inst),
937
843 .slice_elem_val => try self.airSliceElemVal(inst, false),938 .slice_elem_val => try self.airSliceElemVal(inst, false),
844 .ptr_slice_elem_val => try self.airSliceElemVal(inst, true),939 .ptr_slice_elem_val => try self.airSliceElemVal(inst, true),
845940
...@@ -851,12 +946,18 @@ pub const FuncGen = struct {...@@ -851,12 +946,18 @@ pub const FuncGen = struct {
851 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),946 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),
852 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),947 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
853948
949 .wrap_optional => try self.airWrapOptional(inst),
950 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
951 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
952
953 .constant => unreachable,
954 .const_ty => unreachable,
955 .ref => unreachable, // TODO eradicate this instruction
854 .unreach => self.airUnreach(inst),956 .unreach => self.airUnreach(inst),
855 .dbg_stmt => blk: {957 .dbg_stmt => blk: {
856 // TODO: implement debug info958 // TODO: implement debug info
857 break :blk null;959 break :blk null;
858 },960 },
859 else => |tag| return self.todo("implement AIR instruction: {}", .{tag}),
860 // zig fmt: on961 // zig fmt: on
861 };962 };
862 if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa, inst, val);963 if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa, inst, val);
...@@ -867,47 +968,32 @@ pub const FuncGen = struct {...@@ -867,47 +968,32 @@ pub const FuncGen = struct {
867 const pl_op = self.air.instructions.items(.data)[inst].pl_op;968 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
868 const extra = self.air.extraData(Air.Call, pl_op.payload);969 const extra = self.air.extraData(Air.Call, pl_op.payload);
869 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);970 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
971 const zig_fn_type = self.air.typeOf(pl_op.operand);
972 const return_type = zig_fn_type.fnReturnType();
973 const llvm_fn = try self.resolveInst(pl_op.operand);
870974
871 if (self.air.value(pl_op.operand)) |func_value| {975 const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len);
872 const fn_decl = if (func_value.castTag(.extern_fn)) |extern_fn|976 defer self.gpa.free(llvm_param_vals);
873 extern_fn.data
874 else if (func_value.castTag(.function)) |func_payload|
875 func_payload.data.owner_decl
876 else
877 unreachable;
878
879 assert(fn_decl.has_tv);
880 const zig_fn_type = fn_decl.ty;
881 const llvm_fn = try self.dg.resolveLLVMFunction(fn_decl);
882977
883 const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len);978 for (args) |arg, i| {
884 defer self.gpa.free(llvm_param_vals);979 llvm_param_vals[i] = try self.resolveInst(arg);
980 }
885981
886 for (args) |arg, i| {982 const call = self.builder.buildCall(
887 llvm_param_vals[i] = try self.resolveInst(arg);983 llvm_fn,
888 }984 llvm_param_vals.ptr,
985 @intCast(c_uint, args.len),
986 "",
987 );
889988
890 // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs989 if (return_type.isNoReturn()) {
891 // Do we need that?990 _ = self.builder.buildUnreachable();
892 const call = self.builder.buildCall(991 }
893 llvm_fn,
894 llvm_param_vals.ptr,
895 @intCast(c_uint, args.len),
896 "",
897 );
898
899 const return_type = zig_fn_type.fnReturnType();
900 if (return_type.tag() == .noreturn) {
901 _ = self.builder.buildUnreachable();
902 }
903992
904 // No need to store the LLVM value if the return type is void or noreturn993 // No need to store the LLVM value if the return type is void or noreturn
905 if (!return_type.hasCodeGenBits()) return null;994 if (!return_type.hasCodeGenBits()) return null;
906995
907 return call;996 return call;
908 } else {
909 return self.todo("implement calling runtime known function pointer", .{});
910 }
911 }997 }
912998
913 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {999 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
...@@ -1026,6 +1112,11 @@ pub const FuncGen = struct {...@@ -1026,6 +1112,11 @@ pub const FuncGen = struct {
1026 return null;1112 return null;
1027 }1113 }
10281114
1115 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1116 _ = inst;
1117 return self.todo("implement llvm codegen for switch_br", .{});
1118 }
1119
1029 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1120 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1030 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1121 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1031 const loop = self.air.extraData(Air.Block, ty_pl.payload);1122 const loop = self.air.extraData(Air.Block, ty_pl.payload);
...@@ -1082,10 +1173,32 @@ pub const FuncGen = struct {...@@ -1082,10 +1173,32 @@ pub const FuncGen = struct {
1082 };1173 };
10831174
1084 const indices: [1]*const llvm.Value = .{rhs};1175 const indices: [1]*const llvm.Value = .{rhs};
1085 const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, 1, "");1176 const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
1086 return self.builder.buildLoad(ptr, "");1177 return self.builder.buildLoad(ptr, "");
1087 }1178 }
10881179
1180 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1181 if (self.liveness.isUnused(inst))
1182 return null;
1183
1184 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1185 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
1186 const struct_ptr = try self.resolveInst(struct_field.struct_operand);
1187 const field_index = @intCast(c_uint, struct_field.field_index);
1188 return self.builder.buildStructGEP(struct_ptr, field_index, "");
1189 }
1190
1191 fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1192 if (self.liveness.isUnused(inst))
1193 return null;
1194
1195 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1196 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
1197 const struct_byval = try self.resolveInst(struct_field.struct_operand);
1198 const field_index = @intCast(c_uint, struct_field.field_index);
1199 return self.builder.buildExtractValue(struct_byval, field_index, "");
1200 }
1201
1089 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1202 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1090 if (self.liveness.isUnused(inst))1203 if (self.liveness.isUnused(inst))
1091 return null;1204 return null;
...@@ -1321,7 +1434,7 @@ pub const FuncGen = struct {...@@ -1321,7 +1434,7 @@ pub const FuncGen = struct {
13211434
1322 _ = operand;1435 _ = operand;
1323 _ = operand_is_ptr;1436 _ = operand_is_ptr;
1324 return self.todo("implement 'airErrUnionPayload' for type {}", .{self.air.typeOf(ty_op.operand)});1437 return self.todo("implement llvm codegen for 'airErrUnionPayload' for type {}", .{self.air.typeOf(ty_op.operand)});
1325 }1438 }
13261439
1327 fn airErrUnionErr(1440 fn airErrUnionErr(
...@@ -1332,42 +1445,123 @@ pub const FuncGen = struct {...@@ -1332,42 +1445,123 @@ pub const FuncGen = struct {
1332 if (self.liveness.isUnused(inst))1445 if (self.liveness.isUnused(inst))
1333 return null;1446 return null;
13341447
1335 _ = operand_is_ptr;1448 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1336 return self.todo("implement 'airErrUnionErr'", .{});1449 const operand = try self.resolveInst(ty_op.operand);
1450 const operand_ty = self.air.typeOf(ty_op.operand);
1451
1452 const payload_ty = operand_ty.errorUnionPayload();
1453 if (!payload_ty.hasCodeGenBits()) {
1454 if (!operand_is_ptr) return operand;
1455 return self.builder.buildLoad(operand, "");
1456 }
1457 return self.todo("implement llvm codegen for 'airErrUnionErr'", .{});
1458 }
1459
1460 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1461 if (self.liveness.isUnused(inst))
1462 return null;
1463
1464 return self.todo("implement llvm codegen for 'airWrapOptional'", .{});
1465 }
1466
1467 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1468 if (self.liveness.isUnused(inst))
1469 return null;
1470
1471 return self.todo("implement llvm codegen for 'airWrapErrUnionPayload'", .{});
1472 }
1473
1474 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1475 if (self.liveness.isUnused(inst))
1476 return null;
1477
1478 return self.todo("implement llvm codegen for 'airWrapErrUnionErr'", .{});
1337 }1479 }
13381480
1339 fn airAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1481 fn airAdd(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
1340 if (self.liveness.isUnused(inst))1482 if (self.liveness.isUnused(inst))
1341 return null;1483 return null;
1484
1342 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1485 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1343 const lhs = try self.resolveInst(bin_op.lhs);1486 const lhs = try self.resolveInst(bin_op.lhs);
1344 const rhs = try self.resolveInst(bin_op.rhs);1487 const rhs = try self.resolveInst(bin_op.rhs);
1345 const inst_ty = self.air.typeOfIndex(inst);1488 const inst_ty = self.air.typeOfIndex(inst);
13461489
1347 if (!inst_ty.isInt())1490 if (inst_ty.isFloat()) return self.builder.buildFAdd(lhs, rhs, "");
1348 return self.todo("implement 'airAdd' for type {}", .{inst_ty});1491 if (wrap) return self.builder.buildAdd(lhs, rhs, "");
1492 if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
1493 return self.builder.buildNUWAdd(lhs, rhs, "");
1494 }
13491495
1350 return if (inst_ty.isSignedInt())1496 fn airSub(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
1351 self.builder.buildNSWAdd(lhs, rhs, "")1497 if (self.liveness.isUnused(inst))
1352 else1498 return null;
1353 self.builder.buildNUWAdd(lhs, rhs, "");1499
1500 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1501 const lhs = try self.resolveInst(bin_op.lhs);
1502 const rhs = try self.resolveInst(bin_op.rhs);
1503 const inst_ty = self.air.typeOfIndex(inst);
1504
1505 if (inst_ty.isFloat()) return self.builder.buildFSub(lhs, rhs, "");
1506 if (wrap) return self.builder.buildSub(lhs, rhs, "");
1507 if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
1508 return self.builder.buildNUWSub(lhs, rhs, "");
1354 }1509 }
13551510
1356 fn airSub(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1511 fn airMul(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
1357 if (self.liveness.isUnused(inst))1512 if (self.liveness.isUnused(inst))
1358 return null;1513 return null;
1514
1359 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1515 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1360 const lhs = try self.resolveInst(bin_op.lhs);1516 const lhs = try self.resolveInst(bin_op.lhs);
1361 const rhs = try self.resolveInst(bin_op.rhs);1517 const rhs = try self.resolveInst(bin_op.rhs);
1362 const inst_ty = self.air.typeOfIndex(inst);1518 const inst_ty = self.air.typeOfIndex(inst);
13631519
1364 if (!inst_ty.isInt())1520 if (inst_ty.isFloat()) return self.builder.buildFMul(lhs, rhs, "");
1365 return self.todo("implement 'airSub' for type {}", .{inst_ty});1521 if (wrap) return self.builder.buildMul(lhs, rhs, "");
1522 if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
1523 return self.builder.buildNUWMul(lhs, rhs, "");
1524 }
13661525
1367 return if (inst_ty.isSignedInt())1526 fn airDiv(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1368 self.builder.buildNSWSub(lhs, rhs, "")1527 if (self.liveness.isUnused(inst))
1369 else1528 return null;
1370 self.builder.buildNUWSub(lhs, rhs, "");1529
1530 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1531 const lhs = try self.resolveInst(bin_op.lhs);
1532 const rhs = try self.resolveInst(bin_op.rhs);
1533 const inst_ty = self.air.typeOfIndex(inst);
1534
1535 if (inst_ty.isFloat()) return self.builder.buildFDiv(lhs, rhs, "");
1536 if (inst_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
1537 return self.builder.buildUDiv(lhs, rhs, "");
1538 }
1539
1540 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1541 if (self.liveness.isUnused(inst))
1542 return null;
1543 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1544 const lhs = try self.resolveInst(bin_op.lhs);
1545 const rhs = try self.resolveInst(bin_op.rhs);
1546 return self.builder.buildAnd(lhs, rhs, "");
1547 }
1548
1549 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1550 if (self.liveness.isUnused(inst))
1551 return null;
1552 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1553 const lhs = try self.resolveInst(bin_op.lhs);
1554 const rhs = try self.resolveInst(bin_op.rhs);
1555 return self.builder.buildOr(lhs, rhs, "");
1556 }
1557
1558 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1559 if (self.liveness.isUnused(inst))
1560 return null;
1561 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1562 const lhs = try self.resolveInst(bin_op.lhs);
1563 const rhs = try self.resolveInst(bin_op.rhs);
1564 return self.builder.buildXor(lhs, rhs, "");
1371 }1565 }
13721566
1373 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1567 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
...@@ -1384,6 +1578,14 @@ pub const FuncGen = struct {...@@ -1384,6 +1578,14 @@ pub const FuncGen = struct {
1384 return self.builder.buildIntCast2(operand, try self.dg.llvmType(inst_ty), llvm.Bool.fromBool(signed), "");1578 return self.builder.buildIntCast2(operand, try self.dg.llvmType(inst_ty), llvm.Bool.fromBool(signed), "");
1385 }1579 }
13861580
1581 fn airFloatCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1582 if (self.liveness.isUnused(inst))
1583 return null;
1584
1585 // TODO split floatcast AIR into float_widen and float_shorten
1586 return self.todo("implement 'airFloatCast'", .{});
1587 }
1588
1387 fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1589 fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1388 if (self.liveness.isUnused(inst))1590 if (self.liveness.isUnused(inst))
1389 return null;1591 return null;
...@@ -1474,8 +1676,8 @@ pub const FuncGen = struct {...@@ -1474,8 +1676,8 @@ pub const FuncGen = struct {
14741676
1475 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1677 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1476 _ = inst;1678 _ = inst;
1477 const llvn_fn = self.getIntrinsic("llvm.debugtrap");1679 const llvm_fn = self.getIntrinsic("llvm.debugtrap");
1478 _ = self.builder.buildCall(llvn_fn, undefined, 0, "");1680 _ = self.builder.buildCall(llvm_fn, undefined, 0, "");
1479 return null;1681 return null;
1480 }1682 }
14811683
src/codegen/llvm/bindings.zig+131-2
...@@ -82,6 +82,24 @@ pub const Value = opaque {...@@ -82,6 +82,24 @@ pub const Value = opaque {
8282
83 pub const setGlobalConstant = LLVMSetGlobalConstant;83 pub const setGlobalConstant = LLVMSetGlobalConstant;
84 extern fn LLVMSetGlobalConstant(GlobalVar: *const Value, IsConstant: Bool) void;84 extern fn LLVMSetGlobalConstant(GlobalVar: *const Value, IsConstant: Bool) void;
85
86 pub const setLinkage = LLVMSetLinkage;
87 extern fn LLVMSetLinkage(Global: *const Value, Linkage: Linkage) void;
88
89 pub const setUnnamedAddr = LLVMSetUnnamedAddr;
90 extern fn LLVMSetUnnamedAddr(Global: *const Value, HasUnnamedAddr: Bool) void;
91
92 pub const deleteGlobal = LLVMDeleteGlobal;
93 extern fn LLVMDeleteGlobal(GlobalVar: *const Value) void;
94
95 pub const getNextGlobalAlias = LLVMGetNextGlobalAlias;
96 extern fn LLVMGetNextGlobalAlias(GA: *const Value) *const Value;
97
98 pub const getAliasee = LLVMAliasGetAliasee;
99 extern fn LLVMAliasGetAliasee(Alias: *const Value) *const Value;
100
101 pub const setAliasee = LLVMAliasSetAliasee;
102 extern fn LLVMAliasSetAliasee(Alias: *const Value, Aliasee: *const Value) void;
85};103};
86104
87pub const Type = opaque {105pub const Type = opaque {
...@@ -145,6 +163,27 @@ pub const Module = opaque {...@@ -145,6 +163,27 @@ pub const Module = opaque {
145163
146 pub const dump = LLVMDumpModule;164 pub const dump = LLVMDumpModule;
147 extern fn LLVMDumpModule(M: *const Module) void;165 extern fn LLVMDumpModule(M: *const Module) void;
166
167 pub const getFirstGlobalAlias = LLVMGetFirstGlobalAlias;
168 extern fn LLVMGetFirstGlobalAlias(M: *const Module) *const Value;
169
170 pub const getLastGlobalAlias = LLVMGetLastGlobalAlias;
171 extern fn LLVMGetLastGlobalAlias(M: *const Module) *const Value;
172
173 pub const addAlias = LLVMAddAlias;
174 extern fn LLVMAddAlias(
175 M: *const Module,
176 Ty: *const Type,
177 Aliasee: *const Value,
178 Name: [*:0]const u8,
179 ) *const Value;
180
181 pub const getNamedGlobalAlias = LLVMGetNamedGlobalAlias;
182 extern fn LLVMGetNamedGlobalAlias(
183 M: *const Module,
184 Name: [*]const u8,
185 NameLen: usize,
186 ) ?*const Value;
148};187};
149188
150pub const lookupIntrinsicID = LLVMLookupIntrinsicID;189pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
...@@ -252,18 +291,60 @@ pub const Builder = opaque {...@@ -252,18 +291,60 @@ pub const Builder = opaque {
252 pub const buildNot = LLVMBuildNot;291 pub const buildNot = LLVMBuildNot;
253 extern fn LLVMBuildNot(*const Builder, V: *const Value, Name: [*:0]const u8) *const Value;292 extern fn LLVMBuildNot(*const Builder, V: *const Value, Name: [*:0]const u8) *const Value;
254293
294 pub const buildFAdd = LLVMBuildFAdd;
295 extern fn LLVMBuildFAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
296
297 pub const buildAdd = LLVMBuildAdd;
298 extern fn LLVMBuildAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
299
255 pub const buildNSWAdd = LLVMBuildNSWAdd;300 pub const buildNSWAdd = LLVMBuildNSWAdd;
256 extern fn LLVMBuildNSWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;301 extern fn LLVMBuildNSWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
257302
258 pub const buildNUWAdd = LLVMBuildNUWAdd;303 pub const buildNUWAdd = LLVMBuildNUWAdd;
259 extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;304 extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
260305
306 pub const buildFSub = LLVMBuildFSub;
307 extern fn LLVMBuildFSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
308
309 pub const buildSub = LLVMBuildSub;
310 extern fn LLVMBuildSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
311
261 pub const buildNSWSub = LLVMBuildNSWSub;312 pub const buildNSWSub = LLVMBuildNSWSub;
262 extern fn LLVMBuildNSWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;313 extern fn LLVMBuildNSWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
263314
264 pub const buildNUWSub = LLVMBuildNUWSub;315 pub const buildNUWSub = LLVMBuildNUWSub;
265 extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;316 extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
266317
318 pub const buildFMul = LLVMBuildFMul;
319 extern fn LLVMBuildFMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
320
321 pub const buildMul = LLVMBuildMul;
322 extern fn LLVMBuildMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
323
324 pub const buildNSWMul = LLVMBuildNSWMul;
325 extern fn LLVMBuildNSWMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
326
327 pub const buildNUWMul = LLVMBuildNUWMul;
328 extern fn LLVMBuildNUWMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
329
330 pub const buildUDiv = LLVMBuildUDiv;
331 extern fn LLVMBuildUDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
332
333 pub const buildSDiv = LLVMBuildSDiv;
334 extern fn LLVMBuildSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
335
336 pub const buildFDiv = LLVMBuildFDiv;
337 extern fn LLVMBuildFDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
338
339 pub const buildAnd = LLVMBuildAnd;
340 extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
341
342 pub const buildOr = LLVMBuildOr;
343 extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
344
345 pub const buildXor = LLVMBuildXor;
346 extern fn LLVMBuildXor(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
347
267 pub const buildIntCast2 = LLVMBuildIntCast2;348 pub const buildIntCast2 = LLVMBuildIntCast2;
268 extern fn LLVMBuildIntCast2(*const Builder, Val: *const Value, DestTy: *const Type, IsSigned: Bool, Name: [*:0]const u8) *const Value;349 extern fn LLVMBuildIntCast2(*const Builder, Val: *const Value, DestTy: *const Type, IsSigned: Bool, Name: [*:0]const u8) *const Value;
269350
...@@ -279,6 +360,16 @@ pub const Builder = opaque {...@@ -279,6 +360,16 @@ pub const Builder = opaque {
279 Name: [*:0]const u8,360 Name: [*:0]const u8,
280 ) *const Value;361 ) *const Value;
281362
363 pub const buildInBoundsGEP2 = LLVMBuildInBoundsGEP2;
364 extern fn LLVMBuildInBoundsGEP2(
365 B: *const Builder,
366 Ty: *const Type,
367 Pointer: *const Value,
368 Indices: [*]const *const Value,
369 NumIndices: c_uint,
370 Name: [*:0]const u8,
371 ) *const Value;
372
282 pub const buildICmp = LLVMBuildICmp;373 pub const buildICmp = LLVMBuildICmp;
283 extern fn LLVMBuildICmp(*const Builder, Op: IntPredicate, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;374 extern fn LLVMBuildICmp(*const Builder, Op: IntPredicate, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
284375
...@@ -292,10 +383,28 @@ pub const Builder = opaque {...@@ -292,10 +383,28 @@ pub const Builder = opaque {
292 extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value;383 extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value;
293384
294 pub const buildExtractValue = LLVMBuildExtractValue;385 pub const buildExtractValue = LLVMBuildExtractValue;
295 extern fn LLVMBuildExtractValue(*const Builder, AggVal: *const Value, Index: c_uint, Name: [*:0]const u8) *const Value;386 extern fn LLVMBuildExtractValue(
387 *const Builder,
388 AggVal: *const Value,
389 Index: c_uint,
390 Name: [*:0]const u8,
391 ) *const Value;
296392
297 pub const buildPtrToInt = LLVMBuildPtrToInt;393 pub const buildPtrToInt = LLVMBuildPtrToInt;
298 extern fn LLVMBuildPtrToInt(*const Builder, Val: *const Value, DestTy: *const Type, Name: [*:0]const u8) *const Value;394 extern fn LLVMBuildPtrToInt(
395 *const Builder,
396 Val: *const Value,
397 DestTy: *const Type,
398 Name: [*:0]const u8,
399 ) *const Value;
400
401 pub const buildStructGEP = LLVMBuildStructGEP;
402 extern fn LLVMBuildStructGEP(
403 B: *const Builder,
404 Pointer: *const Value,
405 Idx: c_uint,
406 Name: [*:0]const u8,
407 ) *const Value;
299};408};
300409
301pub const IntPredicate = enum(c_int) {410pub const IntPredicate = enum(c_int) {
...@@ -715,3 +824,23 @@ extern fn ZigLLVMWriteImportLibrary(...@@ -715,3 +824,23 @@ extern fn ZigLLVMWriteImportLibrary(
715 output_lib_path: [*c]const u8,824 output_lib_path: [*c]const u8,
716 kill_at: bool,825 kill_at: bool,
717) bool;826) bool;
827
828pub const Linkage = enum(c_uint) {
829 External,
830 AvailableExternally,
831 LinkOnceAny,
832 LinkOnceODR,
833 LinkOnceODRAutoHide,
834 WeakAny,
835 WeakODR,
836 Appending,
837 Internal,
838 Private,
839 DLLImport,
840 DLLExport,
841 ExternalWeak,
842 Ghost,
843 Common,
844 LinkerPrivate,
845 LinkerPrivateWeak,
846};
src/codegen/wasm.zig+1-1
...@@ -1306,7 +1306,7 @@ pub const Context = struct {...@@ -1306,7 +1306,7 @@ pub const Context = struct {
1306 fn airStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {1306 fn airStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
1307 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1307 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1308 const extra = self.air.extraData(Air.StructField, ty_pl.payload);1308 const extra = self.air.extraData(Air.StructField, ty_pl.payload);
1309 const struct_ptr = self.resolveInst(extra.data.struct_ptr);1309 const struct_ptr = self.resolveInst(extra.data.struct_operand);
13101310
1311 return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, extra.data.field_index) };1311 return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, extra.data.field_index) };
1312 }1312 }
src/link/Coff.zig+12-2
...@@ -777,8 +777,18 @@ pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {...@@ -777,8 +777,18 @@ pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {
777 self.offset_table_free_list.append(self.base.allocator, decl.link.coff.offset_table_index) catch {};777 self.offset_table_free_list.append(self.base.allocator, decl.link.coff.offset_table_index) catch {};
778}778}
779779
780pub fn updateDeclExports(self: *Coff, module: *Module, decl: *Module.Decl, exports: []const *Module.Export) !void {780pub fn updateDeclExports(
781 if (self.llvm_object) |_| return;781 self: *Coff,
782 module: *Module,
783 decl: *Module.Decl,
784 exports: []const *Module.Export,
785) !void {
786 if (build_options.skip_non_native and builtin.object_format != .coff) {
787 @panic("Attempted to compile for object format that was disabled by build configuration");
788 }
789 if (build_options.have_llvm) {
790 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl, exports);
791 }
782792
783 for (exports) |exp| {793 for (exports) |exp| {
784 if (exp.options.section) |section_name| {794 if (exp.options.section) |section_name| {
src/link/Elf.zig+6-1
...@@ -2716,7 +2716,12 @@ pub fn updateDeclExports(...@@ -2716,7 +2716,12 @@ pub fn updateDeclExports(
2716 decl: *Module.Decl,2716 decl: *Module.Decl,
2717 exports: []const *Module.Export,2717 exports: []const *Module.Export,
2718) !void {2718) !void {
2719 if (self.llvm_object) |_| return;2719 if (build_options.skip_non_native and builtin.object_format != .elf) {
2720 @panic("Attempted to compile for object format that was disabled by build configuration");
2721 }
2722 if (build_options.have_llvm) {
2723 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl, exports);
2724 }
27202725
2721 const tracy = trace(@src());2726 const tracy = trace(@src());
2722 defer tracy.end();2727 defer tracy.end();
src/link/MachO.zig+6
...@@ -3785,6 +3785,12 @@ pub fn updateDeclExports(...@@ -3785,6 +3785,12 @@ pub fn updateDeclExports(
3785 decl: *Module.Decl,3785 decl: *Module.Decl,
3786 exports: []const *Module.Export,3786 exports: []const *Module.Export,
3787) !void {3787) !void {
3788 if (build_options.skip_non_native and builtin.object_format != .macho) {
3789 @panic("Attempted to compile for object format that was disabled by build configuration");
3790 }
3791 if (build_options.have_llvm) {
3792 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl, exports);
3793 }
3788 const tracy = trace(@src());3794 const tracy = trace(@src());
3789 defer tracy.end();3795 defer tracy.end();
37903796
src/link/Wasm.zig+6-4
...@@ -330,10 +330,12 @@ pub fn updateDeclExports(...@@ -330,10 +330,12 @@ pub fn updateDeclExports(
330 decl: *const Module.Decl,330 decl: *const Module.Decl,
331 exports: []const *Module.Export,331 exports: []const *Module.Export,
332) !void {332) !void {
333 _ = self;333 if (build_options.skip_non_native and builtin.object_format != .wasm) {
334 _ = module;334 @panic("Attempted to compile for object format that was disabled by build configuration");
335 _ = decl;335 }
336 _ = exports;336 if (build_options.have_llvm) {
337 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl, exports);
338 }
337}339}
338340
339pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {341pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
src/print_air.zig+4-3
...@@ -171,7 +171,8 @@ const Writer = struct {...@@ -171,7 +171,8 @@ const Writer = struct {
171 .loop,171 .loop,
172 => try w.writeBlock(s, inst),172 => try w.writeBlock(s, inst),
173173
174 .struct_field_ptr => try w.writeStructFieldPtr(s, inst),174 .struct_field_ptr => try w.writeStructField(s, inst),
175 .struct_field_val => try w.writeStructField(s, inst),
175 .varptr => try w.writeVarPtr(s, inst),176 .varptr => try w.writeVarPtr(s, inst),
176 .constant => try w.writeConstant(s, inst),177 .constant => try w.writeConstant(s, inst),
177 .assembly => try w.writeAssembly(s, inst),178 .assembly => try w.writeAssembly(s, inst),
...@@ -233,11 +234,11 @@ const Writer = struct {...@@ -233,11 +234,11 @@ const Writer = struct {
233 try s.writeAll("}");234 try s.writeAll("}");
234 }235 }
235236
236 fn writeStructFieldPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {237 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
237 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;238 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
238 const extra = w.air.extraData(Air.StructField, ty_pl.payload);239 const extra = w.air.extraData(Air.StructField, ty_pl.payload);
239240
240 try w.writeOperand(s, inst, 0, extra.data.struct_ptr);241 try w.writeOperand(s, inst, 0, extra.data.struct_operand);
241 try s.print(", {d}", .{extra.data.field_index});242 try s.print(", {d}", .{extra.data.field_index});
242 }243 }
243244