authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-28 22:38:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-28 22:38:51-07:00
log33e77f127d8237088b561fae2ca0f4412bc1d6c9
tree2ad81a2a7ac5fa5635d6d03456333d30fe568364
parent7efc2a06264170632e56256a5fad97e945768056

stage2: implement `@clz` and `@ctz`

Also improve the LLVM backend to support lowering bigints to LLVM values. Moves over a bunch of math.zig test cases to the "passing for stage2" section.

12 files changed, 379 insertions(+), 216 deletions(-)

src/Air.zig+10
......@@ -160,6 +160,14 @@ pub const Inst = struct {
160160 /// Result type is the return type of the function being called.
161161 /// Uses the `pl_op` field with the `Call` payload. operand is the callee.
162162 call,
163 /// Count leading zeroes of an integer according to its representation in twos complement.
164 /// Result type will always be an unsigned integer big enough to fit the answer.
165 /// Uses the `ty_op` field.
166 clz,
167 /// Count trailing zeroes of an integer according to its representation in twos complement.
168 /// Result type will always be an unsigned integer big enough to fit the answer.
169 /// Uses the `ty_op` field.
170 ctz,
163171
164172 /// `<`. Result type is always bool.
165173 /// Uses the `bin_op` field.
......@@ -669,6 +677,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
669677 .float_to_int,
670678 .int_to_float,
671679 .get_union_tag,
680 .clz,
681 .ctz,
672682 => return air.getRefType(datas[inst].ty_op.ty),
673683
674684 .loop,
src/Liveness.zig+2
......@@ -304,6 +304,8 @@ fn analyzeInst(
304304 .float_to_int,
305305 .int_to_float,
306306 .get_union_tag,
307 .clz,
308 .ctz,
307309 => {
308310 const o = inst_datas[inst].ty_op;
309311 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
src/Sema.zig+56-27
......@@ -4611,8 +4611,8 @@ fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
46114611 const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs);
46124612 const operand = sema.resolveInst(extra.rhs);
46134613
4614 const dest_is_comptime_int = try sema.requireIntegerType(block, dest_ty_src, dest_type);
4615 _ = try sema.requireIntegerType(block, operand_src, sema.typeOf(operand));
4614 const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_type);
4615 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
46164616
46174617 if (try sema.isComptimeKnown(block, operand_src, operand)) {
46184618 return sema.coerce(block, dest_type, operand, operand_src);
......@@ -8384,7 +8384,7 @@ fn zirIntToFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile
83848384 const operand = sema.resolveInst(extra.rhs);
83858385 const operand_ty = sema.typeOf(operand);
83868386
8387 try sema.checkIntType(block, ty_src, dest_ty);
8387 _ = try sema.checkIntType(block, ty_src, dest_ty);
83888388 try sema.checkFloatType(block, operand_src, operand_ty);
83898389
83908390 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
......@@ -8493,8 +8493,8 @@ fn zirTruncate(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
84938493 const operand = sema.resolveInst(extra.rhs);
84948494 const operand_ty = sema.typeOf(operand);
84958495 const mod = sema.mod;
8496 const dest_is_comptime_int = try sema.requireIntegerType(block, dest_ty_src, dest_ty);
8497 const src_is_comptime_int = try sema.requireIntegerType(block, operand_src, operand_ty);
8496 const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_ty);
8497 const src_is_comptime_int = try sema.checkIntType(block, operand_src, operand_ty);
84988498
84998499 if (dest_is_comptime_int) {
85008500 return sema.coerce(block, dest_ty, operand, operand_src);
......@@ -8552,14 +8552,56 @@ fn zirAlignCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
85528552
85538553fn zirClz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
85548554 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
8555 const src = inst_data.src();
8556 return sema.mod.fail(&block.base, src, "TODO: Sema.zirClz", .{});
8555 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
8556 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
8557 const operand = sema.resolveInst(inst_data.operand);
8558 const operand_ty = sema.typeOf(operand);
8559 // TODO implement support for vectors
8560 if (operand_ty.zigTypeTag() != .Int) {
8561 return sema.mod.fail(&block.base, ty_src, "expected integer type, found '{}'", .{
8562 operand_ty,
8563 });
8564 }
8565 const target = sema.mod.getTarget();
8566 const bits = operand_ty.intInfo(target).bits;
8567 if (bits == 0) return Air.Inst.Ref.zero;
8568
8569 const result_ty = try Type.smallestUnsignedInt(sema.arena, bits);
8570
8571 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
8572 if (val.isUndef()) return sema.addConstUndef(result_ty);
8573 return sema.addIntUnsigned(result_ty, val.clz(operand_ty, target));
8574 } else operand_src;
8575
8576 try sema.requireRuntimeBlock(block, runtime_src);
8577 return block.addTyOp(.clz, result_ty, operand);
85578578}
85588579
85598580fn zirCtz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
85608581 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
8561 const src = inst_data.src();
8562 return sema.mod.fail(&block.base, src, "TODO: Sema.zirCtz", .{});
8582 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
8583 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
8584 const operand = sema.resolveInst(inst_data.operand);
8585 const operand_ty = sema.typeOf(operand);
8586 // TODO implement support for vectors
8587 if (operand_ty.zigTypeTag() != .Int) {
8588 return sema.mod.fail(&block.base, ty_src, "expected integer type, found '{}'", .{
8589 operand_ty,
8590 });
8591 }
8592 const target = sema.mod.getTarget();
8593 const bits = operand_ty.intInfo(target).bits;
8594 if (bits == 0) return Air.Inst.Ref.zero;
8595
8596 const result_ty = try Type.smallestUnsignedInt(sema.arena, bits);
8597
8598 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
8599 if (val.isUndef()) return sema.addConstUndef(result_ty);
8600 return sema.mod.fail(&block.base, operand_src, "TODO: implement comptime @ctz", .{});
8601 } else operand_src;
8602
8603 try sema.requireRuntimeBlock(block, runtime_src);
8604 return block.addTyOp(.ctz, result_ty, operand);
85638605}
85648606
85658607fn zirPopCount(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -8616,17 +8658,12 @@ fn zirOffsetOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
86168658 return sema.mod.fail(&block.base, src, "TODO: Sema.zirOffsetOf", .{});
86178659}
86188660
8619fn checkIntType(
8620 sema: *Sema,
8621 block: *Scope.Block,
8622 ty_src: LazySrcLoc,
8623 ty: Type,
8624) CompileError!void {
8661/// Returns `true` if the type was a comptime_int.
8662fn checkIntType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) CompileError!bool {
86258663 switch (ty.zigTypeTag()) {
8626 .ComptimeInt, .Int => {},
8627 else => return sema.mod.fail(&block.base, ty_src, "expected integer type, found '{}'", .{
8628 ty,
8629 }),
8664 .ComptimeInt => return true,
8665 .Int => return false,
8666 else => return sema.mod.fail(&block.base, src, "expected integer type, found '{}'", .{ty}),
86308667 }
86318668}
86328669
......@@ -9416,14 +9453,6 @@ fn requireRuntimeBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void
94169453 try sema.requireFunctionBlock(block, src);
94179454}
94189455
9419fn requireIntegerType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) !bool {
9420 switch (ty.zigTypeTag()) {
9421 .ComptimeInt => return true,
9422 .Int => return false,
9423 else => return sema.mod.fail(&block.base, src, "expected integer type, found '{}'", .{ty}),
9424 }
9425}
9426
94279456/// Emit a compile error if type cannot be used for a runtime variable.
94289457fn validateVarType(
94299458 sema: *Sema,
src/codegen.zig+18
......@@ -896,6 +896,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
896896 .memset => try self.airMemset(inst),
897897 .set_union_tag => try self.airSetUnionTag(inst),
898898 .get_union_tag => try self.airGetUnionTag(inst),
899 .clz => try self.airClz(inst),
900 .ctz => try self.airCtz(inst),
899901
900902 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
901903 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -1606,6 +1608,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16061608 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
16071609 }
16081610
1611 fn airClz(self: *Self, inst: Air.Inst.Index) !void {
1612 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1613 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1614 else => return self.fail("TODO implement airClz for {}", .{self.target.cpu.arch}),
1615 };
1616 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1617 }
1618
1619 fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
1620 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1621 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1622 else => return self.fail("TODO implement airCtz for {}", .{self.target.cpu.arch}),
1623 };
1624 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1625 }
1626
16091627 fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {
16101628 if (!self.liveness.operandDies(inst, op_index))
16111629 return false;
src/codegen/c.zig+19
......@@ -962,6 +962,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
962962 .memcpy => try airMemcpy(f, inst),
963963 .set_union_tag => try airSetUnionTag(f, inst),
964964 .get_union_tag => try airGetUnionTag(f, inst),
965 .clz => try airBuiltinCall(f, inst, "clz"),
966 .ctz => try airBuiltinCall(f, inst, "ctz"),
965967
966968 .int_to_float,
967969 .float_to_int,
......@@ -2075,6 +2077,23 @@ fn airSimpleCast(f: *Function, inst: Air.Inst.Index) !CValue {
20752077 return local;
20762078}
20772079
2080fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue {
2081 if (f.liveness.isUnused(inst)) return CValue.none;
2082
2083 const inst_ty = f.air.typeOfIndex(inst);
2084 const local = try f.allocLocal(inst_ty, .Const);
2085 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
2086 const writer = f.object.writer();
2087 const operand = try f.resolveInst(ty_op.operand);
2088
2089 // TODO implement the function in zig.h and call it here
2090
2091 try writer.print(" = {s}(", .{fn_name});
2092 try f.writeCValue(writer, operand);
2093 try writer.writeAll(");\n");
2094 return local;
2095}
2096
20782097fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
20792098 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
20802099 const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
src/codegen/llvm.zig+43-6
......@@ -889,14 +889,14 @@ pub const DeclGen = struct {
889889 const llvm_type = try self.llvmType(tv.ty);
890890 if (bigint.eqZero()) return llvm_type.constNull();
891891
892 if (bigint.limbs.len != 1) {
893 return self.todo("implement bigger bigint", .{});
894 }
895 const llvm_int = llvm_type.constInt(bigint.limbs[0], .False);
892 const unsigned_val = if (bigint.limbs.len == 1)
893 llvm_type.constInt(bigint.limbs[0], .False)
894 else
895 llvm_type.constIntOfArbitraryPrecision(@intCast(c_uint, bigint.limbs.len), bigint.limbs.ptr);
896896 if (!bigint.positive) {
897 return llvm.constNeg(llvm_int);
897 return llvm.constNeg(unsigned_val);
898898 }
899 return llvm_int;
899 return unsigned_val;
900900 },
901901 .Enum => {
902902 const llvm_type = try self.llvmType(tv.ty);
......@@ -1310,6 +1310,8 @@ pub const FuncGen = struct {
13101310 .memcpy => try self.airMemcpy(inst),
13111311 .set_union_tag => try self.airSetUnionTag(inst),
13121312 .get_union_tag => try self.airGetUnionTag(inst),
1313 .clz => try self.airClzCtz(inst, "ctlz"),
1314 .ctz => try self.airClzCtz(inst, "cttz"),
13131315
13141316 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
13151317 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -2699,6 +2701,41 @@ pub const FuncGen = struct {
26992701 return self.builder.buildExtractValue(un, 1, "");
27002702 }
27012703
2704 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, prefix: [*:0]const u8) !?*const llvm.Value {
2705 if (self.liveness.isUnused(inst)) return null;
2706
2707 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2708 const operand_ty = self.air.typeOf(ty_op.operand);
2709 const operand = try self.resolveInst(ty_op.operand);
2710 const target = self.dg.module.getTarget();
2711 const bits = operand_ty.intInfo(target).bits;
2712
2713 var fn_name_buf: [100]u8 = undefined;
2714 const llvm_fn_name = std.fmt.bufPrintZ(&fn_name_buf, "llvm.{s}.i{d}", .{
2715 prefix, bits,
2716 }) catch unreachable;
2717 const llvm_i1 = self.context.intType(1);
2718 const fn_val = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
2719 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
2720 const param_types = [_]*const llvm.Type{ operand_llvm_ty, llvm_i1 };
2721 const fn_type = llvm.functionType(operand_llvm_ty, &param_types, param_types.len, .False);
2722 break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
2723 };
2724
2725 const params = [_]*const llvm.Value{ operand, llvm_i1.constNull() };
2726 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, "");
2727 const result_ty = self.air.typeOfIndex(inst);
2728 const result_llvm_ty = try self.dg.llvmType(result_ty);
2729 const result_bits = result_ty.intInfo(target).bits;
2730 if (bits > result_bits) {
2731 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
2732 } else if (bits < result_bits) {
2733 return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
2734 } else {
2735 return wrong_size_result;
2736 }
2737 }
2738
27022739 fn fieldPtr(
27032740 self: *FuncGen,
27042741 inst: Air.Inst.Index,
src/codegen/llvm/bindings.zig+5-2
......@@ -172,6 +172,9 @@ pub const Type = opaque {
172172 pub const constInt = LLVMConstInt;
173173 extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: Bool) *const Value;
174174
175 pub const constIntOfArbitraryPrecision = LLVMConstIntOfArbitraryPrecision;
176 extern fn LLVMConstIntOfArbitraryPrecision(IntTy: *const Type, NumWords: c_uint, Words: [*]const u64) *const Value;
177
175178 pub const constReal = LLVMConstReal;
176179 extern fn LLVMConstReal(RealTy: *const Type, N: f64) *const Value;
177180
......@@ -300,7 +303,7 @@ extern fn LLVMGetInlineAsm(
300303pub const functionType = LLVMFunctionType;
301304extern fn LLVMFunctionType(
302305 ReturnType: *const Type,
303 ParamTypes: [*]*const Type,
306 ParamTypes: [*]const *const Type,
304307 ParamCount: c_uint,
305308 IsVarArg: Bool,
306309) *const Type;
......@@ -346,7 +349,7 @@ pub const Builder = opaque {
346349 extern fn LLVMBuildCall(
347350 *const Builder,
348351 Fn: *const Value,
349 Args: [*]*const Value,
352 Args: [*]const *const Value,
350353 NumArgs: c_uint,
351354 Name: [*:0]const u8,
352355 ) *const Value;
src/print_air.zig+2
......@@ -186,6 +186,8 @@ const Writer = struct {
186186 .int_to_float,
187187 .float_to_int,
188188 .get_union_tag,
189 .clz,
190 .ctz,
189191 => try w.writeTyOp(s, inst),
190192
191193 .block,
src/type.zig+3-3
......@@ -3902,16 +3902,16 @@ pub const Type = extern union {
39023902 const bits = bits: {
39033903 if (max == 0) break :bits 0;
39043904 const base = std.math.log2(max);
3905 const upper = (@as(u64, 1) << base) - 1;
3905 const upper = (@as(u64, 1) << @intCast(u6, base)) - 1;
39063906 break :bits base + @boolToInt(upper < max);
39073907 };
3908 return switch (bits) {
3908 return switch (@intCast(u16, bits)) {
39093909 1 => initTag(.u1),
39103910 8 => initTag(.u8),
39113911 16 => initTag(.u16),
39123912 32 => initTag(.u32),
39133913 64 => initTag(.u64),
3914 else => return Tag.int_unsigned.create(arena, bits),
3914 else => |b| return Tag.int_unsigned.create(arena, b),
39153915 };
39163916 }
39173917};
src/value.zig+39
......@@ -962,6 +962,45 @@ pub const Value = extern union {
962962 };
963963 }
964964
965 pub fn clz(val: Value, ty: Type, target: Target) u64 {
966 const ty_bits = ty.intInfo(target).bits;
967 switch (val.tag()) {
968 .zero, .bool_false => return ty_bits,
969 .one, .bool_true => return ty_bits - 1,
970
971 .int_u64 => {
972 const big = @clz(u64, val.castTag(.int_u64).?.data);
973 return big + ty_bits - 64;
974 },
975 .int_i64 => {
976 @panic("TODO implement i64 Value clz");
977 },
978 .int_big_positive => {
979 // TODO: move this code into std lib big ints
980 const bigint = val.castTag(.int_big_positive).?.asBigInt();
981 // Limbs are stored in little-endian order but we need
982 // to iterate big-endian.
983 var total_limb_lz: u64 = 0;
984 var i: usize = bigint.limbs.len;
985 const bits_per_limb = @sizeOf(std.math.big.Limb) * 8;
986 while (i != 0) {
987 i -= 1;
988 const limb = bigint.limbs[i];
989 const this_limb_lz = @clz(std.math.big.Limb, limb);
990 total_limb_lz += this_limb_lz;
991 if (this_limb_lz != bits_per_limb) break;
992 }
993 const total_limb_bits = bigint.limbs.len * bits_per_limb;
994 return total_limb_lz + ty_bits - total_limb_bits;
995 },
996 .int_big_negative => {
997 @panic("TODO implement int_big_negative Value clz");
998 },
999
1000 else => unreachable,
1001 }
1002 }
1003
9651004 /// Asserts the value is an integer and not undefined.
9661005 /// Returns the number of bits the value requires to represent stored in twos complement form.
9671006 pub fn intBitCountTwosComp(self: Value) usize {
test/behavior/math.zig+182
......@@ -53,3 +53,185 @@ fn testThreeExprInARow(f: bool, t: bool) !void {
5353fn assertFalse(b: bool) !void {
5454 try expect(!b);
5555}
56
57test "@clz" {
58 try testClz();
59 comptime try testClz();
60}
61
62fn testClz() !void {
63 try expect(testOneClz(u8, 0b10001010) == 0);
64 try expect(testOneClz(u8, 0b00001010) == 4);
65 try expect(testOneClz(u8, 0b00011010) == 3);
66 try expect(testOneClz(u8, 0b00000000) == 8);
67 try expect(testOneClz(u128, 0xffffffffffffffff) == 64);
68 try expect(testOneClz(u128, 0x10000000000000000) == 63);
69}
70
71fn testOneClz(comptime T: type, x: T) u32 {
72 return @clz(T, x);
73}
74
75test "const number literal" {
76 const one = 1;
77 const eleven = ten + one;
78
79 try expect(eleven == 11);
80}
81const ten = 10;
82
83test "float equality" {
84 const x: f64 = 0.012;
85 const y: f64 = x + 1.0;
86
87 try testFloatEqualityImpl(x, y);
88 comptime try testFloatEqualityImpl(x, y);
89}
90
91fn testFloatEqualityImpl(x: f64, y: f64) !void {
92 const y2 = x + 1.0;
93 try expect(y == y2);
94}
95
96test "hex float literal parsing" {
97 comptime try expect(0x1.0 == 1.0);
98}
99
100test "quad hex float literal parsing in range" {
101 const a = 0x1.af23456789bbaaab347645365cdep+5;
102 const b = 0x1.dedafcff354b6ae9758763545432p-9;
103 const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534;
104 const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
105 _ = a;
106 _ = b;
107 _ = c;
108 _ = d;
109}
110
111test "underscore separator parsing" {
112 try expect(0_0_0_0 == 0);
113 try expect(1_234_567 == 1234567);
114 try expect(001_234_567 == 1234567);
115 try expect(0_0_1_2_3_4_5_6_7 == 1234567);
116
117 try expect(0b0_0_0_0 == 0);
118 try expect(0b1010_1010 == 0b10101010);
119 try expect(0b0000_1010_1010 == 0b10101010);
120 try expect(0b1_0_1_0_1_0_1_0 == 0b10101010);
121
122 try expect(0o0_0_0_0 == 0);
123 try expect(0o1010_1010 == 0o10101010);
124 try expect(0o0000_1010_1010 == 0o10101010);
125 try expect(0o1_0_1_0_1_0_1_0 == 0o10101010);
126
127 try expect(0x0_0_0_0 == 0);
128 try expect(0x1010_1010 == 0x10101010);
129 try expect(0x0000_1010_1010 == 0x10101010);
130 try expect(0x1_0_1_0_1_0_1_0 == 0x10101010);
131
132 try expect(123_456.789_000e1_0 == 123456.789000e10);
133 try expect(0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10);
134
135 try expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10);
136 try expect(0x1_2_3_4_5_6_7_8.9_A_B_C_D_E_F_0p-0_0_0_1_0 == 0x12345678.9ABCDEF0p-10);
137}
138
139test "hex float literal within range" {
140 const a = 0x1.0p16383;
141 const b = 0x0.1p16387;
142 const c = 0x1.0p-16382;
143 _ = a;
144 _ = b;
145 _ = c;
146}
147
148test "comptime_int addition" {
149 comptime {
150 try expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
151 try expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
152 }
153}
154
155test "comptime_int multiplication" {
156 comptime {
157 try expect(
158 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567,
159 );
160 try expect(
161 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016,
162 );
163 }
164}
165
166test "comptime_int shifting" {
167 comptime {
168 try expect((@as(u128, 1) << 127) == 0x80000000000000000000000000000000);
169 }
170}
171
172test "comptime_int multi-limb shift and mask" {
173 comptime {
174 var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
175
176 try expect(@as(u32, a & 0xffffffff) == 0xaaaaaaab);
177 a >>= 32;
178 try expect(@as(u32, a & 0xffffffff) == 0xeeeeeeef);
179 a >>= 32;
180 try expect(@as(u32, a & 0xffffffff) == 0xa0000001);
181 a >>= 32;
182 try expect(@as(u32, a & 0xffffffff) == 0xefffffff);
183 a >>= 32;
184
185 try expect(a == 0);
186 }
187}
188
189test "comptime_int multi-limb partial shift right" {
190 comptime {
191 var a = 0x1ffffffffeeeeeeee;
192 a >>= 16;
193 try expect(a == 0x1ffffffffeeee);
194 }
195}
196
197test "xor" {
198 try test_xor();
199 comptime try test_xor();
200}
201
202fn test_xor() !void {
203 try testOneXor(0xFF, 0x00, 0xFF);
204 try testOneXor(0xF0, 0x0F, 0xFF);
205 try testOneXor(0xFF, 0xF0, 0x0F);
206 try testOneXor(0xFF, 0x0F, 0xF0);
207 try testOneXor(0xFF, 0xFF, 0x00);
208}
209
210fn testOneXor(a: u8, b: u8, c: u8) !void {
211 try expect(a ^ b == c);
212}
213
214test "comptime_int xor" {
215 comptime {
216 try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
217 try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
218 try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
219 try expect(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
220 try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
221 try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
222 try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
223 try expect(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
224 }
225}
226
227test "comptime_int param and return" {
228 const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
229 try expect(a == 137114567242441932203689521744947848950);
230
231 const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768);
232 try expect(b == 985095453608931032642182098849559179469148836107390954364380);
233}
234
235fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
236 return a + b;
237}
test/behavior/math_stage1.zig-178
......@@ -117,20 +117,6 @@ test "@*WithOverflow with u0 values" {
117117 try expect(!@shlWithOverflow(u0, 0, 0, &result));
118118}
119119
120test "@clz" {
121 try testClz();
122 comptime try testClz();
123}
124
125fn testClz() !void {
126 try expect(@clz(u8, 0b10001010) == 0);
127 try expect(@clz(u8, 0b00001010) == 4);
128 try expect(@clz(u8, 0b00011010) == 3);
129 try expect(@clz(u8, 0b00000000) == 8);
130 try expect(@clz(u128, 0xffffffffffffffff) == 64);
131 try expect(@clz(u128, 0x10000000000000000) == 63);
132}
133
134120test "@clz vectors" {
135121 try testClzVectors();
136122 comptime try testClzVectors();
......@@ -171,14 +157,6 @@ fn testCtzVectors() !void {
171157 try expectEqual(@ctz(u16, @splat(64, @as(u16, 0b00000000))), @splat(64, @as(u5, 16)));
172158}
173159
174test "const number literal" {
175 const one = 1;
176 const eleven = ten + one;
177
178 try expect(eleven == 11);
179}
180const ten = 10;
181
182160test "unsigned wrapping" {
183161 try testUnsignedWrappingEval(maxInt(u32));
184162 comptime try testUnsignedWrappingEval(maxInt(u32));
......@@ -274,19 +252,6 @@ test "small int addition" {
274252 try expect(result == 0);
275253}
276254
277test "float equality" {
278 const x: f64 = 0.012;
279 const y: f64 = x + 1.0;
280
281 try testFloatEqualityImpl(x, y);
282 comptime try testFloatEqualityImpl(x, y);
283}
284
285fn testFloatEqualityImpl(x: f64, y: f64) !void {
286 const y2 = x + 1.0;
287 try expect(y == y2);
288}
289
290255test "allow signed integer division/remainder when values are comptime known and positive or exact" {
291256 try expect(5 / 3 == 1);
292257 try expect(-5 / -3 == 1);
......@@ -296,23 +261,6 @@ test "allow signed integer division/remainder when values are comptime known and
296261 try expect(-6 % 3 == 0);
297262}
298263
299test "hex float literal parsing" {
300 comptime try expect(0x1.0 == 1.0);
301}
302
303test "quad hex float literal parsing in range" {
304 const a = 0x1.af23456789bbaaab347645365cdep+5;
305 const b = 0x1.dedafcff354b6ae9758763545432p-9;
306 const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534;
307 const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
308 if (false) {
309 a;
310 b;
311 c;
312 d;
313 }
314}
315
316264test "quad hex float literal parsing accurate" {
317265 const a: f128 = 0x1.1111222233334444555566667777p+0;
318266
......@@ -403,45 +351,6 @@ test "quad hex float literal parsing accurate" {
403351 comptime try S.doTheTest();
404352}
405353
406test "underscore separator parsing" {
407 try expect(0_0_0_0 == 0);
408 try expect(1_234_567 == 1234567);
409 try expect(001_234_567 == 1234567);
410 try expect(0_0_1_2_3_4_5_6_7 == 1234567);
411
412 try expect(0b0_0_0_0 == 0);
413 try expect(0b1010_1010 == 0b10101010);
414 try expect(0b0000_1010_1010 == 0b10101010);
415 try expect(0b1_0_1_0_1_0_1_0 == 0b10101010);
416
417 try expect(0o0_0_0_0 == 0);
418 try expect(0o1010_1010 == 0o10101010);
419 try expect(0o0000_1010_1010 == 0o10101010);
420 try expect(0o1_0_1_0_1_0_1_0 == 0o10101010);
421
422 try expect(0x0_0_0_0 == 0);
423 try expect(0x1010_1010 == 0x10101010);
424 try expect(0x0000_1010_1010 == 0x10101010);
425 try expect(0x1_0_1_0_1_0_1_0 == 0x10101010);
426
427 try expect(123_456.789_000e1_0 == 123456.789000e10);
428 try expect(0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10);
429
430 try expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10);
431 try expect(0x1_2_3_4_5_6_7_8.9_A_B_C_D_E_F_0p-0_0_0_1_0 == 0x12345678.9ABCDEF0p-10);
432}
433
434test "hex float literal within range" {
435 const a = 0x1.0p16383;
436 const b = 0x0.1p16387;
437 const c = 0x1.0p-16382;
438 if (false) {
439 a;
440 b;
441 c;
442 }
443}
444
445354test "truncating shift left" {
446355 try testShlTrunc(maxInt(u16));
447356 comptime try testShlTrunc(maxInt(u16));
......@@ -497,81 +406,6 @@ test "shift left/right on u0 operand" {
497406 comptime try S.doTheTest();
498407}
499408
500test "comptime_int addition" {
501 comptime {
502 try expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
503 try expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
504 }
505}
506
507test "comptime_int multiplication" {
508 comptime {
509 try expect(
510 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567,
511 );
512 try expect(
513 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016,
514 );
515 }
516}
517
518test "comptime_int shifting" {
519 comptime {
520 try expect((@as(u128, 1) << 127) == 0x80000000000000000000000000000000);
521 }
522}
523
524test "comptime_int multi-limb shift and mask" {
525 comptime {
526 var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
527
528 try expect(@as(u32, a & 0xffffffff) == 0xaaaaaaab);
529 a >>= 32;
530 try expect(@as(u32, a & 0xffffffff) == 0xeeeeeeef);
531 a >>= 32;
532 try expect(@as(u32, a & 0xffffffff) == 0xa0000001);
533 a >>= 32;
534 try expect(@as(u32, a & 0xffffffff) == 0xefffffff);
535 a >>= 32;
536
537 try expect(a == 0);
538 }
539}
540
541test "comptime_int multi-limb partial shift right" {
542 comptime {
543 var a = 0x1ffffffffeeeeeeee;
544 a >>= 16;
545 try expect(a == 0x1ffffffffeeee);
546 }
547}
548
549test "xor" {
550 try test_xor();
551 comptime try test_xor();
552}
553
554fn test_xor() !void {
555 try expect(0xFF ^ 0x00 == 0xFF);
556 try expect(0xF0 ^ 0x0F == 0xFF);
557 try expect(0xFF ^ 0xF0 == 0x0F);
558 try expect(0xFF ^ 0x0F == 0xF0);
559 try expect(0xFF ^ 0xFF == 0x00);
560}
561
562test "comptime_int xor" {
563 comptime {
564 try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
565 try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
566 try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
567 try expect(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
568 try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
569 try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
570 try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
571 try expect(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
572 }
573}
574
575409test "f128" {
576410 try test_f128();
577411 comptime try test_f128();
......@@ -757,18 +591,6 @@ fn testRound(comptime T: type, x: T) !void {
757591 try expectEqual(x, z);
758592}
759593
760test "comptime_int param and return" {
761 const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
762 try expect(a == 137114567242441932203689521744947848950);
763
764 const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768);
765 try expect(b == 985095453608931032642182098849559179469148836107390954364380);
766}
767
768fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
769 return a + b;
770}
771
772594test "vector integer addition" {
773595 const S = struct {
774596 fn doTheTest() !void {