| author | |
| committer | |
| log | 35d3444e2742faa3c2e805cdcbfeceaf0287eefc |
| tree | 408182308c5f962660f200c59b2619be8d194ffc |
| parent | 54675b060ae6139f60e111521b9a2688f66977a0 |
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 #41328 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 | }; |
| 1236 | 1236 | ||
| 1237 | struct BuiltinFnEntry { | 1237 | struct 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 | } |
| 801 | 801 | ||
| 802 | void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { | 802 | void 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); |
| 66 | void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2); | 66 | void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2); |
| 67 | 67 | ||
| 68 | void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2); | 68 | void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2); |
| 69 | void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); | 69 | void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); |
| 70 | void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); | 70 | void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); |
| 71 | 71 | ||
| 72 | void bigint_negate(BigInt *dest, const BigInt *op); | 72 | void 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 |
| 1153 | static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry, | 1155 | static 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 shift | 1158 | // for unsigned left shifting, we do the lossy shift, then logically shift |
| 1157 | // right the same number of bits | 1159 | // right the same number of bits |
| 1158 | // if the values don't match, we have an overflow | 1160 | // if the values don't match, we have an overflow |
| 1159 | // for signed left shifting we do the same except arithmetic shift right | 1161 | // 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); |
| 1175 | 1177 | ||
| 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 | |||
| 1185 | static 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); | ||
| 1178 | 1205 | ||
| 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 | } |
| 4560 | 4601 | ||
| 4561 | static const char *bool_to_str(bool b) { | 4602 | static 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 | }; |
| 29 | 30 | ||
| 30 | const char *err_str(int err); | 31 | const 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 |
| 4457 | 4453 | ||
| 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 | } |
| 8592 | 8627 | ||
| 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 |
| 1131 | static BinOpType tok_to_bit_shift_op(Token *token) { | 1131 | static 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 |
| 754 | LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | 754 | LLVMValueRef 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 | |||
| 760 | LLVMValueRef 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 | } |
| 759 | 765 | ||
| 766 | LLVMValueRef 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" |
| 761 | 774 | ||
| 762 | bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag_buf) { | 775 | bool 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); |
| 49 | LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | 49 | LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, |
| 50 | const char *name); | 50 | const char *name); |
| 51 | LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 52 | const char *name); | ||
| 53 | LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 54 | const char *name); | ||
| 51 | 55 | ||
| 52 | ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type, | 56 | ZigLLVMDIType *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; |
| 23 | 23 | ||
| 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; |
| 27 | 27 | ||
| 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; |
| 31 | 31 | ||
| ... | @@ -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; |
| 39 | 39 | ||
| 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; |
| 43 | 43 | ||
| 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; |
| 50 | 50 | ||
| 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 | } |
| 54 | 54 | ||
| ... | @@ -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 | } |
| 84 | 84 | ||
| 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; |
| 89 | 89 | ||
| 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; |
| 93 | 93 | ||
| 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; |
| 97 | 97 | ||
| ... | @@ -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 | } |
| 101 | 101 | ||
| 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 the | 84 | // 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; |
| 89 | 89 |
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 | } |
| 126 | 126 | ||
| 127 | const twopk = @bitCast(f32, u32((0x7F + k) <<% 23)); | 127 | const twopk = @bitCast(f32, u32((0x7F + k) << 23)); |
| 128 | 128 | ||
| 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 | } |
| 255 | 255 | ||
| 256 | const twopk = @bitCast(f64, u64(0x3FF + k) <<% 52); | 256 | const twopk = @bitCast(f64, u64(0x3FF + k) << 52); |
| 257 | 257 | ||
| 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 { |
| 49 | 49 | ||
| 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 { |
| 84 | 84 | ||
| 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) = -inf | 38 | // 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(-#) = nan | 42 | // log(-#) = nan |
| ... | @@ -91,7 +91,7 @@ fn lnd(x_: f64) -> f64 { | ... | @@ -91,7 +91,7 @@ fn lnd(x_: f64) -> f64 { |
| 91 | 91 | ||
| 92 | if (hx < 0x00100000 or hx >> 31 != 0) { | 92 | if (hx < 0x00100000 or hx >> 31 != 0) { |
| 93 | // log(+-0) = -inf | 93 | // 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(-#) = nan | 97 | // 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) = -inf | 40 | // 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(-#) = nan | 44 | // log(-#) = nan |
| ... | @@ -100,7 +100,7 @@ fn log10_64(x_: f64) -> f64 { | ... | @@ -100,7 +100,7 @@ fn log10_64(x_: f64) -> f64 { |
| 100 | 100 | ||
| 101 | if (hx < 0x00100000 or hx >> 31 != 0) { | 101 | if (hx < 0x00100000 or hx >> 31 != 0) { |
| 102 | // log(+-0) = -inf | 102 | // 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(-#) = nan | 106 | // 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); |
| 145 | 145 |
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 subnormal | 53 | // 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) = -inf | 38 | // 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(-#) = nan | 42 | // log(-#) = nan |
| ... | @@ -94,7 +94,7 @@ fn log2_64(x_: f64) -> f64 { | ... | @@ -94,7 +94,7 @@ fn log2_64(x_: f64) -> f64 { |
| 94 | 94 | ||
| 95 | if (hx < 0x00100000 or hx >> 31 != 0) { | 95 | if (hx < 0x00100000 or hx >> 31 != 0) { |
| 96 | // log(+-0) = -inf | 96 | // 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(-#) = nan | 100 | // 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); |
| 139 | 139 |
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 part | 44 | // 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) { // nan | 47 | 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 part | 88 | // 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) { // nan | 91 | 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; |
| 183 | 183 | ||
| 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); |
| 188 | 188 | ||
| 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; |
| 49 | 49 | ||
| 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); |
| 52 | 52 | ||
| 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 | } |
| 58 | 58 | ||
| 59 | // normalize x and y | 59 | // 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 | } |
| 76 | 76 | ||
| 77 | // x mod y | 77 | // 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}) {} |
| 94 | 94 | ||
| 95 | // scale result up | 95 | // 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 | } |
| 170 | 170 | ||
| 171 | test "shift left wrapping" { | ||
| 172 | testShlWrappingEval(@maxValue(u16)); | ||
| 173 | comptime testShlWrappingEval(@maxValue(u16)); | ||
| 174 | } | ||
| 175 | fn testShlWrappingEval(x: u16) { | ||
| 176 | const shifted = x <<% 1; | ||
| 177 | assert(shifted == 65534); | ||
| 178 | } | ||
| 179 | |||
| 180 | test "unsigned 64-bit division" { | 171 | test "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 | |||
| 252 | test "truncating shift left" { | ||
| 253 | testShlTrunc(@maxValue(u16)); | ||
| 254 | comptime testShlTrunc(@maxValue(u16)); | ||
| 255 | } | ||
| 256 | fn testShlTrunc(x: u16) { | ||
| 257 | const shifted = x << 1; | ||
| 258 | assert(shifted == 65534); | ||
| 259 | } | ||
| 260 | |||
| 261 | test "truncating shift right" { | ||
| 262 | testShrTrunc(@maxValue(u16)); | ||
| 263 | comptime testShrTrunc(@maxValue(u16)); | ||
| 264 | } | ||
| 265 | fn testShrTrunc(x: u16) { | ||
| 266 | const shifted = x >> 1; | ||
| 267 | assert(shifted == 32767); | ||
| 268 | } | ||
| 269 | |||
| 270 | test "exact shift left" { | ||
| 271 | testShlExact(0b00110101); | ||
| 272 | comptime testShlExact(0b00110101); | ||
| 273 | } | ||
| 274 | fn testShlExact(x: u8) { | ||
| 275 | const shifted = @shlExact(x, 2); | ||
| 276 | assert(shifted == 0b11010100); | ||
| 277 | } | ||
| 278 | |||
| 279 | test "exact shift right" { | ||
| 280 | testShrExact(0b10110100); | ||
| 281 | comptime testShrExact(0b10110100); | ||
| 282 | } | ||
| 283 | fn 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 << b | 115 | \\ @shlExact(a, b) |
| 116 | \\} | 116 | \\} |
| 117 | ); | 117 | ); |
| 118 | 118 | ||
| ... | @@ -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 << b | 130 | \\ @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 | ); |
| 133 | 163 |