| 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 | 493 | BinOpTypeAssignMinus, |
| 494 | 494 | BinOpTypeAssignMinusWrap, |
| 495 | 495 | BinOpTypeAssignBitShiftLeft, |
| 496 | BinOpTypeAssignBitShiftLeftWrap, | |
| 497 | 496 | BinOpTypeAssignBitShiftRight, |
| 498 | 497 | BinOpTypeAssignBitAnd, |
| 499 | 498 | BinOpTypeAssignBitXor, |
| ... | ... | @@ -512,7 +511,6 @@ enum BinOpType { |
| 512 | 511 | BinOpTypeBinXor, |
| 513 | 512 | BinOpTypeBinAnd, |
| 514 | 513 | BinOpTypeBitShiftLeft, |
| 515 | BinOpTypeBitShiftLeftWrap, | |
| 516 | 514 | BinOpTypeBitShiftRight, |
| 517 | 515 | BinOpTypeAdd, |
| 518 | 516 | BinOpTypeAddWrap, |
| ... | ... | @@ -1232,6 +1230,8 @@ enum BuiltinFnId { |
| 1232 | 1230 | BuiltinFnIdOffsetOf, |
| 1233 | 1231 | BuiltinFnIdInlineCall, |
| 1234 | 1232 | BuiltinFnIdTypeId, |
| 1233 | BuiltinFnIdShlExact, | |
| 1234 | BuiltinFnIdShrExact, | |
| 1235 | 1235 | }; |
| 1236 | 1236 | |
| 1237 | 1237 | struct BuiltinFnEntry { |
| ... | ... | @@ -1248,7 +1248,8 @@ enum PanicMsgId { |
| 1248 | 1248 | PanicMsgIdCastNegativeToUnsigned, |
| 1249 | 1249 | PanicMsgIdCastTruncatedData, |
| 1250 | 1250 | PanicMsgIdIntegerOverflow, |
| 1251 | PanicMsgIdShiftOverflowedBits, | |
| 1251 | PanicMsgIdShlOverflowedBits, | |
| 1252 | PanicMsgIdShrOverflowedBits, | |
| 1252 | 1253 | PanicMsgIdDivisionByZero, |
| 1253 | 1254 | PanicMsgIdRemainderDivisionByZero, |
| 1254 | 1255 | PanicMsgIdExactDivisionRemainder, |
| ... | ... | @@ -1930,9 +1931,10 @@ enum IrBinOp { |
| 1930 | 1931 | IrBinOpBinOr, |
| 1931 | 1932 | IrBinOpBinXor, |
| 1932 | 1933 | IrBinOpBinAnd, |
| 1933 | IrBinOpBitShiftLeft, | |
| 1934 | IrBinOpBitShiftLeftWrap, | |
| 1935 | IrBinOpBitShiftRight, | |
| 1934 | IrBinOpBitShiftLeftLossy, | |
| 1935 | IrBinOpBitShiftLeftExact, | |
| 1936 | IrBinOpBitShiftRightLossy, | |
| 1937 | IrBinOpBitShiftRightExact, | |
| 1936 | 1938 | IrBinOpAdd, |
| 1937 | 1939 | IrBinOpAddWrap, |
| 1938 | 1940 | IrBinOpSub, |
src/ast_render.cpp-2| ... | ... | @@ -26,7 +26,6 @@ static const char *bin_op_str(BinOpType bin_op) { |
| 26 | 26 | case BinOpTypeBinXor: return "^"; |
| 27 | 27 | case BinOpTypeBinAnd: return "&"; |
| 28 | 28 | case BinOpTypeBitShiftLeft: return "<<"; |
| 29 | case BinOpTypeBitShiftLeftWrap: return "<<%"; | |
| 30 | 29 | case BinOpTypeBitShiftRight: return ">>"; |
| 31 | 30 | case BinOpTypeAdd: return "+"; |
| 32 | 31 | case BinOpTypeAddWrap: return "+%"; |
| ... | ... | @@ -46,7 +45,6 @@ static const char *bin_op_str(BinOpType bin_op) { |
| 46 | 45 | case BinOpTypeAssignMinus: return "-="; |
| 47 | 46 | case BinOpTypeAssignMinusWrap: return "-%="; |
| 48 | 47 | case BinOpTypeAssignBitShiftLeft: return "<<="; |
| 49 | case BinOpTypeAssignBitShiftLeftWrap: return "<<%="; | |
| 50 | 48 | case BinOpTypeAssignBitShiftRight: return ">>="; |
| 51 | 49 | case BinOpTypeAssignBitAnd: return "&="; |
| 52 | 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 | 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 | 803 | BigInt unwrapped = {0}; |
| 804 | 804 | bigint_shl(&unwrapped, op1, op2); |
| 805 | 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 | 66 | void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2); |
| 67 | 67 | |
| 68 | 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 | 70 | void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); |
| 71 | 71 | |
| 72 | 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 | 694 | return buf_create_from_str("integer cast truncated bits"); |
| 695 | 695 | case PanicMsgIdIntegerOverflow: |
| 696 | 696 | return buf_create_from_str("integer overflow"); |
| 697 | case PanicMsgIdShiftOverflowedBits: | |
| 697 | case PanicMsgIdShlOverflowedBits: | |
| 698 | 698 | return buf_create_from_str("left shift overflowed bits"); |
| 699 | case PanicMsgIdShrOverflowedBits: | |
| 700 | return buf_create_from_str("right shift overflowed bits"); | |
| 699 | 701 | case PanicMsgIdDivisionByZero: |
| 700 | 702 | return buf_create_from_str("division by zero"); |
| 701 | 703 | case PanicMsgIdRemainderDivisionByZero: |
| ... | ... | @@ -1153,7 +1155,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 1153 | 1155 | static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry, |
| 1154 | 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 | 1159 | // right the same number of bits |
| 1158 | 1160 | // if the values don't match, we have an overflow |
| 1159 | 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 | 1176 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 1175 | 1177 | |
| 1176 | 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 | 1206 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 1180 | 1207 | return result; |
| ... | ... | @@ -1496,12 +1523,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1496 | 1523 | return LLVMBuildXor(g->builder, op1_value, op2_value, ""); |
| 1497 | 1524 | case IrBinOpBinAnd: |
| 1498 | 1525 | return LLVMBuildAnd(g->builder, op1_value, op2_value, ""); |
| 1499 | case IrBinOpBitShiftLeft: | |
| 1500 | case IrBinOpBitShiftLeftWrap: | |
| 1526 | case IrBinOpBitShiftLeftLossy: | |
| 1527 | case IrBinOpBitShiftLeftExact: | |
| 1501 | 1528 | { |
| 1502 | 1529 | assert(type_entry->id == TypeTableEntryIdInt); |
| 1503 | bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap); | |
| 1504 | if (is_wrapping) { | |
| 1530 | bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy); | |
| 1531 | if (is_sloppy) { | |
| 1505 | 1532 | return LLVMBuildShl(g->builder, op1_value, op2_value, ""); |
| 1506 | 1533 | } else if (want_debug_safety) { |
| 1507 | 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 | 1538 | return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, ""); |
| 1512 | 1539 | } |
| 1513 | 1540 | } |
| 1514 | case IrBinOpBitShiftRight: | |
| 1515 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 1516 | if (type_entry->data.integral.is_signed) { | |
| 1517 | return LLVMBuildAShr(g->builder, op1_value, op2_value, ""); | |
| 1518 | } else { | |
| 1519 | return LLVMBuildLShr(g->builder, op1_value, op2_value, ""); | |
| 1541 | case IrBinOpBitShiftRightLossy: | |
| 1542 | case IrBinOpBitShiftRightExact: | |
| 1543 | { | |
| 1544 | assert(type_entry->id == TypeTableEntryIdInt); | |
| 1545 | bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy); | |
| 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 | 1560 | case IrBinOpSub: |
| 1522 | 1561 | case IrBinOpSubWrap: |
| ... | ... | @@ -4556,6 +4595,8 @@ static void define_builtin_fns(CodeGen *g) { |
| 4556 | 4595 | create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); |
| 4557 | 4596 | create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); |
| 4558 | 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 | 4602 | static const char *bool_to_str(bool b) { |
src/error.cpp+1| ... | ... | @@ -25,6 +25,7 @@ const char *err_str(int err) { |
| 25 | 25 | case ErrorUnexpected: return "unexpected error"; |
| 26 | 26 | case ErrorExactDivRemainder: return "exact division had a remainder"; |
| 27 | 27 | case ErrorNegativeDenominator: return "negative denominator"; |
| 28 | case ErrorShiftedOutOneBits: return "exact shift shifted out one bits"; | |
| 28 | 29 | } |
| 29 | 30 | return "(invalid error)"; |
| 30 | 31 | } |
src/error.hpp+1| ... | ... | @@ -25,6 +25,7 @@ enum Error { |
| 25 | 25 | ErrorUnexpected, |
| 26 | 26 | ErrorExactDivRemainder, |
| 27 | 27 | ErrorNegativeDenominator, |
| 28 | ErrorShiftedOutOneBits, | |
| 28 | 29 | }; |
| 29 | 30 | |
| 30 | 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 | 3625 | case BinOpTypeAssignMinusWrap: |
| 3626 | 3626 | return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap); |
| 3627 | 3627 | case BinOpTypeAssignBitShiftLeft: |
| 3628 | return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeft); | |
| 3629 | case BinOpTypeAssignBitShiftLeftWrap: | |
| 3630 | return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftWrap); | |
| 3628 | return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy); | |
| 3631 | 3629 | case BinOpTypeAssignBitShiftRight: |
| 3632 | return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRight); | |
| 3630 | return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy); | |
| 3633 | 3631 | case BinOpTypeAssignBitAnd: |
| 3634 | 3632 | return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd); |
| 3635 | 3633 | case BinOpTypeAssignBitXor: |
| ... | ... | @@ -3663,11 +3661,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) |
| 3663 | 3661 | case BinOpTypeBinAnd: |
| 3664 | 3662 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd); |
| 3665 | 3663 | case BinOpTypeBitShiftLeft: |
| 3666 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeft); | |
| 3667 | case BinOpTypeBitShiftLeftWrap: | |
| 3668 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftWrap); | |
| 3664 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy); | |
| 3669 | 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 | 3667 | case BinOpTypeAdd: |
| 3672 | 3668 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd); |
| 3673 | 3669 | case BinOpTypeAddWrap: |
| ... | ... | @@ -4457,6 +4453,34 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4457 | 4453 | |
| 4458 | 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 | 4485 | zig_unreachable(); |
| 4462 | 4486 | } |
| ... | ... | @@ -8362,16 +8386,27 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val, |
| 8362 | 8386 | assert(is_int); |
| 8363 | 8387 | bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); |
| 8364 | 8388 | break; |
| 8365 | case IrBinOpBitShiftLeft: | |
| 8389 | case IrBinOpBitShiftLeftExact: | |
| 8366 | 8390 | assert(is_int); |
| 8367 | 8391 | bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); |
| 8368 | 8392 | break; |
| 8369 | case IrBinOpBitShiftLeftWrap: | |
| 8393 | case IrBinOpBitShiftLeftLossy: | |
| 8370 | 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 | 8396 | type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); |
| 8373 | 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 | 8410 | assert(is_int); |
| 8376 | 8411 | bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); |
| 8377 | 8412 | break; |
| ... | ... | @@ -8591,8 +8626,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 8591 | 8626 | } |
| 8592 | 8627 | |
| 8593 | 8628 | if (resolved_type->id == TypeTableEntryIdNumLitInt) { |
| 8594 | if (op_id == IrBinOpBitShiftLeftWrap) { | |
| 8595 | op_id = IrBinOpBitShiftLeft; | |
| 8629 | if (op_id == IrBinOpBitShiftLeftLossy) { | |
| 8630 | op_id = IrBinOpBitShiftLeftExact; | |
| 8596 | 8631 | } else if (op_id == IrBinOpAddWrap) { |
| 8597 | 8632 | op_id = IrBinOpAdd; |
| 8598 | 8633 | } else if (op_id == IrBinOpSubWrap) { |
| ... | ... | @@ -8631,6 +8666,9 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 8631 | 8666 | } else if (err == ErrorNegativeDenominator) { |
| 8632 | 8667 | ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("negative denominator")); |
| 8633 | 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 | 8672 | } else { |
| 8635 | 8673 | zig_unreachable(); |
| 8636 | 8674 | } |
| ... | ... | @@ -8857,9 +8895,10 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi |
| 8857 | 8895 | case IrBinOpBinOr: |
| 8858 | 8896 | case IrBinOpBinXor: |
| 8859 | 8897 | case IrBinOpBinAnd: |
| 8860 | case IrBinOpBitShiftLeft: | |
| 8861 | case IrBinOpBitShiftLeftWrap: | |
| 8862 | case IrBinOpBitShiftRight: | |
| 8898 | case IrBinOpBitShiftLeftLossy: | |
| 8899 | case IrBinOpBitShiftLeftExact: | |
| 8900 | case IrBinOpBitShiftRightLossy: | |
| 8901 | case IrBinOpBitShiftRightExact: | |
| 8863 | 8902 | case IrBinOpAdd: |
| 8864 | 8903 | case IrBinOpAddWrap: |
| 8865 | 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 | 92 | return "^"; |
| 93 | 93 | case IrBinOpBinAnd: |
| 94 | 94 | return "&"; |
| 95 | case IrBinOpBitShiftLeft: | |
| 95 | case IrBinOpBitShiftLeftLossy: | |
| 96 | 96 | return "<<"; |
| 97 | case IrBinOpBitShiftLeftWrap: | |
| 98 | return "<<%"; | |
| 99 | case IrBinOpBitShiftRight: | |
| 97 | case IrBinOpBitShiftLeftExact: | |
| 98 | return "@shlExact"; | |
| 99 | case IrBinOpBitShiftRightLossy: | |
| 100 | 100 | return ">>"; |
| 101 | case IrBinOpBitShiftRightExact: | |
| 102 | return "@shrExact"; | |
| 101 | 103 | case IrBinOpAdd: |
| 102 | 104 | return "+"; |
| 103 | 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 | 1131 | static BinOpType tok_to_bit_shift_op(Token *token) { |
| 1132 | 1132 | switch (token->id) { |
| 1133 | 1133 | case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft; |
| 1134 | case TokenIdBitShiftLeftPercent: return BinOpTypeBitShiftLeftWrap; | |
| 1135 | 1134 | case TokenIdBitShiftRight: return BinOpTypeBitShiftRight; |
| 1136 | 1135 | default: return BinOpTypeInvalid; |
| 1137 | 1136 | } |
| ... | ... | @@ -1909,7 +1908,6 @@ static BinOpType tok_to_ass_op(Token *token) { |
| 1909 | 1908 | case TokenIdMinusEq: return BinOpTypeAssignMinus; |
| 1910 | 1909 | case TokenIdMinusPercentEq: return BinOpTypeAssignMinusWrap; |
| 1911 | 1910 | case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft; |
| 1912 | case TokenIdBitShiftLeftPercentEq: return BinOpTypeAssignBitShiftLeftWrap; | |
| 1913 | 1911 | case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight; |
| 1914 | 1912 | case TokenIdBitAndEq: return BinOpTypeAssignBitAnd; |
| 1915 | 1913 | case TokenIdBitXorEq: return BinOpTypeAssignBitXor; |
src/tokenizer.cpp-22| ... | ... | @@ -201,7 +201,6 @@ enum TokenizeState { |
| 201 | 201 | TokenizeStateSawBang, |
| 202 | 202 | TokenizeStateSawLessThan, |
| 203 | 203 | TokenizeStateSawLessThanLessThan, |
| 204 | TokenizeStateSawShiftLeftPercent, | |
| 205 | 204 | TokenizeStateSawGreaterThan, |
| 206 | 205 | TokenizeStateSawGreaterThanGreaterThan, |
| 207 | 206 | TokenizeStateSawDot, |
| ... | ... | @@ -673,24 +672,6 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 673 | 672 | end_token(&t); |
| 674 | 673 | t.state = TokenizeStateStart; |
| 675 | 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 | 675 | default: |
| 695 | 676 | t.pos -= 1; |
| 696 | 677 | end_token(&t); |
| ... | ... | @@ -1410,7 +1391,6 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1410 | 1391 | case TokenizeStateSawStarPercent: |
| 1411 | 1392 | case TokenizeStateSawPlusPercent: |
| 1412 | 1393 | case TokenizeStateSawMinusPercent: |
| 1413 | case TokenizeStateSawShiftLeftPercent: | |
| 1414 | 1394 | case TokenizeStateLineString: |
| 1415 | 1395 | case TokenizeStateLineStringEnd: |
| 1416 | 1396 | end_token(&t); |
| ... | ... | @@ -1451,8 +1431,6 @@ const char * token_name(TokenId id) { |
| 1451 | 1431 | case TokenIdBitOrEq: return "|="; |
| 1452 | 1432 | case TokenIdBitShiftLeft: return "<<"; |
| 1453 | 1433 | case TokenIdBitShiftLeftEq: return "<<="; |
| 1454 | case TokenIdBitShiftLeftPercent: return "<<%"; | |
| 1455 | case TokenIdBitShiftLeftPercentEq: return "<<%="; | |
| 1456 | 1434 | case TokenIdBitShiftRight: return ">>"; |
| 1457 | 1435 | case TokenIdBitShiftRightEq: return ">>="; |
| 1458 | 1436 | case TokenIdBitXorEq: return "^="; |
src/tokenizer.hpp-2| ... | ... | @@ -23,8 +23,6 @@ enum TokenId { |
| 23 | 23 | TokenIdBitOrEq, |
| 24 | 24 | TokenIdBitShiftLeft, |
| 25 | 25 | TokenIdBitShiftLeftEq, |
| 26 | TokenIdBitShiftLeftPercent, | |
| 27 | TokenIdBitShiftLeftPercentEq, | |
| 28 | 26 | TokenIdBitShiftRight, |
| 29 | 27 | TokenIdBitShiftRightEq, |
| 30 | 28 | TokenIdBitXorEq, |
src/zig_llvm.cpp+14-1| ... | ... | @@ -754,9 +754,22 @@ LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMVa |
| 754 | 754 | LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, |
| 755 | 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 | 773 | #include "buffer.hpp" |
| 761 | 774 | |
| 762 | 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 | 48 | const char *name); |
| 49 | 49 | LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, |
| 50 | 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 | 56 | ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type, |
| 53 | 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 | 21 | dest[out_index] = alphabet[(source[i] >> 2) & 0x3f]; |
| 22 | 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 | 25 | ((source[i + 1] & 0xf0) >> 4)]; |
| 26 | 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 | 29 | ((source[i + 2] & 0xc0) >> 6)]; |
| 30 | 30 | out_index += 1; |
| 31 | 31 | |
| ... | ... | @@ -38,17 +38,17 @@ pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8) |
| 38 | 38 | out_index += 1; |
| 39 | 39 | |
| 40 | 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 | 42 | out_index += 1; |
| 43 | 43 | |
| 44 | 44 | dest[out_index] = alphabet[64]; |
| 45 | 45 | out_index += 1; |
| 46 | 46 | } else { |
| 47 | dest[out_index] = alphabet[((source[i] & 0x3) <<% 4) | | |
| 47 | dest[out_index] = alphabet[((source[i] & 0x3) << 4) | | |
| 48 | 48 | ((source[i + 1] & 0xf0) >> 4)]; |
| 49 | 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 | 52 | out_index += 1; |
| 53 | 53 | } |
| 54 | 54 | |
| ... | ... | @@ -83,15 +83,15 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8 |
| 83 | 83 | } |
| 84 | 84 | |
| 85 | 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 | 87 | ascii6[source[src_index + 1]] >> 4; |
| 88 | 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 | 91 | ascii6[source[src_index + 2]] >> 2; |
| 92 | 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 | 95 | ascii6[source[src_index + 3]]; |
| 96 | 96 | dest_index += 1; |
| 97 | 97 | |
| ... | ... | @@ -100,17 +100,17 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8 |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | 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 | 104 | ascii6[source[src_index + 1]] >> 4; |
| 105 | 105 | dest_index += 1; |
| 106 | 106 | } |
| 107 | 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 | 109 | ascii6[source[src_index + 2]] >> 2; |
| 110 | 110 | dest_index += 1; |
| 111 | 111 | } |
| 112 | 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 | 114 | ascii6[source[src_index + 3]]; |
| 115 | 115 | dest_index += 1; |
| 116 | 116 | } |
std/math/exp2.zig+1-1| ... | ... | @@ -83,7 +83,7 @@ fn exp2_32(x: f32) -> f32 { |
| 83 | 83 | const k = i0 / tblsiz; |
| 84 | 84 | // NOTE: musl relies on undefined overflow shift behaviour. Appears that this produces the |
| 85 | 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 | 87 | i0 &= tblsiz - 1; |
| 88 | 88 | uf -= redux; |
| 89 | 89 |
std/math/expm1.zig+2-2| ... | ... | @@ -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 | 129 | if (k < 0 or k > 56) { |
| 130 | 130 | var y = x - e + 1.0; |
| ... | ... | @@ -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 | 258 | if (k < 0 or k > 56) { |
| 259 | 259 | var y = x - e + 1.0; |
std/math/ilogb.zig+2-2| ... | ... | @@ -49,7 +49,7 @@ fn ilogb32(x: f32) -> i32 { |
| 49 | 49 | |
| 50 | 50 | if (e == 0xFF) { |
| 51 | 51 | math.raiseInvalid(); |
| 52 | if (u <<% 9 != 0) { | |
| 52 | if (u << 9 != 0) { | |
| 53 | 53 | return fp_ilogbnan; |
| 54 | 54 | } else { |
| 55 | 55 | return @maxValue(i32); |
| ... | ... | @@ -84,7 +84,7 @@ fn ilogb64(x: f64) -> i32 { |
| 84 | 84 | |
| 85 | 85 | if (e == 0x7FF) { |
| 86 | 86 | math.raiseInvalid(); |
| 87 | if (u <<% 12 != 0) { | |
| 87 | if (u << 12 != 0) { | |
| 88 | 88 | return fp_ilogbnan; |
| 89 | 89 | } else { |
| 90 | 90 | return @maxValue(i32); |
std/math/ln.zig+2-2| ... | ... | @@ -36,7 +36,7 @@ fn lnf(x_: f32) -> f32 { |
| 36 | 36 | // x < 2^(-126) |
| 37 | 37 | if (ix < 0x00800000 or ix >> 31 != 0) { |
| 38 | 38 | // log(+-0) = -inf |
| 39 | if (ix <<% 1 == 0) { | |
| 39 | if (ix << 1 == 0) { | |
| 40 | 40 | return -math.inf(f32); |
| 41 | 41 | } |
| 42 | 42 | // log(-#) = nan |
| ... | ... | @@ -91,7 +91,7 @@ fn lnd(x_: f64) -> f64 { |
| 91 | 91 | |
| 92 | 92 | if (hx < 0x00100000 or hx >> 31 != 0) { |
| 93 | 93 | // log(+-0) = -inf |
| 94 | if (ix <<% 1 == 0) { | |
| 94 | if (ix << 1 == 0) { | |
| 95 | 95 | return -math.inf(f64); |
| 96 | 96 | } |
| 97 | 97 | // log(-#) = nan |
std/math/log10.zig+3-3| ... | ... | @@ -38,7 +38,7 @@ fn log10_32(x_: f32) -> f32 { |
| 38 | 38 | // x < 2^(-126) |
| 39 | 39 | if (ix < 0x00800000 or ix >> 31 != 0) { |
| 40 | 40 | // log(+-0) = -inf |
| 41 | if (ix <<% 1 == 0) { | |
| 41 | if (ix << 1 == 0) { | |
| 42 | 42 | return -math.inf(f32); |
| 43 | 43 | } |
| 44 | 44 | // log(-#) = nan |
| ... | ... | @@ -100,7 +100,7 @@ fn log10_64(x_: f64) -> f64 { |
| 100 | 100 | |
| 101 | 101 | if (hx < 0x00100000 or hx >> 31 != 0) { |
| 102 | 102 | // log(+-0) = -inf |
| 103 | if (ix <<% 1 == 0) { | |
| 103 | if (ix << 1 == 0) { | |
| 104 | 104 | return -math.inf(f32); |
| 105 | 105 | } |
| 106 | 106 | // log(-#) = nan |
| ... | ... | @@ -139,7 +139,7 @@ fn log10_64(x_: f64) -> f64 { |
| 139 | 139 | // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f) |
| 140 | 140 | var hi = f - hfsq; |
| 141 | 141 | var hii = @bitCast(u64, hi); |
| 142 | hii &= u64(@maxValue(u64)) <<% 32; | |
| 142 | hii &= u64(@maxValue(u64)) << 32; | |
| 143 | 143 | hi = @bitCast(f64, hii); |
| 144 | 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 | 49 | } |
| 50 | 50 | } |
| 51 | 51 | // |x| < 2^(-24) |
| 52 | if ((ix <<% 1) < (0x33800000 << 1)) { | |
| 52 | if ((ix << 1) < (0x33800000 << 1)) { | |
| 53 | 53 | // underflow if subnormal |
| 54 | 54 | if (ix & 0x7F800000 == 0) { |
| 55 | 55 | math.forceEval(x * x); |
| ... | ... | @@ -128,7 +128,7 @@ fn log1p_64(x: f64) -> f64 { |
| 128 | 128 | } |
| 129 | 129 | } |
| 130 | 130 | // |x| < 2^(-53) |
| 131 | if ((hx <<% 1) < (0x3CA00000 << 1)) { | |
| 131 | if ((hx << 1) < (0x3CA00000 << 1)) { | |
| 132 | 132 | if ((hx & 0x7FF00000) == 0) { |
| 133 | 133 | math.raiseUnderflow(); |
| 134 | 134 | } |
std/math/log2.zig+3-3| ... | ... | @@ -36,7 +36,7 @@ fn log2_32(x_: f32) -> f32 { |
| 36 | 36 | // x < 2^(-126) |
| 37 | 37 | if (ix < 0x00800000 or ix >> 31 != 0) { |
| 38 | 38 | // log(+-0) = -inf |
| 39 | if (ix <<% 1 == 0) { | |
| 39 | if (ix << 1 == 0) { | |
| 40 | 40 | return -math.inf(f32); |
| 41 | 41 | } |
| 42 | 42 | // log(-#) = nan |
| ... | ... | @@ -94,7 +94,7 @@ fn log2_64(x_: f64) -> f64 { |
| 94 | 94 | |
| 95 | 95 | if (hx < 0x00100000 or hx >> 31 != 0) { |
| 96 | 96 | // log(+-0) = -inf |
| 97 | if (ix <<% 1 == 0) { | |
| 97 | if (ix << 1 == 0) { | |
| 98 | 98 | return -math.inf(f64); |
| 99 | 99 | } |
| 100 | 100 | // log(-#) = nan |
| ... | ... | @@ -133,7 +133,7 @@ fn log2_64(x_: f64) -> f64 { |
| 133 | 133 | // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f) |
| 134 | 134 | var hi = f - hfsq; |
| 135 | 135 | var hii = @bitCast(u64, hi); |
| 136 | hii &= u64(@maxValue(u64)) <<% 32; | |
| 136 | hii &= u64(@maxValue(u64)) << 32; | |
| 137 | 137 | hi = @bitCast(f64, hii); |
| 138 | 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 | 44 | // no fractional part |
| 45 | 45 | if (e >= 23) { |
| 46 | 46 | result.ipart = x; |
| 47 | if (e == 0x80 and u <<% 9 != 0) { // nan | |
| 47 | if (e == 0x80 and u << 9 != 0) { // nan | |
| 48 | 48 | result.fpart = x; |
| 49 | 49 | } else { |
| 50 | 50 | result.fpart = @bitCast(f32, us); |
| ... | ... | @@ -88,7 +88,7 @@ fn modf64(x: f64) -> modf64_result { |
| 88 | 88 | // no fractional part |
| 89 | 89 | if (e >= 52) { |
| 90 | 90 | result.ipart = x; |
| 91 | if (e == 0x400 and u <<% 12 != 0) { // nan | |
| 91 | if (e == 0x400 and u << 12 != 0) { // nan | |
| 92 | 92 | result.fpart = x; |
| 93 | 93 | } else { |
| 94 | 94 | result.fpart = @bitCast(f64, us); |
std/rand.zig+2-2| ... | ... | @@ -182,8 +182,8 @@ fn MersenneTwister( |
| 182 | 182 | mt.index += 1; |
| 183 | 183 | |
| 184 | 184 | x ^= ((x >> u) & d); |
| 185 | x ^= ((x <<% s) & b); | |
| 186 | x ^= ((x <<% t) & c); | |
| 185 | x ^= ((x << s) & b); | |
| 186 | x ^= ((x << t) & c); | |
| 187 | 187 | x ^= (x >> l); |
| 188 | 188 | |
| 189 | 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 | 47 | const sx = if (T == f32) u32(ux & 0x80000000) else i32(ux >> bits_minus_1); |
| 48 | 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 | 51 | return (x * y) / (x * y); |
| 52 | 52 | |
| 53 | if (ux <<% 1 <= uy <<% 1) { | |
| 54 | if (ux <<% 1 == uy <<% 1) | |
| 53 | if (ux << 1 <= uy << 1) { | |
| 54 | if (ux << 1 == uy << 1) | |
| 55 | 55 | return 0 * x; |
| 56 | 56 | return x; |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 59 | // normalize x and y |
| 60 | 60 | if (ex == 0) { |
| 61 | i = ux <<% exp_bits; | |
| 62 | while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<%= 1}) {} | |
| 63 | ux <<%= @bitCast(u32, -ex + 1); | |
| 61 | i = ux << exp_bits; | |
| 62 | while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<= 1}) {} | |
| 63 | ux <<= @bitCast(u32, -ex + 1); | |
| 64 | 64 | } else { |
| 65 | 65 | ux &= @maxValue(uint) >> exp_bits; |
| 66 | ux |= 1 <<% digits; | |
| 66 | ux |= 1 << digits; | |
| 67 | 67 | } |
| 68 | 68 | if (ey == 0) { |
| 69 | i = uy <<% exp_bits; | |
| 70 | while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<%= 1}) {} | |
| 69 | i = uy << exp_bits; | |
| 70 | while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<= 1}) {} | |
| 71 | 71 | uy <<= @bitCast(u32, -ey + 1); |
| 72 | 72 | } else { |
| 73 | 73 | uy &= @maxValue(uint) >> exp_bits; |
| 74 | uy |= 1 <<% digits; | |
| 74 | uy |= 1 << digits; | |
| 75 | 75 | } |
| 76 | 76 | |
| 77 | 77 | // x mod y |
| ... | ... | @@ -82,7 +82,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { |
| 82 | 82 | return 0 * x; |
| 83 | 83 | ux = i; |
| 84 | 84 | } |
| 85 | ux <<%= 1; | |
| 85 | ux <<= 1; | |
| 86 | 86 | } |
| 87 | 87 | i = ux -% uy; |
| 88 | 88 | if (i >> bits_minus_1 == 0) { |
| ... | ... | @@ -90,19 +90,19 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { |
| 90 | 90 | return 0 * x; |
| 91 | 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 | 95 | // scale result up |
| 96 | 96 | if (ex > 0) { |
| 97 | ux -%= 1 <<% digits; | |
| 98 | ux |= @bitCast(u32, ex) <<% digits; | |
| 97 | ux -%= 1 << digits; | |
| 98 | ux |= @bitCast(u32, ex) << digits; | |
| 99 | 99 | } else { |
| 100 | 100 | ux >>= @bitCast(u32, -ex + 1); |
| 101 | 101 | } |
| 102 | 102 | if (T == f32) { |
| 103 | 103 | ux |= sx; |
| 104 | 104 | } else { |
| 105 | ux |= uint(sx) <<% bits_minus_1; | |
| 105 | ux |= uint(sx) << bits_minus_1; | |
| 106 | 106 | } |
| 107 | 107 | return *@ptrCast(&const T, &ux); |
| 108 | 108 | } |
| ... | ... | @@ -111,7 +111,7 @@ fn isNan(comptime T: type, bits: T) -> bool { |
| 111 | 111 | if (T == u32) { |
| 112 | 112 | return (bits & 0x7fffffff) > 0x7f800000; |
| 113 | 113 | } else if (T == u64) { |
| 114 | return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) <<% 52); | |
| 114 | return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52); | |
| 115 | 115 | } else { |
| 116 | 116 | unreachable; |
| 117 | 117 | } |
test/cases/math.zig+36-9| ... | ... | @@ -168,15 +168,6 @@ fn testNegationWrappingEval(x: i16) { |
| 168 | 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 | 171 | test "unsigned 64-bit division" { |
| 181 | 172 | test_u64_div(); |
| 182 | 173 | comptime test_u64_div(); |
| ... | ... | @@ -257,3 +248,39 @@ test "hex float literal within range" { |
| 257 | 248 | const b = 0x0.1p1027; |
| 258 | 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 | 1959 | \\} |
| 1960 | 1960 | , |
| 1961 | 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 | 112 | \\ if (x == 0) return error.Whatever; |
| 113 | 113 | \\} |
| 114 | 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 | 127 | \\ if (x == 0) return error.Whatever; |
| 128 | 128 | \\} |
| 129 | 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 |