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,
|
BinOpTypeAssignMinus,
|
||||||
BinOpTypeAssignMinusWrap,
|
BinOpTypeAssignMinusWrap,
|
||||||
BinOpTypeAssignBitShiftLeft,
|
BinOpTypeAssignBitShiftLeft,
|
||||||
BinOpTypeAssignBitShiftLeftWrap,
|
|
||||||
BinOpTypeAssignBitShiftRight,
|
BinOpTypeAssignBitShiftRight,
|
||||||
BinOpTypeAssignBitAnd,
|
BinOpTypeAssignBitAnd,
|
||||||
BinOpTypeAssignBitXor,
|
BinOpTypeAssignBitXor,
|
||||||
@ -512,7 +511,6 @@ enum BinOpType {
|
|||||||
BinOpTypeBinXor,
|
BinOpTypeBinXor,
|
||||||
BinOpTypeBinAnd,
|
BinOpTypeBinAnd,
|
||||||
BinOpTypeBitShiftLeft,
|
BinOpTypeBitShiftLeft,
|
||||||
BinOpTypeBitShiftLeftWrap,
|
|
||||||
BinOpTypeBitShiftRight,
|
BinOpTypeBitShiftRight,
|
||||||
BinOpTypeAdd,
|
BinOpTypeAdd,
|
||||||
BinOpTypeAddWrap,
|
BinOpTypeAddWrap,
|
||||||
@ -1232,6 +1230,8 @@ enum BuiltinFnId {
|
|||||||
BuiltinFnIdOffsetOf,
|
BuiltinFnIdOffsetOf,
|
||||||
BuiltinFnIdInlineCall,
|
BuiltinFnIdInlineCall,
|
||||||
BuiltinFnIdTypeId,
|
BuiltinFnIdTypeId,
|
||||||
|
BuiltinFnIdShlExact,
|
||||||
|
BuiltinFnIdShrExact,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BuiltinFnEntry {
|
struct BuiltinFnEntry {
|
||||||
@ -1248,7 +1248,8 @@ enum PanicMsgId {
|
|||||||
PanicMsgIdCastNegativeToUnsigned,
|
PanicMsgIdCastNegativeToUnsigned,
|
||||||
PanicMsgIdCastTruncatedData,
|
PanicMsgIdCastTruncatedData,
|
||||||
PanicMsgIdIntegerOverflow,
|
PanicMsgIdIntegerOverflow,
|
||||||
PanicMsgIdShiftOverflowedBits,
|
PanicMsgIdShlOverflowedBits,
|
||||||
|
PanicMsgIdShrOverflowedBits,
|
||||||
PanicMsgIdDivisionByZero,
|
PanicMsgIdDivisionByZero,
|
||||||
PanicMsgIdRemainderDivisionByZero,
|
PanicMsgIdRemainderDivisionByZero,
|
||||||
PanicMsgIdExactDivisionRemainder,
|
PanicMsgIdExactDivisionRemainder,
|
||||||
@ -1930,9 +1931,10 @@ enum IrBinOp {
|
|||||||
IrBinOpBinOr,
|
IrBinOpBinOr,
|
||||||
IrBinOpBinXor,
|
IrBinOpBinXor,
|
||||||
IrBinOpBinAnd,
|
IrBinOpBinAnd,
|
||||||
IrBinOpBitShiftLeft,
|
IrBinOpBitShiftLeftLossy,
|
||||||
IrBinOpBitShiftLeftWrap,
|
IrBinOpBitShiftLeftExact,
|
||||||
IrBinOpBitShiftRight,
|
IrBinOpBitShiftRightLossy,
|
||||||
|
IrBinOpBitShiftRightExact,
|
||||||
IrBinOpAdd,
|
IrBinOpAdd,
|
||||||
IrBinOpAddWrap,
|
IrBinOpAddWrap,
|
||||||
IrBinOpSub,
|
IrBinOpSub,
|
||||||
|
@ -26,7 +26,6 @@ static const char *bin_op_str(BinOpType bin_op) {
|
|||||||
case BinOpTypeBinXor: return "^";
|
case BinOpTypeBinXor: return "^";
|
||||||
case BinOpTypeBinAnd: return "&";
|
case BinOpTypeBinAnd: return "&";
|
||||||
case BinOpTypeBitShiftLeft: return "<<";
|
case BinOpTypeBitShiftLeft: return "<<";
|
||||||
case BinOpTypeBitShiftLeftWrap: return "<<%";
|
|
||||||
case BinOpTypeBitShiftRight: return ">>";
|
case BinOpTypeBitShiftRight: return ">>";
|
||||||
case BinOpTypeAdd: return "+";
|
case BinOpTypeAdd: return "+";
|
||||||
case BinOpTypeAddWrap: return "+%";
|
case BinOpTypeAddWrap: return "+%";
|
||||||
@ -46,7 +45,6 @@ static const char *bin_op_str(BinOpType bin_op) {
|
|||||||
case BinOpTypeAssignMinus: return "-=";
|
case BinOpTypeAssignMinus: return "-=";
|
||||||
case BinOpTypeAssignMinusWrap: return "-%=";
|
case BinOpTypeAssignMinusWrap: return "-%=";
|
||||||
case BinOpTypeAssignBitShiftLeft: return "<<=";
|
case BinOpTypeAssignBitShiftLeft: return "<<=";
|
||||||
case BinOpTypeAssignBitShiftLeftWrap: return "<<%=";
|
|
||||||
case BinOpTypeAssignBitShiftRight: return ">>=";
|
case BinOpTypeAssignBitShiftRight: return ">>=";
|
||||||
case BinOpTypeAssignBitAnd: return "&=";
|
case BinOpTypeAssignBitAnd: return "&=";
|
||||||
case BinOpTypeAssignBitXor: return "^=";
|
case BinOpTypeAssignBitXor: return "^=";
|
||||||
|
@ -799,7 +799,7 @@ void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2) {
|
|||||||
bigint_normalize(dest);
|
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 unwrapped = {0};
|
||||||
bigint_shl(&unwrapped, op1, op2);
|
bigint_shl(&unwrapped, op1, op2);
|
||||||
bigint_truncate(dest, &unwrapped, bit_count, is_signed);
|
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_xor(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
|
||||||
void bigint_shl(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_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
|
||||||
void bigint_negate(BigInt *dest, const BigInt *op);
|
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");
|
return buf_create_from_str("integer cast truncated bits");
|
||||||
case PanicMsgIdIntegerOverflow:
|
case PanicMsgIdIntegerOverflow:
|
||||||
return buf_create_from_str("integer overflow");
|
return buf_create_from_str("integer overflow");
|
||||||
case PanicMsgIdShiftOverflowedBits:
|
case PanicMsgIdShlOverflowedBits:
|
||||||
return buf_create_from_str("left shift overflowed bits");
|
return buf_create_from_str("left shift overflowed bits");
|
||||||
|
case PanicMsgIdShrOverflowedBits:
|
||||||
|
return buf_create_from_str("right shift overflowed bits");
|
||||||
case PanicMsgIdDivisionByZero:
|
case PanicMsgIdDivisionByZero:
|
||||||
return buf_create_from_str("division by zero");
|
return buf_create_from_str("division by zero");
|
||||||
case PanicMsgIdRemainderDivisionByZero:
|
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,
|
static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
|
||||||
LLVMValueRef val1, LLVMValueRef val2)
|
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
|
// right the same number of bits
|
||||||
// if the values don't match, we have an overflow
|
// if the values don't match, we have an overflow
|
||||||
// for signed left shifting we do the same except arithmetic shift right
|
// 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);
|
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(g->builder, 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);
|
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||||
return result;
|
return result;
|
||||||
@ -1496,12 +1523,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
|||||||
return LLVMBuildXor(g->builder, op1_value, op2_value, "");
|
return LLVMBuildXor(g->builder, op1_value, op2_value, "");
|
||||||
case IrBinOpBinAnd:
|
case IrBinOpBinAnd:
|
||||||
return LLVMBuildAnd(g->builder, op1_value, op2_value, "");
|
return LLVMBuildAnd(g->builder, op1_value, op2_value, "");
|
||||||
case IrBinOpBitShiftLeft:
|
case IrBinOpBitShiftLeftLossy:
|
||||||
case IrBinOpBitShiftLeftWrap:
|
case IrBinOpBitShiftLeftExact:
|
||||||
{
|
{
|
||||||
assert(type_entry->id == TypeTableEntryIdInt);
|
assert(type_entry->id == TypeTableEntryIdInt);
|
||||||
bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);
|
bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy);
|
||||||
if (is_wrapping) {
|
if (is_sloppy) {
|
||||||
return LLVMBuildShl(g->builder, op1_value, op2_value, "");
|
return LLVMBuildShl(g->builder, op1_value, op2_value, "");
|
||||||
} else if (want_debug_safety) {
|
} else if (want_debug_safety) {
|
||||||
return gen_overflow_shl_op(g, type_entry, op1_value, op2_value);
|
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, "");
|
return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case IrBinOpBitShiftRight:
|
case IrBinOpBitShiftRightLossy:
|
||||||
assert(type_entry->id == TypeTableEntryIdInt);
|
case IrBinOpBitShiftRightExact:
|
||||||
if (type_entry->data.integral.is_signed) {
|
{
|
||||||
return LLVMBuildAShr(g->builder, op1_value, op2_value, "");
|
assert(type_entry->id == TypeTableEntryIdInt);
|
||||||
} else {
|
bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy);
|
||||||
return LLVMBuildLShr(g->builder, op1_value, op2_value, "");
|
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 IrBinOpSub:
|
||||||
case IrBinOpSubWrap:
|
case IrBinOpSubWrap:
|
||||||
@ -4556,6 +4595,8 @@ static void define_builtin_fns(CodeGen *g) {
|
|||||||
create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
|
create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
|
||||||
create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
|
create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
|
||||||
create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
|
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) {
|
static const char *bool_to_str(bool b) {
|
||||||
|
@ -25,6 +25,7 @@ const char *err_str(int err) {
|
|||||||
case ErrorUnexpected: return "unexpected error";
|
case ErrorUnexpected: return "unexpected error";
|
||||||
case ErrorExactDivRemainder: return "exact division had a remainder";
|
case ErrorExactDivRemainder: return "exact division had a remainder";
|
||||||
case ErrorNegativeDenominator: return "negative denominator";
|
case ErrorNegativeDenominator: return "negative denominator";
|
||||||
|
case ErrorShiftedOutOneBits: return "exact shift shifted out one bits";
|
||||||
}
|
}
|
||||||
return "(invalid error)";
|
return "(invalid error)";
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ enum Error {
|
|||||||
ErrorUnexpected,
|
ErrorUnexpected,
|
||||||
ErrorExactDivRemainder,
|
ErrorExactDivRemainder,
|
||||||
ErrorNegativeDenominator,
|
ErrorNegativeDenominator,
|
||||||
|
ErrorShiftedOutOneBits,
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *err_str(int err);
|
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:
|
case BinOpTypeAssignMinusWrap:
|
||||||
return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap);
|
return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap);
|
||||||
case BinOpTypeAssignBitShiftLeft:
|
case BinOpTypeAssignBitShiftLeft:
|
||||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeft);
|
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy);
|
||||||
case BinOpTypeAssignBitShiftLeftWrap:
|
|
||||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftWrap);
|
|
||||||
case BinOpTypeAssignBitShiftRight:
|
case BinOpTypeAssignBitShiftRight:
|
||||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRight);
|
return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy);
|
||||||
case BinOpTypeAssignBitAnd:
|
case BinOpTypeAssignBitAnd:
|
||||||
return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd);
|
return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd);
|
||||||
case BinOpTypeAssignBitXor:
|
case BinOpTypeAssignBitXor:
|
||||||
@ -3663,11 +3661,9 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
|
|||||||
case BinOpTypeBinAnd:
|
case BinOpTypeBinAnd:
|
||||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd);
|
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd);
|
||||||
case BinOpTypeBitShiftLeft:
|
case BinOpTypeBitShiftLeft:
|
||||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeft);
|
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy);
|
||||||
case BinOpTypeBitShiftLeftWrap:
|
|
||||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftWrap);
|
|
||||||
case BinOpTypeBitShiftRight:
|
case BinOpTypeBitShiftRight:
|
||||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRight);
|
return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy);
|
||||||
case BinOpTypeAdd:
|
case BinOpTypeAdd:
|
||||||
return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd);
|
return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd);
|
||||||
case BinOpTypeAddWrap:
|
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);
|
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();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
@ -8362,16 +8386,27 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,
|
|||||||
assert(is_int);
|
assert(is_int);
|
||||||
bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||||
break;
|
break;
|
||||||
case IrBinOpBitShiftLeft:
|
case IrBinOpBitShiftLeftExact:
|
||||||
assert(is_int);
|
assert(is_int);
|
||||||
bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||||
break;
|
break;
|
||||||
case IrBinOpBitShiftLeftWrap:
|
case IrBinOpBitShiftLeftLossy:
|
||||||
assert(type_entry->id == TypeTableEntryIdInt);
|
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);
|
type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);
|
||||||
break;
|
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);
|
assert(is_int);
|
||||||
bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||||
break;
|
break;
|
||||||
@ -8591,8 +8626,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (resolved_type->id == TypeTableEntryIdNumLitInt) {
|
if (resolved_type->id == TypeTableEntryIdNumLitInt) {
|
||||||
if (op_id == IrBinOpBitShiftLeftWrap) {
|
if (op_id == IrBinOpBitShiftLeftLossy) {
|
||||||
op_id = IrBinOpBitShiftLeft;
|
op_id = IrBinOpBitShiftLeftExact;
|
||||||
} else if (op_id == IrBinOpAddWrap) {
|
} else if (op_id == IrBinOpAddWrap) {
|
||||||
op_id = IrBinOpAdd;
|
op_id = IrBinOpAdd;
|
||||||
} else if (op_id == IrBinOpSubWrap) {
|
} else if (op_id == IrBinOpSubWrap) {
|
||||||
@ -8631,6 +8666,9 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
|
|||||||
} else if (err == ErrorNegativeDenominator) {
|
} else if (err == ErrorNegativeDenominator) {
|
||||||
ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("negative denominator"));
|
ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("negative denominator"));
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
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 {
|
} else {
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
@ -8857,9 +8895,10 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
|
|||||||
case IrBinOpBinOr:
|
case IrBinOpBinOr:
|
||||||
case IrBinOpBinXor:
|
case IrBinOpBinXor:
|
||||||
case IrBinOpBinAnd:
|
case IrBinOpBinAnd:
|
||||||
case IrBinOpBitShiftLeft:
|
case IrBinOpBitShiftLeftLossy:
|
||||||
case IrBinOpBitShiftLeftWrap:
|
case IrBinOpBitShiftLeftExact:
|
||||||
case IrBinOpBitShiftRight:
|
case IrBinOpBitShiftRightLossy:
|
||||||
|
case IrBinOpBitShiftRightExact:
|
||||||
case IrBinOpAdd:
|
case IrBinOpAdd:
|
||||||
case IrBinOpAddWrap:
|
case IrBinOpAddWrap:
|
||||||
case IrBinOpSub:
|
case IrBinOpSub:
|
||||||
|
@ -92,12 +92,14 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
|
|||||||
return "^";
|
return "^";
|
||||||
case IrBinOpBinAnd:
|
case IrBinOpBinAnd:
|
||||||
return "&";
|
return "&";
|
||||||
case IrBinOpBitShiftLeft:
|
case IrBinOpBitShiftLeftLossy:
|
||||||
return "<<";
|
return "<<";
|
||||||
case IrBinOpBitShiftLeftWrap:
|
case IrBinOpBitShiftLeftExact:
|
||||||
return "<<%";
|
return "@shlExact";
|
||||||
case IrBinOpBitShiftRight:
|
case IrBinOpBitShiftRightLossy:
|
||||||
return ">>";
|
return ">>";
|
||||||
|
case IrBinOpBitShiftRightExact:
|
||||||
|
return "@shrExact";
|
||||||
case IrBinOpAdd:
|
case IrBinOpAdd:
|
||||||
return "+";
|
return "+";
|
||||||
case IrBinOpAddWrap:
|
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) {
|
static BinOpType tok_to_bit_shift_op(Token *token) {
|
||||||
switch (token->id) {
|
switch (token->id) {
|
||||||
case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft;
|
case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft;
|
||||||
case TokenIdBitShiftLeftPercent: return BinOpTypeBitShiftLeftWrap;
|
|
||||||
case TokenIdBitShiftRight: return BinOpTypeBitShiftRight;
|
case TokenIdBitShiftRight: return BinOpTypeBitShiftRight;
|
||||||
default: return BinOpTypeInvalid;
|
default: return BinOpTypeInvalid;
|
||||||
}
|
}
|
||||||
@ -1909,7 +1908,6 @@ static BinOpType tok_to_ass_op(Token *token) {
|
|||||||
case TokenIdMinusEq: return BinOpTypeAssignMinus;
|
case TokenIdMinusEq: return BinOpTypeAssignMinus;
|
||||||
case TokenIdMinusPercentEq: return BinOpTypeAssignMinusWrap;
|
case TokenIdMinusPercentEq: return BinOpTypeAssignMinusWrap;
|
||||||
case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft;
|
case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft;
|
||||||
case TokenIdBitShiftLeftPercentEq: return BinOpTypeAssignBitShiftLeftWrap;
|
|
||||||
case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight;
|
case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight;
|
||||||
case TokenIdBitAndEq: return BinOpTypeAssignBitAnd;
|
case TokenIdBitAndEq: return BinOpTypeAssignBitAnd;
|
||||||
case TokenIdBitXorEq: return BinOpTypeAssignBitXor;
|
case TokenIdBitXorEq: return BinOpTypeAssignBitXor;
|
||||||
|
@ -201,7 +201,6 @@ enum TokenizeState {
|
|||||||
TokenizeStateSawBang,
|
TokenizeStateSawBang,
|
||||||
TokenizeStateSawLessThan,
|
TokenizeStateSawLessThan,
|
||||||
TokenizeStateSawLessThanLessThan,
|
TokenizeStateSawLessThanLessThan,
|
||||||
TokenizeStateSawShiftLeftPercent,
|
|
||||||
TokenizeStateSawGreaterThan,
|
TokenizeStateSawGreaterThan,
|
||||||
TokenizeStateSawGreaterThanGreaterThan,
|
TokenizeStateSawGreaterThanGreaterThan,
|
||||||
TokenizeStateSawDot,
|
TokenizeStateSawDot,
|
||||||
@ -673,24 +672,6 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
end_token(&t);
|
end_token(&t);
|
||||||
t.state = TokenizeStateStart;
|
t.state = TokenizeStateStart;
|
||||||
break;
|
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:
|
default:
|
||||||
t.pos -= 1;
|
t.pos -= 1;
|
||||||
end_token(&t);
|
end_token(&t);
|
||||||
@ -1410,7 +1391,6 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
case TokenizeStateSawStarPercent:
|
case TokenizeStateSawStarPercent:
|
||||||
case TokenizeStateSawPlusPercent:
|
case TokenizeStateSawPlusPercent:
|
||||||
case TokenizeStateSawMinusPercent:
|
case TokenizeStateSawMinusPercent:
|
||||||
case TokenizeStateSawShiftLeftPercent:
|
|
||||||
case TokenizeStateLineString:
|
case TokenizeStateLineString:
|
||||||
case TokenizeStateLineStringEnd:
|
case TokenizeStateLineStringEnd:
|
||||||
end_token(&t);
|
end_token(&t);
|
||||||
@ -1451,8 +1431,6 @@ const char * token_name(TokenId id) {
|
|||||||
case TokenIdBitOrEq: return "|=";
|
case TokenIdBitOrEq: return "|=";
|
||||||
case TokenIdBitShiftLeft: return "<<";
|
case TokenIdBitShiftLeft: return "<<";
|
||||||
case TokenIdBitShiftLeftEq: return "<<=";
|
case TokenIdBitShiftLeftEq: return "<<=";
|
||||||
case TokenIdBitShiftLeftPercent: return "<<%";
|
|
||||||
case TokenIdBitShiftLeftPercentEq: return "<<%=";
|
|
||||||
case TokenIdBitShiftRight: return ">>";
|
case TokenIdBitShiftRight: return ">>";
|
||||||
case TokenIdBitShiftRightEq: return ">>=";
|
case TokenIdBitShiftRightEq: return ">>=";
|
||||||
case TokenIdBitXorEq: return "^=";
|
case TokenIdBitXorEq: return "^=";
|
||||||
|
@ -23,8 +23,6 @@ enum TokenId {
|
|||||||
TokenIdBitOrEq,
|
TokenIdBitOrEq,
|
||||||
TokenIdBitShiftLeft,
|
TokenIdBitShiftLeft,
|
||||||
TokenIdBitShiftLeftEq,
|
TokenIdBitShiftLeftEq,
|
||||||
TokenIdBitShiftLeftPercent,
|
|
||||||
TokenIdBitShiftLeftPercentEq,
|
|
||||||
TokenIdBitShiftRight,
|
TokenIdBitShiftRight,
|
||||||
TokenIdBitShiftRightEq,
|
TokenIdBitShiftRightEq,
|
||||||
TokenIdBitXorEq,
|
TokenIdBitXorEq,
|
||||||
|
@ -754,9 +754,22 @@ LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMVa
|
|||||||
LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
||||||
const char *name)
|
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"
|
#include "buffer.hpp"
|
||||||
|
|
||||||
bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag_buf) {
|
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);
|
const char *name);
|
||||||
LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
||||||
const char *name);
|
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,
|
ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type,
|
||||||
uint64_t size_in_bits, uint64_t align_in_bits, const char *name);
|
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];
|
dest[out_index] = alphabet[(source[i] >> 2) & 0x3f];
|
||||||
out_index += 1;
|
out_index += 1;
|
||||||
|
|
||||||
dest[out_index] = alphabet[((source[i] & 0x3) <<% 4) |
|
dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
|
||||||
((source[i + 1] & 0xf0) >> 4)];
|
((source[i + 1] & 0xf0) >> 4)];
|
||||||
out_index += 1;
|
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)];
|
((source[i + 2] & 0xc0) >> 6)];
|
||||||
out_index += 1;
|
out_index += 1;
|
||||||
|
|
||||||
@ -38,17 +38,17 @@ pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8)
|
|||||||
out_index += 1;
|
out_index += 1;
|
||||||
|
|
||||||
if (i + 1 == source.len) {
|
if (i + 1 == source.len) {
|
||||||
dest[out_index] = alphabet[(source[i] & 0x3) <<% 4];
|
dest[out_index] = alphabet[(source[i] & 0x3) << 4];
|
||||||
out_index += 1;
|
out_index += 1;
|
||||||
|
|
||||||
dest[out_index] = alphabet[64];
|
dest[out_index] = alphabet[64];
|
||||||
out_index += 1;
|
out_index += 1;
|
||||||
} else {
|
} else {
|
||||||
dest[out_index] = alphabet[((source[i] & 0x3) <<% 4) |
|
dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
|
||||||
((source[i + 1] & 0xf0) >> 4)];
|
((source[i + 1] & 0xf0) >> 4)];
|
||||||
out_index += 1;
|
out_index += 1;
|
||||||
|
|
||||||
dest[out_index] = alphabet[(source[i + 1] & 0xf) <<% 2];
|
dest[out_index] = alphabet[(source[i + 1] & 0xf) << 2];
|
||||||
out_index += 1;
|
out_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,15 +83,15 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (in_buf_len > 4) {
|
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;
|
ascii6[source[src_index + 1]] >> 4;
|
||||||
dest_index += 1;
|
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;
|
ascii6[source[src_index + 2]] >> 2;
|
||||||
dest_index += 1;
|
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]];
|
ascii6[source[src_index + 3]];
|
||||||
dest_index += 1;
|
dest_index += 1;
|
||||||
|
|
||||||
@ -100,17 +100,17 @@ pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (in_buf_len > 1) {
|
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;
|
ascii6[source[src_index + 1]] >> 4;
|
||||||
dest_index += 1;
|
dest_index += 1;
|
||||||
}
|
}
|
||||||
if (in_buf_len > 2) {
|
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;
|
ascii6[source[src_index + 2]] >> 2;
|
||||||
dest_index += 1;
|
dest_index += 1;
|
||||||
}
|
}
|
||||||
if (in_buf_len > 3) {
|
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]];
|
ascii6[source[src_index + 3]];
|
||||||
dest_index += 1;
|
dest_index += 1;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ fn exp2_32(x: f32) -> f32 {
|
|||||||
const k = i0 / tblsiz;
|
const k = i0 / tblsiz;
|
||||||
// NOTE: musl relies on undefined overflow shift behaviour. Appears that this produces the
|
// 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.
|
// 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;
|
i0 &= tblsiz - 1;
|
||||||
uf -= redux;
|
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) {
|
if (k < 0 or k > 56) {
|
||||||
var y = x - e + 1.0;
|
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) {
|
if (k < 0 or k > 56) {
|
||||||
var y = x - e + 1.0;
|
var y = x - e + 1.0;
|
||||||
|
@ -49,7 +49,7 @@ fn ilogb32(x: f32) -> i32 {
|
|||||||
|
|
||||||
if (e == 0xFF) {
|
if (e == 0xFF) {
|
||||||
math.raiseInvalid();
|
math.raiseInvalid();
|
||||||
if (u <<% 9 != 0) {
|
if (u << 9 != 0) {
|
||||||
return fp_ilogbnan;
|
return fp_ilogbnan;
|
||||||
} else {
|
} else {
|
||||||
return @maxValue(i32);
|
return @maxValue(i32);
|
||||||
@ -84,7 +84,7 @@ fn ilogb64(x: f64) -> i32 {
|
|||||||
|
|
||||||
if (e == 0x7FF) {
|
if (e == 0x7FF) {
|
||||||
math.raiseInvalid();
|
math.raiseInvalid();
|
||||||
if (u <<% 12 != 0) {
|
if (u << 12 != 0) {
|
||||||
return fp_ilogbnan;
|
return fp_ilogbnan;
|
||||||
} else {
|
} else {
|
||||||
return @maxValue(i32);
|
return @maxValue(i32);
|
||||||
|
@ -36,7 +36,7 @@ fn lnf(x_: f32) -> f32 {
|
|||||||
// x < 2^(-126)
|
// x < 2^(-126)
|
||||||
if (ix < 0x00800000 or ix >> 31 != 0) {
|
if (ix < 0x00800000 or ix >> 31 != 0) {
|
||||||
// log(+-0) = -inf
|
// log(+-0) = -inf
|
||||||
if (ix <<% 1 == 0) {
|
if (ix << 1 == 0) {
|
||||||
return -math.inf(f32);
|
return -math.inf(f32);
|
||||||
}
|
}
|
||||||
// log(-#) = nan
|
// log(-#) = nan
|
||||||
@ -91,7 +91,7 @@ fn lnd(x_: f64) -> f64 {
|
|||||||
|
|
||||||
if (hx < 0x00100000 or hx >> 31 != 0) {
|
if (hx < 0x00100000 or hx >> 31 != 0) {
|
||||||
// log(+-0) = -inf
|
// log(+-0) = -inf
|
||||||
if (ix <<% 1 == 0) {
|
if (ix << 1 == 0) {
|
||||||
return -math.inf(f64);
|
return -math.inf(f64);
|
||||||
}
|
}
|
||||||
// log(-#) = nan
|
// log(-#) = nan
|
||||||
|
@ -38,7 +38,7 @@ fn log10_32(x_: f32) -> f32 {
|
|||||||
// x < 2^(-126)
|
// x < 2^(-126)
|
||||||
if (ix < 0x00800000 or ix >> 31 != 0) {
|
if (ix < 0x00800000 or ix >> 31 != 0) {
|
||||||
// log(+-0) = -inf
|
// log(+-0) = -inf
|
||||||
if (ix <<% 1 == 0) {
|
if (ix << 1 == 0) {
|
||||||
return -math.inf(f32);
|
return -math.inf(f32);
|
||||||
}
|
}
|
||||||
// log(-#) = nan
|
// log(-#) = nan
|
||||||
@ -100,7 +100,7 @@ fn log10_64(x_: f64) -> f64 {
|
|||||||
|
|
||||||
if (hx < 0x00100000 or hx >> 31 != 0) {
|
if (hx < 0x00100000 or hx >> 31 != 0) {
|
||||||
// log(+-0) = -inf
|
// log(+-0) = -inf
|
||||||
if (ix <<% 1 == 0) {
|
if (ix << 1 == 0) {
|
||||||
return -math.inf(f32);
|
return -math.inf(f32);
|
||||||
}
|
}
|
||||||
// log(-#) = nan
|
// log(-#) = nan
|
||||||
@ -139,7 +139,7 @@ fn log10_64(x_: f64) -> f64 {
|
|||||||
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
||||||
var hi = f - hfsq;
|
var hi = f - hfsq;
|
||||||
var hii = @bitCast(u64, hi);
|
var hii = @bitCast(u64, hi);
|
||||||
hii &= u64(@maxValue(u64)) <<% 32;
|
hii &= u64(@maxValue(u64)) << 32;
|
||||||
hi = @bitCast(f64, hii);
|
hi = @bitCast(f64, hii);
|
||||||
const lo = f - hi - hfsq + s * (hfsq + R);
|
const lo = f - hi - hfsq + s * (hfsq + R);
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ fn log1p_32(x: f32) -> f32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// |x| < 2^(-24)
|
// |x| < 2^(-24)
|
||||||
if ((ix <<% 1) < (0x33800000 << 1)) {
|
if ((ix << 1) < (0x33800000 << 1)) {
|
||||||
// underflow if subnormal
|
// underflow if subnormal
|
||||||
if (ix & 0x7F800000 == 0) {
|
if (ix & 0x7F800000 == 0) {
|
||||||
math.forceEval(x * x);
|
math.forceEval(x * x);
|
||||||
@ -128,7 +128,7 @@ fn log1p_64(x: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// |x| < 2^(-53)
|
// |x| < 2^(-53)
|
||||||
if ((hx <<% 1) < (0x3CA00000 << 1)) {
|
if ((hx << 1) < (0x3CA00000 << 1)) {
|
||||||
if ((hx & 0x7FF00000) == 0) {
|
if ((hx & 0x7FF00000) == 0) {
|
||||||
math.raiseUnderflow();
|
math.raiseUnderflow();
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ fn log2_32(x_: f32) -> f32 {
|
|||||||
// x < 2^(-126)
|
// x < 2^(-126)
|
||||||
if (ix < 0x00800000 or ix >> 31 != 0) {
|
if (ix < 0x00800000 or ix >> 31 != 0) {
|
||||||
// log(+-0) = -inf
|
// log(+-0) = -inf
|
||||||
if (ix <<% 1 == 0) {
|
if (ix << 1 == 0) {
|
||||||
return -math.inf(f32);
|
return -math.inf(f32);
|
||||||
}
|
}
|
||||||
// log(-#) = nan
|
// log(-#) = nan
|
||||||
@ -94,7 +94,7 @@ fn log2_64(x_: f64) -> f64 {
|
|||||||
|
|
||||||
if (hx < 0x00100000 or hx >> 31 != 0) {
|
if (hx < 0x00100000 or hx >> 31 != 0) {
|
||||||
// log(+-0) = -inf
|
// log(+-0) = -inf
|
||||||
if (ix <<% 1 == 0) {
|
if (ix << 1 == 0) {
|
||||||
return -math.inf(f64);
|
return -math.inf(f64);
|
||||||
}
|
}
|
||||||
// log(-#) = nan
|
// log(-#) = nan
|
||||||
@ -133,7 +133,7 @@ fn log2_64(x_: f64) -> f64 {
|
|||||||
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
||||||
var hi = f - hfsq;
|
var hi = f - hfsq;
|
||||||
var hii = @bitCast(u64, hi);
|
var hii = @bitCast(u64, hi);
|
||||||
hii &= u64(@maxValue(u64)) <<% 32;
|
hii &= u64(@maxValue(u64)) << 32;
|
||||||
hi = @bitCast(f64, hii);
|
hi = @bitCast(f64, hii);
|
||||||
const lo = f - hi - hfsq + s * (hfsq + R);
|
const lo = f - hi - hfsq + s * (hfsq + R);
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ fn modf32(x: f32) -> modf32_result {
|
|||||||
// no fractional part
|
// no fractional part
|
||||||
if (e >= 23) {
|
if (e >= 23) {
|
||||||
result.ipart = x;
|
result.ipart = x;
|
||||||
if (e == 0x80 and u <<% 9 != 0) { // nan
|
if (e == 0x80 and u << 9 != 0) { // nan
|
||||||
result.fpart = x;
|
result.fpart = x;
|
||||||
} else {
|
} else {
|
||||||
result.fpart = @bitCast(f32, us);
|
result.fpart = @bitCast(f32, us);
|
||||||
@ -88,7 +88,7 @@ fn modf64(x: f64) -> modf64_result {
|
|||||||
// no fractional part
|
// no fractional part
|
||||||
if (e >= 52) {
|
if (e >= 52) {
|
||||||
result.ipart = x;
|
result.ipart = x;
|
||||||
if (e == 0x400 and u <<% 12 != 0) { // nan
|
if (e == 0x400 and u << 12 != 0) { // nan
|
||||||
result.fpart = x;
|
result.fpart = x;
|
||||||
} else {
|
} else {
|
||||||
result.fpart = @bitCast(f64, us);
|
result.fpart = @bitCast(f64, us);
|
||||||
|
@ -182,8 +182,8 @@ fn MersenneTwister(
|
|||||||
mt.index += 1;
|
mt.index += 1;
|
||||||
|
|
||||||
x ^= ((x >> u) & d);
|
x ^= ((x >> u) & d);
|
||||||
x ^= ((x <<% s) & b);
|
x ^= ((x << s) & b);
|
||||||
x ^= ((x <<% t) & c);
|
x ^= ((x << t) & c);
|
||||||
x ^= (x >> l);
|
x ^= (x >> l);
|
||||||
|
|
||||||
return x;
|
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);
|
const sx = if (T == f32) u32(ux & 0x80000000) else i32(ux >> bits_minus_1);
|
||||||
var i: uint = undefined;
|
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);
|
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 0 * x;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize x and y
|
// normalize x and y
|
||||||
if (ex == 0) {
|
if (ex == 0) {
|
||||||
i = ux <<% exp_bits;
|
i = ux << exp_bits;
|
||||||
while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<%= 1}) {}
|
while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<= 1}) {}
|
||||||
ux <<%= @bitCast(u32, -ex + 1);
|
ux <<= @bitCast(u32, -ex + 1);
|
||||||
} else {
|
} else {
|
||||||
ux &= @maxValue(uint) >> exp_bits;
|
ux &= @maxValue(uint) >> exp_bits;
|
||||||
ux |= 1 <<% digits;
|
ux |= 1 << digits;
|
||||||
}
|
}
|
||||||
if (ey == 0) {
|
if (ey == 0) {
|
||||||
i = uy <<% exp_bits;
|
i = uy << exp_bits;
|
||||||
while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<%= 1}) {}
|
while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<= 1}) {}
|
||||||
uy <<= @bitCast(u32, -ey + 1);
|
uy <<= @bitCast(u32, -ey + 1);
|
||||||
} else {
|
} else {
|
||||||
uy &= @maxValue(uint) >> exp_bits;
|
uy &= @maxValue(uint) >> exp_bits;
|
||||||
uy |= 1 <<% digits;
|
uy |= 1 << digits;
|
||||||
}
|
}
|
||||||
|
|
||||||
// x mod y
|
// x mod y
|
||||||
@ -82,7 +82,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
|||||||
return 0 * x;
|
return 0 * x;
|
||||||
ux = i;
|
ux = i;
|
||||||
}
|
}
|
||||||
ux <<%= 1;
|
ux <<= 1;
|
||||||
}
|
}
|
||||||
i = ux -% uy;
|
i = ux -% uy;
|
||||||
if (i >> bits_minus_1 == 0) {
|
if (i >> bits_minus_1 == 0) {
|
||||||
@ -90,19 +90,19 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
|
|||||||
return 0 * x;
|
return 0 * x;
|
||||||
ux = i;
|
ux = i;
|
||||||
}
|
}
|
||||||
while (ux >> digits == 0) : ({ux <<%= 1; ex -= 1}) {}
|
while (ux >> digits == 0) : ({ux <<= 1; ex -= 1}) {}
|
||||||
|
|
||||||
// scale result up
|
// scale result up
|
||||||
if (ex > 0) {
|
if (ex > 0) {
|
||||||
ux -%= 1 <<% digits;
|
ux -%= 1 << digits;
|
||||||
ux |= @bitCast(u32, ex) <<% digits;
|
ux |= @bitCast(u32, ex) << digits;
|
||||||
} else {
|
} else {
|
||||||
ux >>= @bitCast(u32, -ex + 1);
|
ux >>= @bitCast(u32, -ex + 1);
|
||||||
}
|
}
|
||||||
if (T == f32) {
|
if (T == f32) {
|
||||||
ux |= sx;
|
ux |= sx;
|
||||||
} else {
|
} else {
|
||||||
ux |= uint(sx) <<% bits_minus_1;
|
ux |= uint(sx) << bits_minus_1;
|
||||||
}
|
}
|
||||||
return *@ptrCast(&const T, &ux);
|
return *@ptrCast(&const T, &ux);
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ fn isNan(comptime T: type, bits: T) -> bool {
|
|||||||
if (T == u32) {
|
if (T == u32) {
|
||||||
return (bits & 0x7fffffff) > 0x7f800000;
|
return (bits & 0x7fffffff) > 0x7f800000;
|
||||||
} else if (T == u64) {
|
} else if (T == u64) {
|
||||||
return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) <<% 52);
|
return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52);
|
||||||
} else {
|
} else {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
@ -168,15 +168,6 @@ fn testNegationWrappingEval(x: i16) {
|
|||||||
assert(neg == -32768);
|
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 "unsigned 64-bit division" {
|
||||||
test_u64_div();
|
test_u64_div();
|
||||||
comptime test_u64_div();
|
comptime test_u64_div();
|
||||||
@ -257,3 +248,39 @@ test "hex float literal within range" {
|
|||||||
const b = 0x0.1p1027;
|
const b = 0x0.1p1027;
|
||||||
const c = 0x1.0p-1022;
|
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'");
|
".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;
|
\\ if (x == 0) return error.Whatever;
|
||||||
\\}
|
\\}
|
||||||
\\fn shl(a: i16, b: i16) -> i16 {
|
\\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;
|
\\ if (x == 0) return error.Whatever;
|
||||||
\\}
|
\\}
|
||||||
\\fn shl(a: u16, b: u16) -> u16 {
|
\\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