mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 16:45:27 +00:00
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
This commit is contained in:
parent
54675b060a
commit
35d3444e27
@ -493,7 +493,6 @@ enum BinOpType {
|
||||
BinOpTypeAssignMinus,
|
||||
BinOpTypeAssignMinusWrap,
|
||||
BinOpTypeAssignBitShiftLeft,
|
||||
BinOpTypeAssignBitShiftLeftWrap,
|
||||
BinOpTypeAssignBitShiftRight,
|
||||
BinOpTypeAssignBitAnd,
|
||||
BinOpTypeAssignBitXor,
|
||||
@ -512,7 +511,6 @@ enum BinOpType {
|
||||
BinOpTypeBinXor,
|
||||
BinOpTypeBinAnd,
|
||||
BinOpTypeBitShiftLeft,
|
||||
BinOpTypeBitShiftLeftWrap,
|
||||
BinOpTypeBitShiftRight,
|
||||
BinOpTypeAdd,
|
||||
BinOpTypeAddWrap,
|
||||
@ -1232,6 +1230,8 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdOffsetOf,
|
||||
BuiltinFnIdInlineCall,
|
||||
BuiltinFnIdTypeId,
|
||||
BuiltinFnIdShlExact,
|
||||
BuiltinFnIdShrExact,
|
||||
};
|
||||
|
||||
struct BuiltinFnEntry {
|
||||
@ -1248,7 +1248,8 @@ enum PanicMsgId {
|
||||
PanicMsgIdCastNegativeToUnsigned,
|
||||
PanicMsgIdCastTruncatedData,
|
||||
PanicMsgIdIntegerOverflow,
|
||||
PanicMsgIdShiftOverflowedBits,
|
||||
PanicMsgIdShlOverflowedBits,
|
||||
PanicMsgIdShrOverflowedBits,
|
||||
PanicMsgIdDivisionByZero,
|
||||
PanicMsgIdRemainderDivisionByZero,
|
||||
PanicMsgIdExactDivisionRemainder,
|
||||
@ -1930,9 +1931,10 @@ enum IrBinOp {
|
||||
IrBinOpBinOr,
|
||||
IrBinOpBinXor,
|
||||
IrBinOpBinAnd,
|
||||
IrBinOpBitShiftLeft,
|
||||
IrBinOpBitShiftLeftWrap,
|
||||
IrBinOpBitShiftRight,
|
||||
IrBinOpBitShiftLeftLossy,
|
||||
IrBinOpBitShiftLeftExact,
|
||||
IrBinOpBitShiftRightLossy,
|
||||
IrBinOpBitShiftRightExact,
|
||||
IrBinOpAdd,
|
||||
IrBinOpAddWrap,
|
||||
IrBinOpSub,
|
||||
|
@ -26,7 +26,6 @@ static const char *bin_op_str(BinOpType bin_op) {
|
||||
case BinOpTypeBinXor: return "^";
|
||||
case BinOpTypeBinAnd: return "&";
|
||||
case BinOpTypeBitShiftLeft: return "<<";
|
||||
case BinOpTypeBitShiftLeftWrap: return "<<%";
|
||||
case BinOpTypeBitShiftRight: return ">>";
|
||||
case BinOpTypeAdd: return "+";
|
||||
case BinOpTypeAddWrap: return "+%";
|
||||
@ -46,7 +45,6 @@ static const char *bin_op_str(BinOpType bin_op) {
|
||||
case BinOpTypeAssignMinus: return "-=";
|
||||
case BinOpTypeAssignMinusWrap: return "-%=";
|
||||
case BinOpTypeAssignBitShiftLeft: return "<<=";
|
||||
case BinOpTypeAssignBitShiftLeftWrap: return "<<%=";
|
||||
case BinOpTypeAssignBitShiftRight: return ">>=";
|
||||
case BinOpTypeAssignBitAnd: return "&=";
|
||||
case BinOpTypeAssignBitXor: return "^=";
|
||||
|
@ -799,7 +799,7 @@ void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2) {
|
||||
bigint_normalize(dest);
|
||||
}
|
||||
|
||||
void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) {
|
||||
void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) {
|
||||
BigInt unwrapped = {0};
|
||||
bigint_shl(&unwrapped, op1, op2);
|
||||
bigint_truncate(dest, &unwrapped, bit_count, is_signed);
|
||||
|
@ -66,7 +66,7 @@ void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||
void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||
|
||||
void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||
void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
||||
void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
||||
void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||
|
||||
void bigint_negate(BigInt *dest, const BigInt *op);
|
||||
|
@ -694,8 +694,10 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
|
||||
return buf_create_from_str("integer cast truncated bits");
|
||||
case PanicMsgIdIntegerOverflow:
|
||||
return buf_create_from_str("integer overflow");
|
||||
case PanicMsgIdShiftOverflowedBits:
|
||||
case PanicMsgIdShlOverflowedBits:
|
||||
return buf_create_from_str("left shift overflowed bits");
|
||||
case PanicMsgIdShrOverflowedBits:
|
||||
return buf_create_from_str("right shift overflowed bits");
|
||||
case PanicMsgIdDivisionByZero:
|
||||
return buf_create_from_str("division by zero");
|
||||
case PanicMsgIdRemainderDivisionByZero:
|
||||
@ -1153,7 +1155,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
|
||||
static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
|
||||
LLVMValueRef val1, LLVMValueRef val2)
|
||||
{
|
||||
// for unsigned left shifting, we do the wrapping shift, then logically shift
|
||||
// for unsigned left shifting, we do the lossy shift, then logically shift
|
||||
// right the same number of bits
|
||||
// if the values don't match, we have an overflow
|
||||
// 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,
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
gen_debug_safety_crash(g, PanicMsgIdShiftOverflowedBits);
|
||||
gen_debug_safety_crash(g, PanicMsgIdShlOverflowedBits);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
return result;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_overflow_shr_op(CodeGen *g, TypeTableEntry *type_entry,
|
||||
LLVMValueRef val1, LLVMValueRef val2)
|
||||
{
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
|
||||
LLVMValueRef result;
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
result = LLVMBuildAShr(g->builder, val1, val2, "");
|
||||
} else {
|
||||
result = LLVMBuildLShr(g->builder, val1, val2, "");
|
||||
}
|
||||
LLVMValueRef orig_val = LLVMBuildShl(g->builder, result, val2, "");
|
||||
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
|
||||
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
gen_debug_safety_crash(g, PanicMsgIdShrOverflowedBits);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
return result;
|
||||
@ -1496,12 +1523,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
return LLVMBuildXor(g->builder, op1_value, op2_value, "");
|
||||
case IrBinOpBinAnd:
|
||||
return LLVMBuildAnd(g->builder, op1_value, op2_value, "");
|
||||
case IrBinOpBitShiftLeft:
|
||||
case IrBinOpBitShiftLeftWrap:
|
||||
case IrBinOpBitShiftLeftLossy:
|
||||
case IrBinOpBitShiftLeftExact:
|
||||
{
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);
|
||||
if (is_wrapping) {
|
||||
bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy);
|
||||
if (is_sloppy) {
|
||||
return LLVMBuildShl(g->builder, op1_value, op2_value, "");
|
||||
} else if (want_debug_safety) {
|
||||
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,
|
||||
return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
}
|
||||
case IrBinOpBitShiftRight:
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMBuildAShr(g->builder, op1_value, op2_value, "");
|
||||
} else {
|
||||
return LLVMBuildLShr(g->builder, op1_value, op2_value, "");
|
||||
case IrBinOpBitShiftRightLossy:
|
||||
case IrBinOpBitShiftRightExact:
|
||||
{
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy);
|
||||
if (is_sloppy) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMBuildAShr(g->builder, op1_value, op2_value, "");
|
||||
} else {
|
||||
return LLVMBuildLShr(g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
} else if (want_debug_safety) {
|
||||
return gen_overflow_shr_op(g, type_entry, op1_value, op2_value);
|
||||
} else if (type_entry->data.integral.is_signed) {
|
||||
return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_value, "");
|
||||
} else {
|
||||
return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
}
|
||||
case IrBinOpSub:
|
||||
case IrBinOpSubWrap:
|
||||
@ -4556,6 +4595,8 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
|
||||
create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
|
||||
}
|
||||
|
||||
static const char *bool_to_str(bool b) {
|
||||
|
@ -25,6 +25,7 @@ const char *err_str(int err) {
|
||||
case ErrorUnexpected: return "unexpected error";
|
||||
case ErrorExactDivRemainder: return "exact division had a remainder";
|
||||
case ErrorNegativeDenominator: return "negative denominator";
|
||||
case ErrorShiftedOutOneBits: return "exact shift shifted out one bits";
|
||||
}
|
||||
return "(invalid error)";
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ enum Error {
|
||||
ErrorUnexpected,
|
||||
ErrorExactDivRemainder,
|
||||
ErrorNegativeDenominator,
|
||||
ErrorShiftedOutOneBits,
|
||||
};
|
||||
|
||||
const char *err_str(int err);
|
||||
|
73
src/ir.cpp
73
src/ir.cpp
@ -3625,11 +3625,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
|
||||
case BinOpTypeAssignMinusWrap:
|
||||
return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap);
|
||||
case BinOpTypeAssignBitShiftLeft:
|
||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeft);
|
||||
case BinOpTypeAssignBitShiftLeftWrap:
|
||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftWrap);
|
||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy);
|
||||
case BinOpTypeAssignBitShiftRight:
|
||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRight);
|
||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy);
|
||||
case BinOpTypeAssignBitAnd:
|
||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd);
|
||||
case BinOpTypeAssignBitXor:
|
||||
@ -3663,11 +3661,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
|
||||
case BinOpTypeBinAnd:
|
||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd);
|
||||
case BinOpTypeBitShiftLeft:
|
||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeft);
|
||||
case BinOpTypeBitShiftLeftWrap:
|
||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftWrap);
|
||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy);
|
||||
case BinOpTypeBitShiftRight:
|
||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRight);
|
||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy);
|
||||
case BinOpTypeAdd:
|
||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd);
|
||||
case BinOpTypeAddWrap:
|
||||
@ -4457,6 +4453,34 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
|
||||
return ir_build_type_id(irb, scope, node, arg0_value);
|
||||
}
|
||||
case BuiltinFnIdShlExact:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
return ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true);
|
||||
}
|
||||
case BuiltinFnIdShrExact:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
return ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true);
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -8362,16 +8386,27 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,
|
||||
assert(is_int);
|
||||
bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||
break;
|
||||
case IrBinOpBitShiftLeft:
|
||||
case IrBinOpBitShiftLeftExact:
|
||||
assert(is_int);
|
||||
bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||
break;
|
||||
case IrBinOpBitShiftLeftWrap:
|
||||
case IrBinOpBitShiftLeftLossy:
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
bigint_shl_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint,
|
||||
bigint_shl_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint,
|
||||
type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);
|
||||
break;
|
||||
case IrBinOpBitShiftRight:
|
||||
case IrBinOpBitShiftRightExact:
|
||||
{
|
||||
assert(is_int);
|
||||
bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||
BigInt orig_bigint;
|
||||
bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||
if (bigint_cmp(&op1_val->data.x_bigint, &orig_bigint) != CmpEQ) {
|
||||
return ErrorShiftedOutOneBits;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrBinOpBitShiftRightLossy:
|
||||
assert(is_int);
|
||||
bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||
break;
|
||||
@ -8591,8 +8626,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
|
||||
}
|
||||
|
||||
if (resolved_type->id == TypeTableEntryIdNumLitInt) {
|
||||
if (op_id == IrBinOpBitShiftLeftWrap) {
|
||||
op_id = IrBinOpBitShiftLeft;
|
||||
if (op_id == IrBinOpBitShiftLeftLossy) {
|
||||
op_id = IrBinOpBitShiftLeftExact;
|
||||
} else if (op_id == IrBinOpAddWrap) {
|
||||
op_id = IrBinOpAdd;
|
||||
} else if (op_id == IrBinOpSubWrap) {
|
||||
@ -8631,6 +8666,9 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
|
||||
} else if (err == ErrorNegativeDenominator) {
|
||||
ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("negative denominator"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else if (err == ErrorShiftedOutOneBits) {
|
||||
ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("exact shift shifted out 1 bits"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -8857,9 +8895,10 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
|
||||
case IrBinOpBinOr:
|
||||
case IrBinOpBinXor:
|
||||
case IrBinOpBinAnd:
|
||||
case IrBinOpBitShiftLeft:
|
||||
case IrBinOpBitShiftLeftWrap:
|
||||
case IrBinOpBitShiftRight:
|
||||
case IrBinOpBitShiftLeftLossy:
|
||||
case IrBinOpBitShiftLeftExact:
|
||||
case IrBinOpBitShiftRightLossy:
|
||||
case IrBinOpBitShiftRightExact:
|
||||
case IrBinOpAdd:
|
||||
case IrBinOpAddWrap:
|
||||
case IrBinOpSub:
|
||||
|
@ -92,12 +92,14 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
|
||||
return "^";
|
||||
case IrBinOpBinAnd:
|
||||
return "&";
|
||||
case IrBinOpBitShiftLeft:
|
||||
case IrBinOpBitShiftLeftLossy:
|
||||
return "<<";
|
||||
case IrBinOpBitShiftLeftWrap:
|
||||
return "<<%";
|
||||
case IrBinOpBitShiftRight:
|
||||
case IrBinOpBitShiftLeftExact:
|
||||
return "@shlExact";
|
||||
case IrBinOpBitShiftRightLossy:
|
||||
return ">>";
|
||||
case IrBinOpBitShiftRightExact:
|
||||
return "@shrExact";
|
||||
case IrBinOpAdd:
|
||||
return "+";
|
||||
case IrBinOpAddWrap:
|
||||
|
@ -1131,7 +1131,6 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, size_t *token_index, bool m
|
||||
static BinOpType tok_to_bit_shift_op(Token *token) {
|
||||
switch (token->id) {
|
||||
case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft;
|
||||
case TokenIdBitShiftLeftPercent: return BinOpTypeBitShiftLeftWrap;
|
||||
case TokenIdBitShiftRight: return BinOpTypeBitShiftRight;
|
||||
default: return BinOpTypeInvalid;
|
||||
}
|
||||
@ -1909,7 +1908,6 @@ static BinOpType tok_to_ass_op(Token *token) {
|
||||
case TokenIdMinusEq: return BinOpTypeAssignMinus;
|
||||
case TokenIdMinusPercentEq: return BinOpTypeAssignMinusWrap;
|
||||
case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft;
|
||||
case TokenIdBitShiftLeftPercentEq: return BinOpTypeAssignBitShiftLeftWrap;
|
||||
case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight;
|
||||
case TokenIdBitAndEq: return BinOpTypeAssignBitAnd;
|
||||
case TokenIdBitXorEq: return BinOpTypeAssignBitXor;
|
||||
|
@ -201,7 +201,6 @@ enum TokenizeState {
|
||||
TokenizeStateSawBang,
|
||||
TokenizeStateSawLessThan,
|
||||
TokenizeStateSawLessThanLessThan,
|
||||
TokenizeStateSawShiftLeftPercent,
|
||||
TokenizeStateSawGreaterThan,
|
||||
TokenizeStateSawGreaterThanGreaterThan,
|
||||
TokenizeStateSawDot,
|
||||
@ -673,24 +672,6 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
case '%':
|
||||
set_token_id(&t, t.cur_tok, TokenIdBitShiftLeftPercent);
|
||||
t.state = TokenizeStateSawShiftLeftPercent;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case TokenizeStateSawShiftLeftPercent:
|
||||
switch (c) {
|
||||
case '=':
|
||||
set_token_id(&t, t.cur_tok, TokenIdBitShiftLeftPercentEq);
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
@ -1410,7 +1391,6 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
case TokenizeStateSawStarPercent:
|
||||
case TokenizeStateSawPlusPercent:
|
||||
case TokenizeStateSawMinusPercent:
|
||||
case TokenizeStateSawShiftLeftPercent:
|
||||
case TokenizeStateLineString:
|
||||
case TokenizeStateLineStringEnd:
|
||||
end_token(&t);
|
||||
@ -1451,8 +1431,6 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdBitOrEq: return "|=";
|
||||
case TokenIdBitShiftLeft: return "<<";
|
||||
case TokenIdBitShiftLeftEq: return "<<=";
|
||||
case TokenIdBitShiftLeftPercent: return "<<%";
|
||||
case TokenIdBitShiftLeftPercentEq: return "<<%=";
|
||||
case TokenIdBitShiftRight: return ">>";
|
||||
case TokenIdBitShiftRightEq: return ">>=";
|
||||
case TokenIdBitXorEq: return "^=";
|
||||
|
@ -23,8 +23,6 @@ enum TokenId {
|
||||
TokenIdBitOrEq,
|
||||
TokenIdBitShiftLeft,
|
||||
TokenIdBitShiftLeftEq,
|
||||
TokenIdBitShiftLeftPercent,
|
||||
TokenIdBitShiftLeftPercentEq,
|
||||
TokenIdBitShiftRight,
|
||||
TokenIdBitShiftRightEq,
|
||||
TokenIdBitXorEq,
|
||||
|
@ -754,9 +754,22 @@ LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMVa
|
||||
LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
||||
const char *name)
|
||||
{
|
||||
return wrap(unwrap(builder)->CreateShl(unwrap(LHS), unwrap(RHS), name, false, true));
|
||||
return wrap(unwrap(builder)->CreateShl(unwrap(LHS), unwrap(RHS), name, true, false));
|
||||
}
|
||||
|
||||
LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
||||
const char *name)
|
||||
{
|
||||
return wrap(unwrap(builder)->CreateLShr(unwrap(LHS), unwrap(RHS), name, true));
|
||||
}
|
||||
|
||||
LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
||||
const char *name)
|
||||
{
|
||||
return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
|
||||
}
|
||||
|
||||
|
||||
#include "buffer.hpp"
|
||||
|
||||
bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag_buf) {
|
||||
|
@ -48,6 +48,10 @@ LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMVa
|
||||
const char *name);
|
||||
LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
||||
const char *name);
|
||||
LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
||||
const char *name);
|
||||
LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
||||
const char *name);
|
||||
|
||||
ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type,
|
||||
uint64_t size_in_bits, uint64_t align_in_bits, const char *name);
|
||||
|
@ -21,11 +21,11 @@ pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8)
|
||||
dest[out_index] = alphabet[(source[i] >> 2) & 0x3f];
|
||||
out_index += 1;
|
||||
|
||||
dest[out_index] = alphabet[((source[i] & 0x3) <<% 4) |
|
||||
dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
|
||||
((source[i + 1] & 0xf0) >> 4)];
|
||||
out_index += 1;
|
||||
|
||||
dest[out_index] = alphabet[((source[i + 1] & 0xf) <<% 2) |
|
||||
dest[out_index] = alphabet[((source[i + 1] & 0xf) << 2) |
|
||||
((source[i + 2] & 0xc0) >> 6)];
|
||||
out_index += 1;
|
||||
|
||||
@ -38,17 +38,17 @@ pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8)
|
||||
out_index += 1;
|
||||
|
||||
if (i + 1 == source.len) {
|
||||
dest[out_index] = alphabet[(source[i] & 0x3) <<% 4];
|
||||
dest[out_index] = alphabet[(source[i] & 0x3) << 4];
|
||||
out_index += 1;
|
||||
|
||||
dest[out_index] = alphabet[64];
|
||||
out_index += 1;
|
||||
} else {
|
||||
dest[out_index] = alphabet[((source[i] & 0x3) <<% 4) |
|
||||
dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
|
||||
((source[i + 1] & 0xf0) >> 4)];
|
||||
out_index += 1;
|
||||
|
||||
dest[out_index] = alphabet[(source[i + 1] & 0xf) <<% 2];
|
||||
dest[out_index] = alphabet[(source[i + 1] & 0xf) << 2];
|
||||
out_index += 1;
|
||||
}
|
||||
|
||||
@ -83,15 +83,15 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8
|
||||
}
|
||||
|
||||
while (in_buf_len > 4) {
|
||||
dest[dest_index] = ascii6[source[src_index + 0]] <<% 2 |
|
||||
dest[dest_index] = ascii6[source[src_index + 0]] << 2 |
|
||||
ascii6[source[src_index + 1]] >> 4;
|
||||
dest_index += 1;
|
||||
|
||||
dest[dest_index] = ascii6[source[src_index + 1]] <<% 4 |
|
||||
dest[dest_index] = ascii6[source[src_index + 1]] << 4 |
|
||||
ascii6[source[src_index + 2]] >> 2;
|
||||
dest_index += 1;
|
||||
|
||||
dest[dest_index] = ascii6[source[src_index + 2]] <<% 6 |
|
||||
dest[dest_index] = ascii6[source[src_index + 2]] << 6 |
|
||||
ascii6[source[src_index + 3]];
|
||||
dest_index += 1;
|
||||
|
||||
@ -100,17 +100,17 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8
|
||||
}
|
||||
|
||||
if (in_buf_len > 1) {
|
||||
dest[dest_index] = ascii6[source[src_index + 0]] <<% 2 |
|
||||
dest[dest_index] = ascii6[source[src_index + 0]] << 2 |
|
||||
ascii6[source[src_index + 1]] >> 4;
|
||||
dest_index += 1;
|
||||
}
|
||||
if (in_buf_len > 2) {
|
||||
dest[dest_index] = ascii6[source[src_index + 1]] <<% 4 |
|
||||
dest[dest_index] = ascii6[source[src_index + 1]] << 4 |
|
||||
ascii6[source[src_index + 2]] >> 2;
|
||||
dest_index += 1;
|
||||
}
|
||||
if (in_buf_len > 3) {
|
||||
dest[dest_index] = ascii6[source[src_index + 2]] <<% 6 |
|
||||
dest[dest_index] = ascii6[source[src_index + 2]] << 6 |
|
||||
ascii6[source[src_index + 3]];
|
||||
dest_index += 1;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ fn exp2_32(x: f32) -> f32 {
|
||||
const k = i0 / tblsiz;
|
||||
// NOTE: musl relies on undefined overflow shift behaviour. Appears that this produces the
|
||||
// intended result but should confirm how GCC/Clang handle this to ensure.
|
||||
const uk = @bitCast(f64, u64(0x3FF + k) <<% 52);
|
||||
const uk = @bitCast(f64, u64(0x3FF + k) << 52);
|
||||
i0 &= tblsiz - 1;
|
||||
uf -= redux;
|
||||
|
||||
|
@ -124,7 +124,7 @@ fn expm1_32(x_: f32) -> f32 {
|
||||
}
|
||||
}
|
||||
|
||||
const twopk = @bitCast(f32, u32((0x7F + k) <<% 23));
|
||||
const twopk = @bitCast(f32, u32((0x7F + k) << 23));
|
||||
|
||||
if (k < 0 or k > 56) {
|
||||
var y = x - e + 1.0;
|
||||
@ -253,7 +253,7 @@ fn expm1_64(x_: f64) -> f64 {
|
||||
}
|
||||
}
|
||||
|
||||
const twopk = @bitCast(f64, u64(0x3FF + k) <<% 52);
|
||||
const twopk = @bitCast(f64, u64(0x3FF + k) << 52);
|
||||
|
||||
if (k < 0 or k > 56) {
|
||||
var y = x - e + 1.0;
|
||||
|
@ -49,7 +49,7 @@ fn ilogb32(x: f32) -> i32 {
|
||||
|
||||
if (e == 0xFF) {
|
||||
math.raiseInvalid();
|
||||
if (u <<% 9 != 0) {
|
||||
if (u << 9 != 0) {
|
||||
return fp_ilogbnan;
|
||||
} else {
|
||||
return @maxValue(i32);
|
||||
@ -84,7 +84,7 @@ fn ilogb64(x: f64) -> i32 {
|
||||
|
||||
if (e == 0x7FF) {
|
||||
math.raiseInvalid();
|
||||
if (u <<% 12 != 0) {
|
||||
if (u << 12 != 0) {
|
||||
return fp_ilogbnan;
|
||||
} else {
|
||||
return @maxValue(i32);
|
||||
|
@ -36,7 +36,7 @@ fn lnf(x_: f32) -> f32 {
|
||||
// x < 2^(-126)
|
||||
if (ix < 0x00800000 or ix >> 31 != 0) {
|
||||
// log(+-0) = -inf
|
||||
if (ix <<% 1 == 0) {
|
||||
if (ix << 1 == 0) {
|
||||
return -math.inf(f32);
|
||||
}
|
||||
// log(-#) = nan
|
||||
@ -91,7 +91,7 @@ fn lnd(x_: f64) -> f64 {
|
||||
|
||||
if (hx < 0x00100000 or hx >> 31 != 0) {
|
||||
// log(+-0) = -inf
|
||||
if (ix <<% 1 == 0) {
|
||||
if (ix << 1 == 0) {
|
||||
return -math.inf(f64);
|
||||
}
|
||||
// log(-#) = nan
|
||||
|
@ -38,7 +38,7 @@ fn log10_32(x_: f32) -> f32 {
|
||||
// x < 2^(-126)
|
||||
if (ix < 0x00800000 or ix >> 31 != 0) {
|
||||
// log(+-0) = -inf
|
||||
if (ix <<% 1 == 0) {
|
||||
if (ix << 1 == 0) {
|
||||
return -math.inf(f32);
|
||||
}
|
||||
// log(-#) = nan
|
||||
@ -100,7 +100,7 @@ fn log10_64(x_: f64) -> f64 {
|
||||
|
||||
if (hx < 0x00100000 or hx >> 31 != 0) {
|
||||
// log(+-0) = -inf
|
||||
if (ix <<% 1 == 0) {
|
||||
if (ix << 1 == 0) {
|
||||
return -math.inf(f32);
|
||||
}
|
||||
// log(-#) = nan
|
||||
@ -139,7 +139,7 @@ fn log10_64(x_: f64) -> f64 {
|
||||
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
||||
var hi = f - hfsq;
|
||||
var hii = @bitCast(u64, hi);
|
||||
hii &= u64(@maxValue(u64)) <<% 32;
|
||||
hii &= u64(@maxValue(u64)) << 32;
|
||||
hi = @bitCast(f64, hii);
|
||||
const lo = f - hi - hfsq + s * (hfsq + R);
|
||||
|
||||
|
@ -49,7 +49,7 @@ fn log1p_32(x: f32) -> f32 {
|
||||
}
|
||||
}
|
||||
// |x| < 2^(-24)
|
||||
if ((ix <<% 1) < (0x33800000 << 1)) {
|
||||
if ((ix << 1) < (0x33800000 << 1)) {
|
||||
// underflow if subnormal
|
||||
if (ix & 0x7F800000 == 0) {
|
||||
math.forceEval(x * x);
|
||||
@ -128,7 +128,7 @@ fn log1p_64(x: f64) -> f64 {
|
||||
}
|
||||
}
|
||||
// |x| < 2^(-53)
|
||||
if ((hx <<% 1) < (0x3CA00000 << 1)) {
|
||||
if ((hx << 1) < (0x3CA00000 << 1)) {
|
||||
if ((hx & 0x7FF00000) == 0) {
|
||||
math.raiseUnderflow();
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ fn log2_32(x_: f32) -> f32 {
|
||||
// x < 2^(-126)
|
||||
if (ix < 0x00800000 or ix >> 31 != 0) {
|
||||
// log(+-0) = -inf
|
||||
if (ix <<% 1 == 0) {
|
||||
if (ix << 1 == 0) {
|
||||
return -math.inf(f32);
|
||||
}
|
||||
// log(-#) = nan
|
||||
@ -94,7 +94,7 @@ fn log2_64(x_: f64) -> f64 {
|
||||
|
||||
if (hx < 0x00100000 or hx >> 31 != 0) {
|
||||
// log(+-0) = -inf
|
||||
if (ix <<% 1 == 0) {
|
||||
if (ix << 1 == 0) {
|
||||
return -math.inf(f64);
|
||||
}
|
||||
// log(-#) = nan
|
||||
@ -133,7 +133,7 @@ fn log2_64(x_: f64) -> f64 {
|
||||
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
||||
var hi = f - hfsq;
|
||||
var hii = @bitCast(u64, hi);
|
||||
hii &= u64(@maxValue(u64)) <<% 32;
|
||||
hii &= u64(@maxValue(u64)) << 32;
|
||||
hi = @bitCast(f64, hii);
|
||||
const lo = f - hi - hfsq + s * (hfsq + R);
|
||||
|
||||
|
@ -44,7 +44,7 @@ fn modf32(x: f32) -> modf32_result {
|
||||
// no fractional part
|
||||
if (e >= 23) {
|
||||
result.ipart = x;
|
||||
if (e == 0x80 and u <<% 9 != 0) { // nan
|
||||
if (e == 0x80 and u << 9 != 0) { // nan
|
||||
result.fpart = x;
|
||||
} else {
|
||||
result.fpart = @bitCast(f32, us);
|
||||
@ -88,7 +88,7 @@ fn modf64(x: f64) -> modf64_result {
|
||||
// no fractional part
|
||||
if (e >= 52) {
|
||||
result.ipart = x;
|
||||
if (e == 0x400 and u <<% 12 != 0) { // nan
|
||||
if (e == 0x400 and u << 12 != 0) { // nan
|
||||
result.fpart = x;
|
||||
} else {
|
||||
result.fpart = @bitCast(f64, us);
|
||||
|
@ -182,8 +182,8 @@ fn MersenneTwister(
|
||||
mt.index += 1;
|
||||
|
||||
x ^= ((x >> u) & d);
|
||||
x ^= ((x <<% s) & b);
|
||||
x ^= ((x <<% t) & c);
|
||||
x ^= ((x << s) & b);
|
||||
x ^= ((x << t) & c);
|
||||
x ^= (x >> l);
|
||||
|
||||
return x;
|
||||
|
@ -47,31 +47,31 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
||||
const sx = if (T == f32) u32(ux & 0x80000000) else i32(ux >> bits_minus_1);
|
||||
var i: uint = undefined;
|
||||
|
||||
if (uy <<% 1 == 0 or isNan(uint, uy) or ex == mask)
|
||||
if (uy << 1 == 0 or isNan(uint, uy) or ex == mask)
|
||||
return (x * y) / (x * y);
|
||||
|
||||
if (ux <<% 1 <= uy <<% 1) {
|
||||
if (ux <<% 1 == uy <<% 1)
|
||||
if (ux << 1 <= uy << 1) {
|
||||
if (ux << 1 == uy << 1)
|
||||
return 0 * x;
|
||||
return x;
|
||||
}
|
||||
|
||||
// normalize x and y
|
||||
if (ex == 0) {
|
||||
i = ux <<% exp_bits;
|
||||
while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<%= 1}) {}
|
||||
ux <<%= @bitCast(u32, -ex + 1);
|
||||
i = ux << exp_bits;
|
||||
while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<= 1}) {}
|
||||
ux <<= @bitCast(u32, -ex + 1);
|
||||
} else {
|
||||
ux &= @maxValue(uint) >> exp_bits;
|
||||
ux |= 1 <<% digits;
|
||||
ux |= 1 << digits;
|
||||
}
|
||||
if (ey == 0) {
|
||||
i = uy <<% exp_bits;
|
||||
while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<%= 1}) {}
|
||||
i = uy << exp_bits;
|
||||
while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<= 1}) {}
|
||||
uy <<= @bitCast(u32, -ey + 1);
|
||||
} else {
|
||||
uy &= @maxValue(uint) >> exp_bits;
|
||||
uy |= 1 <<% digits;
|
||||
uy |= 1 << digits;
|
||||
}
|
||||
|
||||
// x mod y
|
||||
@ -82,7 +82,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
||||
return 0 * x;
|
||||
ux = i;
|
||||
}
|
||||
ux <<%= 1;
|
||||
ux <<= 1;
|
||||
}
|
||||
i = ux -% uy;
|
||||
if (i >> bits_minus_1 == 0) {
|
||||
@ -90,19 +90,19 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
||||
return 0 * x;
|
||||
ux = i;
|
||||
}
|
||||
while (ux >> digits == 0) : ({ux <<%= 1; ex -= 1}) {}
|
||||
while (ux >> digits == 0) : ({ux <<= 1; ex -= 1}) {}
|
||||
|
||||
// scale result up
|
||||
if (ex > 0) {
|
||||
ux -%= 1 <<% digits;
|
||||
ux |= @bitCast(u32, ex) <<% digits;
|
||||
ux -%= 1 << digits;
|
||||
ux |= @bitCast(u32, ex) << digits;
|
||||
} else {
|
||||
ux >>= @bitCast(u32, -ex + 1);
|
||||
}
|
||||
if (T == f32) {
|
||||
ux |= sx;
|
||||
} else {
|
||||
ux |= uint(sx) <<% bits_minus_1;
|
||||
ux |= uint(sx) << bits_minus_1;
|
||||
}
|
||||
return *@ptrCast(&const T, &ux);
|
||||
}
|
||||
@ -111,7 +111,7 @@ fn isNan(comptime T: type, bits: T) -> bool {
|
||||
if (T == u32) {
|
||||
return (bits & 0x7fffffff) > 0x7f800000;
|
||||
} else if (T == u64) {
|
||||
return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) <<% 52);
|
||||
return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52);
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
|
@ -168,15 +168,6 @@ fn testNegationWrappingEval(x: i16) {
|
||||
assert(neg == -32768);
|
||||
}
|
||||
|
||||
test "shift left wrapping" {
|
||||
testShlWrappingEval(@maxValue(u16));
|
||||
comptime testShlWrappingEval(@maxValue(u16));
|
||||
}
|
||||
fn testShlWrappingEval(x: u16) {
|
||||
const shifted = x <<% 1;
|
||||
assert(shifted == 65534);
|
||||
}
|
||||
|
||||
test "unsigned 64-bit division" {
|
||||
test_u64_div();
|
||||
comptime test_u64_div();
|
||||
@ -257,3 +248,39 @@ test "hex float literal within range" {
|
||||
const b = 0x0.1p1027;
|
||||
const c = 0x1.0p-1022;
|
||||
}
|
||||
|
||||
test "truncating shift left" {
|
||||
testShlTrunc(@maxValue(u16));
|
||||
comptime testShlTrunc(@maxValue(u16));
|
||||
}
|
||||
fn testShlTrunc(x: u16) {
|
||||
const shifted = x << 1;
|
||||
assert(shifted == 65534);
|
||||
}
|
||||
|
||||
test "truncating shift right" {
|
||||
testShrTrunc(@maxValue(u16));
|
||||
comptime testShrTrunc(@maxValue(u16));
|
||||
}
|
||||
fn testShrTrunc(x: u16) {
|
||||
const shifted = x >> 1;
|
||||
assert(shifted == 32767);
|
||||
}
|
||||
|
||||
test "exact shift left" {
|
||||
testShlExact(0b00110101);
|
||||
comptime testShlExact(0b00110101);
|
||||
}
|
||||
fn testShlExact(x: u8) {
|
||||
const shifted = @shlExact(x, 2);
|
||||
assert(shifted == 0b11010100);
|
||||
}
|
||||
|
||||
test "exact shift right" {
|
||||
testShrExact(0b10110100);
|
||||
comptime testShrExact(0b10110100);
|
||||
}
|
||||
fn testShrExact(x: u8) {
|
||||
const shifted = @shrExact(x, 2);
|
||||
assert(shifted == 0b00101101);
|
||||
}
|
||||
|
@ -1959,4 +1959,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:15: error: expected pointer, found 'i32'");
|
||||
|
||||
cases.add("@shlExact shifts out 1 bits",
|
||||
\\comptime {
|
||||
\\ const x = @shlExact(u8(0b01010101), 2);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:15: error: operation caused overflow");
|
||||
|
||||
cases.add("@shrExact shifts out 1 bits",
|
||||
\\comptime {
|
||||
\\ const x = @shrExact(u8(0b10101010), 2);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:15: error: exact shift shifted out 1 bits");
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
||||
\\ if (x == 0) return error.Whatever;
|
||||
\\}
|
||||
\\fn shl(a: i16, b: i16) -> i16 {
|
||||
\\ a << b
|
||||
\\ @shlExact(a, b)
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -127,7 +127,37 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
|
||||
\\ if (x == 0) return error.Whatever;
|
||||
\\}
|
||||
\\fn shl(a: u16, b: u16) -> u16 {
|
||||
\\ a << b
|
||||
\\ @shlExact(a, b)
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addDebugSafety("signed shift right overflow",
|
||||
\\pub fn panic(message: []const u8) -> noreturn {
|
||||
\\ @breakpoint();
|
||||
\\ while (true) {}
|
||||
\\}
|
||||
\\error Whatever;
|
||||
\\pub fn main() -> %void {
|
||||
\\ const x = shr(-16385, 1);
|
||||
\\ if (x == 0) return error.Whatever;
|
||||
\\}
|
||||
\\fn shr(a: i16, b: i16) -> i16 {
|
||||
\\ @shrExact(a, b)
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addDebugSafety("unsigned shift right overflow",
|
||||
\\pub fn panic(message: []const u8) -> noreturn {
|
||||
\\ @breakpoint();
|
||||
\\ while (true) {}
|
||||
\\}
|
||||
\\error Whatever;
|
||||
\\pub fn main() -> %void {
|
||||
\\ const x = shr(0b0010111111111111, 3);
|
||||
\\ if (x == 0) return error.Whatever;
|
||||
\\}
|
||||
\\fn shr(a: u16, b: u16) -> u16 {
|
||||
\\ @shrExact(a, b)
|
||||
\\}
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user