Commit 33e77f127d
Changed files (12)
src
test
behavior
src/codegen/llvm/bindings.zig
@@ -172,6 +172,9 @@ pub const Type = opaque {
pub const constInt = LLVMConstInt;
extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: Bool) *const Value;
+ pub const constIntOfArbitraryPrecision = LLVMConstIntOfArbitraryPrecision;
+ extern fn LLVMConstIntOfArbitraryPrecision(IntTy: *const Type, NumWords: c_uint, Words: [*]const u64) *const Value;
+
pub const constReal = LLVMConstReal;
extern fn LLVMConstReal(RealTy: *const Type, N: f64) *const Value;
@@ -300,7 +303,7 @@ extern fn LLVMGetInlineAsm(
pub const functionType = LLVMFunctionType;
extern fn LLVMFunctionType(
ReturnType: *const Type,
- ParamTypes: [*]*const Type,
+ ParamTypes: [*]const *const Type,
ParamCount: c_uint,
IsVarArg: Bool,
) *const Type;
@@ -346,7 +349,7 @@ pub const Builder = opaque {
extern fn LLVMBuildCall(
*const Builder,
Fn: *const Value,
- Args: [*]*const Value,
+ Args: [*]const *const Value,
NumArgs: c_uint,
Name: [*:0]const u8,
) *const Value;
src/codegen/c.zig
@@ -962,6 +962,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.memcpy => try airMemcpy(f, inst),
.set_union_tag => try airSetUnionTag(f, inst),
.get_union_tag => try airGetUnionTag(f, inst),
+ .clz => try airBuiltinCall(f, inst, "clz"),
+ .ctz => try airBuiltinCall(f, inst, "ctz"),
.int_to_float,
.float_to_int,
@@ -2075,6 +2077,23 @@ fn airSimpleCast(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
+fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue {
+ if (f.liveness.isUnused(inst)) return CValue.none;
+
+ const inst_ty = f.air.typeOfIndex(inst);
+ const local = try f.allocLocal(inst_ty, .Const);
+ const ty_op = f.air.instructions.items(.data)[inst].ty_op;
+ const writer = f.object.writer();
+ const operand = try f.resolveInst(ty_op.operand);
+
+ // TODO implement the function in zig.h and call it here
+
+ try writer.print(" = {s}(", .{fn_name});
+ try f.writeCValue(writer, operand);
+ try writer.writeAll(");\n");
+ return local;
+}
+
fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
src/codegen/llvm.zig
@@ -889,14 +889,14 @@ pub const DeclGen = struct {
const llvm_type = try self.llvmType(tv.ty);
if (bigint.eqZero()) return llvm_type.constNull();
- if (bigint.limbs.len != 1) {
- return self.todo("implement bigger bigint", .{});
- }
- const llvm_int = llvm_type.constInt(bigint.limbs[0], .False);
+ const unsigned_val = if (bigint.limbs.len == 1)
+ llvm_type.constInt(bigint.limbs[0], .False)
+ else
+ llvm_type.constIntOfArbitraryPrecision(@intCast(c_uint, bigint.limbs.len), bigint.limbs.ptr);
if (!bigint.positive) {
- return llvm.constNeg(llvm_int);
+ return llvm.constNeg(unsigned_val);
}
- return llvm_int;
+ return unsigned_val;
},
.Enum => {
const llvm_type = try self.llvmType(tv.ty);
@@ -1310,6 +1310,8 @@ pub const FuncGen = struct {
.memcpy => try self.airMemcpy(inst),
.set_union_tag => try self.airSetUnionTag(inst),
.get_union_tag => try self.airGetUnionTag(inst),
+ .clz => try self.airClzCtz(inst, "ctlz"),
+ .ctz => try self.airClzCtz(inst, "cttz"),
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
@@ -2699,6 +2701,41 @@ pub const FuncGen = struct {
return self.builder.buildExtractValue(un, 1, "");
}
+ fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, prefix: [*:0]const u8) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst)) return null;
+
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand_ty = self.air.typeOf(ty_op.operand);
+ const operand = try self.resolveInst(ty_op.operand);
+ const target = self.dg.module.getTarget();
+ const bits = operand_ty.intInfo(target).bits;
+
+ var fn_name_buf: [100]u8 = undefined;
+ const llvm_fn_name = std.fmt.bufPrintZ(&fn_name_buf, "llvm.{s}.i{d}", .{
+ prefix, bits,
+ }) catch unreachable;
+ const llvm_i1 = self.context.intType(1);
+ const fn_val = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
+ const operand_llvm_ty = try self.dg.llvmType(operand_ty);
+ const param_types = [_]*const llvm.Type{ operand_llvm_ty, llvm_i1 };
+ const fn_type = llvm.functionType(operand_llvm_ty, ¶m_types, param_types.len, .False);
+ break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
+ };
+
+ const params = [_]*const llvm.Value{ operand, llvm_i1.constNull() };
+ const wrong_size_result = self.builder.buildCall(fn_val, ¶ms, params.len, "");
+ const result_ty = self.air.typeOfIndex(inst);
+ const result_llvm_ty = try self.dg.llvmType(result_ty);
+ const result_bits = result_ty.intInfo(target).bits;
+ if (bits > result_bits) {
+ return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
+ } else if (bits < result_bits) {
+ return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
+ } else {
+ return wrong_size_result;
+ }
+ }
+
fn fieldPtr(
self: *FuncGen,
inst: Air.Inst.Index,
src/Air.zig
@@ -160,6 +160,14 @@ pub const Inst = struct {
/// Result type is the return type of the function being called.
/// Uses the `pl_op` field with the `Call` payload. operand is the callee.
call,
+ /// Count leading zeroes of an integer according to its representation in twos complement.
+ /// Result type will always be an unsigned integer big enough to fit the answer.
+ /// Uses the `ty_op` field.
+ clz,
+ /// Count trailing zeroes of an integer according to its representation in twos complement.
+ /// Result type will always be an unsigned integer big enough to fit the answer.
+ /// Uses the `ty_op` field.
+ ctz,
/// `<`. Result type is always bool.
/// Uses the `bin_op` field.
@@ -669,6 +677,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.float_to_int,
.int_to_float,
.get_union_tag,
+ .clz,
+ .ctz,
=> return air.getRefType(datas[inst].ty_op.ty),
.loop,
src/codegen.zig
@@ -896,6 +896,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.memset => try self.airMemset(inst),
.set_union_tag => try self.airSetUnionTag(inst),
.get_union_tag => try self.airGetUnionTag(inst),
+ .clz => try self.airClz(inst),
+ .ctz => try self.airCtz(inst),
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
@@ -1606,6 +1608,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
+ fn airClz(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 airClz for {}", .{self.target.cpu.arch}),
+ };
+ return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
+ }
+
+ fn airCtz(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 airCtz for {}", .{self.target.cpu.arch}),
+ };
+ return self.finishAir(inst, result, .{ ty_op.operand, .none, .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;
src/Liveness.zig
@@ -304,6 +304,8 @@ fn analyzeInst(
.float_to_int,
.int_to_float,
.get_union_tag,
+ .clz,
+ .ctz,
=> {
const o = inst_datas[inst].ty_op;
return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
src/print_air.zig
@@ -186,6 +186,8 @@ const Writer = struct {
.int_to_float,
.float_to_int,
.get_union_tag,
+ .clz,
+ .ctz,
=> try w.writeTyOp(s, inst),
.block,
src/Sema.zig
@@ -4611,8 +4611,8 @@ fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs);
const operand = sema.resolveInst(extra.rhs);
- const dest_is_comptime_int = try sema.requireIntegerType(block, dest_ty_src, dest_type);
- _ = try sema.requireIntegerType(block, operand_src, sema.typeOf(operand));
+ const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_type);
+ _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
if (try sema.isComptimeKnown(block, operand_src, operand)) {
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
const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
- try sema.checkIntType(block, ty_src, dest_ty);
+ _ = try sema.checkIntType(block, ty_src, dest_ty);
try sema.checkFloatType(block, operand_src, operand_ty);
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
const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
const mod = sema.mod;
- const dest_is_comptime_int = try sema.requireIntegerType(block, dest_ty_src, dest_ty);
- const src_is_comptime_int = try sema.requireIntegerType(block, operand_src, operand_ty);
+ const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_ty);
+ const src_is_comptime_int = try sema.checkIntType(block, operand_src, operand_ty);
if (dest_is_comptime_int) {
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
fn zirClz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
- const src = inst_data.src();
- return sema.mod.fail(&block.base, src, "TODO: Sema.zirClz", .{});
+ const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+ const operand = sema.resolveInst(inst_data.operand);
+ const operand_ty = sema.typeOf(operand);
+ // TODO implement support for vectors
+ if (operand_ty.zigTypeTag() != .Int) {
+ return sema.mod.fail(&block.base, ty_src, "expected integer type, found '{}'", .{
+ operand_ty,
+ });
+ }
+ const target = sema.mod.getTarget();
+ const bits = operand_ty.intInfo(target).bits;
+ if (bits == 0) return Air.Inst.Ref.zero;
+
+ const result_ty = try Type.smallestUnsignedInt(sema.arena, bits);
+
+ const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
+ if (val.isUndef()) return sema.addConstUndef(result_ty);
+ return sema.addIntUnsigned(result_ty, val.clz(operand_ty, target));
+ } else operand_src;
+
+ try sema.requireRuntimeBlock(block, runtime_src);
+ return block.addTyOp(.clz, result_ty, operand);
}
fn zirCtz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
- const src = inst_data.src();
- return sema.mod.fail(&block.base, src, "TODO: Sema.zirCtz", .{});
+ const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+ const operand = sema.resolveInst(inst_data.operand);
+ const operand_ty = sema.typeOf(operand);
+ // TODO implement support for vectors
+ if (operand_ty.zigTypeTag() != .Int) {
+ return sema.mod.fail(&block.base, ty_src, "expected integer type, found '{}'", .{
+ operand_ty,
+ });
+ }
+ const target = sema.mod.getTarget();
+ const bits = operand_ty.intInfo(target).bits;
+ if (bits == 0) return Air.Inst.Ref.zero;
+
+ const result_ty = try Type.smallestUnsignedInt(sema.arena, bits);
+
+ const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
+ if (val.isUndef()) return sema.addConstUndef(result_ty);
+ return sema.mod.fail(&block.base, operand_src, "TODO: implement comptime @ctz", .{});
+ } else operand_src;
+
+ try sema.requireRuntimeBlock(block, runtime_src);
+ return block.addTyOp(.ctz, result_ty, operand);
}
fn 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
return sema.mod.fail(&block.base, src, "TODO: Sema.zirOffsetOf", .{});
}
-fn checkIntType(
- sema: *Sema,
- block: *Scope.Block,
- ty_src: LazySrcLoc,
- ty: Type,
-) CompileError!void {
+/// Returns `true` if the type was a comptime_int.
+fn checkIntType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) CompileError!bool {
switch (ty.zigTypeTag()) {
- .ComptimeInt, .Int => {},
- else => return sema.mod.fail(&block.base, ty_src, "expected integer type, found '{}'", .{
- ty,
- }),
+ .ComptimeInt => return true,
+ .Int => return false,
+ else => return sema.mod.fail(&block.base, src, "expected integer type, found '{}'", .{ty}),
}
}
@@ -9416,14 +9453,6 @@ fn requireRuntimeBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void
try sema.requireFunctionBlock(block, src);
}
-fn requireIntegerType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) !bool {
- switch (ty.zigTypeTag()) {
- .ComptimeInt => return true,
- .Int => return false,
- else => return sema.mod.fail(&block.base, src, "expected integer type, found '{}'", .{ty}),
- }
-}
-
/// Emit a compile error if type cannot be used for a runtime variable.
fn validateVarType(
sema: *Sema,
src/type.zig
@@ -3902,16 +3902,16 @@ pub const Type = extern union {
const bits = bits: {
if (max == 0) break :bits 0;
const base = std.math.log2(max);
- const upper = (@as(u64, 1) << base) - 1;
+ const upper = (@as(u64, 1) << @intCast(u6, base)) - 1;
break :bits base + @boolToInt(upper < max);
};
- return switch (bits) {
+ return switch (@intCast(u16, bits)) {
1 => initTag(.u1),
8 => initTag(.u8),
16 => initTag(.u16),
32 => initTag(.u32),
64 => initTag(.u64),
- else => return Tag.int_unsigned.create(arena, bits),
+ else => |b| return Tag.int_unsigned.create(arena, b),
};
}
};
src/value.zig
@@ -962,6 +962,45 @@ pub const Value = extern union {
};
}
+ pub fn clz(val: Value, ty: Type, target: Target) u64 {
+ const ty_bits = ty.intInfo(target).bits;
+ switch (val.tag()) {
+ .zero, .bool_false => return ty_bits,
+ .one, .bool_true => return ty_bits - 1,
+
+ .int_u64 => {
+ const big = @clz(u64, val.castTag(.int_u64).?.data);
+ return big + ty_bits - 64;
+ },
+ .int_i64 => {
+ @panic("TODO implement i64 Value clz");
+ },
+ .int_big_positive => {
+ // TODO: move this code into std lib big ints
+ const bigint = val.castTag(.int_big_positive).?.asBigInt();
+ // Limbs are stored in little-endian order but we need
+ // to iterate big-endian.
+ var total_limb_lz: u64 = 0;
+ var i: usize = bigint.limbs.len;
+ const bits_per_limb = @sizeOf(std.math.big.Limb) * 8;
+ while (i != 0) {
+ i -= 1;
+ const limb = bigint.limbs[i];
+ const this_limb_lz = @clz(std.math.big.Limb, limb);
+ total_limb_lz += this_limb_lz;
+ if (this_limb_lz != bits_per_limb) break;
+ }
+ const total_limb_bits = bigint.limbs.len * bits_per_limb;
+ return total_limb_lz + ty_bits - total_limb_bits;
+ },
+ .int_big_negative => {
+ @panic("TODO implement int_big_negative Value clz");
+ },
+
+ else => unreachable,
+ }
+ }
+
/// Asserts the value is an integer and not undefined.
/// Returns the number of bits the value requires to represent stored in twos complement form.
pub fn intBitCountTwosComp(self: Value) usize {
test/behavior/math.zig
@@ -53,3 +53,185 @@ fn testThreeExprInARow(f: bool, t: bool) !void {
fn assertFalse(b: bool) !void {
try expect(!b);
}
+
+test "@clz" {
+ try testClz();
+ comptime try testClz();
+}
+
+fn testClz() !void {
+ try expect(testOneClz(u8, 0b10001010) == 0);
+ try expect(testOneClz(u8, 0b00001010) == 4);
+ try expect(testOneClz(u8, 0b00011010) == 3);
+ try expect(testOneClz(u8, 0b00000000) == 8);
+ try expect(testOneClz(u128, 0xffffffffffffffff) == 64);
+ try expect(testOneClz(u128, 0x10000000000000000) == 63);
+}
+
+fn testOneClz(comptime T: type, x: T) u32 {
+ return @clz(T, x);
+}
+
+test "const number literal" {
+ const one = 1;
+ const eleven = ten + one;
+
+ try expect(eleven == 11);
+}
+const ten = 10;
+
+test "float equality" {
+ const x: f64 = 0.012;
+ const y: f64 = x + 1.0;
+
+ try testFloatEqualityImpl(x, y);
+ comptime try testFloatEqualityImpl(x, y);
+}
+
+fn testFloatEqualityImpl(x: f64, y: f64) !void {
+ const y2 = x + 1.0;
+ try expect(y == y2);
+}
+
+test "hex float literal parsing" {
+ comptime try expect(0x1.0 == 1.0);
+}
+
+test "quad hex float literal parsing in range" {
+ const a = 0x1.af23456789bbaaab347645365cdep+5;
+ const b = 0x1.dedafcff354b6ae9758763545432p-9;
+ const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534;
+ const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
+ _ = a;
+ _ = b;
+ _ = c;
+ _ = d;
+}
+
+test "underscore separator parsing" {
+ try expect(0_0_0_0 == 0);
+ try expect(1_234_567 == 1234567);
+ try expect(001_234_567 == 1234567);
+ try expect(0_0_1_2_3_4_5_6_7 == 1234567);
+
+ try expect(0b0_0_0_0 == 0);
+ try expect(0b1010_1010 == 0b10101010);
+ try expect(0b0000_1010_1010 == 0b10101010);
+ try expect(0b1_0_1_0_1_0_1_0 == 0b10101010);
+
+ try expect(0o0_0_0_0 == 0);
+ try expect(0o1010_1010 == 0o10101010);
+ try expect(0o0000_1010_1010 == 0o10101010);
+ try expect(0o1_0_1_0_1_0_1_0 == 0o10101010);
+
+ try expect(0x0_0_0_0 == 0);
+ try expect(0x1010_1010 == 0x10101010);
+ try expect(0x0000_1010_1010 == 0x10101010);
+ try expect(0x1_0_1_0_1_0_1_0 == 0x10101010);
+
+ try expect(123_456.789_000e1_0 == 123456.789000e10);
+ try expect(0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10);
+
+ try expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10);
+ 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);
+}
+
+test "hex float literal within range" {
+ const a = 0x1.0p16383;
+ const b = 0x0.1p16387;
+ const c = 0x1.0p-16382;
+ _ = a;
+ _ = b;
+ _ = c;
+}
+
+test "comptime_int addition" {
+ comptime {
+ try expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
+ try expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
+ }
+}
+
+test "comptime_int multiplication" {
+ comptime {
+ try expect(
+ 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567,
+ );
+ try expect(
+ 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016,
+ );
+ }
+}
+
+test "comptime_int shifting" {
+ comptime {
+ try expect((@as(u128, 1) << 127) == 0x80000000000000000000000000000000);
+ }
+}
+
+test "comptime_int multi-limb shift and mask" {
+ comptime {
+ var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
+
+ try expect(@as(u32, a & 0xffffffff) == 0xaaaaaaab);
+ a >>= 32;
+ try expect(@as(u32, a & 0xffffffff) == 0xeeeeeeef);
+ a >>= 32;
+ try expect(@as(u32, a & 0xffffffff) == 0xa0000001);
+ a >>= 32;
+ try expect(@as(u32, a & 0xffffffff) == 0xefffffff);
+ a >>= 32;
+
+ try expect(a == 0);
+ }
+}
+
+test "comptime_int multi-limb partial shift right" {
+ comptime {
+ var a = 0x1ffffffffeeeeeeee;
+ a >>= 16;
+ try expect(a == 0x1ffffffffeeee);
+ }
+}
+
+test "xor" {
+ try test_xor();
+ comptime try test_xor();
+}
+
+fn test_xor() !void {
+ try testOneXor(0xFF, 0x00, 0xFF);
+ try testOneXor(0xF0, 0x0F, 0xFF);
+ try testOneXor(0xFF, 0xF0, 0x0F);
+ try testOneXor(0xFF, 0x0F, 0xF0);
+ try testOneXor(0xFF, 0xFF, 0x00);
+}
+
+fn testOneXor(a: u8, b: u8, c: u8) !void {
+ try expect(a ^ b == c);
+}
+
+test "comptime_int xor" {
+ comptime {
+ try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
+ try expect(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
+ try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
+ try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
+ try expect(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
+ }
+}
+
+test "comptime_int param and return" {
+ const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
+ try expect(a == 137114567242441932203689521744947848950);
+
+ const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768);
+ try expect(b == 985095453608931032642182098849559179469148836107390954364380);
+}
+
+fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
+ return a + b;
+}
test/behavior/math_stage1.zig
@@ -117,20 +117,6 @@ test "@*WithOverflow with u0 values" {
try expect(!@shlWithOverflow(u0, 0, 0, &result));
}
-test "@clz" {
- try testClz();
- comptime try testClz();
-}
-
-fn testClz() !void {
- try expect(@clz(u8, 0b10001010) == 0);
- try expect(@clz(u8, 0b00001010) == 4);
- try expect(@clz(u8, 0b00011010) == 3);
- try expect(@clz(u8, 0b00000000) == 8);
- try expect(@clz(u128, 0xffffffffffffffff) == 64);
- try expect(@clz(u128, 0x10000000000000000) == 63);
-}
-
test "@clz vectors" {
try testClzVectors();
comptime try testClzVectors();
@@ -171,14 +157,6 @@ fn testCtzVectors() !void {
try expectEqual(@ctz(u16, @splat(64, @as(u16, 0b00000000))), @splat(64, @as(u5, 16)));
}
-test "const number literal" {
- const one = 1;
- const eleven = ten + one;
-
- try expect(eleven == 11);
-}
-const ten = 10;
-
test "unsigned wrapping" {
try testUnsignedWrappingEval(maxInt(u32));
comptime try testUnsignedWrappingEval(maxInt(u32));
@@ -274,19 +252,6 @@ test "small int addition" {
try expect(result == 0);
}
-test "float equality" {
- const x: f64 = 0.012;
- const y: f64 = x + 1.0;
-
- try testFloatEqualityImpl(x, y);
- comptime try testFloatEqualityImpl(x, y);
-}
-
-fn testFloatEqualityImpl(x: f64, y: f64) !void {
- const y2 = x + 1.0;
- try expect(y == y2);
-}
-
test "allow signed integer division/remainder when values are comptime known and positive or exact" {
try expect(5 / 3 == 1);
try expect(-5 / -3 == 1);
@@ -296,23 +261,6 @@ test "allow signed integer division/remainder when values are comptime known and
try expect(-6 % 3 == 0);
}
-test "hex float literal parsing" {
- comptime try expect(0x1.0 == 1.0);
-}
-
-test "quad hex float literal parsing in range" {
- const a = 0x1.af23456789bbaaab347645365cdep+5;
- const b = 0x1.dedafcff354b6ae9758763545432p-9;
- const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534;
- const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
- if (false) {
- a;
- b;
- c;
- d;
- }
-}
-
test "quad hex float literal parsing accurate" {
const a: f128 = 0x1.1111222233334444555566667777p+0;
@@ -403,45 +351,6 @@ test "quad hex float literal parsing accurate" {
comptime try S.doTheTest();
}
-test "underscore separator parsing" {
- try expect(0_0_0_0 == 0);
- try expect(1_234_567 == 1234567);
- try expect(001_234_567 == 1234567);
- try expect(0_0_1_2_3_4_5_6_7 == 1234567);
-
- try expect(0b0_0_0_0 == 0);
- try expect(0b1010_1010 == 0b10101010);
- try expect(0b0000_1010_1010 == 0b10101010);
- try expect(0b1_0_1_0_1_0_1_0 == 0b10101010);
-
- try expect(0o0_0_0_0 == 0);
- try expect(0o1010_1010 == 0o10101010);
- try expect(0o0000_1010_1010 == 0o10101010);
- try expect(0o1_0_1_0_1_0_1_0 == 0o10101010);
-
- try expect(0x0_0_0_0 == 0);
- try expect(0x1010_1010 == 0x10101010);
- try expect(0x0000_1010_1010 == 0x10101010);
- try expect(0x1_0_1_0_1_0_1_0 == 0x10101010);
-
- try expect(123_456.789_000e1_0 == 123456.789000e10);
- try expect(0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10);
-
- try expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10);
- 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);
-}
-
-test "hex float literal within range" {
- const a = 0x1.0p16383;
- const b = 0x0.1p16387;
- const c = 0x1.0p-16382;
- if (false) {
- a;
- b;
- c;
- }
-}
-
test "truncating shift left" {
try testShlTrunc(maxInt(u16));
comptime try testShlTrunc(maxInt(u16));
@@ -497,81 +406,6 @@ test "shift left/right on u0 operand" {
comptime try S.doTheTest();
}
-test "comptime_int addition" {
- comptime {
- try expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
- try expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
- }
-}
-
-test "comptime_int multiplication" {
- comptime {
- try expect(
- 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567,
- );
- try expect(
- 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016,
- );
- }
-}
-
-test "comptime_int shifting" {
- comptime {
- try expect((@as(u128, 1) << 127) == 0x80000000000000000000000000000000);
- }
-}
-
-test "comptime_int multi-limb shift and mask" {
- comptime {
- var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
-
- try expect(@as(u32, a & 0xffffffff) == 0xaaaaaaab);
- a >>= 32;
- try expect(@as(u32, a & 0xffffffff) == 0xeeeeeeef);
- a >>= 32;
- try expect(@as(u32, a & 0xffffffff) == 0xa0000001);
- a >>= 32;
- try expect(@as(u32, a & 0xffffffff) == 0xefffffff);
- a >>= 32;
-
- try expect(a == 0);
- }
-}
-
-test "comptime_int multi-limb partial shift right" {
- comptime {
- var a = 0x1ffffffffeeeeeeee;
- a >>= 16;
- try expect(a == 0x1ffffffffeeee);
- }
-}
-
-test "xor" {
- try test_xor();
- comptime try test_xor();
-}
-
-fn test_xor() !void {
- try expect(0xFF ^ 0x00 == 0xFF);
- try expect(0xF0 ^ 0x0F == 0xFF);
- try expect(0xFF ^ 0xF0 == 0x0F);
- try expect(0xFF ^ 0x0F == 0xF0);
- try expect(0xFF ^ 0xFF == 0x00);
-}
-
-test "comptime_int xor" {
- comptime {
- try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
- try expect(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
- try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
- try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
- try expect(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
- }
-}
-
test "f128" {
try test_f128();
comptime try test_f128();
@@ -757,18 +591,6 @@ fn testRound(comptime T: type, x: T) !void {
try expectEqual(x, z);
}
-test "comptime_int param and return" {
- const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
- try expect(a == 137114567242441932203689521744947848950);
-
- const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768);
- try expect(b == 985095453608931032642182098849559179469148836107390954364380);
-}
-
-fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
- return a + b;
-}
-
test "vector integer addition" {
const S = struct {
fn doTheTest() !void {