| author | |
| committer | |
| log | 33e77f127d8237088b561fae2ca0f4412bc1d6c9 |
| tree | 2ad81a2a7ac5fa5635d6d03456333d30fe568364 |
| parent | 7efc2a06264170632e56256a5fad97e945768056 |
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 { |
| 160 | 160 | /// Result type is the return type of the function being called. |
| 161 | 161 | /// Uses the `pl_op` field with the `Call` payload. operand is the callee. |
| 162 | 162 | 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, | |
| 163 | 171 | |
| 164 | 172 | /// `<`. Result type is always bool. |
| 165 | 173 | /// Uses the `bin_op` field. |
| ... | ... | @@ -669,6 +677,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 669 | 677 | .float_to_int, |
| 670 | 678 | .int_to_float, |
| 671 | 679 | .get_union_tag, |
| 680 | .clz, | |
| 681 | .ctz, | |
| 672 | 682 | => return air.getRefType(datas[inst].ty_op.ty), |
| 673 | 683 | |
| 674 | 684 | .loop, |
src/Liveness.zig+2| ... | ... | @@ -304,6 +304,8 @@ fn analyzeInst( |
| 304 | 304 | .float_to_int, |
| 305 | 305 | .int_to_float, |
| 306 | 306 | .get_union_tag, |
| 307 | .clz, | |
| 308 | .ctz, | |
| 307 | 309 | => { |
| 308 | 310 | const o = inst_datas[inst].ty_op; |
| 309 | 311 | 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 |
| 4611 | 4611 | const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 4612 | 4612 | const operand = sema.resolveInst(extra.rhs); |
| 4613 | 4613 | |
| 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)); | |
| 4616 | 4616 | |
| 4617 | 4617 | if (try sema.isComptimeKnown(block, operand_src, operand)) { |
| 4618 | 4618 | 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 |
| 8384 | 8384 | const operand = sema.resolveInst(extra.rhs); |
| 8385 | 8385 | const operand_ty = sema.typeOf(operand); |
| 8386 | 8386 | |
| 8387 | try sema.checkIntType(block, ty_src, dest_ty); | |
| 8387 | _ = try sema.checkIntType(block, ty_src, dest_ty); | |
| 8388 | 8388 | try sema.checkFloatType(block, operand_src, operand_ty); |
| 8389 | 8389 | |
| 8390 | 8390 | 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 |
| 8493 | 8493 | const operand = sema.resolveInst(extra.rhs); |
| 8494 | 8494 | const operand_ty = sema.typeOf(operand); |
| 8495 | 8495 | 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); | |
| 8498 | 8498 | |
| 8499 | 8499 | if (dest_is_comptime_int) { |
| 8500 | 8500 | 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 |
| 8552 | 8552 | |
| 8553 | 8553 | fn zirClz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8554 | 8554 | 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); | |
| 8557 | 8578 | } |
| 8558 | 8579 | |
| 8559 | 8580 | fn zirCtz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8560 | 8581 | 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); | |
| 8563 | 8605 | } |
| 8564 | 8606 | |
| 8565 | 8607 | 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 |
| 8616 | 8658 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirOffsetOf", .{}); |
| 8617 | 8659 | } |
| 8618 | 8660 | |
| 8619 | fn 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. | |
| 8662 | fn checkIntType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) CompileError!bool { | |
| 8625 | 8663 | 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}), | |
| 8630 | 8667 | } |
| 8631 | 8668 | } |
| 8632 | 8669 | |
| ... | ... | @@ -9416,14 +9453,6 @@ fn requireRuntimeBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void |
| 9416 | 9453 | try sema.requireFunctionBlock(block, src); |
| 9417 | 9454 | } |
| 9418 | 9455 | |
| 9419 | fn 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 | ||
| 9427 | 9456 | /// Emit a compile error if type cannot be used for a runtime variable. |
| 9428 | 9457 | fn validateVarType( |
| 9429 | 9458 | sema: *Sema, |
src/codegen.zig+18| ... | ... | @@ -896,6 +896,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 896 | 896 | .memset => try self.airMemset(inst), |
| 897 | 897 | .set_union_tag => try self.airSetUnionTag(inst), |
| 898 | 898 | .get_union_tag => try self.airGetUnionTag(inst), |
| 899 | .clz => try self.airClz(inst), | |
| 900 | .ctz => try self.airCtz(inst), | |
| 899 | 901 | |
| 900 | 902 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 901 | 903 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| ... | ... | @@ -1606,6 +1608,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1606 | 1608 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1607 | 1609 | } |
| 1608 | 1610 | |
| 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 | ||
| 1609 | 1627 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { |
| 1610 | 1628 | if (!self.liveness.operandDies(inst, op_index)) |
| 1611 | 1629 | return false; |
src/codegen/c.zig+19| ... | ... | @@ -962,6 +962,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 962 | 962 | .memcpy => try airMemcpy(f, inst), |
| 963 | 963 | .set_union_tag => try airSetUnionTag(f, inst), |
| 964 | 964 | .get_union_tag => try airGetUnionTag(f, inst), |
| 965 | .clz => try airBuiltinCall(f, inst, "clz"), | |
| 966 | .ctz => try airBuiltinCall(f, inst, "ctz"), | |
| 965 | 967 | |
| 966 | 968 | .int_to_float, |
| 967 | 969 | .float_to_int, |
| ... | ... | @@ -2075,6 +2077,23 @@ fn airSimpleCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2075 | 2077 | return local; |
| 2076 | 2078 | } |
| 2077 | 2079 | |
| 2080 | fn 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 | ||
| 2078 | 2097 | fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { |
| 2079 | 2098 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 2080 | 2099 | 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 { |
| 889 | 889 | const llvm_type = try self.llvmType(tv.ty); |
| 890 | 890 | if (bigint.eqZero()) return llvm_type.constNull(); |
| 891 | 891 | |
| 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); | |
| 896 | 896 | if (!bigint.positive) { |
| 897 | return llvm.constNeg(llvm_int); | |
| 897 | return llvm.constNeg(unsigned_val); | |
| 898 | 898 | } |
| 899 | return llvm_int; | |
| 899 | return unsigned_val; | |
| 900 | 900 | }, |
| 901 | 901 | .Enum => { |
| 902 | 902 | const llvm_type = try self.llvmType(tv.ty); |
| ... | ... | @@ -1310,6 +1310,8 @@ pub const FuncGen = struct { |
| 1310 | 1310 | .memcpy => try self.airMemcpy(inst), |
| 1311 | 1311 | .set_union_tag => try self.airSetUnionTag(inst), |
| 1312 | 1312 | .get_union_tag => try self.airGetUnionTag(inst), |
| 1313 | .clz => try self.airClzCtz(inst, "ctlz"), | |
| 1314 | .ctz => try self.airClzCtz(inst, "cttz"), | |
| 1313 | 1315 | |
| 1314 | 1316 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 1315 | 1317 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| ... | ... | @@ -2699,6 +2701,41 @@ pub const FuncGen = struct { |
| 2699 | 2701 | return self.builder.buildExtractValue(un, 1, ""); |
| 2700 | 2702 | } |
| 2701 | 2703 | |
| 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 | ||
| 2702 | 2739 | fn fieldPtr( |
| 2703 | 2740 | self: *FuncGen, |
| 2704 | 2741 | inst: Air.Inst.Index, |
src/codegen/llvm/bindings.zig+5-2| ... | ... | @@ -172,6 +172,9 @@ pub const Type = opaque { |
| 172 | 172 | pub const constInt = LLVMConstInt; |
| 173 | 173 | extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: Bool) *const Value; |
| 174 | 174 | |
| 175 | pub const constIntOfArbitraryPrecision = LLVMConstIntOfArbitraryPrecision; | |
| 176 | extern fn LLVMConstIntOfArbitraryPrecision(IntTy: *const Type, NumWords: c_uint, Words: [*]const u64) *const Value; | |
| 177 | ||
| 175 | 178 | pub const constReal = LLVMConstReal; |
| 176 | 179 | extern fn LLVMConstReal(RealTy: *const Type, N: f64) *const Value; |
| 177 | 180 | |
| ... | ... | @@ -300,7 +303,7 @@ extern fn LLVMGetInlineAsm( |
| 300 | 303 | pub const functionType = LLVMFunctionType; |
| 301 | 304 | extern fn LLVMFunctionType( |
| 302 | 305 | ReturnType: *const Type, |
| 303 | ParamTypes: [*]*const Type, | |
| 306 | ParamTypes: [*]const *const Type, | |
| 304 | 307 | ParamCount: c_uint, |
| 305 | 308 | IsVarArg: Bool, |
| 306 | 309 | ) *const Type; |
| ... | ... | @@ -346,7 +349,7 @@ pub const Builder = opaque { |
| 346 | 349 | extern fn LLVMBuildCall( |
| 347 | 350 | *const Builder, |
| 348 | 351 | Fn: *const Value, |
| 349 | Args: [*]*const Value, | |
| 352 | Args: [*]const *const Value, | |
| 350 | 353 | NumArgs: c_uint, |
| 351 | 354 | Name: [*:0]const u8, |
| 352 | 355 | ) *const Value; |
src/print_air.zig+2| ... | ... | @@ -186,6 +186,8 @@ const Writer = struct { |
| 186 | 186 | .int_to_float, |
| 187 | 187 | .float_to_int, |
| 188 | 188 | .get_union_tag, |
| 189 | .clz, | |
| 190 | .ctz, | |
| 189 | 191 | => try w.writeTyOp(s, inst), |
| 190 | 192 | |
| 191 | 193 | .block, |
src/type.zig+3-3| ... | ... | @@ -3902,16 +3902,16 @@ pub const Type = extern union { |
| 3902 | 3902 | const bits = bits: { |
| 3903 | 3903 | if (max == 0) break :bits 0; |
| 3904 | 3904 | const base = std.math.log2(max); |
| 3905 | const upper = (@as(u64, 1) << base) - 1; | |
| 3905 | const upper = (@as(u64, 1) << @intCast(u6, base)) - 1; | |
| 3906 | 3906 | break :bits base + @boolToInt(upper < max); |
| 3907 | 3907 | }; |
| 3908 | return switch (bits) { | |
| 3908 | return switch (@intCast(u16, bits)) { | |
| 3909 | 3909 | 1 => initTag(.u1), |
| 3910 | 3910 | 8 => initTag(.u8), |
| 3911 | 3911 | 16 => initTag(.u16), |
| 3912 | 3912 | 32 => initTag(.u32), |
| 3913 | 3913 | 64 => initTag(.u64), |
| 3914 | else => return Tag.int_unsigned.create(arena, bits), | |
| 3914 | else => |b| return Tag.int_unsigned.create(arena, b), | |
| 3915 | 3915 | }; |
| 3916 | 3916 | } |
| 3917 | 3917 | }; |
src/value.zig+39| ... | ... | @@ -962,6 +962,45 @@ pub const Value = extern union { |
| 962 | 962 | }; |
| 963 | 963 | } |
| 964 | 964 | |
| 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 | ||
| 965 | 1004 | /// Asserts the value is an integer and not undefined. |
| 966 | 1005 | /// Returns the number of bits the value requires to represent stored in twos complement form. |
| 967 | 1006 | pub fn intBitCountTwosComp(self: Value) usize { |
test/behavior/math.zig+182| ... | ... | @@ -53,3 +53,185 @@ fn testThreeExprInARow(f: bool, t: bool) !void { |
| 53 | 53 | fn assertFalse(b: bool) !void { |
| 54 | 54 | try expect(!b); |
| 55 | 55 | } |
| 56 | ||
| 57 | test "@clz" { | |
| 58 | try testClz(); | |
| 59 | comptime try testClz(); | |
| 60 | } | |
| 61 | ||
| 62 | fn 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 | ||
| 71 | fn testOneClz(comptime T: type, x: T) u32 { | |
| 72 | return @clz(T, x); | |
| 73 | } | |
| 74 | ||
| 75 | test "const number literal" { | |
| 76 | const one = 1; | |
| 77 | const eleven = ten + one; | |
| 78 | ||
| 79 | try expect(eleven == 11); | |
| 80 | } | |
| 81 | const ten = 10; | |
| 82 | ||
| 83 | test "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 | ||
| 91 | fn testFloatEqualityImpl(x: f64, y: f64) !void { | |
| 92 | const y2 = x + 1.0; | |
| 93 | try expect(y == y2); | |
| 94 | } | |
| 95 | ||
| 96 | test "hex float literal parsing" { | |
| 97 | comptime try expect(0x1.0 == 1.0); | |
| 98 | } | |
| 99 | ||
| 100 | test "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 | ||
| 111 | test "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 | ||
| 139 | test "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 | ||
| 148 | test "comptime_int addition" { | |
| 149 | comptime { | |
| 150 | try expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); | |
| 151 | try expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); | |
| 152 | } | |
| 153 | } | |
| 154 | ||
| 155 | test "comptime_int multiplication" { | |
| 156 | comptime { | |
| 157 | try expect( | |
| 158 | 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, | |
| 159 | ); | |
| 160 | try expect( | |
| 161 | 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, | |
| 162 | ); | |
| 163 | } | |
| 164 | } | |
| 165 | ||
| 166 | test "comptime_int shifting" { | |
| 167 | comptime { | |
| 168 | try expect((@as(u128, 1) << 127) == 0x80000000000000000000000000000000); | |
| 169 | } | |
| 170 | } | |
| 171 | ||
| 172 | test "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 | ||
| 189 | test "comptime_int multi-limb partial shift right" { | |
| 190 | comptime { | |
| 191 | var a = 0x1ffffffffeeeeeeee; | |
| 192 | a >>= 16; | |
| 193 | try expect(a == 0x1ffffffffeeee); | |
| 194 | } | |
| 195 | } | |
| 196 | ||
| 197 | test "xor" { | |
| 198 | try test_xor(); | |
| 199 | comptime try test_xor(); | |
| 200 | } | |
| 201 | ||
| 202 | fn 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 | ||
| 210 | fn testOneXor(a: u8, b: u8, c: u8) !void { | |
| 211 | try expect(a ^ b == c); | |
| 212 | } | |
| 213 | ||
| 214 | test "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 | ||
| 227 | test "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 | ||
| 235 | fn 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" { |
| 117 | 117 | try expect(!@shlWithOverflow(u0, 0, 0, &result)); |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | test "@clz" { | |
| 121 | try testClz(); | |
| 122 | comptime try testClz(); | |
| 123 | } | |
| 124 | ||
| 125 | fn 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 | ||
| 134 | 120 | test "@clz vectors" { |
| 135 | 121 | try testClzVectors(); |
| 136 | 122 | comptime try testClzVectors(); |
| ... | ... | @@ -171,14 +157,6 @@ fn testCtzVectors() !void { |
| 171 | 157 | try expectEqual(@ctz(u16, @splat(64, @as(u16, 0b00000000))), @splat(64, @as(u5, 16))); |
| 172 | 158 | } |
| 173 | 159 | |
| 174 | test "const number literal" { | |
| 175 | const one = 1; | |
| 176 | const eleven = ten + one; | |
| 177 | ||
| 178 | try expect(eleven == 11); | |
| 179 | } | |
| 180 | const ten = 10; | |
| 181 | ||
| 182 | 160 | test "unsigned wrapping" { |
| 183 | 161 | try testUnsignedWrappingEval(maxInt(u32)); |
| 184 | 162 | comptime try testUnsignedWrappingEval(maxInt(u32)); |
| ... | ... | @@ -274,19 +252,6 @@ test "small int addition" { |
| 274 | 252 | try expect(result == 0); |
| 275 | 253 | } |
| 276 | 254 | |
| 277 | test "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 | ||
| 285 | fn testFloatEqualityImpl(x: f64, y: f64) !void { | |
| 286 | const y2 = x + 1.0; | |
| 287 | try expect(y == y2); | |
| 288 | } | |
| 289 | ||
| 290 | 255 | test "allow signed integer division/remainder when values are comptime known and positive or exact" { |
| 291 | 256 | try expect(5 / 3 == 1); |
| 292 | 257 | try expect(-5 / -3 == 1); |
| ... | ... | @@ -296,23 +261,6 @@ test "allow signed integer division/remainder when values are comptime known and |
| 296 | 261 | try expect(-6 % 3 == 0); |
| 297 | 262 | } |
| 298 | 263 | |
| 299 | test "hex float literal parsing" { | |
| 300 | comptime try expect(0x1.0 == 1.0); | |
| 301 | } | |
| 302 | ||
| 303 | test "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 | ||
| 316 | 264 | test "quad hex float literal parsing accurate" { |
| 317 | 265 | const a: f128 = 0x1.1111222233334444555566667777p+0; |
| 318 | 266 | |
| ... | ... | @@ -403,45 +351,6 @@ test "quad hex float literal parsing accurate" { |
| 403 | 351 | comptime try S.doTheTest(); |
| 404 | 352 | } |
| 405 | 353 | |
| 406 | test "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 | ||
| 434 | test "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 | ||
| 445 | 354 | test "truncating shift left" { |
| 446 | 355 | try testShlTrunc(maxInt(u16)); |
| 447 | 356 | comptime try testShlTrunc(maxInt(u16)); |
| ... | ... | @@ -497,81 +406,6 @@ test "shift left/right on u0 operand" { |
| 497 | 406 | comptime try S.doTheTest(); |
| 498 | 407 | } |
| 499 | 408 | |
| 500 | test "comptime_int addition" { | |
| 501 | comptime { | |
| 502 | try expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); | |
| 503 | try expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); | |
| 504 | } | |
| 505 | } | |
| 506 | ||
| 507 | test "comptime_int multiplication" { | |
| 508 | comptime { | |
| 509 | try expect( | |
| 510 | 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, | |
| 511 | ); | |
| 512 | try expect( | |
| 513 | 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, | |
| 514 | ); | |
| 515 | } | |
| 516 | } | |
| 517 | ||
| 518 | test "comptime_int shifting" { | |
| 519 | comptime { | |
| 520 | try expect((@as(u128, 1) << 127) == 0x80000000000000000000000000000000); | |
| 521 | } | |
| 522 | } | |
| 523 | ||
| 524 | test "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 | ||
| 541 | test "comptime_int multi-limb partial shift right" { | |
| 542 | comptime { | |
| 543 | var a = 0x1ffffffffeeeeeeee; | |
| 544 | a >>= 16; | |
| 545 | try expect(a == 0x1ffffffffeeee); | |
| 546 | } | |
| 547 | } | |
| 548 | ||
| 549 | test "xor" { | |
| 550 | try test_xor(); | |
| 551 | comptime try test_xor(); | |
| 552 | } | |
| 553 | ||
| 554 | fn 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 | ||
| 562 | test "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 | ||
| 575 | 409 | test "f128" { |
| 576 | 410 | try test_f128(); |
| 577 | 411 | comptime try test_f128(); |
| ... | ... | @@ -757,18 +591,6 @@ fn testRound(comptime T: type, x: T) !void { |
| 757 | 591 | try expectEqual(x, z); |
| 758 | 592 | } |
| 759 | 593 | |
| 760 | test "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 | ||
| 768 | fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { | |
| 769 | return a + b; | |
| 770 | } | |
| 771 | ||
| 772 | 594 | test "vector integer addition" { |
| 773 | 595 | const S = struct { |
| 774 | 596 | fn doTheTest() !void { |