stage2: improvements towards zig test

* There is now a main_pkg in addition to root_pkg. They are usually the
   same. When using `zig test`, main_pkg is the user's source file and
   root_pkg has the test runner.
 * scanDecl no longer looks for test decls outside the package being
   tested. honoring `--test-filter` is still TODO.
 * test runner main function has a void return value rather than
   `anyerror!void`
 * Sema is improved to generate better AIR for for loops on slices.
 * Sema: fix incorrect capacity calculation in zirBoolBr
 * Sema: add compile errors for trying to use slice fields as an lvalue.
 * Sema: fix type coercion for error unions
 * Sema: fix analyzeVarRef generating garbage AIR
 * C codegen: fix renderValue for error unions with 0 bit payload
 * C codegen: implement function pointer calls
 * CLI: fix usage text

 Adds 4 new AIR instructions:

  * slice_len, slice_ptr: to get the ptr and len fields of a slice.
  * slice_elem_val, ptr_slice_elem_val: to get the element value of
    a slice, and a pointer to a slice.

AstGen gains a new functionality:

 * One of the unused flags of struct decls is now used to indicate
   structs that are known to have non-zero size based on the AST alone.
This commit is contained in:
Andrew Kelley
2021-07-23 22:23:03 -07:00
parent f9798108f8
commit 7b8cb881df
25 changed files with 612 additions and 175 deletions

View File

@@ -853,6 +853,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.struct_field_ptr=> try self.airStructFieldPtr(inst),
.switch_br => try self.airSwitch(inst),
.varptr => try self.airVarPtr(inst),
.slice_ptr => try self.airSlicePtr(inst),
.slice_len => try self.airSliceLen(inst),
.slice_elem_val => try self.airSliceElemVal(inst),
.ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
.constant => unreachable, // excluded from function bodies
.const_ty => unreachable, // excluded from function bodies
@@ -1333,6 +1338,38 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return self.finishAir(inst, result, .{ .none, .none, .none });
}
fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
else => return self.fail("TODO implement slice_ptr for {}", .{self.target.cpu.arch}),
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
else => return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch}),
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
else => return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch}),
};
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
fn airPtrSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
else => return self.fail("TODO implement ptr_slice_elem_val for {}", .{self.target.cpu.arch}),
};
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {
if (!self.liveness.operandDies(inst, op_index))
return false;