authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-09 10:09:38-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-09 10:09:38-04:00
log35d3444e2742faa3c2e805cdcbfeceaf0287eefc
tree408182308c5f962660f200c59b2619be8d194ffc
parent54675b060ae6139f60e111521b9a2688f66977a0

more intuitive left shift and right shift operators

Before: * << is left shift, not allowed to shift 1 bits out * <<% is left shift, allowed to shift 1 bits out * >> is right shift, allowed to shift 1 bits out After: * << is left shift, allowed to shift 1 bits out * >> is right shift, allowed to shift 1 bits out * @shlExact is left shift, not allowed to shift 1 bits out * @shrExact is right shift, not allowed to shift 1 bits out Closes #413

28 files changed, 274 insertions(+), 128 deletions(-)

src/all_types.hpp+8-6
...@@ -493,7 +493,6 @@ enum BinOpType {...@@ -493,7 +493,6 @@ enum BinOpType {
493 BinOpTypeAssignMinus,493 BinOpTypeAssignMinus,
494 BinOpTypeAssignMinusWrap,494 BinOpTypeAssignMinusWrap,
495 BinOpTypeAssignBitShiftLeft,495 BinOpTypeAssignBitShiftLeft,
496 BinOpTypeAssignBitShiftLeftWrap,
497 BinOpTypeAssignBitShiftRight,496 BinOpTypeAssignBitShiftRight,
498 BinOpTypeAssignBitAnd,497 BinOpTypeAssignBitAnd,
499 BinOpTypeAssignBitXor,498 BinOpTypeAssignBitXor,
...@@ -512,7 +511,6 @@ enum BinOpType {...@@ -512,7 +511,6 @@ enum BinOpType {
512 BinOpTypeBinXor,511 BinOpTypeBinXor,
513 BinOpTypeBinAnd,512 BinOpTypeBinAnd,
514 BinOpTypeBitShiftLeft,513 BinOpTypeBitShiftLeft,
515 BinOpTypeBitShiftLeftWrap,
516 BinOpTypeBitShiftRight,514 BinOpTypeBitShiftRight,
517 BinOpTypeAdd,515 BinOpTypeAdd,
518 BinOpTypeAddWrap,516 BinOpTypeAddWrap,
...@@ -1232,6 +1230,8 @@ enum BuiltinFnId {...@@ -1232,6 +1230,8 @@ enum BuiltinFnId {
1232 BuiltinFnIdOffsetOf,1230 BuiltinFnIdOffsetOf,
1233 BuiltinFnIdInlineCall,1231 BuiltinFnIdInlineCall,
1234 BuiltinFnIdTypeId,1232 BuiltinFnIdTypeId,
1233 BuiltinFnIdShlExact,
1234 BuiltinFnIdShrExact,
1235};1235};
12361236
1237struct BuiltinFnEntry {1237struct BuiltinFnEntry {
...@@ -1248,7 +1248,8 @@ enum PanicMsgId {...@@ -1248,7 +1248,8 @@ enum PanicMsgId {
1248 PanicMsgIdCastNegativeToUnsigned,1248 PanicMsgIdCastNegativeToUnsigned,
1249 PanicMsgIdCastTruncatedData,1249 PanicMsgIdCastTruncatedData,
1250 PanicMsgIdIntegerOverflow,1250 PanicMsgIdIntegerOverflow,
1251 PanicMsgIdShiftOverflowedBits,1251 PanicMsgIdShlOverflowedBits,
1252 PanicMsgIdShrOverflowedBits,
1252 PanicMsgIdDivisionByZero,1253 PanicMsgIdDivisionByZero,
1253 PanicMsgIdRemainderDivisionByZero,1254 PanicMsgIdRemainderDivisionByZero,
1254 PanicMsgIdExactDivisionRemainder,1255 PanicMsgIdExactDivisionRemainder,
...@@ -1930,9 +1931,10 @@ enum IrBinOp {...@@ -1930,9 +1931,10 @@ enum IrBinOp {
1930 IrBinOpBinOr,1931 IrBinOpBinOr,
1931 IrBinOpBinXor,1932 IrBinOpBinXor,
1932 IrBinOpBinAnd,1933 IrBinOpBinAnd,
1933 IrBinOpBitShiftLeft,1934 IrBinOpBitShiftLeftLossy,
1934 IrBinOpBitShiftLeftWrap,1935 IrBinOpBitShiftLeftExact,
1935 IrBinOpBitShiftRight,1936 IrBinOpBitShiftRightLossy,
1937 IrBinOpBitShiftRightExact,
1936 IrBinOpAdd,1938 IrBinOpAdd,
1937 IrBinOpAddWrap,1939 IrBinOpAddWrap,
1938 IrBinOpSub,1940 IrBinOpSub,
src/ast_render.cpp-2
...@@ -26,7 +26,6 @@ static const char *bin_op_str(BinOpType bin_op) {...@@ -26,7 +26,6 @@ static const char *bin_op_str(BinOpType bin_op) {
26 case BinOpTypeBinXor: return "^";26 case BinOpTypeBinXor: return "^";
27 case BinOpTypeBinAnd: return "&";27 case BinOpTypeBinAnd: return "&";
28 case BinOpTypeBitShiftLeft: return "<<";28 case BinOpTypeBitShiftLeft: return "<<";
29 case BinOpTypeBitShiftLeftWrap: return "<<%";
30 case BinOpTypeBitShiftRight: return ">>";29 case BinOpTypeBitShiftRight: return ">>";
31 case BinOpTypeAdd: return "+";30 case BinOpTypeAdd: return "+";
32 case BinOpTypeAddWrap: return "+%";31 case BinOpTypeAddWrap: return "+%";
...@@ -46,7 +45,6 @@ static const char *bin_op_str(BinOpType bin_op) {...@@ -46,7 +45,6 @@ static const char *bin_op_str(BinOpType bin_op) {
46 case BinOpTypeAssignMinus: return "-=";45 case BinOpTypeAssignMinus: return "-=";
47 case BinOpTypeAssignMinusWrap: return "-%=";46 case BinOpTypeAssignMinusWrap: return "-%=";
48 case BinOpTypeAssignBitShiftLeft: return "<<=";47 case BinOpTypeAssignBitShiftLeft: return "<<=";
49 case BinOpTypeAssignBitShiftLeftWrap: return "<<%=";
50 case BinOpTypeAssignBitShiftRight: return ">>=";48 case BinOpTypeAssignBitShiftRight: return ">>=";
51 case BinOpTypeAssignBitAnd: return "&=";49 case BinOpTypeAssignBitAnd: return "&=";
52 case BinOpTypeAssignBitXor: return "^=";50 case BinOpTypeAssignBitXor: return "^=";
src/bigint.cpp+1-1
...@@ -799,7 +799,7 @@ void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -799,7 +799,7 @@ void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2) {
799 bigint_normalize(dest);799 bigint_normalize(dest);
800}800}
801801
802void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) {802void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) {
803 BigInt unwrapped = {0};803 BigInt unwrapped = {0};
804 bigint_shl(&unwrapped, op1, op2);804 bigint_shl(&unwrapped, op1, op2);
805 bigint_truncate(dest, &unwrapped, bit_count, is_signed);805 bigint_truncate(dest, &unwrapped, bit_count, is_signed);
src/bigint.hpp+1-1
...@@ -66,7 +66,7 @@ void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2);...@@ -66,7 +66,7 @@ void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2);
66void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2);66void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2);
6767
68void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2);68void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2);
69void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);69void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
70void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);70void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
7171
72void bigint_negate(BigInt *dest, const BigInt *op);72void bigint_negate(BigInt *dest, const BigInt *op);
src/codegen.cpp+54-13
...@@ -694,8 +694,10 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -694,8 +694,10 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
694 return buf_create_from_str("integer cast truncated bits");694 return buf_create_from_str("integer cast truncated bits");
695 case PanicMsgIdIntegerOverflow:695 case PanicMsgIdIntegerOverflow:
696 return buf_create_from_str("integer overflow");696 return buf_create_from_str("integer overflow");
697 case PanicMsgIdShiftOverflowedBits:697 case PanicMsgIdShlOverflowedBits:
698 return buf_create_from_str("left shift overflowed bits");698 return buf_create_from_str("left shift overflowed bits");
699 case PanicMsgIdShrOverflowedBits:
700 return buf_create_from_str("right shift overflowed bits");
699 case PanicMsgIdDivisionByZero:701 case PanicMsgIdDivisionByZero:
700 return buf_create_from_str("division by zero");702 return buf_create_from_str("division by zero");
701 case PanicMsgIdRemainderDivisionByZero:703 case PanicMsgIdRemainderDivisionByZero:
...@@ -1153,7 +1155,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns...@@ -1153,7 +1155,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
1153static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,1155static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
1154 LLVMValueRef val1, LLVMValueRef val2)1156 LLVMValueRef val1, LLVMValueRef val2)
1155{1157{
1156 // for unsigned left shifting, we do the wrapping shift, then logically shift1158 // for unsigned left shifting, we do the lossy shift, then logically shift
1157 // right the same number of bits1159 // right the same number of bits
1158 // if the values don't match, we have an overflow1160 // if the values don't match, we have an overflow
1159 // for signed left shifting we do the same except arithmetic shift right1161 // for signed left shifting we do the same except arithmetic shift right
...@@ -1174,7 +1176,32 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,...@@ -1174,7 +1176,32 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
1174 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);1176 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
11751177
1176 LLVMPositionBuilderAtEnd(g->builder, fail_block);1178 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1177 gen_debug_safety_crash(g, PanicMsgIdShiftOverflowedBits);1179 gen_debug_safety_crash(g, PanicMsgIdShlOverflowedBits);
1180
1181 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1182 return result;
1183}
1184
1185static LLVMValueRef gen_overflow_shr_op(CodeGen *g, TypeTableEntry *type_entry,
1186 LLVMValueRef val1, LLVMValueRef val2)
1187{
1188 assert(type_entry->id == TypeTableEntryIdInt);
1189
1190 LLVMValueRef result;
1191 if (type_entry->data.integral.is_signed) {
1192 result = LLVMBuildAShr(g->builder, val1, val2, "");
1193 } else {
1194 result = LLVMBuildLShr(g->builder, val1, val2, "");
1195 }
1196 LLVMValueRef orig_val = LLVMBuildShl(g->builder, result, val2, "");
1197 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
1198
1199 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
1200 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
1201 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
1202
1203 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1204 gen_debug_safety_crash(g, PanicMsgIdShrOverflowedBits);
11781205
1179 LLVMPositionBuilderAtEnd(g->builder, ok_block);1206 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1180 return result;1207 return result;
...@@ -1496,12 +1523,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -1496,12 +1523,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
1496 return LLVMBuildXor(g->builder, op1_value, op2_value, "");1523 return LLVMBuildXor(g->builder, op1_value, op2_value, "");
1497 case IrBinOpBinAnd:1524 case IrBinOpBinAnd:
1498 return LLVMBuildAnd(g->builder, op1_value, op2_value, "");1525 return LLVMBuildAnd(g->builder, op1_value, op2_value, "");
1499 case IrBinOpBitShiftLeft:1526 case IrBinOpBitShiftLeftLossy:
1500 case IrBinOpBitShiftLeftWrap:1527 case IrBinOpBitShiftLeftExact:
1501 {1528 {
1502 assert(type_entry->id == TypeTableEntryIdInt);1529 assert(type_entry->id == TypeTableEntryIdInt);
1503 bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);1530 bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy);
1504 if (is_wrapping) {1531 if (is_sloppy) {
1505 return LLVMBuildShl(g->builder, op1_value, op2_value, "");1532 return LLVMBuildShl(g->builder, op1_value, op2_value, "");
1506 } else if (want_debug_safety) {1533 } else if (want_debug_safety) {
1507 return gen_overflow_shl_op(g, type_entry, op1_value, op2_value);1534 return gen_overflow_shl_op(g, type_entry, op1_value, op2_value);
...@@ -1511,12 +1538,24 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -1511,12 +1538,24 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
1511 return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, "");1538 return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, "");
1512 }1539 }
1513 }1540 }
1514 case IrBinOpBitShiftRight:1541 case IrBinOpBitShiftRightLossy:
1515 assert(type_entry->id == TypeTableEntryIdInt);1542 case IrBinOpBitShiftRightExact:
1516 if (type_entry->data.integral.is_signed) {1543 {
1517 return LLVMBuildAShr(g->builder, op1_value, op2_value, "");1544 assert(type_entry->id == TypeTableEntryIdInt);
1518 } else {1545 bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy);
1519 return LLVMBuildLShr(g->builder, op1_value, op2_value, "");1546 if (is_sloppy) {
1547 if (type_entry->data.integral.is_signed) {
1548 return LLVMBuildAShr(g->builder, op1_value, op2_value, "");
1549 } else {
1550 return LLVMBuildLShr(g->builder, op1_value, op2_value, "");
1551 }
1552 } else if (want_debug_safety) {
1553 return gen_overflow_shr_op(g, type_entry, op1_value, op2_value);
1554 } else if (type_entry->data.integral.is_signed) {
1555 return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_value, "");
1556 } else {
1557 return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_value, "");
1558 }
1520 }1559 }
1521 case IrBinOpSub:1560 case IrBinOpSub:
1522 case IrBinOpSubWrap:1561 case IrBinOpSubWrap:
...@@ -4556,6 +4595,8 @@ static void define_builtin_fns(CodeGen *g) {...@@ -4556,6 +4595,8 @@ static void define_builtin_fns(CodeGen *g) {
4556 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);4595 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
4557 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);4596 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
4558 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);4597 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
4598 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
4599 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
4559}4600}
45604601
4561static const char *bool_to_str(bool b) {4602static const char *bool_to_str(bool b) {
src/error.cpp+1
...@@ -25,6 +25,7 @@ const char *err_str(int err) {...@@ -25,6 +25,7 @@ const char *err_str(int err) {
25 case ErrorUnexpected: return "unexpected error";25 case ErrorUnexpected: return "unexpected error";
26 case ErrorExactDivRemainder: return "exact division had a remainder";26 case ErrorExactDivRemainder: return "exact division had a remainder";
27 case ErrorNegativeDenominator: return "negative denominator";27 case ErrorNegativeDenominator: return "negative denominator";
28 case ErrorShiftedOutOneBits: return "exact shift shifted out one bits";
28 }29 }
29 return "(invalid error)";30 return "(invalid error)";
30}31}
src/error.hpp+1
...@@ -25,6 +25,7 @@ enum Error {...@@ -25,6 +25,7 @@ enum Error {
25 ErrorUnexpected,25 ErrorUnexpected,
26 ErrorExactDivRemainder,26 ErrorExactDivRemainder,
27 ErrorNegativeDenominator,27 ErrorNegativeDenominator,
28 ErrorShiftedOutOneBits,
28};29};
2930
30const char *err_str(int err);31const char *err_str(int err);
src/ir.cpp+56-17
...@@ -3625,11 +3625,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)...@@ -3625,11 +3625,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
3625 case BinOpTypeAssignMinusWrap:3625 case BinOpTypeAssignMinusWrap:
3626 return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap);3626 return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap);
3627 case BinOpTypeAssignBitShiftLeft:3627 case BinOpTypeAssignBitShiftLeft:
3628 return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeft);3628 return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy);
3629 case BinOpTypeAssignBitShiftLeftWrap:
3630 return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftWrap);
3631 case BinOpTypeAssignBitShiftRight:3629 case BinOpTypeAssignBitShiftRight:
3632 return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRight);3630 return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy);
3633 case BinOpTypeAssignBitAnd:3631 case BinOpTypeAssignBitAnd:
3634 return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd);3632 return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd);
3635 case BinOpTypeAssignBitXor:3633 case BinOpTypeAssignBitXor:
...@@ -3663,11 +3661,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)...@@ -3663,11 +3661,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
3663 case BinOpTypeBinAnd:3661 case BinOpTypeBinAnd:
3664 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd);3662 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd);
3665 case BinOpTypeBitShiftLeft:3663 case BinOpTypeBitShiftLeft:
3666 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeft);3664 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy);
3667 case BinOpTypeBitShiftLeftWrap:
3668 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftWrap);
3669 case BinOpTypeBitShiftRight:3665 case BinOpTypeBitShiftRight:
3670 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRight);3666 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy);
3671 case BinOpTypeAdd:3667 case BinOpTypeAdd:
3672 return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd);3668 return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd);
3673 case BinOpTypeAddWrap:3669 case BinOpTypeAddWrap:
...@@ -4457,6 +4453,34 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4457,6 +4453,34 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
44574453
4458 return ir_build_type_id(irb, scope, node, arg0_value);4454 return ir_build_type_id(irb, scope, node, arg0_value);
4459 }4455 }
4456 case BuiltinFnIdShlExact:
4457 {
4458 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4459 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4460 if (arg0_value == irb->codegen->invalid_instruction)
4461 return arg0_value;
4462
4463 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4464 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4465 if (arg1_value == irb->codegen->invalid_instruction)
4466 return arg1_value;
4467
4468 return ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true);
4469 }
4470 case BuiltinFnIdShrExact:
4471 {
4472 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4473 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4474 if (arg0_value == irb->codegen->invalid_instruction)
4475 return arg0_value;
4476
4477 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4478 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4479 if (arg1_value == irb->codegen->invalid_instruction)
4480 return arg1_value;
4481
4482 return ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true);
4483 }
4460 }4484 }
4461 zig_unreachable();4485 zig_unreachable();
4462}4486}
...@@ -8362,16 +8386,27 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,...@@ -8362,16 +8386,27 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,
8362 assert(is_int);8386 assert(is_int);
8363 bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);8387 bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
8364 break;8388 break;
8365 case IrBinOpBitShiftLeft:8389 case IrBinOpBitShiftLeftExact:
8366 assert(is_int);8390 assert(is_int);
8367 bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);8391 bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
8368 break;8392 break;
8369 case IrBinOpBitShiftLeftWrap:8393 case IrBinOpBitShiftLeftLossy:
8370 assert(type_entry->id == TypeTableEntryIdInt);8394 assert(type_entry->id == TypeTableEntryIdInt);
8371 bigint_shl_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint,8395 bigint_shl_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint,
8372 type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);8396 type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);
8373 break;8397 break;
8374 case IrBinOpBitShiftRight:8398 case IrBinOpBitShiftRightExact:
8399 {
8400 assert(is_int);
8401 bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
8402 BigInt orig_bigint;
8403 bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint);
8404 if (bigint_cmp(&op1_val->data.x_bigint, &orig_bigint) != CmpEQ) {
8405 return ErrorShiftedOutOneBits;
8406 }
8407 break;
8408 }
8409 case IrBinOpBitShiftRightLossy:
8375 assert(is_int);8410 assert(is_int);
8376 bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);8411 bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
8377 break;8412 break;
...@@ -8591,8 +8626,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -8591,8 +8626,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
8591 }8626 }
85928627
8593 if (resolved_type->id == TypeTableEntryIdNumLitInt) {8628 if (resolved_type->id == TypeTableEntryIdNumLitInt) {
8594 if (op_id == IrBinOpBitShiftLeftWrap) {8629 if (op_id == IrBinOpBitShiftLeftLossy) {
8595 op_id = IrBinOpBitShiftLeft;8630 op_id = IrBinOpBitShiftLeftExact;
8596 } else if (op_id == IrBinOpAddWrap) {8631 } else if (op_id == IrBinOpAddWrap) {
8597 op_id = IrBinOpAdd;8632 op_id = IrBinOpAdd;
8598 } else if (op_id == IrBinOpSubWrap) {8633 } else if (op_id == IrBinOpSubWrap) {
...@@ -8631,6 +8666,9 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -8631,6 +8666,9 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
8631 } else if (err == ErrorNegativeDenominator) {8666 } else if (err == ErrorNegativeDenominator) {
8632 ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("negative denominator"));8667 ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("negative denominator"));
8633 return ira->codegen->builtin_types.entry_invalid;8668 return ira->codegen->builtin_types.entry_invalid;
8669 } else if (err == ErrorShiftedOutOneBits) {
8670 ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("exact shift shifted out 1 bits"));
8671 return ira->codegen->builtin_types.entry_invalid;
8634 } else {8672 } else {
8635 zig_unreachable();8673 zig_unreachable();
8636 }8674 }
...@@ -8857,9 +8895,10 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi...@@ -8857,9 +8895,10 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
8857 case IrBinOpBinOr:8895 case IrBinOpBinOr:
8858 case IrBinOpBinXor:8896 case IrBinOpBinXor:
8859 case IrBinOpBinAnd:8897 case IrBinOpBinAnd:
8860 case IrBinOpBitShiftLeft:8898 case IrBinOpBitShiftLeftLossy:
8861 case IrBinOpBitShiftLeftWrap:8899 case IrBinOpBitShiftLeftExact:
8862 case IrBinOpBitShiftRight:8900 case IrBinOpBitShiftRightLossy:
8901 case IrBinOpBitShiftRightExact:
8863 case IrBinOpAdd:8902 case IrBinOpAdd:
8864 case IrBinOpAddWrap:8903 case IrBinOpAddWrap:
8865 case IrBinOpSub:8904 case IrBinOpSub:
src/ir_print.cpp+6-4
...@@ -92,12 +92,14 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {...@@ -92,12 +92,14 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
92 return "^";92 return "^";
93 case IrBinOpBinAnd:93 case IrBinOpBinAnd:
94 return "&";94 return "&";
95 case IrBinOpBitShiftLeft:95 case IrBinOpBitShiftLeftLossy:
96 return "<<";96 return "<<";
97 case IrBinOpBitShiftLeftWrap:97 case IrBinOpBitShiftLeftExact:
98 return "<<%";98 return "@shlExact";
99 case IrBinOpBitShiftRight:99 case IrBinOpBitShiftRightLossy:
100 return ">>";100 return ">>";
101 case IrBinOpBitShiftRightExact:
102 return "@shrExact";
101 case IrBinOpAdd:103 case IrBinOpAdd:
102 return "+";104 return "+";
103 case IrBinOpAddWrap:105 case IrBinOpAddWrap:
src/parser.cpp-2
...@@ -1131,7 +1131,6 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, size_t *token_index, bool m...@@ -1131,7 +1131,6 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, size_t *token_index, bool m
1131static BinOpType tok_to_bit_shift_op(Token *token) {1131static BinOpType tok_to_bit_shift_op(Token *token) {
1132 switch (token->id) {1132 switch (token->id) {
1133 case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft;1133 case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft;
1134 case TokenIdBitShiftLeftPercent: return BinOpTypeBitShiftLeftWrap;
1135 case TokenIdBitShiftRight: return BinOpTypeBitShiftRight;1134 case TokenIdBitShiftRight: return BinOpTypeBitShiftRight;
1136 default: return BinOpTypeInvalid;1135 default: return BinOpTypeInvalid;
1137 }1136 }
...@@ -1909,7 +1908,6 @@ static BinOpType tok_to_ass_op(Token *token) {...@@ -1909,7 +1908,6 @@ static BinOpType tok_to_ass_op(Token *token) {
1909 case TokenIdMinusEq: return BinOpTypeAssignMinus;1908 case TokenIdMinusEq: return BinOpTypeAssignMinus;
1910 case TokenIdMinusPercentEq: return BinOpTypeAssignMinusWrap;1909 case TokenIdMinusPercentEq: return BinOpTypeAssignMinusWrap;
1911 case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft;1910 case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft;
1912 case TokenIdBitShiftLeftPercentEq: return BinOpTypeAssignBitShiftLeftWrap;
1913 case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight;1911 case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight;
1914 case TokenIdBitAndEq: return BinOpTypeAssignBitAnd;1912 case TokenIdBitAndEq: return BinOpTypeAssignBitAnd;
1915 case TokenIdBitXorEq: return BinOpTypeAssignBitXor;1913 case TokenIdBitXorEq: return BinOpTypeAssignBitXor;
src/tokenizer.cpp-22
...@@ -201,7 +201,6 @@ enum TokenizeState {...@@ -201,7 +201,6 @@ enum TokenizeState {
201 TokenizeStateSawBang,201 TokenizeStateSawBang,
202 TokenizeStateSawLessThan,202 TokenizeStateSawLessThan,
203 TokenizeStateSawLessThanLessThan,203 TokenizeStateSawLessThanLessThan,
204 TokenizeStateSawShiftLeftPercent,
205 TokenizeStateSawGreaterThan,204 TokenizeStateSawGreaterThan,
206 TokenizeStateSawGreaterThanGreaterThan,205 TokenizeStateSawGreaterThanGreaterThan,
207 TokenizeStateSawDot,206 TokenizeStateSawDot,
...@@ -673,24 +672,6 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -673,24 +672,6 @@ void tokenize(Buf *buf, Tokenization *out) {
673 end_token(&t);672 end_token(&t);
674 t.state = TokenizeStateStart;673 t.state = TokenizeStateStart;
675 break;674 break;
676 case '%':
677 set_token_id(&t, t.cur_tok, TokenIdBitShiftLeftPercent);
678 t.state = TokenizeStateSawShiftLeftPercent;
679 break;
680 default:
681 t.pos -= 1;
682 end_token(&t);
683 t.state = TokenizeStateStart;
684 continue;
685 }
686 break;
687 case TokenizeStateSawShiftLeftPercent:
688 switch (c) {
689 case '=':
690 set_token_id(&t, t.cur_tok, TokenIdBitShiftLeftPercentEq);
691 end_token(&t);
692 t.state = TokenizeStateStart;
693 break;
694 default:675 default:
695 t.pos -= 1;676 t.pos -= 1;
696 end_token(&t);677 end_token(&t);
...@@ -1410,7 +1391,6 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -1410,7 +1391,6 @@ void tokenize(Buf *buf, Tokenization *out) {
1410 case TokenizeStateSawStarPercent:1391 case TokenizeStateSawStarPercent:
1411 case TokenizeStateSawPlusPercent:1392 case TokenizeStateSawPlusPercent:
1412 case TokenizeStateSawMinusPercent:1393 case TokenizeStateSawMinusPercent:
1413 case TokenizeStateSawShiftLeftPercent:
1414 case TokenizeStateLineString:1394 case TokenizeStateLineString:
1415 case TokenizeStateLineStringEnd:1395 case TokenizeStateLineStringEnd:
1416 end_token(&t);1396 end_token(&t);
...@@ -1451,8 +1431,6 @@ const char * token_name(TokenId id) {...@@ -1451,8 +1431,6 @@ const char * token_name(TokenId id) {
1451 case TokenIdBitOrEq: return "|=";1431 case TokenIdBitOrEq: return "|=";
1452 case TokenIdBitShiftLeft: return "<<";1432 case TokenIdBitShiftLeft: return "<<";
1453 case TokenIdBitShiftLeftEq: return "<<=";1433 case TokenIdBitShiftLeftEq: return "<<=";
1454 case TokenIdBitShiftLeftPercent: return "<<%";
1455 case TokenIdBitShiftLeftPercentEq: return "<<%=";
1456 case TokenIdBitShiftRight: return ">>";1434 case TokenIdBitShiftRight: return ">>";
1457 case TokenIdBitShiftRightEq: return ">>=";1435 case TokenIdBitShiftRightEq: return ">>=";
1458 case TokenIdBitXorEq: return "^=";1436 case TokenIdBitXorEq: return "^=";
src/tokenizer.hpp-2
...@@ -23,8 +23,6 @@ enum TokenId {...@@ -23,8 +23,6 @@ enum TokenId {
23 TokenIdBitOrEq,23 TokenIdBitOrEq,
24 TokenIdBitShiftLeft,24 TokenIdBitShiftLeft,
25 TokenIdBitShiftLeftEq,25 TokenIdBitShiftLeftEq,
26 TokenIdBitShiftLeftPercent,
27 TokenIdBitShiftLeftPercentEq,
28 TokenIdBitShiftRight,26 TokenIdBitShiftRight,
29 TokenIdBitShiftRightEq,27 TokenIdBitShiftRightEq,
30 TokenIdBitXorEq,28 TokenIdBitXorEq,
src/zig_llvm.cpp+14-1
...@@ -754,9 +754,22 @@ LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMVa...@@ -754,9 +754,22 @@ LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMVa
754LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,754LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
755 const char *name)755 const char *name)
756{756{
757 return wrap(unwrap(builder)->CreateShl(unwrap(LHS), unwrap(RHS), name, false, true));757 return wrap(unwrap(builder)->CreateShl(unwrap(LHS), unwrap(RHS), name, true, false));
758}
759
760LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
761 const char *name)
762{
763 return wrap(unwrap(builder)->CreateLShr(unwrap(LHS), unwrap(RHS), name, true));
758}764}
759765
766LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
767 const char *name)
768{
769 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
770}
771
772
760#include "buffer.hpp"773#include "buffer.hpp"
761774
762bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag_buf) {775bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag_buf) {
src/zig_llvm.hpp+4
...@@ -48,6 +48,10 @@ LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMVa...@@ -48,6 +48,10 @@ LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMVa
48 const char *name);48 const char *name);
49LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,49LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
50 const char *name);50 const char *name);
51LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
52 const char *name);
53LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
54 const char *name);
5155
52ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type,56ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type,
53 uint64_t size_in_bits, uint64_t align_in_bits, const char *name);57 uint64_t size_in_bits, uint64_t align_in_bits, const char *name);
std/base64.zig+11-11
...@@ -21,11 +21,11 @@ pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8)...@@ -21,11 +21,11 @@ pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8)
21 dest[out_index] = alphabet[(source[i] >> 2) & 0x3f];21 dest[out_index] = alphabet[(source[i] >> 2) & 0x3f];
22 out_index += 1;22 out_index += 1;
2323
24 dest[out_index] = alphabet[((source[i] & 0x3) <<% 4) |24 dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
25 ((source[i + 1] & 0xf0) >> 4)];25 ((source[i + 1] & 0xf0) >> 4)];
26 out_index += 1;26 out_index += 1;
2727
28 dest[out_index] = alphabet[((source[i + 1] & 0xf) <<% 2) |28 dest[out_index] = alphabet[((source[i + 1] & 0xf) << 2) |
29 ((source[i + 2] & 0xc0) >> 6)];29 ((source[i + 2] & 0xc0) >> 6)];
30 out_index += 1;30 out_index += 1;
3131
...@@ -38,17 +38,17 @@ pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8)...@@ -38,17 +38,17 @@ pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8)
38 out_index += 1;38 out_index += 1;
3939
40 if (i + 1 == source.len) {40 if (i + 1 == source.len) {
41 dest[out_index] = alphabet[(source[i] & 0x3) <<% 4];41 dest[out_index] = alphabet[(source[i] & 0x3) << 4];
42 out_index += 1;42 out_index += 1;
4343
44 dest[out_index] = alphabet[64];44 dest[out_index] = alphabet[64];
45 out_index += 1;45 out_index += 1;
46 } else {46 } else {
47 dest[out_index] = alphabet[((source[i] & 0x3) <<% 4) |47 dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
48 ((source[i + 1] & 0xf0) >> 4)];48 ((source[i + 1] & 0xf0) >> 4)];
49 out_index += 1;49 out_index += 1;
5050
51 dest[out_index] = alphabet[(source[i + 1] & 0xf) <<% 2];51 dest[out_index] = alphabet[(source[i + 1] & 0xf) << 2];
52 out_index += 1;52 out_index += 1;
53 }53 }
5454
...@@ -83,15 +83,15 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8...@@ -83,15 +83,15 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8
83 }83 }
8484
85 while (in_buf_len > 4) {85 while (in_buf_len > 4) {
86 dest[dest_index] = ascii6[source[src_index + 0]] <<% 2 |86 dest[dest_index] = ascii6[source[src_index + 0]] << 2 |
87 ascii6[source[src_index + 1]] >> 4;87 ascii6[source[src_index + 1]] >> 4;
88 dest_index += 1;88 dest_index += 1;
8989
90 dest[dest_index] = ascii6[source[src_index + 1]] <<% 4 |90 dest[dest_index] = ascii6[source[src_index + 1]] << 4 |
91 ascii6[source[src_index + 2]] >> 2;91 ascii6[source[src_index + 2]] >> 2;
92 dest_index += 1;92 dest_index += 1;
9393
94 dest[dest_index] = ascii6[source[src_index + 2]] <<% 6 |94 dest[dest_index] = ascii6[source[src_index + 2]] << 6 |
95 ascii6[source[src_index + 3]];95 ascii6[source[src_index + 3]];
96 dest_index += 1;96 dest_index += 1;
9797
...@@ -100,17 +100,17 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8...@@ -100,17 +100,17 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8
100 }100 }
101101
102 if (in_buf_len > 1) {102 if (in_buf_len > 1) {
103 dest[dest_index] = ascii6[source[src_index + 0]] <<% 2 |103 dest[dest_index] = ascii6[source[src_index + 0]] << 2 |
104 ascii6[source[src_index + 1]] >> 4;104 ascii6[source[src_index + 1]] >> 4;
105 dest_index += 1;105 dest_index += 1;
106 }106 }
107 if (in_buf_len > 2) {107 if (in_buf_len > 2) {
108 dest[dest_index] = ascii6[source[src_index + 1]] <<% 4 |108 dest[dest_index] = ascii6[source[src_index + 1]] << 4 |
109 ascii6[source[src_index + 2]] >> 2;109 ascii6[source[src_index + 2]] >> 2;
110 dest_index += 1;110 dest_index += 1;
111 }111 }
112 if (in_buf_len > 3) {112 if (in_buf_len > 3) {
113 dest[dest_index] = ascii6[source[src_index + 2]] <<% 6 |113 dest[dest_index] = ascii6[source[src_index + 2]] << 6 |
114 ascii6[source[src_index + 3]];114 ascii6[source[src_index + 3]];
115 dest_index += 1;115 dest_index += 1;
116 }116 }
std/math/exp2.zig+1-1
...@@ -83,7 +83,7 @@ fn exp2_32(x: f32) -> f32 {...@@ -83,7 +83,7 @@ fn exp2_32(x: f32) -> f32 {
83 const k = i0 / tblsiz;83 const k = i0 / tblsiz;
84 // NOTE: musl relies on undefined overflow shift behaviour. Appears that this produces the84 // NOTE: musl relies on undefined overflow shift behaviour. Appears that this produces the
85 // intended result but should confirm how GCC/Clang handle this to ensure.85 // intended result but should confirm how GCC/Clang handle this to ensure.
86 const uk = @bitCast(f64, u64(0x3FF + k) <<% 52);86 const uk = @bitCast(f64, u64(0x3FF + k) << 52);
87 i0 &= tblsiz - 1;87 i0 &= tblsiz - 1;
88 uf -= redux;88 uf -= redux;
8989
std/math/expm1.zig+2-2
...@@ -124,7 +124,7 @@ fn expm1_32(x_: f32) -> f32 {...@@ -124,7 +124,7 @@ fn expm1_32(x_: f32) -> f32 {
124 }124 }
125 }125 }
126126
127 const twopk = @bitCast(f32, u32((0x7F + k) <<% 23));127 const twopk = @bitCast(f32, u32((0x7F + k) << 23));
128128
129 if (k < 0 or k > 56) {129 if (k < 0 or k > 56) {
130 var y = x - e + 1.0;130 var y = x - e + 1.0;
...@@ -253,7 +253,7 @@ fn expm1_64(x_: f64) -> f64 {...@@ -253,7 +253,7 @@ fn expm1_64(x_: f64) -> f64 {
253 }253 }
254 }254 }
255255
256 const twopk = @bitCast(f64, u64(0x3FF + k) <<% 52);256 const twopk = @bitCast(f64, u64(0x3FF + k) << 52);
257257
258 if (k < 0 or k > 56) {258 if (k < 0 or k > 56) {
259 var y = x - e + 1.0;259 var y = x - e + 1.0;
std/math/ilogb.zig+2-2
...@@ -49,7 +49,7 @@ fn ilogb32(x: f32) -> i32 {...@@ -49,7 +49,7 @@ fn ilogb32(x: f32) -> i32 {
4949
50 if (e == 0xFF) {50 if (e == 0xFF) {
51 math.raiseInvalid();51 math.raiseInvalid();
52 if (u <<% 9 != 0) {52 if (u << 9 != 0) {
53 return fp_ilogbnan;53 return fp_ilogbnan;
54 } else {54 } else {
55 return @maxValue(i32);55 return @maxValue(i32);
...@@ -84,7 +84,7 @@ fn ilogb64(x: f64) -> i32 {...@@ -84,7 +84,7 @@ fn ilogb64(x: f64) -> i32 {
8484
85 if (e == 0x7FF) {85 if (e == 0x7FF) {
86 math.raiseInvalid();86 math.raiseInvalid();
87 if (u <<% 12 != 0) {87 if (u << 12 != 0) {
88 return fp_ilogbnan;88 return fp_ilogbnan;
89 } else {89 } else {
90 return @maxValue(i32);90 return @maxValue(i32);
std/math/ln.zig+2-2
...@@ -36,7 +36,7 @@ fn lnf(x_: f32) -> f32 {...@@ -36,7 +36,7 @@ fn lnf(x_: f32) -> f32 {
36 // x < 2^(-126)36 // x < 2^(-126)
37 if (ix < 0x00800000 or ix >> 31 != 0) {37 if (ix < 0x00800000 or ix >> 31 != 0) {
38 // log(+-0) = -inf38 // log(+-0) = -inf
39 if (ix <<% 1 == 0) {39 if (ix << 1 == 0) {
40 return -math.inf(f32);40 return -math.inf(f32);
41 }41 }
42 // log(-#) = nan42 // log(-#) = nan
...@@ -91,7 +91,7 @@ fn lnd(x_: f64) -> f64 {...@@ -91,7 +91,7 @@ fn lnd(x_: f64) -> f64 {
9191
92 if (hx < 0x00100000 or hx >> 31 != 0) {92 if (hx < 0x00100000 or hx >> 31 != 0) {
93 // log(+-0) = -inf93 // log(+-0) = -inf
94 if (ix <<% 1 == 0) {94 if (ix << 1 == 0) {
95 return -math.inf(f64);95 return -math.inf(f64);
96 }96 }
97 // log(-#) = nan97 // log(-#) = nan
std/math/log10.zig+3-3
...@@ -38,7 +38,7 @@ fn log10_32(x_: f32) -> f32 {...@@ -38,7 +38,7 @@ fn log10_32(x_: f32) -> f32 {
38 // x < 2^(-126)38 // x < 2^(-126)
39 if (ix < 0x00800000 or ix >> 31 != 0) {39 if (ix < 0x00800000 or ix >> 31 != 0) {
40 // log(+-0) = -inf40 // log(+-0) = -inf
41 if (ix <<% 1 == 0) {41 if (ix << 1 == 0) {
42 return -math.inf(f32);42 return -math.inf(f32);
43 }43 }
44 // log(-#) = nan44 // log(-#) = nan
...@@ -100,7 +100,7 @@ fn log10_64(x_: f64) -> f64 {...@@ -100,7 +100,7 @@ fn log10_64(x_: f64) -> f64 {
100100
101 if (hx < 0x00100000 or hx >> 31 != 0) {101 if (hx < 0x00100000 or hx >> 31 != 0) {
102 // log(+-0) = -inf102 // log(+-0) = -inf
103 if (ix <<% 1 == 0) {103 if (ix << 1 == 0) {
104 return -math.inf(f32);104 return -math.inf(f32);
105 }105 }
106 // log(-#) = nan106 // log(-#) = nan
...@@ -139,7 +139,7 @@ fn log10_64(x_: f64) -> f64 {...@@ -139,7 +139,7 @@ fn log10_64(x_: f64) -> f64 {
139 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)139 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
140 var hi = f - hfsq;140 var hi = f - hfsq;
141 var hii = @bitCast(u64, hi);141 var hii = @bitCast(u64, hi);
142 hii &= u64(@maxValue(u64)) <<% 32;142 hii &= u64(@maxValue(u64)) << 32;
143 hi = @bitCast(f64, hii);143 hi = @bitCast(f64, hii);
144 const lo = f - hi - hfsq + s * (hfsq + R);144 const lo = f - hi - hfsq + s * (hfsq + R);
145145
std/math/log1p.zig+2-2
...@@ -49,7 +49,7 @@ fn log1p_32(x: f32) -> f32 {...@@ -49,7 +49,7 @@ fn log1p_32(x: f32) -> f32 {
49 }49 }
50 }50 }
51 // |x| < 2^(-24)51 // |x| < 2^(-24)
52 if ((ix <<% 1) < (0x33800000 << 1)) {52 if ((ix << 1) < (0x33800000 << 1)) {
53 // underflow if subnormal53 // underflow if subnormal
54 if (ix & 0x7F800000 == 0) {54 if (ix & 0x7F800000 == 0) {
55 math.forceEval(x * x);55 math.forceEval(x * x);
...@@ -128,7 +128,7 @@ fn log1p_64(x: f64) -> f64 {...@@ -128,7 +128,7 @@ fn log1p_64(x: f64) -> f64 {
128 }128 }
129 }129 }
130 // |x| < 2^(-53)130 // |x| < 2^(-53)
131 if ((hx <<% 1) < (0x3CA00000 << 1)) {131 if ((hx << 1) < (0x3CA00000 << 1)) {
132 if ((hx & 0x7FF00000) == 0) {132 if ((hx & 0x7FF00000) == 0) {
133 math.raiseUnderflow();133 math.raiseUnderflow();
134 }134 }
std/math/log2.zig+3-3
...@@ -36,7 +36,7 @@ fn log2_32(x_: f32) -> f32 {...@@ -36,7 +36,7 @@ fn log2_32(x_: f32) -> f32 {
36 // x < 2^(-126)36 // x < 2^(-126)
37 if (ix < 0x00800000 or ix >> 31 != 0) {37 if (ix < 0x00800000 or ix >> 31 != 0) {
38 // log(+-0) = -inf38 // log(+-0) = -inf
39 if (ix <<% 1 == 0) {39 if (ix << 1 == 0) {
40 return -math.inf(f32);40 return -math.inf(f32);
41 }41 }
42 // log(-#) = nan42 // log(-#) = nan
...@@ -94,7 +94,7 @@ fn log2_64(x_: f64) -> f64 {...@@ -94,7 +94,7 @@ fn log2_64(x_: f64) -> f64 {
9494
95 if (hx < 0x00100000 or hx >> 31 != 0) {95 if (hx < 0x00100000 or hx >> 31 != 0) {
96 // log(+-0) = -inf96 // log(+-0) = -inf
97 if (ix <<% 1 == 0) {97 if (ix << 1 == 0) {
98 return -math.inf(f64);98 return -math.inf(f64);
99 }99 }
100 // log(-#) = nan100 // log(-#) = nan
...@@ -133,7 +133,7 @@ fn log2_64(x_: f64) -> f64 {...@@ -133,7 +133,7 @@ fn log2_64(x_: f64) -> f64 {
133 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)133 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
134 var hi = f - hfsq;134 var hi = f - hfsq;
135 var hii = @bitCast(u64, hi);135 var hii = @bitCast(u64, hi);
136 hii &= u64(@maxValue(u64)) <<% 32;136 hii &= u64(@maxValue(u64)) << 32;
137 hi = @bitCast(f64, hii);137 hi = @bitCast(f64, hii);
138 const lo = f - hi - hfsq + s * (hfsq + R);138 const lo = f - hi - hfsq + s * (hfsq + R);
139139
std/math/modf.zig+2-2
...@@ -44,7 +44,7 @@ fn modf32(x: f32) -> modf32_result {...@@ -44,7 +44,7 @@ fn modf32(x: f32) -> modf32_result {
44 // no fractional part44 // no fractional part
45 if (e >= 23) {45 if (e >= 23) {
46 result.ipart = x;46 result.ipart = x;
47 if (e == 0x80 and u <<% 9 != 0) { // nan47 if (e == 0x80 and u << 9 != 0) { // nan
48 result.fpart = x;48 result.fpart = x;
49 } else {49 } else {
50 result.fpart = @bitCast(f32, us);50 result.fpart = @bitCast(f32, us);
...@@ -88,7 +88,7 @@ fn modf64(x: f64) -> modf64_result {...@@ -88,7 +88,7 @@ fn modf64(x: f64) -> modf64_result {
88 // no fractional part88 // no fractional part
89 if (e >= 52) {89 if (e >= 52) {
90 result.ipart = x;90 result.ipart = x;
91 if (e == 0x400 and u <<% 12 != 0) { // nan91 if (e == 0x400 and u << 12 != 0) { // nan
92 result.fpart = x;92 result.fpart = x;
93 } else {93 } else {
94 result.fpart = @bitCast(f64, us);94 result.fpart = @bitCast(f64, us);
std/rand.zig+2-2
...@@ -182,8 +182,8 @@ fn MersenneTwister(...@@ -182,8 +182,8 @@ fn MersenneTwister(
182 mt.index += 1;182 mt.index += 1;
183183
184 x ^= ((x >> u) & d);184 x ^= ((x >> u) & d);
185 x ^= ((x <<% s) & b);185 x ^= ((x << s) & b);
186 x ^= ((x <<% t) & c);186 x ^= ((x << t) & c);
187 x ^= (x >> l);187 x ^= (x >> l);
188188
189 return x;189 return x;
std/special/builtin.zig+16-16
...@@ -47,31 +47,31 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {...@@ -47,31 +47,31 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
47 const sx = if (T == f32) u32(ux & 0x80000000) else i32(ux >> bits_minus_1);47 const sx = if (T == f32) u32(ux & 0x80000000) else i32(ux >> bits_minus_1);
48 var i: uint = undefined;48 var i: uint = undefined;
4949
50 if (uy <<% 1 == 0 or isNan(uint, uy) or ex == mask)50 if (uy << 1 == 0 or isNan(uint, uy) or ex == mask)
51 return (x * y) / (x * y);51 return (x * y) / (x * y);
5252
53 if (ux <<% 1 <= uy <<% 1) {53 if (ux << 1 <= uy << 1) {
54 if (ux <<% 1 == uy <<% 1)54 if (ux << 1 == uy << 1)
55 return 0 * x;55 return 0 * x;
56 return x;56 return x;
57 }57 }
5858
59 // normalize x and y59 // normalize x and y
60 if (ex == 0) {60 if (ex == 0) {
61 i = ux <<% exp_bits;61 i = ux << exp_bits;
62 while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<%= 1}) {}62 while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<= 1}) {}
63 ux <<%= @bitCast(u32, -ex + 1);63 ux <<= @bitCast(u32, -ex + 1);
64 } else {64 } else {
65 ux &= @maxValue(uint) >> exp_bits;65 ux &= @maxValue(uint) >> exp_bits;
66 ux |= 1 <<% digits;66 ux |= 1 << digits;
67 }67 }
68 if (ey == 0) {68 if (ey == 0) {
69 i = uy <<% exp_bits;69 i = uy << exp_bits;
70 while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<%= 1}) {}70 while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<= 1}) {}
71 uy <<= @bitCast(u32, -ey + 1);71 uy <<= @bitCast(u32, -ey + 1);
72 } else {72 } else {
73 uy &= @maxValue(uint) >> exp_bits;73 uy &= @maxValue(uint) >> exp_bits;
74 uy |= 1 <<% digits;74 uy |= 1 << digits;
75 }75 }
7676
77 // x mod y77 // x mod y
...@@ -82,7 +82,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {...@@ -82,7 +82,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
82 return 0 * x;82 return 0 * x;
83 ux = i;83 ux = i;
84 }84 }
85 ux <<%= 1;85 ux <<= 1;
86 }86 }
87 i = ux -% uy;87 i = ux -% uy;
88 if (i >> bits_minus_1 == 0) {88 if (i >> bits_minus_1 == 0) {
...@@ -90,19 +90,19 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {...@@ -90,19 +90,19 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
90 return 0 * x;90 return 0 * x;
91 ux = i;91 ux = i;
92 }92 }
93 while (ux >> digits == 0) : ({ux <<%= 1; ex -= 1}) {}93 while (ux >> digits == 0) : ({ux <<= 1; ex -= 1}) {}
9494
95 // scale result up95 // scale result up
96 if (ex > 0) {96 if (ex > 0) {
97 ux -%= 1 <<% digits;97 ux -%= 1 << digits;
98 ux |= @bitCast(u32, ex) <<% digits;98 ux |= @bitCast(u32, ex) << digits;
99 } else {99 } else {
100 ux >>= @bitCast(u32, -ex + 1);100 ux >>= @bitCast(u32, -ex + 1);
101 }101 }
102 if (T == f32) {102 if (T == f32) {
103 ux |= sx;103 ux |= sx;
104 } else {104 } else {
105 ux |= uint(sx) <<% bits_minus_1;105 ux |= uint(sx) << bits_minus_1;
106 }106 }
107 return *@ptrCast(&const T, &ux);107 return *@ptrCast(&const T, &ux);
108}108}
...@@ -111,7 +111,7 @@ fn isNan(comptime T: type, bits: T) -> bool {...@@ -111,7 +111,7 @@ fn isNan(comptime T: type, bits: T) -> bool {
111 if (T == u32) {111 if (T == u32) {
112 return (bits & 0x7fffffff) > 0x7f800000;112 return (bits & 0x7fffffff) > 0x7f800000;
113 } else if (T == u64) {113 } else if (T == u64) {
114 return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) <<% 52);114 return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52);
115 } else {115 } else {
116 unreachable;116 unreachable;
117 }117 }
test/cases/math.zig+36-9
...@@ -168,15 +168,6 @@ fn testNegationWrappingEval(x: i16) {...@@ -168,15 +168,6 @@ fn testNegationWrappingEval(x: i16) {
168 assert(neg == -32768);168 assert(neg == -32768);
169}169}
170170
171test "shift left wrapping" {
172 testShlWrappingEval(@maxValue(u16));
173 comptime testShlWrappingEval(@maxValue(u16));
174}
175fn testShlWrappingEval(x: u16) {
176 const shifted = x <<% 1;
177 assert(shifted == 65534);
178}
179
180test "unsigned 64-bit division" {171test "unsigned 64-bit division" {
181 test_u64_div();172 test_u64_div();
182 comptime test_u64_div();173 comptime test_u64_div();
...@@ -257,3 +248,39 @@ test "hex float literal within range" {...@@ -257,3 +248,39 @@ test "hex float literal within range" {
257 const b = 0x0.1p1027;248 const b = 0x0.1p1027;
258 const c = 0x1.0p-1022;249 const c = 0x1.0p-1022;
259}250}
251
252test "truncating shift left" {
253 testShlTrunc(@maxValue(u16));
254 comptime testShlTrunc(@maxValue(u16));
255}
256fn testShlTrunc(x: u16) {
257 const shifted = x << 1;
258 assert(shifted == 65534);
259}
260
261test "truncating shift right" {
262 testShrTrunc(@maxValue(u16));
263 comptime testShrTrunc(@maxValue(u16));
264}
265fn testShrTrunc(x: u16) {
266 const shifted = x >> 1;
267 assert(shifted == 32767);
268}
269
270test "exact shift left" {
271 testShlExact(0b00110101);
272 comptime testShlExact(0b00110101);
273}
274fn testShlExact(x: u8) {
275 const shifted = @shlExact(x, 2);
276 assert(shifted == 0b11010100);
277}
278
279test "exact shift right" {
280 testShrExact(0b10110100);
281 comptime testShrExact(0b10110100);
282}
283fn testShrExact(x: u8) {
284 const shifted = @shrExact(x, 2);
285 assert(shifted == 0b00101101);
286}
test/compile_errors.zig+14
...@@ -1959,4 +1959,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1959,4 +1959,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1959 \\}1959 \\}
1960 ,1960 ,
1961 ".tmp_source.zig:2:15: error: expected pointer, found 'i32'");1961 ".tmp_source.zig:2:15: error: expected pointer, found 'i32'");
1962
1963 cases.add("@shlExact shifts out 1 bits",
1964 \\comptime {
1965 \\ const x = @shlExact(u8(0b01010101), 2);
1966 \\}
1967 ,
1968 ".tmp_source.zig:2:15: error: operation caused overflow");
1969
1970 cases.add("@shrExact shifts out 1 bits",
1971 \\comptime {
1972 \\ const x = @shrExact(u8(0b10101010), 2);
1973 \\}
1974 ,
1975 ".tmp_source.zig:2:15: error: exact shift shifted out 1 bits");
1962}1976}
test/debug_safety.zig+32-2
...@@ -112,7 +112,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -112,7 +112,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
112 \\ if (x == 0) return error.Whatever;112 \\ if (x == 0) return error.Whatever;
113 \\}113 \\}
114 \\fn shl(a: i16, b: i16) -> i16 {114 \\fn shl(a: i16, b: i16) -> i16 {
115 \\ a << b115 \\ @shlExact(a, b)
116 \\}116 \\}
117 );117 );
118118
...@@ -127,7 +127,37 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -127,7 +127,37 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
127 \\ if (x == 0) return error.Whatever;127 \\ if (x == 0) return error.Whatever;
128 \\}128 \\}
129 \\fn shl(a: u16, b: u16) -> u16 {129 \\fn shl(a: u16, b: u16) -> u16 {
130 \\ a << b130 \\ @shlExact(a, b)
131 \\}
132 );
133
134 cases.addDebugSafety("signed shift right overflow",
135 \\pub fn panic(message: []const u8) -> noreturn {
136 \\ @breakpoint();
137 \\ while (true) {}
138 \\}
139 \\error Whatever;
140 \\pub fn main() -> %void {
141 \\ const x = shr(-16385, 1);
142 \\ if (x == 0) return error.Whatever;
143 \\}
144 \\fn shr(a: i16, b: i16) -> i16 {
145 \\ @shrExact(a, b)
146 \\}
147 );
148
149 cases.addDebugSafety("unsigned shift right overflow",
150 \\pub fn panic(message: []const u8) -> noreturn {
151 \\ @breakpoint();
152 \\ while (true) {}
153 \\}
154 \\error Whatever;
155 \\pub fn main() -> %void {
156 \\ const x = shr(0b0010111111111111, 3);
157 \\ if (x == 0) return error.Whatever;
158 \\}
159 \\fn shr(a: u16, b: u16) -> u16 {
160 \\ @shrExact(a, b)
131 \\}161 \\}
132 );162 );
133163