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 {
247247 /// Given a pointer to a struct and a field index, returns a pointer to the field.
248248 /// Uses the `ty_pl` field, payload is `StructField`.
249249 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,
250253 /// Given a slice value, return the length.
251254 /// Result type is always usize.
252255 /// Uses the `ty_op` field.
......@@ -376,7 +379,8 @@ pub const SwitchBr = struct {
376379};
377380
378381pub 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,
380384 field_index: u32,
381385};
382386
......@@ -448,6 +452,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
448452 .constant,
449453 .varptr,
450454 .struct_field_ptr,
455 .struct_field_val,
451456 => return air.getRefType(datas[inst].ty_pl.ty),
452457
453458 .not,
src/Liveness.zig+2-2
......@@ -320,9 +320,9 @@ fn analyzeInst(
320320 }
321321 return extra_tombs.finish();
322322 },
323 .struct_field_ptr => {
323 .struct_field_ptr, .struct_field_val => {
324324 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 });
326326 },
327327 .br => {
328328 const br = inst_datas[inst].br;
src/Module.zig+2-2
......@@ -3702,8 +3702,8 @@ pub fn analyzeExport(
37023702 else => return mod.fail(scope, src, "unable to export type '{}'", .{exported_decl.ty}),
37033703 }
37043704
3705 try mod.decl_exports.ensureCapacity(mod.gpa, mod.decl_exports.count() + 1);
3706 try mod.export_owners.ensureCapacity(mod.gpa, mod.export_owners.count() + 1);
3705 try mod.decl_exports.ensureUnusedCapacity(mod.gpa, 1);
3706 try mod.export_owners.ensureUnusedCapacity(mod.gpa, 1);
37073707
37083708 const new_export = try mod.gpa.create(Export);
37093709 errdefer mod.gpa.destroy(new_export);
src/Sema.zig+318-68
......@@ -655,7 +655,7 @@ fn resolveDefinedValue(
655655 src: LazySrcLoc,
656656 air_ref: Air.Inst.Ref,
657657) CompileError!?Value {
658 if (try sema.resolvePossiblyUndefinedValue(block, src, air_ref)) |val| {
658 if (try sema.resolveMaybeUndefVal(block, src, air_ref)) |val| {
659659 if (val.isUndef()) {
660660 return sema.failWithUseOfUndef(block, src);
661661 }
......@@ -664,7 +664,7 @@ fn resolveDefinedValue(
664664 return null;
665665}
666666
667fn resolvePossiblyUndefinedValue(
667fn resolveMaybeUndefVal(
668668 sema: *Sema,
669669 block: *Scope.Block,
670670 src: LazySrcLoc,
......@@ -1293,7 +1293,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
12931293 };
12941294 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
12951295 }
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);
12971297 const result_ptr_src = array_ptr_src;
12981298 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
12991299}
......@@ -1789,7 +1789,7 @@ fn zirCompileLog(
17891789
17901790 const arg = sema.resolveInst(arg_ref);
17911791 const arg_ty = sema.typeOf(arg);
1792 if (try sema.resolvePossiblyUndefinedValue(block, src, arg)) |val| {
1792 if (try sema.resolveMaybeUndefVal(block, src, arg)) |val| {
17931793 try writer.print("@as({}, {})", .{ arg_ty, val });
17941794 } else {
17951795 try writer.print("@as({}, [runtime value])", .{arg_ty});
......@@ -2579,7 +2579,7 @@ fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile
25792579 const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src);
25802580 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| {
25832583 if (val.isUndef()) {
25842584 return sema.addConstUndef(result_ty);
25852585 }
......@@ -2759,7 +2759,7 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
27592759 return sema.addConstant(int_tag_ty, opv);
27602760 }
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| {
27632763 if (enum_tag_val.castTag(.enum_field_index)) |enum_field_payload| {
27642764 const field_index = enum_field_payload.data;
27652765 switch (enum_tag_ty.tag()) {
......@@ -2806,7 +2806,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
28062806 return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});
28072807 }
28082808
2809 if (try sema.resolvePossiblyUndefinedValue(block, operand_src, operand)) |int_val| {
2809 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |int_val| {
28102810 if (dest_ty.isNonexhaustiveEnum()) {
28112811 return sema.addConstant(dest_ty, int_val);
28122812 }
......@@ -3309,16 +3309,16 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
33093309 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
33103310 const src = inst_data.src();
33113311 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
3312 const lhs_src: LazySrcLoc = src; // TODO
33123313 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
33133314 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
33143315 const object = sema.resolveInst(extra.lhs);
3315 const object_ptr = if (sema.typeOf(object).zigTypeTag() == .Pointer)
3316 object
3317 else
3318 try sema.analyzeRef(block, src, object);
3319 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
3320 const result_ptr_src = src;
3321 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
3316 if (sema.typeOf(object).isSinglePointer()) {
3317 const result_ptr = try sema.fieldPtr(block, src, object, field_name, field_name_src);
3318 return sema.analyzeLoad(block, src, result_ptr, lhs_src);
3319 } else {
3320 return sema.fieldVal(block, src, object, field_name, field_name_src);
3321 }
33223322}
33233323
33243324fn 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
33313331 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
33323332 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
33333333 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);
33353335}
33363336
33373337fn 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
33443344 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
33453345 const object = sema.resolveInst(extra.lhs);
33463346 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
3347 const object_ptr = try sema.analyzeRef(block, src, object);
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);
3347 return sema.fieldVal(block, src, object, field_name, field_name_src);
33503348}
33513349
33523350fn 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
33593357 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
33603358 const object_ptr = sema.resolveInst(extra.lhs);
33613359 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);
33633361}
33643362
33653363fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -4691,8 +4689,8 @@ fn zirBitwise(
46914689 return sema.mod.fail(&block.base, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });
46924690 }
46934691
4694 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, casted_lhs)) |lhs_val| {
4695 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, casted_rhs)) |rhs_val| {
4692 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
4693 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
46964694 if (lhs_val.isUndef() or rhs_val.isUndef()) {
46974695 return sema.addConstUndef(resolved_type);
46984696 }
......@@ -4823,8 +4821,8 @@ fn analyzeArithmetic(
48234821 return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });
48244822 }
48254823
4826 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, casted_lhs)) |lhs_val| {
4827 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, casted_rhs)) |rhs_val| {
4824 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
4825 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
48284826 if (lhs_val.isUndef() or rhs_val.isUndef()) {
48294827 return sema.addConstUndef(resolved_type);
48304828 }
......@@ -5038,8 +5036,8 @@ fn zirCmp(
50385036 if (!is_equality_cmp) {
50395037 return mod.fail(&block.base, src, "{s} operator not allowed for errors", .{@tagName(op)});
50405038 }
5041 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, lhs)) |lval| {
5042 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, rhs)) |rval| {
5039 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lval| {
5040 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rval| {
50435041 if (lval.isUndef() or rval.isUndef()) {
50445042 return sema.addConstUndef(Type.initTag(.bool));
50455043 }
......@@ -5085,8 +5083,8 @@ fn zirCmp(
50855083 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
50865084 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| {
5089 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, casted_rhs)) |rhs_val| {
5086 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
5087 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
50905088 if (lhs_val.isUndef() or rhs_val.isUndef()) {
50915089 return sema.addConstUndef(resolved_type);
50925090 }
......@@ -5759,7 +5757,7 @@ fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref:
57595757 if (is_comptime) {
57605758 const values = try sema.arena.alloc(Value, field_inits.len);
57615759 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).?;
57635761 }
57645762 return sema.addConstant(struct_ty, try Value.Tag.@"struct".create(sema.arena, values.ptr));
57655763 }
......@@ -6234,7 +6232,7 @@ fn zirVarExtended(
62346232 const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
62356233 extra_index += 1;
62366234 const init_air_inst = sema.resolveInst(init_ref);
6237 break :blk (try sema.resolvePossiblyUndefinedValue(block, init_src, init_air_inst)) orelse
6235 break :blk (try sema.resolveMaybeUndefVal(block, init_src, init_air_inst)) orelse
62386236 return sema.failWithNeededComptime(block, init_src);
62396237 } else Value.initTag(.unreachable_value);
62406238
......@@ -6565,31 +6563,203 @@ fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
65656563 }
65666564}
65676565
6568fn namedFieldPtr(
6566fn fieldVal(
65696567 sema: *Sema,
65706568 block: *Scope.Block,
65716569 src: LazySrcLoc,
6572 object_ptr: Air.Inst.Ref,
6570 object: Air.Inst.Ref,
65736571 field_name: []const u8,
65746572 field_name_src: LazySrcLoc,
65756573) 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
65766577 const mod = sema.mod;
65776578 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;
65796749 const object_ptr_src = src; // TODO better source location
65806750 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()) {
65826752 .Pointer => object_ptr_ty.elemType(),
65836753 else => return mod.fail(&block.base, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty}),
65846754 };
6585 switch (elem_ty.zigTypeTag()) {
6755 switch (object_ty.zigTypeTag()) {
65866756 .Array => {
65876757 if (mem.eql(u8, field_name, "len")) {
65886758 return sema.addConstant(
65896759 Type.initTag(.single_const_pointer_to_comptime_int),
65906760 try Value.Tag.ref_val.create(
65916761 arena,
6592 try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
6762 try Value.Tag.int_u64.create(arena, object_ty.arrayLen()),
65936763 ),
65946764 );
65956765 } else {
......@@ -6597,33 +6767,33 @@ fn namedFieldPtr(
65976767 &block.base,
65986768 field_name_src,
65996769 "no member named '{s}' in '{}'",
6600 .{ field_name, elem_ty },
6770 .{ field_name, object_ty },
66016771 );
66026772 }
66036773 },
66046774 .Pointer => {
6605 const ptr_child = elem_ty.elemType();
6775 const ptr_child = object_ty.elemType();
66066776 if (ptr_child.isSlice()) {
66076777 if (mem.eql(u8, field_name, "ptr")) {
66086778 return mod.fail(
66096779 &block.base,
66106780 field_name_src,
66116781 "cannot obtain reference to pointer field of slice '{}'",
6612 .{elem_ty},
6782 .{object_ty},
66136783 );
66146784 } else if (mem.eql(u8, field_name, "len")) {
66156785 return mod.fail(
66166786 &block.base,
66176787 field_name_src,
66186788 "cannot obtain reference to length field of slice '{}'",
6619 .{elem_ty},
6789 .{object_ty},
66206790 );
66216791 } else {
66226792 return mod.fail(
66236793 &block.base,
66246794 field_name_src,
66256795 "no member named '{s}' in '{}'",
6626 .{ field_name, elem_ty },
6796 .{ field_name, object_ty },
66276797 );
66286798 }
66296799 } else switch (ptr_child.zigTypeTag()) {
......@@ -6641,7 +6811,7 @@ fn namedFieldPtr(
66416811 &block.base,
66426812 field_name_src,
66436813 "no member named '{s}' in '{}'",
6644 .{ field_name, elem_ty },
6814 .{ field_name, object_ty },
66456815 );
66466816 }
66476817 },
......@@ -6684,7 +6854,7 @@ fn namedFieldPtr(
66846854 },
66856855 .Struct, .Opaque, .Union => {
66866856 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| {
66886858 return inst;
66896859 }
66906860 }
......@@ -6701,7 +6871,7 @@ fn namedFieldPtr(
67016871 },
67026872 .Enum => {
67036873 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| {
67056875 return inst;
67066876 }
67076877 }
......@@ -6734,20 +6904,20 @@ fn namedFieldPtr(
67346904 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
67356905 }
67366906 },
6737 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
6738 .Union => return sema.analyzeUnionFieldPtr(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),
6908 .Union => return sema.unionFieldPtr(block, src, object_ptr, field_name, field_name_src, object_ty),
67396909 else => {},
67406910 }
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});
67426912}
67436913
6744fn analyzeNamespaceLookup(
6914fn namespaceLookup(
67456915 sema: *Sema,
67466916 block: *Scope.Block,
67476917 src: LazySrcLoc,
67486918 namespace: *Scope.Namespace,
67496919 decl_name: []const u8,
6750) CompileError!?Air.Inst.Ref {
6920) CompileError!?*Decl {
67516921 const mod = sema.mod;
67526922 const gpa = sema.gpa;
67536923 if (try sema.lookupInNamespace(namespace, decl_name)) |decl| {
......@@ -6762,12 +6932,23 @@ fn analyzeNamespaceLookup(
67626932 };
67636933 return mod.failWithOwnedErrorMsg(&block.base, msg);
67646934 }
6765 return try sema.analyzeDeclRef(block, src, decl);
6935 return decl;
67666936 }
67676937 return null;
67686938}
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(
67716952 sema: *Sema,
67726953 block: *Scope.Block,
67736954 src: LazySrcLoc,
......@@ -6803,14 +6984,52 @@ fn analyzeStructFieldPtr(
68036984 .data = .{ .ty_pl = .{
68046985 .ty = try sema.addType(ptr_field_ty),
68056986 .payload = try sema.addExtra(Air.StructField{
6806 .struct_ptr = struct_ptr,
6987 .struct_operand = struct_ptr,
68076988 .field_index = @intCast(u32, field_index),
68086989 }),
68096990 } },
68106991 });
68116992}
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(
68147033 sema: *Sema,
68157034 block: *Scope.Block,
68167035 src: LazySrcLoc,
......@@ -6847,6 +7066,37 @@ fn analyzeUnionFieldPtr(
68477066 return mod.fail(&block.base, src, "TODO implement runtime union field access", .{});
68487067}
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
68507100fn elemPtr(
68517101 sema: *Sema,
68527102 block: *Scope.Block,
......@@ -6973,7 +7223,7 @@ fn coerce(
69737223 const arena = sema.arena;
69747224
69757225 // undefined to anything
6976 if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {
7226 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
69777227 if (val.isUndef() or inst_ty.zigTypeTag() == .Undefined) {
69787228 return sema.addConstant(dest_type, val);
69797229 }
......@@ -7207,8 +7457,8 @@ fn storePtr(
72077457 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
72087458 return;
72097459
7210 if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| blk: {
7211 const const_val = (try sema.resolvePossiblyUndefinedValue(block, src, value)) orelse
7460 if (try sema.resolveMaybeUndefVal(block, src, ptr)) |ptr_val| blk: {
7461 const const_val = (try sema.resolveMaybeUndefVal(block, src, value)) orelse
72127462 return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});
72137463
72147464 if (ptr_val.tag() == .int_u64)
......@@ -7252,7 +7502,7 @@ fn bitcast(
72527502 inst: Air.Inst.Ref,
72537503 inst_src: LazySrcLoc,
72547504) CompileError!Air.Inst.Ref {
7255 if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {
7505 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
72567506 // Keep the comptime Value representation; take the new type.
72577507 return sema.addConstant(dest_type, val);
72587508 }
......@@ -7358,7 +7608,7 @@ fn analyzeRef(
73587608 const operand_ty = sema.typeOf(operand);
73597609 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| {
73627612 return sema.addConstant(ptr_type, try Value.Tag.ref_val.create(sema.arena, val));
73637613 }
73647614
......@@ -7395,7 +7645,7 @@ fn analyzeSliceLen(
73957645 src: LazySrcLoc,
73967646 slice_inst: Air.Inst.Ref,
73977647) 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| {
73997649 if (slice_val.isUndef()) {
74007650 return sema.addConstUndef(Type.initTag(.usize));
74017651 }
......@@ -7413,7 +7663,7 @@ fn analyzeIsNull(
74137663 invert_logic: bool,
74147664) CompileError!Air.Inst.Ref {
74157665 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| {
74177667 if (opt_val.isUndef()) {
74187668 return sema.addConstUndef(result_ty);
74197669 }
......@@ -7442,7 +7692,7 @@ fn analyzeIsNonErr(
74427692 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
74437693 assert(ot == .ErrorUnion);
74447694 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| {
74467696 if (err_union.isUndef()) {
74477697 return sema.addConstUndef(result_ty);
74487698 }
......@@ -7567,8 +7817,8 @@ fn cmpNumeric(
75677817 });
75687818 }
75697819
7570 if (try sema.resolvePossiblyUndefinedValue(block, lhs_src, lhs)) |lhs_val| {
7571 if (try sema.resolvePossiblyUndefinedValue(block, rhs_src, rhs)) |rhs_val| {
7820 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
7821 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
75727822 if (lhs_val.isUndef() or rhs_val.isUndef()) {
75737823 return sema.addConstUndef(Type.initTag(.bool));
75747824 }
......@@ -7635,7 +7885,7 @@ fn cmpNumeric(
76357885 var dest_float_type: ?Type = null;
76367886
76377887 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| {
76397889 if (lhs_val.isUndef())
76407890 return sema.addConstUndef(Type.initTag(.bool));
76417891 const is_unsigned = if (lhs_is_float) x: {
......@@ -7670,7 +7920,7 @@ fn cmpNumeric(
76707920 }
76717921
76727922 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| {
76747924 if (rhs_val.isUndef())
76757925 return sema.addConstUndef(Type.initTag(.bool));
76767926 const is_unsigned = if (rhs_is_float) x: {
......@@ -7725,7 +7975,7 @@ fn wrapOptional(
77257975 inst: Air.Inst.Ref,
77267976 inst_src: LazySrcLoc,
77277977) !Air.Inst.Ref {
7728 if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| {
7978 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
77297979 return sema.addConstant(dest_type, val);
77307980 }
77317981
......@@ -7743,7 +7993,7 @@ fn wrapErrorUnion(
77437993 const inst_ty = sema.typeOf(inst);
77447994 const dest_err_set_ty = dest_type.errorUnionSet();
77457995 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| {
77477997 if (inst_ty.zigTypeTag() != .ErrorSet) {
77487998 _ = try sema.coerce(block, dest_payload_ty, inst, inst_src);
77497999 } else switch (dest_err_set_ty.tag()) {
......@@ -7956,7 +8206,7 @@ fn getBuiltin(
79568206 const mod = sema.mod;
79578207 const std_pkg = mod.main_pkg.table.get("std").?;
79588208 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(
79608210 block,
79618211 src,
79628212 std_file.root_decl.?.namespace,
......@@ -7964,7 +8214,7 @@ fn getBuiltin(
79648214 );
79658215 const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst.?, src);
79668216 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(
79688218 block,
79698219 src,
79708220 builtin_ty.getNamespace().?,
......@@ -8320,5 +8570,5 @@ fn isComptimeKnown(
83208570 src: LazySrcLoc,
83218571 inst: Air.Inst.Ref,
83228572) !bool {
8323 return (try sema.resolvePossiblyUndefinedValue(block, src, inst)) != null;
8573 return (try sema.resolveMaybeUndefVal(block, src, inst)) != null;
83248574}
src/codegen.zig+9
......@@ -851,6 +851,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
851851 .ret => try self.airRet(inst),
852852 .store => try self.airStore(inst),
853853 .struct_field_ptr=> try self.airStructFieldPtr(inst),
854 .struct_field_val=> try self.airStructFieldVal(inst),
854855 .switch_br => try self.airSwitch(inst),
855856 .varptr => try self.airVarPtr(inst),
856857 .slice_ptr => try self.airSlicePtr(inst),
......@@ -1501,6 +1502,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
15011502 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
15021503 }
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
15041513 fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool {
15051514 return switch (mcv) {
15061515 .none => unreachable,
src/codegen/c.zig+23-2
......@@ -935,6 +935,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
935935 .wrap_optional => try airWrapOptional(o, inst),
936936 .ref => try airRef(o, inst),
937937 .struct_field_ptr => try airStructFieldPtr(o, inst),
938 .struct_field_val => try airStructFieldVal(o, inst),
938939 .varptr => try airVarPtr(o, inst),
939940 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),
940941 .slice_len => try airSliceField(o, inst, ".len;\n"),
......@@ -1660,8 +1661,8 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
16601661 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
16611662 const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;
16621663 const writer = o.writer();
1663 const struct_ptr = try o.resolveInst(extra.struct_ptr);
1664 const struct_ptr_ty = o.air.typeOf(extra.struct_ptr);
1664 const struct_ptr = try o.resolveInst(extra.struct_operand);
1665 const struct_ptr_ty = o.air.typeOf(extra.struct_operand);
16651666 const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data;
16661667 const field_name = struct_obj.fields.keys()[extra.field_index];
16671668
......@@ -1680,6 +1681,26 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
16801681 return local;
16811682}
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
16831704// *(E!T) -> E NOT *E
16841705fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {
16851706 if (o.liveness.isUnused(inst))
src/codegen/llvm.zig+278-76
......@@ -350,19 +350,21 @@ pub const Object = struct {
350350 air: Air,
351351 liveness: Liveness,
352352 ) !void {
353 const decl = func.owner_decl;
354
353355 var dg: DeclGen = .{
354356 .context = self.context,
355357 .object = self,
356358 .module = module,
357 .decl = func.owner_decl,
359 .decl = decl,
358360 .err_msg = null,
359361 .gpa = module.gpa,
360362 };
361363
362 const llvm_func = try dg.resolveLLVMFunction(func.owner_decl);
364 const llvm_func = try dg.resolveLlvmFunction(decl);
363365
364366 // 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();
366368 var args = try dg.gpa.alloc(*const llvm.Value, fn_param_len);
367369
368370 for (args) |*arg, i| {
......@@ -400,13 +402,16 @@ pub const Object = struct {
400402
401403 fg.genBody(air.getMainBody()) catch |err| switch (err) {
402404 error.CodegenFail => {
403 func.owner_decl.analysis = .codegen_failure;
404 try module.failed_decls.put(module.gpa, func.owner_decl, dg.err_msg.?);
405 decl.analysis = .codegen_failure;
406 try module.failed_decls.put(module.gpa, decl, dg.err_msg.?);
405407 dg.err_msg = null;
406408 return;
407409 },
408410 else => |e| return e,
409411 };
412
413 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
414 try self.updateDeclExports(module, decl, decl_exports);
410415 }
411416
412417 pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
......@@ -428,6 +433,38 @@ pub const Object = struct {
428433 else => |e| return e,
429434 };
430435 }
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 }
431468};
432469
433470pub const DeclGen = struct {
......@@ -461,21 +498,19 @@ pub const DeclGen = struct {
461498 _ = func_payload;
462499 @panic("TODO llvm backend genDecl function pointer");
463500 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {
464 _ = try self.resolveLLVMFunction(extern_fn.data);
501 _ = try self.resolveLlvmFunction(extern_fn.data);
465502 } else {
466503 _ = try self.resolveGlobalDecl(decl);
467504 }
468505 }
469506
470507 /// If the llvm function does not exist, create it
471 fn resolveLLVMFunction(self: *DeclGen, func: *Module.Decl) !*const llvm.Value {
472 // TODO: do we want to store this in our own datastructure?
473 if (self.llvmModule().getNamedFunction(func.name)) |llvm_fn| return llvm_fn;
508 fn resolveLlvmFunction(self: *DeclGen, decl: *Module.Decl) !*const llvm.Value {
509 if (self.llvmModule().getNamedFunction(decl.name)) |llvm_fn| return llvm_fn;
474510
475 assert(func.has_tv);
476 const zig_fn_type = func.ty;
511 assert(decl.has_tv);
512 const zig_fn_type = decl.ty;
477513 const return_type = zig_fn_type.fnReturnType();
478
479514 const fn_param_len = zig_fn_type.fnParamLen();
480515
481516 const fn_param_types = try self.gpa.alloc(Type, fn_param_len);
......@@ -495,9 +530,17 @@ pub const DeclGen = struct {
495530 @intCast(c_uint, fn_param_len),
496531 .False,
497532 );
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()) {
501544 self.addFnAttr(llvm_fn, "noreturn");
502545 }
503546
......@@ -505,7 +548,6 @@ pub const DeclGen = struct {
505548 }
506549
507550 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?
509551 if (self.llvmModule().getNamedGlobal(decl.name)) |val| return val;
510552
511553 assert(decl.has_tv);
......@@ -515,9 +557,11 @@ pub const DeclGen = struct {
515557 const global = self.llvmModule().addGlobal(llvm_type, decl.name);
516558 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
517559 const variable = payload.data;
518 global.setGlobalConstant(.False);
519560 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
522566 const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val }, null);
523567 llvm.setInitializer(global, llvm_init);
......@@ -602,12 +646,13 @@ pub const DeclGen = struct {
602646 llvm_param.* = try self.llvmType(t.fnParamType(i));
603647 }
604648 const is_var_args = t.fnIsVarArgs();
605 return llvm.functionType(
649 const llvm_fn_ty = llvm.functionType(
606650 ret_ty,
607651 llvm_params.ptr,
608652 @intCast(c_uint, llvm_params.len),
609653 llvm.Bool.fromBool(is_var_args),
610654 );
655 return llvm_fn_ty.pointerType(0);
611656 },
612657 .ComptimeInt => unreachable,
613658 .ComptimeFloat => unreachable,
......@@ -717,6 +762,42 @@ pub const DeclGen = struct {
717762 return self.todo("implement const of optional pointer", .{});
718763 }
719764 },
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 },
720801 else => return self.todo("implement const of type '{}'", .{tv.ty}),
721802 }
722803 }
......@@ -801,8 +882,17 @@ pub const FuncGen = struct {
801882 for (body) |inst| {
802883 const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
803884 // zig fmt: off
804 .add => try self.airAdd(inst),
805 .sub => try self.airSub(inst),
885 .add => try self.airAdd(inst, false),
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
807897 .cmp_eq => try self.airCmp(inst, .eq),
808898 .cmp_gt => try self.airCmp(inst, .gt),
......@@ -825,10 +915,12 @@ pub const FuncGen = struct {
825915 .bitcast => try self.airBitCast(inst),
826916 .block => try self.airBlock(inst),
827917 .br => try self.airBr(inst),
918 .switch_br => try self.airSwitchBr(inst),
828919 .breakpoint => try self.airBreakpoint(inst),
829920 .call => try self.airCall(inst),
830921 .cond_br => try self.airCondBr(inst),
831922 .intcast => try self.airIntCast(inst),
923 .floatcast => try self.airFloatCast(inst),
832924 .ptrtoint => try self.airPtrToInt(inst),
833925 .load => try self.airLoad(inst),
834926 .loop => try self.airLoop(inst),
......@@ -840,6 +932,9 @@ pub const FuncGen = struct {
840932 .slice_ptr => try self.airSliceField(inst, 0),
841933 .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
843938 .slice_elem_val => try self.airSliceElemVal(inst, false),
844939 .ptr_slice_elem_val => try self.airSliceElemVal(inst, true),
845940
......@@ -851,12 +946,18 @@ pub const FuncGen = struct {
851946 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),
852947 .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
854956 .unreach => self.airUnreach(inst),
855957 .dbg_stmt => blk: {
856958 // TODO: implement debug info
857959 break :blk null;
858960 },
859 else => |tag| return self.todo("implement AIR instruction: {}", .{tag}),
860961 // zig fmt: on
861962 };
862963 if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa, inst, val);
......@@ -867,47 +968,32 @@ pub const FuncGen = struct {
867968 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
868969 const extra = self.air.extraData(Air.Call, pl_op.payload);
869970 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| {
872 const fn_decl = if (func_value.castTag(.extern_fn)) |extern_fn|
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);
975 const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len);
976 defer self.gpa.free(llvm_param_vals);
882977
883 const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len);
884 defer self.gpa.free(llvm_param_vals);
978 for (args) |arg, i| {
979 llvm_param_vals[i] = try self.resolveInst(arg);
980 }
885981
886 for (args) |arg, i| {
887 llvm_param_vals[i] = try self.resolveInst(arg);
888 }
982 const call = self.builder.buildCall(
983 llvm_fn,
984 llvm_param_vals.ptr,
985 @intCast(c_uint, args.len),
986 "",
987 );
889988
890 // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs
891 // Do we need that?
892 const call = self.builder.buildCall(
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 }
989 if (return_type.isNoReturn()) {
990 _ = self.builder.buildUnreachable();
991 }
903992
904 // No need to store the LLVM value if the return type is void or noreturn
905 if (!return_type.hasCodeGenBits()) return null;
993 // No need to store the LLVM value if the return type is void or noreturn
994 if (!return_type.hasCodeGenBits()) return null;
906995
907 return call;
908 } else {
909 return self.todo("implement calling runtime known function pointer", .{});
910 }
996 return call;
911997 }
912998
913999 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
......@@ -1026,6 +1112,11 @@ pub const FuncGen = struct {
10261112 return null;
10271113 }
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
10291120 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
10301121 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
10311122 const loop = self.air.extraData(Air.Block, ty_pl.payload);
......@@ -1082,10 +1173,32 @@ pub const FuncGen = struct {
10821173 };
10831174
10841175 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, "");
10861177 return self.builder.buildLoad(ptr, "");
10871178 }
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
10891202 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
10901203 if (self.liveness.isUnused(inst))
10911204 return null;
......@@ -1321,7 +1434,7 @@ pub const FuncGen = struct {
13211434
13221435 _ = operand;
13231436 _ = 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)});
13251438 }
13261439
13271440 fn airErrUnionErr(
......@@ -1332,42 +1445,123 @@ pub const FuncGen = struct {
13321445 if (self.liveness.isUnused(inst))
13331446 return null;
13341447
1335 _ = operand_is_ptr;
1336 return self.todo("implement 'airErrUnionErr'", .{});
1448 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
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'", .{});
13371479 }
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 {
13401482 if (self.liveness.isUnused(inst))
13411483 return null;
1484
13421485 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
13431486 const lhs = try self.resolveInst(bin_op.lhs);
13441487 const rhs = try self.resolveInst(bin_op.rhs);
13451488 const inst_ty = self.air.typeOfIndex(inst);
13461489
1347 if (!inst_ty.isInt())
1348 return self.todo("implement 'airAdd' for type {}", .{inst_ty});
1490 if (inst_ty.isFloat()) return self.builder.buildFAdd(lhs, rhs, "");
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())
1351 self.builder.buildNSWAdd(lhs, rhs, "")
1352 else
1353 self.builder.buildNUWAdd(lhs, rhs, "");
1496 fn airSub(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
1497 if (self.liveness.isUnused(inst))
1498 return null;
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, "");
13541509 }
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 {
13571512 if (self.liveness.isUnused(inst))
13581513 return null;
1514
13591515 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
13601516 const lhs = try self.resolveInst(bin_op.lhs);
13611517 const rhs = try self.resolveInst(bin_op.rhs);
13621518 const inst_ty = self.air.typeOfIndex(inst);
13631519
1364 if (!inst_ty.isInt())
1365 return self.todo("implement 'airSub' for type {}", .{inst_ty});
1520 if (inst_ty.isFloat()) return self.builder.buildFMul(lhs, rhs, "");
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())
1368 self.builder.buildNSWSub(lhs, rhs, "")
1369 else
1370 self.builder.buildNUWSub(lhs, rhs, "");
1526 fn airDiv(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1527 if (self.liveness.isUnused(inst))
1528 return null;
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, "");
13711565 }
13721566
13731567 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
......@@ -1384,6 +1578,14 @@ pub const FuncGen = struct {
13841578 return self.builder.buildIntCast2(operand, try self.dg.llvmType(inst_ty), llvm.Bool.fromBool(signed), "");
13851579 }
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
13871589 fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
13881590 if (self.liveness.isUnused(inst))
13891591 return null;
......@@ -1474,8 +1676,8 @@ pub const FuncGen = struct {
14741676
14751677 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
14761678 _ = inst;
1477 const llvn_fn = self.getIntrinsic("llvm.debugtrap");
1478 _ = self.builder.buildCall(llvn_fn, undefined, 0, "");
1679 const llvm_fn = self.getIntrinsic("llvm.debugtrap");
1680 _ = self.builder.buildCall(llvm_fn, undefined, 0, "");
14791681 return null;
14801682 }
14811683
src/codegen/llvm/bindings.zig+131-2
......@@ -82,6 +82,24 @@ pub const Value = opaque {
8282
8383 pub const setGlobalConstant = LLVMSetGlobalConstant;
8484 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;
85103};
86104
87105pub const Type = opaque {
......@@ -145,6 +163,27 @@ pub const Module = opaque {
145163
146164 pub const dump = LLVMDumpModule;
147165 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;
148187};
149188
150189pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
......@@ -252,18 +291,60 @@ pub const Builder = opaque {
252291 pub const buildNot = LLVMBuildNot;
253292 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
255300 pub const buildNSWAdd = LLVMBuildNSWAdd;
256301 extern fn LLVMBuildNSWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
257302
258303 pub const buildNUWAdd = LLVMBuildNUWAdd;
259304 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
261312 pub const buildNSWSub = LLVMBuildNSWSub;
262313 extern fn LLVMBuildNSWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
263314
264315 pub const buildNUWSub = LLVMBuildNUWSub;
265316 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
267348 pub const buildIntCast2 = LLVMBuildIntCast2;
268349 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 {
279360 Name: [*:0]const u8,
280361 ) *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
282373 pub const buildICmp = LLVMBuildICmp;
283374 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 {
292383 extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value;
293384
294385 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
297393 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;
299408};
300409
301410pub const IntPredicate = enum(c_int) {
......@@ -715,3 +824,23 @@ extern fn ZigLLVMWriteImportLibrary(
715824 output_lib_path: [*c]const u8,
716825 kill_at: bool,
717826) 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 {
13061306 fn airStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
13071307 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
13081308 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
13111311 return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, extra.data.field_index) };
13121312 }
src/link/Coff.zig+12-2
......@@ -777,8 +777,18 @@ pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {
777777 self.offset_table_free_list.append(self.base.allocator, decl.link.coff.offset_table_index) catch {};
778778}
779779
780pub fn updateDeclExports(self: *Coff, module: *Module, decl: *Module.Decl, exports: []const *Module.Export) !void {
781 if (self.llvm_object) |_| return;
780pub fn updateDeclExports(
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
783793 for (exports) |exp| {
784794 if (exp.options.section) |section_name| {
src/link/Elf.zig+6-1
......@@ -2716,7 +2716,12 @@ pub fn updateDeclExports(
27162716 decl: *Module.Decl,
27172717 exports: []const *Module.Export,
27182718) !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
27212726 const tracy = trace(@src());
27222727 defer tracy.end();
src/link/MachO.zig+6
......@@ -3785,6 +3785,12 @@ pub fn updateDeclExports(
37853785 decl: *Module.Decl,
37863786 exports: []const *Module.Export,
37873787) !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 }
37883794 const tracy = trace(@src());
37893795 defer tracy.end();
37903796
src/link/Wasm.zig+6-4
......@@ -330,10 +330,12 @@ pub fn updateDeclExports(
330330 decl: *const Module.Decl,
331331 exports: []const *Module.Export,
332332) !void {
333 _ = self;
334 _ = module;
335 _ = decl;
336 _ = exports;
333 if (build_options.skip_non_native and builtin.object_format != .wasm) {
334 @panic("Attempted to compile for object format that was disabled by build configuration");
335 }
336 if (build_options.have_llvm) {
337 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl, exports);
338 }
337339}
338340
339341pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
src/print_air.zig+4-3
......@@ -171,7 +171,8 @@ const Writer = struct {
171171 .loop,
172172 => 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),
175176 .varptr => try w.writeVarPtr(s, inst),
176177 .constant => try w.writeConstant(s, inst),
177178 .assembly => try w.writeAssembly(s, inst),
......@@ -233,11 +234,11 @@ const Writer = struct {
233234 try s.writeAll("}");
234235 }
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 {
237238 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
238239 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);
241242 try s.print(", {d}", .{extra.data.field_index});
242243 }
243244