From 4210f1f6a0f55fb7c7b287ac691582752340f79d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 18 Jun 2018 03:07:16 -0400
Subject: [PATCH] remove bool to int syntax. add @boolToInt
add missing docs
See #1061
---
doc/langref.html.in | 90 ++++++++++++++++++++------
src/all_types.hpp | 8 +++
src/codegen.cpp | 2 +
src/ir.cpp | 60 +++++++++++++++--
src/ir_print.cpp | 9 +++
std/fmt/errol/index.zig | 4 +-
std/math/big/int.zig | 18 +++---
std/special/compiler_rt/comparetf2.zig | 2 +-
test/cases/bool.zig | 8 +--
9 files changed, 158 insertions(+), 43 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 35ca9a13b43d9c07062d60a55d69541ee139ac2e..7c1f9b53d9e680beb494e0baf3d26450ecdb6b0f 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -4560,6 +4560,19 @@ comptime {
{#see_also|Alignment#}
{#header_close#}
+
+ {#header_open|@boolToInt#}
+ @boolToInt(value: bool) u1
+
+ Converts true to u1(1) and false to
+ u1(0).
+
+
+ If the value is known at compile-time, the return type is comptime_int
+ instead of u1.
+
+ {#header_close#}
+
{#header_open|@cDefine#}
@cDefine(comptime name: []u8, value)
@@ -4834,21 +4847,6 @@ test "main" {
Creates a symbol in the output object file.
{#header_close#}
- {#header_open|@tagName#}
- @tagName(value: var) []const u8
-
- Converts an enum value or union value to a slice of bytes representing the name.
-
- {#header_close#}
- {#header_open|@TagType#}
- @TagType(T: type) type
-
- For an enum, returns the integer type that is used to store the enumeration value.
-
-
- For a union, returns the enum type that is used to store the tag value.
-
- {#header_close#}
{#header_open|@errorName#}
@errorName(err: error) []u8
@@ -4883,6 +4881,12 @@ test "main" {
{#see_also|Compile Variables#}
{#header_close#}
+
+ {#header_open|@field#}
+ @field(lhs: var, comptime field_name: []const u8) (field)
+ Preforms field access equivalent to lhs.->field_name-<.
+ {#header_close#}
+
{#header_open|@fieldParentPtr#}
@fieldParentPtr(comptime ParentType: type, comptime field_name: []const u8,
field_ptr: *T) *ParentType
@@ -4890,6 +4894,23 @@ test "main" {
Given a pointer to a field, returns the base pointer of a struct.
{#header_close#}
+
+ {#header_open|@floatCast#}
+ @floatCast(comptime DestType: type, value: var) DestType
+
+ Convert from one float type to another. This cast is safe, but may cause the
+ numeric value to lose precision.
+
+ {#header_close#}
+
+ {#header_open|@floatToInt#}
+ @floatToInt(comptime DestType: type, float: var) DestType
+
+ Converts the integer part of a floating point number to the destination type.
+ To convert the other way, use {#link|@intToFloat#}. This cast is always safe.
+
+ {#header_close#}
+
{#header_open|@frameAddress#}
@frameAddress()
@@ -4944,12 +4965,30 @@ fn add(a: i32, b: i32) i32 { return a + b; }
{#see_also|@noInlineCall#}
{#header_close#}
+
+ {#header_open|@intCast#}
+ @intCast(comptime DestType: type, int: var) DestType
+
+ Converts an integer to another integer while keeping the same numerical value.
+ Attempting to convert a number which is out of range of the destination type results in
+ {#link|Undefined Behavior#}.
+
+ {#header_close#}
+
+ {#header_open|@intToFloat#}
+ @intToFloat(comptime DestType: type, int: var) DestType
+
+ Converts an integer to the closest floating point representation. To convert the other way, use {#link|@floatToInt#}. This cast is always safe.
+
+ {#header_close#}
+
{#header_open|@intToPtr#}
@intToPtr(comptime DestType: type, int: usize) DestType
Converts an integer to a pointer. To convert the other way, use {#link|@ptrToInt#}.
{#header_close#}
+
{#header_open|@IntType#}
@IntType(comptime is_signed: bool, comptime bit_count: u8) type
@@ -4987,10 +5026,6 @@ fn add(a: i32, b: i32) i32 { return a + b; }
It does not include functions, variables, or constants.
{#header_close#}
- {#header_open|@field#}
- @field(lhs: var, comptime field_name: []const u8) (field)
- Preforms field access equivalent to lhs.->field_name-<.
- {#header_close#}
{#header_open|@memberType#}
@memberType(comptime T: type, comptime index: usize) type
Returns the field type of a struct or union.
@@ -5370,6 +5405,21 @@ pub const FloatMode = enum {
If no overflow or underflow occurs, returns false.
{#header_close#}
+ {#header_open|@tagName#}
+ @tagName(value: var) []const u8
+
+ Converts an enum value or union value to a slice of bytes representing the name.
+
+ {#header_close#}
+ {#header_open|@TagType#}
+ @TagType(T: type) type
+
+ For an enum, returns the integer type that is used to store the enumeration value.
+
+
+ For a union, returns the enum type that is used to store the tag value.
+
+ {#header_close#}
{#header_open|@truncate#}
@truncate(comptime T: type, integer) T
@@ -6665,7 +6715,7 @@ hljs.registerLanguage("zig", function(t) {
a = t.IR + "\\s*\\(",
c = {
keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse",
- built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall",
+ built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall",
literal: "true false null undefined"
},
n = [e, t.CLCM, t.CBCM, s, r];
diff --git a/src/all_types.hpp b/src/all_types.hpp
index bc2fe07c188107b6e3011c1eea29740fb7462e08..d94dfa0fcbe289097e8cfa7f6887ee0cfe7599b2 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1361,6 +1361,7 @@ enum BuiltinFnId {
BuiltinFnIdFloatCast,
BuiltinFnIdIntToFloat,
BuiltinFnIdFloatToInt,
+ BuiltinFnIdBoolToInt,
BuiltinFnIdIntType,
BuiltinFnIdSetCold,
BuiltinFnIdSetRuntimeSafety,
@@ -2048,6 +2049,7 @@ enum IrInstructionId {
IrInstructionIdFloatCast,
IrInstructionIdIntToFloat,
IrInstructionIdFloatToInt,
+ IrInstructionIdBoolToInt,
IrInstructionIdIntType,
IrInstructionIdBoolNot,
IrInstructionIdMemset,
@@ -2668,6 +2670,12 @@ struct IrInstructionFloatToInt {
IrInstruction *target;
};
+struct IrInstructionBoolToInt {
+ IrInstruction base;
+
+ IrInstruction *target;
+};
+
struct IrInstructionIntType {
IrInstruction base;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 4108cbbd687fc01123092077e922105fef105f85..84335d4e067297adc9d70bbb75a091b0dd1dd9c6 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -4726,6 +4726,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdFloatCast:
case IrInstructionIdIntToFloat:
case IrInstructionIdFloatToInt:
+ case IrInstructionIdBoolToInt:
zig_unreachable();
case IrInstructionIdReturn:
@@ -6318,6 +6319,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdFloatCast, "floatCast", 2);
create_builtin_fn(g, BuiltinFnIdIntToFloat, "intToFloat", 2);
create_builtin_fn(g, BuiltinFnIdFloatToInt, "floatToInt", 2);
+ create_builtin_fn(g, BuiltinFnIdBoolToInt, "boolToInt", 1);
create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
diff --git a/src/ir.cpp b/src/ir.cpp
index 0b847fc4e43f03776b4f1672dd37aa4ab74d87e9..e6339a72f6906c8dae263401b08ef00e1cdc873b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -476,6 +476,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatToInt *) {
return IrInstructionIdFloatToInt;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolToInt *) {
+ return IrInstructionIdBoolToInt;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) {
return IrInstructionIdIntType;
}
@@ -1959,6 +1963,15 @@ static IrInstruction *ir_build_float_to_int(IrBuilder *irb, Scope *scope, AstNod
return &instruction->base;
}
+static IrInstruction *ir_build_bool_to_int(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) {
+ IrInstructionBoolToInt *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->target = target;
+
+ ir_ref_instruction(target, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *is_signed, IrInstruction *bit_count) {
IrInstructionIntType *instruction = ir_build_instruction(irb, scope, source_node);
instruction->is_signed = is_signed;
@@ -4071,6 +4084,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value);
return ir_lval_wrap(irb, scope, result, lval);
}
+ case BuiltinFnIdBoolToInt:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ IrInstruction *result = ir_build_bool_to_int(irb, scope, node, arg0_value);
+ return ir_lval_wrap(irb, scope, result, lval);
+ }
case BuiltinFnIdIntType:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@@ -10055,13 +10078,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
}
- // explicit cast from bool to int
- if (wanted_type->id == TypeTableEntryIdInt &&
- actual_type->id == TypeTableEntryIdBool)
- {
- return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBoolToInt, false);
- }
-
// explicit widening conversion
if (wanted_type->id == TypeTableEntryIdInt &&
actual_type->id == TypeTableEntryIdInt &&
@@ -17605,6 +17621,33 @@ static TypeTableEntry *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrIns
return dest_type;
}
+static TypeTableEntry *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstructionBoolToInt *instruction) {
+ IrInstruction *target = instruction->target->other;
+ if (type_is_invalid(target->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (target->value.type->id != TypeTableEntryIdBool) {
+ ir_add_error(ira, instruction->target, buf_sprintf("expected bool, found '%s'",
+ buf_ptr(&target->value.type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ if (instr_is_comptime(target)) {
+ bool is_true;
+ if (!ir_resolve_bool(ira, target, &is_true))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ bigint_init_unsigned(&out_val->data.x_bigint, is_true ? 1 : 0);
+ return ira->codegen->builtin_types.entry_num_lit_int;
+ }
+
+ TypeTableEntry *u1_type = get_int_type(ira->codegen, false, 1);
+ IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, u1_type, CastOpBoolToInt, false);
+ ir_link_new_instruction(result, &instruction->base);
+ return u1_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstructionIntType *instruction) {
IrInstruction *is_signed_value = instruction->is_signed->other;
bool is_signed;
@@ -20143,6 +20186,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction);
case IrInstructionIdFloatToInt:
return ir_analyze_instruction_float_to_int(ira, (IrInstructionFloatToInt *)instruction);
+ case IrInstructionIdBoolToInt:
+ return ir_analyze_instruction_bool_to_int(ira, (IrInstructionBoolToInt *)instruction);
case IrInstructionIdIntType:
return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
case IrInstructionIdBoolNot:
@@ -20490,6 +20535,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdFloatCast:
case IrInstructionIdIntToFloat:
case IrInstructionIdFloatToInt:
+ case IrInstructionIdBoolToInt:
return false;
case IrInstructionIdAsm:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index b5722c52fae799e52c2401cd394ab3cb5fefd816..cb917201805a6897b41ae2b8463d1bef33540e9c 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -680,6 +680,12 @@ static void ir_print_float_to_int(IrPrint *irp, IrInstructionFloatToInt *instruc
fprintf(irp->f, ")");
}
+static void ir_print_bool_to_int(IrPrint *irp, IrInstructionBoolToInt *instruction) {
+ fprintf(irp->f, "@boolToInt(");
+ ir_print_other_instruction(irp, instruction->target);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
fprintf(irp->f, "@IntType(");
ir_print_other_instruction(irp, instruction->is_signed);
@@ -1461,6 +1467,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdFloatToInt:
ir_print_float_to_int(irp, (IrInstructionFloatToInt *)instruction);
break;
+ case IrInstructionIdBoolToInt:
+ ir_print_bool_to_int(irp, (IrInstructionBoolToInt *)instruction);
+ break;
case IrInstructionIdIntType:
ir_print_int_type(irp, (IrInstructionIntType *)instruction);
break;
diff --git a/std/fmt/errol/index.zig b/std/fmt/errol/index.zig
index a5fb692857d92f3910d9c56e845bae26a17aadfa..3222913107159004ea37d7493d5e91891f8b7a72 100644
--- a/std/fmt/errol/index.zig
+++ b/std/fmt/errol/index.zig
@@ -329,7 +329,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
var mi: i32 = mismatch10(l64, h64);
var x: u64 = 1;
{
- var i = i32(lf == hf);
+ var i: i32 = @boolToInt(lf == hf);
while (i < mi) : (i += 1) {
x *= 10;
}
@@ -341,7 +341,7 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
var buf_index = u64toa(m64, buffer) - 1;
if (mi != 0) {
- buffer[buf_index - 1] += u8(buffer[buf_index] >= '5');
+ buffer[buf_index - 1] += @boolToInt(buffer[buf_index] >= '5');
} else {
buf_index += 1;
}
diff --git a/std/math/big/int.zig b/std/math/big/int.zig
index 21d9347c011988aef1fd404803b9521bf9b8fea6..29673538eb86bc14e01c41314f8c564991992507 100644
--- a/std/math/big/int.zig
+++ b/std/math/big/int.zig
@@ -117,7 +117,7 @@ pub const Int = struct {
fn bitcount(self: Int) usize {
const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
- return usize(!self.positive) + u_bit_count;
+ return usize(@boolToInt(!self.positive)) + u_bit_count;
}
pub fn sizeInBase(self: Int, base: usize) usize {
@@ -499,13 +499,13 @@ pub const Int = struct {
while (i < b.len) : (i += 1) {
var c: Limb = 0;
- c += Limb(@addWithOverflow(Limb, a[i], b[i], &r[i]));
- c += Limb(@addWithOverflow(Limb, r[i], carry, &r[i]));
+ c += @boolToInt(@addWithOverflow(Limb, a[i], b[i], &r[i]));
+ c += @boolToInt(@addWithOverflow(Limb, r[i], carry, &r[i]));
carry = c;
}
while (i < a.len) : (i += 1) {
- carry = Limb(@addWithOverflow(Limb, a[i], carry, &r[i]));
+ carry = @boolToInt(@addWithOverflow(Limb, a[i], carry, &r[i]));
}
r[i] = carry;
@@ -577,13 +577,13 @@ pub const Int = struct {
while (i < b.len) : (i += 1) {
var c: Limb = 0;
- c += Limb(@subWithOverflow(Limb, a[i], b[i], &r[i]));
- c += Limb(@subWithOverflow(Limb, r[i], borrow, &r[i]));
+ c += @boolToInt(@subWithOverflow(Limb, a[i], b[i], &r[i]));
+ c += @boolToInt(@subWithOverflow(Limb, r[i], borrow, &r[i]));
borrow = c;
}
while (i < a.len) : (i += 1) {
- borrow = Limb(@subWithOverflow(Limb, a[i], borrow, &r[i]));
+ borrow = @boolToInt(@subWithOverflow(Limb, a[i], borrow, &r[i]));
}
debug.assert(borrow == 0);
@@ -624,7 +624,7 @@ pub const Int = struct {
var r1: Limb = undefined;
// r1 = a + *carry
- const c1 = Limb(@addWithOverflow(Limb, a, carry.*, &r1));
+ const c1: Limb = @boolToInt(@addWithOverflow(Limb, a, carry.*, &r1));
// r2 = b * c
//
@@ -639,7 +639,7 @@ pub const Int = struct {
const c2 = @truncate(Limb, bc >> Limb.bit_count);
// r1 = r1 + r2
- const c3 = Limb(@addWithOverflow(Limb, r1, r2, &r1));
+ const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1));
// This never overflows, c1, c3 are either 0 or 1 and if both are 1 then
// c2 is at least <= @maxValue(Limb) - 2.
diff --git a/std/special/compiler_rt/comparetf2.zig b/std/special/compiler_rt/comparetf2.zig
index d63b7a7c924ad204bfa8fd66628a8d9f0096c092..479ba51962b10f391f38165d8b682920aa140f8e 100644
--- a/std/special/compiler_rt/comparetf2.zig
+++ b/std/special/compiler_rt/comparetf2.zig
@@ -91,5 +91,5 @@ pub extern fn __unordtf2(a: f128, b: f128) c_int {
const aAbs = @bitCast(rep_t, a) & absMask;
const bAbs = @bitCast(rep_t, b) & absMask;
- return c_int(aAbs > infRep or bAbs > infRep);
+ return @boolToInt(aAbs > infRep or bAbs > infRep);
}
diff --git a/test/cases/bool.zig b/test/cases/bool.zig
index 07d30454ee6732f366daee7fa3def3e95d035971..3e4ac9c1cfe4d30f72189c27d47e6b4949ead971 100644
--- a/test/cases/bool.zig
+++ b/test/cases/bool.zig
@@ -8,14 +8,14 @@ test "bool literals" {
test "cast bool to int" {
const t = true;
const f = false;
- assert(i32(t) == i32(1));
- assert(i32(f) == i32(0));
+ assert(@boolToInt(t) == u32(1));
+ assert(@boolToInt(f) == u32(0));
nonConstCastBoolToInt(t, f);
}
fn nonConstCastBoolToInt(t: bool, f: bool) void {
- assert(i32(t) == i32(1));
- assert(i32(f) == i32(0));
+ assert(@boolToInt(t) == u32(1));
+ assert(@boolToInt(f) == u32(0));
}
test "bool cmp" {
--
2.54.0