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

more intuitive left shift and right shift operators

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

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

src/all_types.hpp+8-6
......@@ -493,7 +493,6 @@ enum BinOpType {
493493 BinOpTypeAssignMinus,
494494 BinOpTypeAssignMinusWrap,
495495 BinOpTypeAssignBitShiftLeft,
496 BinOpTypeAssignBitShiftLeftWrap,
497496 BinOpTypeAssignBitShiftRight,
498497 BinOpTypeAssignBitAnd,
499498 BinOpTypeAssignBitXor,
......@@ -512,7 +511,6 @@ enum BinOpType {
512511 BinOpTypeBinXor,
513512 BinOpTypeBinAnd,
514513 BinOpTypeBitShiftLeft,
515 BinOpTypeBitShiftLeftWrap,
516514 BinOpTypeBitShiftRight,
517515 BinOpTypeAdd,
518516 BinOpTypeAddWrap,
......@@ -1232,6 +1230,8 @@ enum BuiltinFnId {
12321230 BuiltinFnIdOffsetOf,
12331231 BuiltinFnIdInlineCall,
12341232 BuiltinFnIdTypeId,
1233 BuiltinFnIdShlExact,
1234 BuiltinFnIdShrExact,
12351235};
12361236
12371237struct BuiltinFnEntry {
......@@ -1248,7 +1248,8 @@ enum PanicMsgId {
12481248 PanicMsgIdCastNegativeToUnsigned,
12491249 PanicMsgIdCastTruncatedData,
12501250 PanicMsgIdIntegerOverflow,
1251 PanicMsgIdShiftOverflowedBits,
1251 PanicMsgIdShlOverflowedBits,
1252 PanicMsgIdShrOverflowedBits,
12521253 PanicMsgIdDivisionByZero,
12531254 PanicMsgIdRemainderDivisionByZero,
12541255 PanicMsgIdExactDivisionRemainder,
......@@ -1930,9 +1931,10 @@ enum IrBinOp {
19301931 IrBinOpBinOr,
19311932 IrBinOpBinXor,
19321933 IrBinOpBinAnd,
1933 IrBinOpBitShiftLeft,
1934 IrBinOpBitShiftLeftWrap,
1935 IrBinOpBitShiftRight,
1934 IrBinOpBitShiftLeftLossy,
1935 IrBinOpBitShiftLeftExact,
1936 IrBinOpBitShiftRightLossy,
1937 IrBinOpBitShiftRightExact,
19361938 IrBinOpAdd,
19371939 IrBinOpAddWrap,
19381940 IrBinOpSub,
src/ast_render.cpp-2
......@@ -26,7 +26,6 @@ static const char *bin_op_str(BinOpType bin_op) {
2626 case BinOpTypeBinXor: return "^";
2727 case BinOpTypeBinAnd: return "&";
2828 case BinOpTypeBitShiftLeft: return "<<";
29 case BinOpTypeBitShiftLeftWrap: return "<<%";
3029 case BinOpTypeBitShiftRight: return ">>";
3130 case BinOpTypeAdd: return "+";
3231 case BinOpTypeAddWrap: return "+%";
......@@ -46,7 +45,6 @@ static const char *bin_op_str(BinOpType bin_op) {
4645 case BinOpTypeAssignMinus: return "-=";
4746 case BinOpTypeAssignMinusWrap: return "-%=";
4847 case BinOpTypeAssignBitShiftLeft: return "<<=";
49 case BinOpTypeAssignBitShiftLeftWrap: return "<<%=";
5048 case BinOpTypeAssignBitShiftRight: return ">>=";
5149 case BinOpTypeAssignBitAnd: return "&=";
5250 case BinOpTypeAssignBitXor: return "^=";
src/bigint.cpp+1-1
......@@ -799,7 +799,7 @@ void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2) {
799799 bigint_normalize(dest);
800800}
801801
802void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) {
802void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) {
803803 BigInt unwrapped = {0};
804804 bigint_shl(&unwrapped, op1, op2);
805805 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);
6666void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2);
6767
6868void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2);
69void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
69void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
7070void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
7171
7272void bigint_negate(BigInt *dest, const BigInt *op);
src/codegen.cpp+54-13
......@@ -694,8 +694,10 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
694694 return buf_create_from_str("integer cast truncated bits");
695695 case PanicMsgIdIntegerOverflow:
696696 return buf_create_from_str("integer overflow");
697 case PanicMsgIdShiftOverflowedBits:
697 case PanicMsgIdShlOverflowedBits:
698698 return buf_create_from_str("left shift overflowed bits");
699 case PanicMsgIdShrOverflowedBits:
700 return buf_create_from_str("right shift overflowed bits");
699701 case PanicMsgIdDivisionByZero:
700702 return buf_create_from_str("division by zero");
701703 case PanicMsgIdRemainderDivisionByZero:
......@@ -1153,7 +1155,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
11531155static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
11541156 LLVMValueRef val1, LLVMValueRef val2)
11551157{
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
11571159 // right the same number of bits
11581160 // if the values don't match, we have an overflow
11591161 // 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,
11741176 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
11751177
11761178 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1177 gen_debug_safety_crash(g, PanicMsgIdShiftOverflowedBits);
1179 gen_debug_safety_crash(g, PanicMsgIdShlOverflowedBits);
1180
1181 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1182 return result;
1183}
1184
1185static LLVMValueRef gen_overflow_shr_op(CodeGen *g, TypeTableEntry *type_entry,
1186 LLVMValueRef val1, LLVMValueRef val2)
1187{
1188 assert(type_entry->id == TypeTableEntryIdInt);
1189
1190 LLVMValueRef result;
1191 if (type_entry->data.integral.is_signed) {
1192 result = LLVMBuildAShr(g->builder, val1, val2, "");
1193 } else {
1194 result = LLVMBuildLShr(g->builder, val1, val2, "");
1195 }
1196 LLVMValueRef orig_val = LLVMBuildShl(g->builder, result, val2, "");
1197 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
1198
1199 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
1200 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
1201 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
1202
1203 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1204 gen_debug_safety_crash(g, PanicMsgIdShrOverflowedBits);
11781205
11791206 LLVMPositionBuilderAtEnd(g->builder, ok_block);
11801207 return result;
......@@ -1496,12 +1523,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
14961523 return LLVMBuildXor(g->builder, op1_value, op2_value, "");
14971524 case IrBinOpBinAnd:
14981525 return LLVMBuildAnd(g->builder, op1_value, op2_value, "");
1499 case IrBinOpBitShiftLeft:
1500 case IrBinOpBitShiftLeftWrap:
1526 case IrBinOpBitShiftLeftLossy:
1527 case IrBinOpBitShiftLeftExact:
15011528 {
15021529 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) {
15051532 return LLVMBuildShl(g->builder, op1_value, op2_value, "");
15061533 } else if (want_debug_safety) {
15071534 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,
15111538 return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, "");
15121539 }
15131540 }
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 }
15201559 }
15211560 case IrBinOpSub:
15221561 case IrBinOpSubWrap:
......@@ -4556,6 +4595,8 @@ static void define_builtin_fns(CodeGen *g) {
45564595 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
45574596 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
45584597 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
4598 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
4599 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
45594600}
45604601
45614602static const char *bool_to_str(bool b) {
src/error.cpp+1
......@@ -25,6 +25,7 @@ const char *err_str(int err) {
2525 case ErrorUnexpected: return "unexpected error";
2626 case ErrorExactDivRemainder: return "exact division had a remainder";
2727 case ErrorNegativeDenominator: return "negative denominator";
28 case ErrorShiftedOutOneBits: return "exact shift shifted out one bits";
2829 }
2930 return "(invalid error)";
3031}
src/error.hpp+1
......@@ -25,6 +25,7 @@ enum Error {
2525 ErrorUnexpected,
2626 ErrorExactDivRemainder,
2727 ErrorNegativeDenominator,
28 ErrorShiftedOutOneBits,
2829};
2930
3031const 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)
36253625 case BinOpTypeAssignMinusWrap:
36263626 return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap);
36273627 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);
36313629 case BinOpTypeAssignBitShiftRight:
3632 return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRight);
3630 return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy);
36333631 case BinOpTypeAssignBitAnd:
36343632 return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd);
36353633 case BinOpTypeAssignBitXor:
......@@ -3663,11 +3661,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
36633661 case BinOpTypeBinAnd:
36643662 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd);
36653663 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);
36693665 case BinOpTypeBitShiftRight:
3670 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRight);
3666 return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy);
36713667 case BinOpTypeAdd:
36723668 return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd);
36733669 case BinOpTypeAddWrap:
......@@ -4457,6 +4453,34 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
44574453
44584454 return ir_build_type_id(irb, scope, node, arg0_value);
44594455 }
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 }
44604484 }
44614485 zig_unreachable();
44624486}
......@@ -8362,16 +8386,27 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,
83628386 assert(is_int);
83638387 bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
83648388 break;
8365 case IrBinOpBitShiftLeft:
8389 case IrBinOpBitShiftLeftExact:
83668390 assert(is_int);
83678391 bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
83688392 break;
8369 case IrBinOpBitShiftLeftWrap:
8393 case IrBinOpBitShiftLeftLossy:
83708394 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,
83728396 type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);
83738397 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:
83758410 assert(is_int);
83768411 bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
83778412 break;
......@@ -8591,8 +8626,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
85918626 }
85928627
85938628 if (resolved_type->id == TypeTableEntryIdNumLitInt) {
8594 if (op_id == IrBinOpBitShiftLeftWrap) {
8595 op_id = IrBinOpBitShiftLeft;
8629 if (op_id == IrBinOpBitShiftLeftLossy) {
8630 op_id = IrBinOpBitShiftLeftExact;
85968631 } else if (op_id == IrBinOpAddWrap) {
85978632 op_id = IrBinOpAdd;
85988633 } else if (op_id == IrBinOpSubWrap) {
......@@ -8631,6 +8666,9 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
86318666 } else if (err == ErrorNegativeDenominator) {
86328667 ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("negative denominator"));
86338668 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;
86348672 } else {
86358673 zig_unreachable();
86368674 }
......@@ -8857,9 +8895,10 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
88578895 case IrBinOpBinOr:
88588896 case IrBinOpBinXor:
88598897 case IrBinOpBinAnd:
8860 case IrBinOpBitShiftLeft:
8861 case IrBinOpBitShiftLeftWrap:
8862 case IrBinOpBitShiftRight:
8898 case IrBinOpBitShiftLeftLossy:
8899 case IrBinOpBitShiftLeftExact:
8900 case IrBinOpBitShiftRightLossy:
8901 case IrBinOpBitShiftRightExact:
88638902 case IrBinOpAdd:
88648903 case IrBinOpAddWrap:
88658904 case IrBinOpSub:
src/ir_print.cpp+6-4
......@@ -92,12 +92,14 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
9292 return "^";
9393 case IrBinOpBinAnd:
9494 return "&";
95 case IrBinOpBitShiftLeft:
95 case IrBinOpBitShiftLeftLossy:
9696 return "<<";
97 case IrBinOpBitShiftLeftWrap:
98 return "<<%";
99 case IrBinOpBitShiftRight:
97 case IrBinOpBitShiftLeftExact:
98 return "@shlExact";
99 case IrBinOpBitShiftRightLossy:
100100 return ">>";
101 case IrBinOpBitShiftRightExact:
102 return "@shrExact";
101103 case IrBinOpAdd:
102104 return "+";
103105 case IrBinOpAddWrap:
src/parser.cpp-2
......@@ -1131,7 +1131,6 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, size_t *token_index, bool m
11311131static BinOpType tok_to_bit_shift_op(Token *token) {
11321132 switch (token->id) {
11331133 case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft;
1134 case TokenIdBitShiftLeftPercent: return BinOpTypeBitShiftLeftWrap;
11351134 case TokenIdBitShiftRight: return BinOpTypeBitShiftRight;
11361135 default: return BinOpTypeInvalid;
11371136 }
......@@ -1909,7 +1908,6 @@ static BinOpType tok_to_ass_op(Token *token) {
19091908 case TokenIdMinusEq: return BinOpTypeAssignMinus;
19101909 case TokenIdMinusPercentEq: return BinOpTypeAssignMinusWrap;
19111910 case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft;
1912 case TokenIdBitShiftLeftPercentEq: return BinOpTypeAssignBitShiftLeftWrap;
19131911 case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight;
19141912 case TokenIdBitAndEq: return BinOpTypeAssignBitAnd;
19151913 case TokenIdBitXorEq: return BinOpTypeAssignBitXor;
src/tokenizer.cpp-22
......@@ -201,7 +201,6 @@ enum TokenizeState {
201201 TokenizeStateSawBang,
202202 TokenizeStateSawLessThan,
203203 TokenizeStateSawLessThanLessThan,
204 TokenizeStateSawShiftLeftPercent,
205204 TokenizeStateSawGreaterThan,
206205 TokenizeStateSawGreaterThanGreaterThan,
207206 TokenizeStateSawDot,
......@@ -673,24 +672,6 @@ void tokenize(Buf *buf, Tokenization *out) {
673672 end_token(&t);
674673 t.state = TokenizeStateStart;
675674 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;
694675 default:
695676 t.pos -= 1;
696677 end_token(&t);
......@@ -1410,7 +1391,6 @@ void tokenize(Buf *buf, Tokenization *out) {
14101391 case TokenizeStateSawStarPercent:
14111392 case TokenizeStateSawPlusPercent:
14121393 case TokenizeStateSawMinusPercent:
1413 case TokenizeStateSawShiftLeftPercent:
14141394 case TokenizeStateLineString:
14151395 case TokenizeStateLineStringEnd:
14161396 end_token(&t);
......@@ -1451,8 +1431,6 @@ const char * token_name(TokenId id) {
14511431 case TokenIdBitOrEq: return "|=";
14521432 case TokenIdBitShiftLeft: return "<<";
14531433 case TokenIdBitShiftLeftEq: return "<<=";
1454 case TokenIdBitShiftLeftPercent: return "<<%";
1455 case TokenIdBitShiftLeftPercentEq: return "<<%=";
14561434 case TokenIdBitShiftRight: return ">>";
14571435 case TokenIdBitShiftRightEq: return ">>=";
14581436 case TokenIdBitXorEq: return "^=";
src/tokenizer.hpp-2
......@@ -23,8 +23,6 @@ enum TokenId {
2323 TokenIdBitOrEq,
2424 TokenIdBitShiftLeft,
2525 TokenIdBitShiftLeftEq,
26 TokenIdBitShiftLeftPercent,
27 TokenIdBitShiftLeftPercentEq,
2826 TokenIdBitShiftRight,
2927 TokenIdBitShiftRightEq,
3028 TokenIdBitXorEq,
src/zig_llvm.cpp+14-1
......@@ -754,9 +754,22 @@ LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMVa
754754LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
755755 const char *name)
756756{
757 return wrap(unwrap(builder)->CreateShl(unwrap(LHS), unwrap(RHS), name, false, true));
757 return wrap(unwrap(builder)->CreateShl(unwrap(LHS), unwrap(RHS), name, true, false));
758}
759
760LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
761 const char *name)
762{
763 return wrap(unwrap(builder)->CreateLShr(unwrap(LHS), unwrap(RHS), name, true));
758764}
759765
766LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
767 const char *name)
768{
769 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
770}
771
772
760773#include "buffer.hpp"
761774
762775bool 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
4848 const char *name);
4949LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
5050 const char *name);
51LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
52 const char *name);
53LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
54 const char *name);
5155
5256ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type,
5357 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)
2121 dest[out_index] = alphabet[(source[i] >> 2) & 0x3f];
2222 out_index += 1;
2323
24 dest[out_index] = alphabet[((source[i] & 0x3) <<% 4) |
24 dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
2525 ((source[i + 1] & 0xf0) >> 4)];
2626 out_index += 1;
2727
28 dest[out_index] = alphabet[((source[i + 1] & 0xf) <<% 2) |
28 dest[out_index] = alphabet[((source[i + 1] & 0xf) << 2) |
2929 ((source[i + 2] & 0xc0) >> 6)];
3030 out_index += 1;
3131
......@@ -38,17 +38,17 @@ pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8)
3838 out_index += 1;
3939
4040 if (i + 1 == source.len) {
41 dest[out_index] = alphabet[(source[i] & 0x3) <<% 4];
41 dest[out_index] = alphabet[(source[i] & 0x3) << 4];
4242 out_index += 1;
4343
4444 dest[out_index] = alphabet[64];
4545 out_index += 1;
4646 } else {
47 dest[out_index] = alphabet[((source[i] & 0x3) <<% 4) |
47 dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
4848 ((source[i + 1] & 0xf0) >> 4)];
4949 out_index += 1;
5050
51 dest[out_index] = alphabet[(source[i + 1] & 0xf) <<% 2];
51 dest[out_index] = alphabet[(source[i + 1] & 0xf) << 2];
5252 out_index += 1;
5353 }
5454
......@@ -83,15 +83,15 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8
8383 }
8484
8585 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 |
8787 ascii6[source[src_index + 1]] >> 4;
8888 dest_index += 1;
8989
90 dest[dest_index] = ascii6[source[src_index + 1]] <<% 4 |
90 dest[dest_index] = ascii6[source[src_index + 1]] << 4 |
9191 ascii6[source[src_index + 2]] >> 2;
9292 dest_index += 1;
9393
94 dest[dest_index] = ascii6[source[src_index + 2]] <<% 6 |
94 dest[dest_index] = ascii6[source[src_index + 2]] << 6 |
9595 ascii6[source[src_index + 3]];
9696 dest_index += 1;
9797
......@@ -100,17 +100,17 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8
100100 }
101101
102102 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 |
104104 ascii6[source[src_index + 1]] >> 4;
105105 dest_index += 1;
106106 }
107107 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 |
109109 ascii6[source[src_index + 2]] >> 2;
110110 dest_index += 1;
111111 }
112112 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 |
114114 ascii6[source[src_index + 3]];
115115 dest_index += 1;
116116 }
std/math/exp2.zig+1-1
......@@ -83,7 +83,7 @@ fn exp2_32(x: f32) -> f32 {
8383 const k = i0 / tblsiz;
8484 // NOTE: musl relies on undefined overflow shift behaviour. Appears that this produces the
8585 // 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);
8787 i0 &= tblsiz - 1;
8888 uf -= redux;
8989
std/math/expm1.zig+2-2
......@@ -124,7 +124,7 @@ fn expm1_32(x_: f32) -> f32 {
124124 }
125125 }
126126
127 const twopk = @bitCast(f32, u32((0x7F + k) <<% 23));
127 const twopk = @bitCast(f32, u32((0x7F + k) << 23));
128128
129129 if (k < 0 or k > 56) {
130130 var y = x - e + 1.0;
......@@ -253,7 +253,7 @@ fn expm1_64(x_: f64) -> f64 {
253253 }
254254 }
255255
256 const twopk = @bitCast(f64, u64(0x3FF + k) <<% 52);
256 const twopk = @bitCast(f64, u64(0x3FF + k) << 52);
257257
258258 if (k < 0 or k > 56) {
259259 var y = x - e + 1.0;
std/math/ilogb.zig+2-2
......@@ -49,7 +49,7 @@ fn ilogb32(x: f32) -> i32 {
4949
5050 if (e == 0xFF) {
5151 math.raiseInvalid();
52 if (u <<% 9 != 0) {
52 if (u << 9 != 0) {
5353 return fp_ilogbnan;
5454 } else {
5555 return @maxValue(i32);
......@@ -84,7 +84,7 @@ fn ilogb64(x: f64) -> i32 {
8484
8585 if (e == 0x7FF) {
8686 math.raiseInvalid();
87 if (u <<% 12 != 0) {
87 if (u << 12 != 0) {
8888 return fp_ilogbnan;
8989 } else {
9090 return @maxValue(i32);
std/math/ln.zig+2-2
......@@ -36,7 +36,7 @@ fn lnf(x_: f32) -> f32 {
3636 // x < 2^(-126)
3737 if (ix < 0x00800000 or ix >> 31 != 0) {
3838 // log(+-0) = -inf
39 if (ix <<% 1 == 0) {
39 if (ix << 1 == 0) {
4040 return -math.inf(f32);
4141 }
4242 // log(-#) = nan
......@@ -91,7 +91,7 @@ fn lnd(x_: f64) -> f64 {
9191
9292 if (hx < 0x00100000 or hx >> 31 != 0) {
9393 // log(+-0) = -inf
94 if (ix <<% 1 == 0) {
94 if (ix << 1 == 0) {
9595 return -math.inf(f64);
9696 }
9797 // log(-#) = nan
std/math/log10.zig+3-3
......@@ -38,7 +38,7 @@ fn log10_32(x_: f32) -> f32 {
3838 // x < 2^(-126)
3939 if (ix < 0x00800000 or ix >> 31 != 0) {
4040 // log(+-0) = -inf
41 if (ix <<% 1 == 0) {
41 if (ix << 1 == 0) {
4242 return -math.inf(f32);
4343 }
4444 // log(-#) = nan
......@@ -100,7 +100,7 @@ fn log10_64(x_: f64) -> f64 {
100100
101101 if (hx < 0x00100000 or hx >> 31 != 0) {
102102 // log(+-0) = -inf
103 if (ix <<% 1 == 0) {
103 if (ix << 1 == 0) {
104104 return -math.inf(f32);
105105 }
106106 // log(-#) = nan
......@@ -139,7 +139,7 @@ fn log10_64(x_: f64) -> f64 {
139139 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
140140 var hi = f - hfsq;
141141 var hii = @bitCast(u64, hi);
142 hii &= u64(@maxValue(u64)) <<% 32;
142 hii &= u64(@maxValue(u64)) << 32;
143143 hi = @bitCast(f64, hii);
144144 const lo = f - hi - hfsq + s * (hfsq + R);
145145
std/math/log1p.zig+2-2
......@@ -49,7 +49,7 @@ fn log1p_32(x: f32) -> f32 {
4949 }
5050 }
5151 // |x| < 2^(-24)
52 if ((ix <<% 1) < (0x33800000 << 1)) {
52 if ((ix << 1) < (0x33800000 << 1)) {
5353 // underflow if subnormal
5454 if (ix & 0x7F800000 == 0) {
5555 math.forceEval(x * x);
......@@ -128,7 +128,7 @@ fn log1p_64(x: f64) -> f64 {
128128 }
129129 }
130130 // |x| < 2^(-53)
131 if ((hx <<% 1) < (0x3CA00000 << 1)) {
131 if ((hx << 1) < (0x3CA00000 << 1)) {
132132 if ((hx & 0x7FF00000) == 0) {
133133 math.raiseUnderflow();
134134 }
std/math/log2.zig+3-3
......@@ -36,7 +36,7 @@ fn log2_32(x_: f32) -> f32 {
3636 // x < 2^(-126)
3737 if (ix < 0x00800000 or ix >> 31 != 0) {
3838 // log(+-0) = -inf
39 if (ix <<% 1 == 0) {
39 if (ix << 1 == 0) {
4040 return -math.inf(f32);
4141 }
4242 // log(-#) = nan
......@@ -94,7 +94,7 @@ fn log2_64(x_: f64) -> f64 {
9494
9595 if (hx < 0x00100000 or hx >> 31 != 0) {
9696 // log(+-0) = -inf
97 if (ix <<% 1 == 0) {
97 if (ix << 1 == 0) {
9898 return -math.inf(f64);
9999 }
100100 // log(-#) = nan
......@@ -133,7 +133,7 @@ fn log2_64(x_: f64) -> f64 {
133133 // hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
134134 var hi = f - hfsq;
135135 var hii = @bitCast(u64, hi);
136 hii &= u64(@maxValue(u64)) <<% 32;
136 hii &= u64(@maxValue(u64)) << 32;
137137 hi = @bitCast(f64, hii);
138138 const lo = f - hi - hfsq + s * (hfsq + R);
139139
std/math/modf.zig+2-2
......@@ -44,7 +44,7 @@ fn modf32(x: f32) -> modf32_result {
4444 // no fractional part
4545 if (e >= 23) {
4646 result.ipart = x;
47 if (e == 0x80 and u <<% 9 != 0) { // nan
47 if (e == 0x80 and u << 9 != 0) { // nan
4848 result.fpart = x;
4949 } else {
5050 result.fpart = @bitCast(f32, us);
......@@ -88,7 +88,7 @@ fn modf64(x: f64) -> modf64_result {
8888 // no fractional part
8989 if (e >= 52) {
9090 result.ipart = x;
91 if (e == 0x400 and u <<% 12 != 0) { // nan
91 if (e == 0x400 and u << 12 != 0) { // nan
9292 result.fpart = x;
9393 } else {
9494 result.fpart = @bitCast(f64, us);
std/rand.zig+2-2
......@@ -182,8 +182,8 @@ fn MersenneTwister(
182182 mt.index += 1;
183183
184184 x ^= ((x >> u) & d);
185 x ^= ((x <<% s) & b);
186 x ^= ((x <<% t) & c);
185 x ^= ((x << s) & b);
186 x ^= ((x << t) & c);
187187 x ^= (x >> l);
188188
189189 return x;
std/special/builtin.zig+16-16
......@@ -47,31 +47,31 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
4747 const sx = if (T == f32) u32(ux & 0x80000000) else i32(ux >> bits_minus_1);
4848 var i: uint = undefined;
4949
50 if (uy <<% 1 == 0 or isNan(uint, uy) or ex == mask)
50 if (uy << 1 == 0 or isNan(uint, uy) or ex == mask)
5151 return (x * y) / (x * y);
5252
53 if (ux <<% 1 <= uy <<% 1) {
54 if (ux <<% 1 == uy <<% 1)
53 if (ux << 1 <= uy << 1) {
54 if (ux << 1 == uy << 1)
5555 return 0 * x;
5656 return x;
5757 }
5858
5959 // normalize x and y
6060 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);
6464 } else {
6565 ux &= @maxValue(uint) >> exp_bits;
66 ux |= 1 <<% digits;
66 ux |= 1 << digits;
6767 }
6868 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}) {}
7171 uy <<= @bitCast(u32, -ey + 1);
7272 } else {
7373 uy &= @maxValue(uint) >> exp_bits;
74 uy |= 1 <<% digits;
74 uy |= 1 << digits;
7575 }
7676
7777 // x mod y
......@@ -82,7 +82,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
8282 return 0 * x;
8383 ux = i;
8484 }
85 ux <<%= 1;
85 ux <<= 1;
8686 }
8787 i = ux -% uy;
8888 if (i >> bits_minus_1 == 0) {
......@@ -90,19 +90,19 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
9090 return 0 * x;
9191 ux = i;
9292 }
93 while (ux >> digits == 0) : ({ux <<%= 1; ex -= 1}) {}
93 while (ux >> digits == 0) : ({ux <<= 1; ex -= 1}) {}
9494
9595 // scale result up
9696 if (ex > 0) {
97 ux -%= 1 <<% digits;
98 ux |= @bitCast(u32, ex) <<% digits;
97 ux -%= 1 << digits;
98 ux |= @bitCast(u32, ex) << digits;
9999 } else {
100100 ux >>= @bitCast(u32, -ex + 1);
101101 }
102102 if (T == f32) {
103103 ux |= sx;
104104 } else {
105 ux |= uint(sx) <<% bits_minus_1;
105 ux |= uint(sx) << bits_minus_1;
106106 }
107107 return *@ptrCast(&const T, &ux);
108108}
......@@ -111,7 +111,7 @@ fn isNan(comptime T: type, bits: T) -> bool {
111111 if (T == u32) {
112112 return (bits & 0x7fffffff) > 0x7f800000;
113113 } else if (T == u64) {
114 return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) <<% 52);
114 return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52);
115115 } else {
116116 unreachable;
117117 }
test/cases/math.zig+36-9
......@@ -168,15 +168,6 @@ fn testNegationWrappingEval(x: i16) {
168168 assert(neg == -32768);
169169}
170170
171test "shift left wrapping" {
172 testShlWrappingEval(@maxValue(u16));
173 comptime testShlWrappingEval(@maxValue(u16));
174}
175fn testShlWrappingEval(x: u16) {
176 const shifted = x <<% 1;
177 assert(shifted == 65534);
178}
179
180171test "unsigned 64-bit division" {
181172 test_u64_div();
182173 comptime test_u64_div();
......@@ -257,3 +248,39 @@ test "hex float literal within range" {
257248 const b = 0x0.1p1027;
258249 const c = 0x1.0p-1022;
259250}
251
252test "truncating shift left" {
253 testShlTrunc(@maxValue(u16));
254 comptime testShlTrunc(@maxValue(u16));
255}
256fn testShlTrunc(x: u16) {
257 const shifted = x << 1;
258 assert(shifted == 65534);
259}
260
261test "truncating shift right" {
262 testShrTrunc(@maxValue(u16));
263 comptime testShrTrunc(@maxValue(u16));
264}
265fn testShrTrunc(x: u16) {
266 const shifted = x >> 1;
267 assert(shifted == 32767);
268}
269
270test "exact shift left" {
271 testShlExact(0b00110101);
272 comptime testShlExact(0b00110101);
273}
274fn testShlExact(x: u8) {
275 const shifted = @shlExact(x, 2);
276 assert(shifted == 0b11010100);
277}
278
279test "exact shift right" {
280 testShrExact(0b10110100);
281 comptime testShrExact(0b10110100);
282}
283fn testShrExact(x: u8) {
284 const shifted = @shrExact(x, 2);
285 assert(shifted == 0b00101101);
286}
test/compile_errors.zig+14
......@@ -1959,4 +1959,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
19591959 \\}
19601960 ,
19611961 ".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");
19621976}
test/debug_safety.zig+32-2
......@@ -112,7 +112,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
112112 \\ if (x == 0) return error.Whatever;
113113 \\}
114114 \\fn shl(a: i16, b: i16) -> i16 {
115 \\ a << b
115 \\ @shlExact(a, b)
116116 \\}
117117 );
118118
......@@ -127,7 +127,37 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
127127 \\ if (x == 0) return error.Whatever;
128128 \\}
129129 \\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)
131161 \\}
132162 );
133163