| author | |
| committer | |
| log | 31a59c229cb39b9ffd1ee3397a1ce87c36b91477 |
| tree | f4074655750f90c6350a8f3070343da9a724ccfd |
| parent | cdeea3b0943b070d49d8d8d0855f9a38843e3ecc |
* 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 | 247 | /// Given a pointer to a struct and a field index, returns a pointer to the field. |
| 248 | 248 | /// Uses the `ty_pl` field, payload is `StructField`. |
| 249 | 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 | 253 | /// Given a slice value, return the length. |
| 251 | 254 | /// Result type is always usize. |
| 252 | 255 | /// Uses the `ty_op` field. |
| ... | ... | @@ -376,7 +379,8 @@ pub const SwitchBr = struct { |
| 376 | 379 | }; |
| 377 | 380 | |
| 378 | 381 | pub 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 | 384 | field_index: u32, |
| 381 | 385 | }; |
| 382 | 386 | |
| ... | ... | @@ -448,6 +452,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 448 | 452 | .constant, |
| 449 | 453 | .varptr, |
| 450 | 454 | .struct_field_ptr, |
| 455 | .struct_field_val, | |
| 451 | 456 | => return air.getRefType(datas[inst].ty_pl.ty), |
| 452 | 457 | |
| 453 | 458 | .not, |
src/Liveness.zig+2-2| ... | ... | @@ -320,9 +320,9 @@ fn analyzeInst( |
| 320 | 320 | } |
| 321 | 321 | return extra_tombs.finish(); |
| 322 | 322 | }, |
| 323 | .struct_field_ptr => { | |
| 323 | .struct_field_ptr, .struct_field_val => { | |
| 324 | 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 | 327 | .br => { |
| 328 | 328 | const br = inst_datas[inst].br; |
src/Module.zig+2-2| ... | ... | @@ -3702,8 +3702,8 @@ pub fn analyzeExport( |
| 3702 | 3702 | else => return mod.fail(scope, src, "unable to export type '{}'", .{exported_decl.ty}), |
| 3703 | 3703 | } |
| 3704 | 3704 | |
| 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); | |
| 3707 | 3707 | |
| 3708 | 3708 | const new_export = try mod.gpa.create(Export); |
| 3709 | 3709 | errdefer mod.gpa.destroy(new_export); |
src/Sema.zig+318-68| ... | ... | @@ -655,7 +655,7 @@ fn resolveDefinedValue( |
| 655 | 655 | src: LazySrcLoc, |
| 656 | 656 | air_ref: Air.Inst.Ref, |
| 657 | 657 | ) CompileError!?Value { |
| 658 | if (try sema.resolvePossiblyUndefinedValue(block, src, air_ref)) |val| { | |
| 658 | if (try sema.resolveMaybeUndefVal(block, src, air_ref)) |val| { | |
| 659 | 659 | if (val.isUndef()) { |
| 660 | 660 | return sema.failWithUseOfUndef(block, src); |
| 661 | 661 | } |
| ... | ... | @@ -664,7 +664,7 @@ fn resolveDefinedValue( |
| 664 | 664 | return null; |
| 665 | 665 | } |
| 666 | 666 | |
| 667 | fn resolvePossiblyUndefinedValue( | |
| 667 | fn resolveMaybeUndefVal( | |
| 668 | 668 | sema: *Sema, |
| 669 | 669 | block: *Scope.Block, |
| 670 | 670 | src: LazySrcLoc, |
| ... | ... | @@ -1293,7 +1293,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co |
| 1293 | 1293 | }; |
| 1294 | 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 | 1297 | const result_ptr_src = array_ptr_src; |
| 1298 | 1298 | return sema.analyzeLoad(block, src, result_ptr, result_ptr_src); |
| 1299 | 1299 | } |
| ... | ... | @@ -1789,7 +1789,7 @@ fn zirCompileLog( |
| 1789 | 1789 | |
| 1790 | 1790 | const arg = sema.resolveInst(arg_ref); |
| 1791 | 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 | 1793 | try writer.print("@as({}, {})", .{ arg_ty, val }); |
| 1794 | 1794 | } else { |
| 1795 | 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 | 2579 | const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src); |
| 2580 | 2580 | const result_ty = Type.initTag(.u16); |
| 2581 | 2581 | |
| 2582 | if (try sema.resolvePossiblyUndefinedValue(block, src, op_coerced)) |val| { | |
| 2582 | if (try sema.resolveMaybeUndefVal(block, src, op_coerced)) |val| { | |
| 2583 | 2583 | if (val.isUndef()) { |
| 2584 | 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 | 2759 | return sema.addConstant(int_tag_ty, opv); |
| 2760 | 2760 | } |
| 2761 | 2761 | |
| 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 | 2763 | if (enum_tag_val.castTag(.enum_field_index)) |enum_field_payload| { |
| 2764 | 2764 | const field_index = enum_field_payload.data; |
| 2765 | 2765 | switch (enum_tag_ty.tag()) { |
| ... | ... | @@ -2806,7 +2806,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE |
| 2806 | 2806 | return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty}); |
| 2807 | 2807 | } |
| 2808 | 2808 | |
| 2809 | if (try sema.resolvePossiblyUndefinedValue(block, operand_src, operand)) |int_val| { | |
| 2809 | if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |int_val| { | |
| 2810 | 2810 | if (dest_ty.isNonexhaustiveEnum()) { |
| 2811 | 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 | 3309 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 3310 | 3310 | const src = inst_data.src(); |
| 3311 | 3311 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 3312 | const lhs_src: LazySrcLoc = src; // TODO | |
| 3312 | 3313 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 3313 | 3314 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); |
| 3314 | 3315 | 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 | } | |
| 3322 | 3322 | } |
| 3323 | 3323 | |
| 3324 | 3324 | fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -3331,7 +3331,7 @@ fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr |
| 3331 | 3331 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 3332 | 3332 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); |
| 3333 | 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 | } |
| 3336 | 3336 | |
| 3337 | 3337 | fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -3344,9 +3344,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp |
| 3344 | 3344 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 3345 | 3345 | const object = sema.resolveInst(extra.lhs); |
| 3346 | 3346 | 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); | |
| 3350 | 3348 | } |
| 3351 | 3349 | |
| 3352 | 3350 | fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -3359,7 +3357,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp |
| 3359 | 3357 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 3360 | 3358 | const object_ptr = sema.resolveInst(extra.lhs); |
| 3361 | 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 | } |
| 3364 | 3362 | |
| 3365 | 3363 | fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -4691,8 +4689,8 @@ fn zirBitwise( |
| 4691 | 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 | } |
| 4693 | 4691 | |
| 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| { | |
| 4696 | 4694 | if (lhs_val.isUndef() or rhs_val.isUndef()) { |
| 4697 | 4695 | return sema.addConstUndef(resolved_type); |
| 4698 | 4696 | } |
| ... | ... | @@ -4823,8 +4821,8 @@ fn analyzeArithmetic( |
| 4823 | 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 | } |
| 4825 | 4823 | |
| 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| { | |
| 4828 | 4826 | if (lhs_val.isUndef() or rhs_val.isUndef()) { |
| 4829 | 4827 | return sema.addConstUndef(resolved_type); |
| 4830 | 4828 | } |
| ... | ... | @@ -5038,8 +5036,8 @@ fn zirCmp( |
| 5038 | 5036 | if (!is_equality_cmp) { |
| 5039 | 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| { | |
| 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| { | |
| 5043 | 5041 | if (lval.isUndef() or rval.isUndef()) { |
| 5044 | 5042 | return sema.addConstUndef(Type.initTag(.bool)); |
| 5045 | 5043 | } |
| ... | ... | @@ -5085,8 +5083,8 @@ fn zirCmp( |
| 5085 | 5083 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 5086 | 5084 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 5087 | 5085 | |
| 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| { | |
| 5090 | 5088 | if (lhs_val.isUndef() or rhs_val.isUndef()) { |
| 5091 | 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 | 5757 | if (is_comptime) { |
| 5760 | 5758 | const values = try sema.arena.alloc(Value, field_inits.len); |
| 5761 | 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 | 5762 | return sema.addConstant(struct_ty, try Value.Tag.@"struct".create(sema.arena, values.ptr)); |
| 5765 | 5763 | } |
| ... | ... | @@ -6234,7 +6232,7 @@ fn zirVarExtended( |
| 6234 | 6232 | const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 6235 | 6233 | extra_index += 1; |
| 6236 | 6234 | 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 | |
| 6238 | 6236 | return sema.failWithNeededComptime(block, init_src); |
| 6239 | 6237 | } else Value.initTag(.unreachable_value); |
| 6240 | 6238 | |
| ... | ... | @@ -6565,31 +6563,203 @@ fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { |
| 6565 | 6563 | } |
| 6566 | 6564 | } |
| 6567 | 6565 | |
| 6568 | fn namedFieldPtr( | |
| 6566 | fn fieldVal( | |
| 6569 | 6567 | sema: *Sema, |
| 6570 | 6568 | block: *Scope.Block, |
| 6571 | 6569 | src: LazySrcLoc, |
| 6572 | object_ptr: Air.Inst.Ref, | |
| 6570 | object: Air.Inst.Ref, | |
| 6573 | 6571 | field_name: []const u8, |
| 6574 | 6572 | field_name_src: LazySrcLoc, |
| 6575 | 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 | 6577 | const mod = sema.mod; |
| 6577 | 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 | } | |
| 6578 | 6735 | |
| 6736 | fn 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 | 6749 | const object_ptr_src = src; // TODO better source location |
| 6580 | 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 | 6752 | .Pointer => object_ptr_ty.elemType(), |
| 6583 | 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 | 6756 | .Array => { |
| 6587 | 6757 | if (mem.eql(u8, field_name, "len")) { |
| 6588 | 6758 | return sema.addConstant( |
| 6589 | 6759 | Type.initTag(.single_const_pointer_to_comptime_int), |
| 6590 | 6760 | try Value.Tag.ref_val.create( |
| 6591 | 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 | 6765 | } else { |
| ... | ... | @@ -6597,33 +6767,33 @@ fn namedFieldPtr( |
| 6597 | 6767 | &block.base, |
| 6598 | 6768 | field_name_src, |
| 6599 | 6769 | "no member named '{s}' in '{}'", |
| 6600 | .{ field_name, elem_ty }, | |
| 6770 | .{ field_name, object_ty }, | |
| 6601 | 6771 | ); |
| 6602 | 6772 | } |
| 6603 | 6773 | }, |
| 6604 | 6774 | .Pointer => { |
| 6605 | const ptr_child = elem_ty.elemType(); | |
| 6775 | const ptr_child = object_ty.elemType(); | |
| 6606 | 6776 | if (ptr_child.isSlice()) { |
| 6607 | 6777 | if (mem.eql(u8, field_name, "ptr")) { |
| 6608 | 6778 | return mod.fail( |
| 6609 | 6779 | &block.base, |
| 6610 | 6780 | field_name_src, |
| 6611 | 6781 | "cannot obtain reference to pointer field of slice '{}'", |
| 6612 | .{elem_ty}, | |
| 6782 | .{object_ty}, | |
| 6613 | 6783 | ); |
| 6614 | 6784 | } else if (mem.eql(u8, field_name, "len")) { |
| 6615 | 6785 | return mod.fail( |
| 6616 | 6786 | &block.base, |
| 6617 | 6787 | field_name_src, |
| 6618 | 6788 | "cannot obtain reference to length field of slice '{}'", |
| 6619 | .{elem_ty}, | |
| 6789 | .{object_ty}, | |
| 6620 | 6790 | ); |
| 6621 | 6791 | } else { |
| 6622 | 6792 | return mod.fail( |
| 6623 | 6793 | &block.base, |
| 6624 | 6794 | field_name_src, |
| 6625 | 6795 | "no member named '{s}' in '{}'", |
| 6626 | .{ field_name, elem_ty }, | |
| 6796 | .{ field_name, object_ty }, | |
| 6627 | 6797 | ); |
| 6628 | 6798 | } |
| 6629 | 6799 | } else switch (ptr_child.zigTypeTag()) { |
| ... | ... | @@ -6641,7 +6811,7 @@ fn namedFieldPtr( |
| 6641 | 6811 | &block.base, |
| 6642 | 6812 | field_name_src, |
| 6643 | 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 | 6854 | }, |
| 6685 | 6855 | .Struct, .Opaque, .Union => { |
| 6686 | 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 | 6858 | return inst; |
| 6689 | 6859 | } |
| 6690 | 6860 | } |
| ... | ... | @@ -6701,7 +6871,7 @@ fn namedFieldPtr( |
| 6701 | 6871 | }, |
| 6702 | 6872 | .Enum => { |
| 6703 | 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 | 6875 | return inst; |
| 6706 | 6876 | } |
| 6707 | 6877 | } |
| ... | ... | @@ -6734,20 +6904,20 @@ fn namedFieldPtr( |
| 6734 | 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), | |
| 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), | |
| 6739 | 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 | } |
| 6743 | 6913 | |
| 6744 | fn analyzeNamespaceLookup( | |
| 6914 | fn namespaceLookup( | |
| 6745 | 6915 | sema: *Sema, |
| 6746 | 6916 | block: *Scope.Block, |
| 6747 | 6917 | src: LazySrcLoc, |
| 6748 | 6918 | namespace: *Scope.Namespace, |
| 6749 | 6919 | decl_name: []const u8, |
| 6750 | ) CompileError!?Air.Inst.Ref { | |
| 6920 | ) CompileError!?*Decl { | |
| 6751 | 6921 | const mod = sema.mod; |
| 6752 | 6922 | const gpa = sema.gpa; |
| 6753 | 6923 | if (try sema.lookupInNamespace(namespace, decl_name)) |decl| { |
| ... | ... | @@ -6762,12 +6932,23 @@ fn analyzeNamespaceLookup( |
| 6762 | 6932 | }; |
| 6763 | 6933 | return mod.failWithOwnedErrorMsg(&block.base, msg); |
| 6764 | 6934 | } |
| 6765 | return try sema.analyzeDeclRef(block, src, decl); | |
| 6935 | return decl; | |
| 6766 | 6936 | } |
| 6767 | 6937 | return null; |
| 6768 | 6938 | } |
| 6769 | 6939 | |
| 6770 | fn analyzeStructFieldPtr( | |
| 6940 | fn 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 | ||
| 6951 | fn structFieldPtr( | |
| 6771 | 6952 | sema: *Sema, |
| 6772 | 6953 | block: *Scope.Block, |
| 6773 | 6954 | src: LazySrcLoc, |
| ... | ... | @@ -6803,14 +6984,52 @@ fn analyzeStructFieldPtr( |
| 6803 | 6984 | .data = .{ .ty_pl = .{ |
| 6804 | 6985 | .ty = try sema.addType(ptr_field_ty), |
| 6805 | 6986 | .payload = try sema.addExtra(Air.StructField{ |
| 6806 | .struct_ptr = struct_ptr, | |
| 6987 | .struct_operand = struct_ptr, | |
| 6807 | 6988 | .field_index = @intCast(u32, field_index), |
| 6808 | 6989 | }), |
| 6809 | 6990 | } }, |
| 6810 | 6991 | }); |
| 6811 | 6992 | } |
| 6812 | 6993 | |
| 6813 | fn analyzeUnionFieldPtr( | |
| 6994 | fn 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 | ||
| 7032 | fn unionFieldPtr( | |
| 6814 | 7033 | sema: *Sema, |
| 6815 | 7034 | block: *Scope.Block, |
| 6816 | 7035 | src: LazySrcLoc, |
| ... | ... | @@ -6847,6 +7066,37 @@ fn analyzeUnionFieldPtr( |
| 6847 | 7066 | return mod.fail(&block.base, src, "TODO implement runtime union field access", .{}); |
| 6848 | 7067 | } |
| 6849 | 7068 | |
| 7069 | fn 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 | ||
| 6850 | 7100 | fn elemPtr( |
| 6851 | 7101 | sema: *Sema, |
| 6852 | 7102 | block: *Scope.Block, |
| ... | ... | @@ -6973,7 +7223,7 @@ fn coerce( |
| 6973 | 7223 | const arena = sema.arena; |
| 6974 | 7224 | |
| 6975 | 7225 | // undefined to anything |
| 6976 | if (try sema.resolvePossiblyUndefinedValue(block, inst_src, inst)) |val| { | |
| 7226 | if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| { | |
| 6977 | 7227 | if (val.isUndef() or inst_ty.zigTypeTag() == .Undefined) { |
| 6978 | 7228 | return sema.addConstant(dest_type, val); |
| 6979 | 7229 | } |
| ... | ... | @@ -7207,8 +7457,8 @@ fn storePtr( |
| 7207 | 7457 | if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null) |
| 7208 | 7458 | return; |
| 7209 | 7459 | |
| 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 | |
| 7212 | 7462 | return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{}); |
| 7213 | 7463 | |
| 7214 | 7464 | if (ptr_val.tag() == .int_u64) |
| ... | ... | @@ -7252,7 +7502,7 @@ fn bitcast( |
| 7252 | 7502 | inst: Air.Inst.Ref, |
| 7253 | 7503 | inst_src: LazySrcLoc, |
| 7254 | 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 | 7506 | // Keep the comptime Value representation; take the new type. |
| 7257 | 7507 | return sema.addConstant(dest_type, val); |
| 7258 | 7508 | } |
| ... | ... | @@ -7358,7 +7608,7 @@ fn analyzeRef( |
| 7358 | 7608 | const operand_ty = sema.typeOf(operand); |
| 7359 | 7609 | const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One); |
| 7360 | 7610 | |
| 7361 | if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |val| { | |
| 7611 | if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| { | |
| 7362 | 7612 | return sema.addConstant(ptr_type, try Value.Tag.ref_val.create(sema.arena, val)); |
| 7363 | 7613 | } |
| 7364 | 7614 | |
| ... | ... | @@ -7395,7 +7645,7 @@ fn analyzeSliceLen( |
| 7395 | 7645 | src: LazySrcLoc, |
| 7396 | 7646 | slice_inst: Air.Inst.Ref, |
| 7397 | 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 | 7649 | if (slice_val.isUndef()) { |
| 7400 | 7650 | return sema.addConstUndef(Type.initTag(.usize)); |
| 7401 | 7651 | } |
| ... | ... | @@ -7413,7 +7663,7 @@ fn analyzeIsNull( |
| 7413 | 7663 | invert_logic: bool, |
| 7414 | 7664 | ) CompileError!Air.Inst.Ref { |
| 7415 | 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 | 7667 | if (opt_val.isUndef()) { |
| 7418 | 7668 | return sema.addConstUndef(result_ty); |
| 7419 | 7669 | } |
| ... | ... | @@ -7442,7 +7692,7 @@ fn analyzeIsNonErr( |
| 7442 | 7692 | if (ot == .ErrorSet) return Air.Inst.Ref.bool_false; |
| 7443 | 7693 | assert(ot == .ErrorUnion); |
| 7444 | 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 | 7696 | if (err_union.isUndef()) { |
| 7447 | 7697 | return sema.addConstUndef(result_ty); |
| 7448 | 7698 | } |
| ... | ... | @@ -7567,8 +7817,8 @@ fn cmpNumeric( |
| 7567 | 7817 | }); |
| 7568 | 7818 | } |
| 7569 | 7819 | |
| 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| { | |
| 7572 | 7822 | if (lhs_val.isUndef() or rhs_val.isUndef()) { |
| 7573 | 7823 | return sema.addConstUndef(Type.initTag(.bool)); |
| 7574 | 7824 | } |
| ... | ... | @@ -7635,7 +7885,7 @@ fn cmpNumeric( |
| 7635 | 7885 | var dest_float_type: ?Type = null; |
| 7636 | 7886 | |
| 7637 | 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 | 7889 | if (lhs_val.isUndef()) |
| 7640 | 7890 | return sema.addConstUndef(Type.initTag(.bool)); |
| 7641 | 7891 | const is_unsigned = if (lhs_is_float) x: { |
| ... | ... | @@ -7670,7 +7920,7 @@ fn cmpNumeric( |
| 7670 | 7920 | } |
| 7671 | 7921 | |
| 7672 | 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 | 7924 | if (rhs_val.isUndef()) |
| 7675 | 7925 | return sema.addConstUndef(Type.initTag(.bool)); |
| 7676 | 7926 | const is_unsigned = if (rhs_is_float) x: { |
| ... | ... | @@ -7725,7 +7975,7 @@ fn wrapOptional( |
| 7725 | 7975 | inst: Air.Inst.Ref, |
| 7726 | 7976 | inst_src: LazySrcLoc, |
| 7727 | 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 | 7979 | return sema.addConstant(dest_type, val); |
| 7730 | 7980 | } |
| 7731 | 7981 | |
| ... | ... | @@ -7743,7 +7993,7 @@ fn wrapErrorUnion( |
| 7743 | 7993 | const inst_ty = sema.typeOf(inst); |
| 7744 | 7994 | const dest_err_set_ty = dest_type.errorUnionSet(); |
| 7745 | 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 | 7997 | if (inst_ty.zigTypeTag() != .ErrorSet) { |
| 7748 | 7998 | _ = try sema.coerce(block, dest_payload_ty, inst, inst_src); |
| 7749 | 7999 | } else switch (dest_err_set_ty.tag()) { |
| ... | ... | @@ -7956,7 +8206,7 @@ fn getBuiltin( |
| 7956 | 8206 | const mod = sema.mod; |
| 7957 | 8207 | const std_pkg = mod.main_pkg.table.get("std").?; |
| 7958 | 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 | 8210 | block, |
| 7961 | 8211 | src, |
| 7962 | 8212 | std_file.root_decl.?.namespace, |
| ... | ... | @@ -7964,7 +8214,7 @@ fn getBuiltin( |
| 7964 | 8214 | ); |
| 7965 | 8215 | const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst.?, src); |
| 7966 | 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 | 8218 | block, |
| 7969 | 8219 | src, |
| 7970 | 8220 | builtin_ty.getNamespace().?, |
| ... | ... | @@ -8320,5 +8570,5 @@ fn isComptimeKnown( |
| 8320 | 8570 | src: LazySrcLoc, |
| 8321 | 8571 | inst: Air.Inst.Ref, |
| 8322 | 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 | 851 | .ret => try self.airRet(inst), |
| 852 | 852 | .store => try self.airStore(inst), |
| 853 | 853 | .struct_field_ptr=> try self.airStructFieldPtr(inst), |
| 854 | .struct_field_val=> try self.airStructFieldVal(inst), | |
| 854 | 855 | .switch_br => try self.airSwitch(inst), |
| 855 | 856 | .varptr => try self.airVarPtr(inst), |
| 856 | 857 | .slice_ptr => try self.airSlicePtr(inst), |
| ... | ... | @@ -1501,6 +1502,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1501 | 1502 | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); |
| 1502 | 1503 | } |
| 1503 | 1504 | |
| 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 | 1513 | fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool { |
| 1505 | 1514 | return switch (mcv) { |
| 1506 | 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 | 935 | .wrap_optional => try airWrapOptional(o, inst), |
| 936 | 936 | .ref => try airRef(o, inst), |
| 937 | 937 | .struct_field_ptr => try airStructFieldPtr(o, inst), |
| 938 | .struct_field_val => try airStructFieldVal(o, inst), | |
| 938 | 939 | .varptr => try airVarPtr(o, inst), |
| 939 | 940 | .slice_ptr => try airSliceField(o, inst, ".ptr;\n"), |
| 940 | 941 | .slice_len => try airSliceField(o, inst, ".len;\n"), |
| ... | ... | @@ -1660,8 +1661,8 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue { |
| 1660 | 1661 | const ty_pl = o.air.instructions.items(.data)[inst].ty_pl; |
| 1661 | 1662 | const extra = o.air.extraData(Air.StructField, ty_pl.payload).data; |
| 1662 | 1663 | 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); | |
| 1665 | 1666 | const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data; |
| 1666 | 1667 | const field_name = struct_obj.fields.keys()[extra.field_index]; |
| 1667 | 1668 | |
| ... | ... | @@ -1680,6 +1681,26 @@ fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue { |
| 1680 | 1681 | return local; |
| 1681 | 1682 | } |
| 1682 | 1683 | |
| 1684 | fn 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 | 1704 | // *(E!T) -> E NOT *E |
| 1684 | 1705 | fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue { |
| 1685 | 1706 | if (o.liveness.isUnused(inst)) |
src/codegen/llvm.zig+278-76| ... | ... | @@ -350,19 +350,21 @@ pub const Object = struct { |
| 350 | 350 | air: Air, |
| 351 | 351 | liveness: Liveness, |
| 352 | 352 | ) !void { |
| 353 | const decl = func.owner_decl; | |
| 354 | ||
| 353 | 355 | var dg: DeclGen = .{ |
| 354 | 356 | .context = self.context, |
| 355 | 357 | .object = self, |
| 356 | 358 | .module = module, |
| 357 | .decl = func.owner_decl, | |
| 359 | .decl = decl, | |
| 358 | 360 | .err_msg = null, |
| 359 | 361 | .gpa = module.gpa, |
| 360 | 362 | }; |
| 361 | 363 | |
| 362 | const llvm_func = try dg.resolveLLVMFunction(func.owner_decl); | |
| 364 | const llvm_func = try dg.resolveLlvmFunction(decl); | |
| 363 | 365 | |
| 364 | 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 | 368 | var args = try dg.gpa.alloc(*const llvm.Value, fn_param_len); |
| 367 | 369 | |
| 368 | 370 | for (args) |*arg, i| { |
| ... | ... | @@ -400,13 +402,16 @@ pub const Object = struct { |
| 400 | 402 | |
| 401 | 403 | fg.genBody(air.getMainBody()) catch |err| switch (err) { |
| 402 | 404 | 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.?); | |
| 405 | 407 | dg.err_msg = null; |
| 406 | 408 | return; |
| 407 | 409 | }, |
| 408 | 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 | } |
| 411 | 416 | |
| 412 | 417 | pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void { |
| ... | ... | @@ -428,6 +433,38 @@ pub const Object = struct { |
| 428 | 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 | }; |
| 432 | 469 | |
| 433 | 470 | pub const DeclGen = struct { |
| ... | ... | @@ -461,21 +498,19 @@ pub const DeclGen = struct { |
| 461 | 498 | _ = func_payload; |
| 462 | 499 | @panic("TODO llvm backend genDecl function pointer"); |
| 463 | 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 | 502 | } else { |
| 466 | 503 | _ = try self.resolveGlobalDecl(decl); |
| 467 | 504 | } |
| 468 | 505 | } |
| 469 | 506 | |
| 470 | 507 | /// 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; | |
| 474 | 510 | |
| 475 | assert(func.has_tv); | |
| 476 | const zig_fn_type = func.ty; | |
| 511 | assert(decl.has_tv); | |
| 512 | const zig_fn_type = decl.ty; | |
| 477 | 513 | const return_type = zig_fn_type.fnReturnType(); |
| 478 | ||
| 479 | 514 | const fn_param_len = zig_fn_type.fnParamLen(); |
| 480 | 515 | |
| 481 | 516 | const fn_param_types = try self.gpa.alloc(Type, fn_param_len); |
| ... | ... | @@ -495,9 +530,17 @@ pub const DeclGen = struct { |
| 495 | 530 | @intCast(c_uint, fn_param_len), |
| 496 | 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`. | |
| 499 | 542 | |
| 500 | if (return_type.tag() == .noreturn) { | |
| 543 | if (return_type.isNoReturn()) { | |
| 501 | 544 | self.addFnAttr(llvm_fn, "noreturn"); |
| 502 | 545 | } |
| 503 | 546 | |
| ... | ... | @@ -505,7 +548,6 @@ pub const DeclGen = struct { |
| 505 | 548 | } |
| 506 | 549 | |
| 507 | 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 | 551 | if (self.llvmModule().getNamedGlobal(decl.name)) |val| return val; |
| 510 | 552 | |
| 511 | 553 | assert(decl.has_tv); |
| ... | ... | @@ -515,9 +557,11 @@ pub const DeclGen = struct { |
| 515 | 557 | const global = self.llvmModule().addGlobal(llvm_type, decl.name); |
| 516 | 558 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { |
| 517 | 559 | const variable = payload.data; |
| 518 | global.setGlobalConstant(.False); | |
| 519 | 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 | }; | |
| 521 | 565 | |
| 522 | 566 | const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val }, null); |
| 523 | 567 | llvm.setInitializer(global, llvm_init); |
| ... | ... | @@ -602,12 +646,13 @@ pub const DeclGen = struct { |
| 602 | 646 | llvm_param.* = try self.llvmType(t.fnParamType(i)); |
| 603 | 647 | } |
| 604 | 648 | const is_var_args = t.fnIsVarArgs(); |
| 605 | return llvm.functionType( | |
| 649 | const llvm_fn_ty = llvm.functionType( | |
| 606 | 650 | ret_ty, |
| 607 | 651 | llvm_params.ptr, |
| 608 | 652 | @intCast(c_uint, llvm_params.len), |
| 609 | 653 | llvm.Bool.fromBool(is_var_args), |
| 610 | 654 | ); |
| 655 | return llvm_fn_ty.pointerType(0); | |
| 611 | 656 | }, |
| 612 | 657 | .ComptimeInt => unreachable, |
| 613 | 658 | .ComptimeFloat => unreachable, |
| ... | ... | @@ -717,6 +762,42 @@ pub const DeclGen = struct { |
| 717 | 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 | 801 | else => return self.todo("implement const of type '{}'", .{tv.ty}), |
| 721 | 802 | } |
| 722 | 803 | } |
| ... | ... | @@ -801,8 +882,17 @@ pub const FuncGen = struct { |
| 801 | 882 | for (body) |inst| { |
| 802 | 883 | const opt_value: ?*const llvm.Value = switch (air_tags[inst]) { |
| 803 | 884 | // 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), | |
| 806 | 896 | |
| 807 | 897 | .cmp_eq => try self.airCmp(inst, .eq), |
| 808 | 898 | .cmp_gt => try self.airCmp(inst, .gt), |
| ... | ... | @@ -825,10 +915,12 @@ pub const FuncGen = struct { |
| 825 | 915 | .bitcast => try self.airBitCast(inst), |
| 826 | 916 | .block => try self.airBlock(inst), |
| 827 | 917 | .br => try self.airBr(inst), |
| 918 | .switch_br => try self.airSwitchBr(inst), | |
| 828 | 919 | .breakpoint => try self.airBreakpoint(inst), |
| 829 | 920 | .call => try self.airCall(inst), |
| 830 | 921 | .cond_br => try self.airCondBr(inst), |
| 831 | 922 | .intcast => try self.airIntCast(inst), |
| 923 | .floatcast => try self.airFloatCast(inst), | |
| 832 | 924 | .ptrtoint => try self.airPtrToInt(inst), |
| 833 | 925 | .load => try self.airLoad(inst), |
| 834 | 926 | .loop => try self.airLoop(inst), |
| ... | ... | @@ -840,6 +932,9 @@ pub const FuncGen = struct { |
| 840 | 932 | .slice_ptr => try self.airSliceField(inst, 0), |
| 841 | 933 | .slice_len => try self.airSliceField(inst, 1), |
| 842 | 934 | |
| 935 | .struct_field_ptr => try self.airStructFieldPtr(inst), | |
| 936 | .struct_field_val => try self.airStructFieldVal(inst), | |
| 937 | ||
| 843 | 938 | .slice_elem_val => try self.airSliceElemVal(inst, false), |
| 844 | 939 | .ptr_slice_elem_val => try self.airSliceElemVal(inst, true), |
| 845 | 940 | |
| ... | ... | @@ -851,12 +946,18 @@ pub const FuncGen = struct { |
| 851 | 946 | .unwrap_errunion_err => try self.airErrUnionErr(inst, false), |
| 852 | 947 | .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true), |
| 853 | 948 | |
| 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 | 956 | .unreach => self.airUnreach(inst), |
| 855 | 957 | .dbg_stmt => blk: { |
| 856 | 958 | // TODO: implement debug info |
| 857 | 959 | break :blk null; |
| 858 | 960 | }, |
| 859 | else => |tag| return self.todo("implement AIR instruction: {}", .{tag}), | |
| 860 | 961 | // zig fmt: on |
| 861 | 962 | }; |
| 862 | 963 | if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa, inst, val); |
| ... | ... | @@ -867,47 +968,32 @@ pub const FuncGen = struct { |
| 867 | 968 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 868 | 969 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 869 | 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); | |
| 870 | 974 | |
| 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); | |
| 882 | 977 | |
| 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 | } | |
| 885 | 981 | |
| 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 | ); | |
| 889 | 988 | |
| 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 | } | |
| 903 | 992 | |
| 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; | |
| 906 | 995 | |
| 907 | return call; | |
| 908 | } else { | |
| 909 | return self.todo("implement calling runtime known function pointer", .{}); | |
| 910 | } | |
| 996 | return call; | |
| 911 | 997 | } |
| 912 | 998 | |
| 913 | 999 | fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | ... | @@ -1026,6 +1112,11 @@ pub const FuncGen = struct { |
| 1026 | 1112 | return null; |
| 1027 | 1113 | } |
| 1028 | 1114 | |
| 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 | 1120 | fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 1030 | 1121 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1031 | 1122 | const loop = self.air.extraData(Air.Block, ty_pl.payload); |
| ... | ... | @@ -1082,10 +1173,32 @@ pub const FuncGen = struct { |
| 1082 | 1173 | }; |
| 1083 | 1174 | |
| 1084 | 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 | 1177 | return self.builder.buildLoad(ptr, ""); |
| 1087 | 1178 | } |
| 1088 | 1179 | |
| 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 | 1202 | fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 1090 | 1203 | if (self.liveness.isUnused(inst)) |
| 1091 | 1204 | return null; |
| ... | ... | @@ -1321,7 +1434,7 @@ pub const FuncGen = struct { |
| 1321 | 1434 | |
| 1322 | 1435 | _ = operand; |
| 1323 | 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 | } |
| 1326 | 1439 | |
| 1327 | 1440 | fn airErrUnionErr( |
| ... | ... | @@ -1332,42 +1445,123 @@ pub const FuncGen = struct { |
| 1332 | 1445 | if (self.liveness.isUnused(inst)) |
| 1333 | 1446 | return null; |
| 1334 | 1447 | |
| 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'", .{}); | |
| 1337 | 1479 | } |
| 1338 | 1480 | |
| 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 | 1482 | if (self.liveness.isUnused(inst)) |
| 1341 | 1483 | return null; |
| 1484 | ||
| 1342 | 1485 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1343 | 1486 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1344 | 1487 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1345 | 1488 | const inst_ty = self.air.typeOfIndex(inst); |
| 1346 | 1489 | |
| 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 | } | |
| 1349 | 1495 | |
| 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, ""); | |
| 1354 | 1509 | } |
| 1355 | 1510 | |
| 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 | 1512 | if (self.liveness.isUnused(inst)) |
| 1358 | 1513 | return null; |
| 1514 | ||
| 1359 | 1515 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1360 | 1516 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1361 | 1517 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1362 | 1518 | const inst_ty = self.air.typeOfIndex(inst); |
| 1363 | 1519 | |
| 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 | } | |
| 1366 | 1525 | |
| 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, ""); | |
| 1371 | 1565 | } |
| 1372 | 1566 | |
| 1373 | 1567 | fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | ... | @@ -1384,6 +1578,14 @@ pub const FuncGen = struct { |
| 1384 | 1578 | return self.builder.buildIntCast2(operand, try self.dg.llvmType(inst_ty), llvm.Bool.fromBool(signed), ""); |
| 1385 | 1579 | } |
| 1386 | 1580 | |
| 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 | 1589 | fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 1388 | 1590 | if (self.liveness.isUnused(inst)) |
| 1389 | 1591 | return null; |
| ... | ... | @@ -1474,8 +1676,8 @@ pub const FuncGen = struct { |
| 1474 | 1676 | |
| 1475 | 1677 | fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 1476 | 1678 | _ = 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, ""); | |
| 1479 | 1681 | return null; |
| 1480 | 1682 | } |
| 1481 | 1683 |
src/codegen/llvm/bindings.zig+131-2| ... | ... | @@ -82,6 +82,24 @@ pub const Value = opaque { |
| 82 | 82 | |
| 83 | 83 | pub const setGlobalConstant = LLVMSetGlobalConstant; |
| 84 | 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 | }; |
| 86 | 104 | |
| 87 | 105 | pub const Type = opaque { |
| ... | ... | @@ -145,6 +163,27 @@ pub const Module = opaque { |
| 145 | 163 | |
| 146 | 164 | pub const dump = LLVMDumpModule; |
| 147 | 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 | }; |
| 149 | 188 | |
| 150 | 189 | pub const lookupIntrinsicID = LLVMLookupIntrinsicID; |
| ... | ... | @@ -252,18 +291,60 @@ pub const Builder = opaque { |
| 252 | 291 | pub const buildNot = LLVMBuildNot; |
| 253 | 292 | extern fn LLVMBuildNot(*const Builder, V: *const Value, Name: [*:0]const u8) *const Value; |
| 254 | 293 | |
| 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 | 300 | pub const buildNSWAdd = LLVMBuildNSWAdd; |
| 256 | 301 | extern fn LLVMBuildNSWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 257 | 302 | |
| 258 | 303 | pub const buildNUWAdd = LLVMBuildNUWAdd; |
| 259 | 304 | extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 260 | 305 | |
| 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 | 312 | pub const buildNSWSub = LLVMBuildNSWSub; |
| 262 | 313 | extern fn LLVMBuildNSWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 263 | 314 | |
| 264 | 315 | pub const buildNUWSub = LLVMBuildNUWSub; |
| 265 | 316 | extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 266 | 317 | |
| 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 | 348 | pub const buildIntCast2 = LLVMBuildIntCast2; |
| 268 | 349 | extern fn LLVMBuildIntCast2(*const Builder, Val: *const Value, DestTy: *const Type, IsSigned: Bool, Name: [*:0]const u8) *const Value; |
| 269 | 350 | |
| ... | ... | @@ -279,6 +360,16 @@ pub const Builder = opaque { |
| 279 | 360 | Name: [*:0]const u8, |
| 280 | 361 | ) *const Value; |
| 281 | 362 | |
| 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 | 373 | pub const buildICmp = LLVMBuildICmp; |
| 283 | 374 | extern fn LLVMBuildICmp(*const Builder, Op: IntPredicate, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 284 | 375 | |
| ... | ... | @@ -292,10 +383,28 @@ pub const Builder = opaque { |
| 292 | 383 | extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value; |
| 293 | 384 | |
| 294 | 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; | |
| 296 | 392 | |
| 297 | 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 | }; |
| 300 | 409 | |
| 301 | 410 | pub const IntPredicate = enum(c_int) { |
| ... | ... | @@ -715,3 +824,23 @@ extern fn ZigLLVMWriteImportLibrary( |
| 715 | 824 | output_lib_path: [*c]const u8, |
| 716 | 825 | kill_at: bool, |
| 717 | 826 | ) bool; |
| 827 | ||
| 828 | pub 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 | 1306 | fn airStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { |
| 1307 | 1307 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1308 | 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); | |
| 1310 | 1310 | |
| 1311 | 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 | 777 | self.offset_table_free_list.append(self.base.allocator, decl.link.coff.offset_table_index) catch {}; |
| 778 | 778 | } |
| 779 | 779 | |
| 780 | pub fn updateDeclExports(self: *Coff, module: *Module, decl: *Module.Decl, exports: []const *Module.Export) !void { | |
| 781 | if (self.llvm_object) |_| return; | |
| 780 | pub 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 | } | |
| 782 | 792 | |
| 783 | 793 | for (exports) |exp| { |
| 784 | 794 | if (exp.options.section) |section_name| { |
src/link/Elf.zig+6-1| ... | ... | @@ -2716,7 +2716,12 @@ pub fn updateDeclExports( |
| 2716 | 2716 | decl: *Module.Decl, |
| 2717 | 2717 | exports: []const *Module.Export, |
| 2718 | 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 | } | |
| 2720 | 2725 | |
| 2721 | 2726 | const tracy = trace(@src()); |
| 2722 | 2727 | defer tracy.end(); |
src/link/MachO.zig+6| ... | ... | @@ -3785,6 +3785,12 @@ pub fn updateDeclExports( |
| 3785 | 3785 | decl: *Module.Decl, |
| 3786 | 3786 | exports: []const *Module.Export, |
| 3787 | 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 | 3794 | const tracy = trace(@src()); |
| 3789 | 3795 | defer tracy.end(); |
| 3790 | 3796 |
src/link/Wasm.zig+6-4| ... | ... | @@ -330,10 +330,12 @@ pub fn updateDeclExports( |
| 330 | 330 | decl: *const Module.Decl, |
| 331 | 331 | exports: []const *Module.Export, |
| 332 | 332 | ) !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 | } | |
| 337 | 339 | } |
| 338 | 340 | |
| 339 | 341 | pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { |
src/print_air.zig+4-3| ... | ... | @@ -171,7 +171,8 @@ const Writer = struct { |
| 171 | 171 | .loop, |
| 172 | 172 | => try w.writeBlock(s, inst), |
| 173 | 173 | |
| 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 | 176 | .varptr => try w.writeVarPtr(s, inst), |
| 176 | 177 | .constant => try w.writeConstant(s, inst), |
| 177 | 178 | .assembly => try w.writeAssembly(s, inst), |
| ... | ... | @@ -233,11 +234,11 @@ const Writer = struct { |
| 233 | 234 | try s.writeAll("}"); |
| 234 | 235 | } |
| 235 | 236 | |
| 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 | 238 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; |
| 238 | 239 | const extra = w.air.extraData(Air.StructField, ty_pl.payload); |
| 239 | 240 | |
| 240 | try w.writeOperand(s, inst, 0, extra.data.struct_ptr); | |
| 241 | try w.writeOperand(s, inst, 0, extra.data.struct_operand); | |
| 241 | 242 | try s.print(", {d}", .{extra.data.field_index}); |
| 242 | 243 | } |
| 243 | 244 |