aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-08-19 01:32:15 -0400
committerAndrew Kelley <superjoe30@gmail.com>2017-08-19 01:43:43 -0400
commit987768778a67538299f84a6ab7ff0ca65f69d2ac (patch)
tree2e7551d76bf9a3e6d242a961eacf7c81aab6025f /src/ir.cpp
parent558ece8f6f1889bc4773432c16cdf96a54ec1431 (diff)
downloadzig-987768778a67538299f84a6ab7ff0ca65f69d2ac.tar.gz
zig-987768778a67538299f84a6ab7ff0ca65f69d2ac.zip
bit shifting safety
* add u3, u4, u5, u6, u7 and i3, i4, i5, i6, i7 * shift operations shift amount parameter type is integer with log2 bit width of other param - This enforces not violating undefined behavior on shift amount >= bit width with the type system * clean up math.log, math.ln, math.log2, math.log10 closes #403
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp91
1 files changed, 81 insertions, 10 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index 57b7f07c20..065af2ed81 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -8510,6 +8510,73 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,
return 0;
}
+static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
+ IrInstruction *op1 = bin_op_instruction->op1->other;
+ if (type_is_invalid(op1->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (op1->value.type->id != TypeTableEntryIdInt && op1->value.type->id != TypeTableEntryIdNumLitInt) {
+ ir_add_error(ira, &bin_op_instruction->base,
+ buf_sprintf("bit shifting operation expected integer type, found '%s'",
+ buf_ptr(&op1->value.type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ IrInstruction *op2 = bin_op_instruction->op2->other;
+ if (type_is_invalid(op2->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *casted_op2;
+ IrBinOp op_id = bin_op_instruction->op_id;
+ if (op1->value.type->id == TypeTableEntryIdNumLitInt) {
+ casted_op2 = op2;
+
+ if (op_id == IrBinOpBitShiftLeftLossy) {
+ op_id = IrBinOpBitShiftLeftExact;
+ }
+ } else {
+ TypeTableEntry *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
+ op1->value.type->data.integral.bit_count - 1);
+
+ casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);
+ if (casted_op2 == ira->codegen->invalid_instruction)
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) {
+ ConstExprValue *op1_val = &op1->value;
+ ConstExprValue *op2_val = &casted_op2->value;
+ ConstExprValue *out_val = &bin_op_instruction->base.value;
+
+ bin_op_instruction->base.other = &bin_op_instruction->base;
+
+ int err;
+ if ((err = ir_eval_math_op(op1->value.type, op1_val, op_id, op2_val, out_val))) {
+ if (err == ErrorOverflow) {
+ ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("operation caused overflow"));
+ 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();
+ }
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ ir_num_lit_fits_in_other_type(ira, &bin_op_instruction->base, op1->value.type, false);
+ return op1->value.type;
+ } else if (op1->value.type->id == TypeTableEntryIdNumLitInt) {
+ ir_add_error(ira, &bin_op_instruction->base,
+ buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id,
+ op1, casted_op2, bin_op_instruction->safety_check_on);
+ return op1->value.type;
+}
+
static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
IrInstruction *op1 = bin_op_instruction->op1->other;
IrInstruction *op2 = bin_op_instruction->op2->other;
@@ -8626,9 +8693,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
}
if (resolved_type->id == TypeTableEntryIdNumLitInt) {
- if (op_id == IrBinOpBitShiftLeftLossy) {
- op_id = IrBinOpBitShiftLeftExact;
- } else if (op_id == IrBinOpAddWrap) {
+ if (op_id == IrBinOpAddWrap) {
op_id = IrBinOpAdd;
} else if (op_id == IrBinOpSubWrap) {
op_id = IrBinOpSub;
@@ -8666,9 +8731,6 @@ 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();
}
@@ -8892,13 +8954,14 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
case IrBinOpCmpLessOrEq:
case IrBinOpCmpGreaterOrEq:
return ir_analyze_bin_op_cmp(ira, bin_op_instruction);
- case IrBinOpBinOr:
- case IrBinOpBinXor:
- case IrBinOpBinAnd:
case IrBinOpBitShiftLeftLossy:
case IrBinOpBitShiftLeftExact:
case IrBinOpBitShiftRightLossy:
case IrBinOpBitShiftRightExact:
+ return ir_analyze_bit_shift(ira, bin_op_instruction);
+ case IrBinOpBinOr:
+ case IrBinOpBinXor:
+ case IrBinOpBinAnd:
case IrBinOpAdd:
case IrBinOpAddWrap:
case IrBinOpSub:
@@ -13171,6 +13234,7 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst
IrInstruction *type_value = instruction->type_value->other;
if (type_is_invalid(type_value->value.type))
return ira->codegen->builtin_types.entry_invalid;
+
TypeTableEntry *dest_type = ir_resolve_type(ira, type_value);
if (type_is_invalid(dest_type))
return ira->codegen->builtin_types.entry_invalid;
@@ -13193,7 +13257,14 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst
if (type_is_invalid(op2->value.type))
return ira->codegen->builtin_types.entry_invalid;
- IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, dest_type);
+ IrInstruction *casted_op2;
+ if (instruction->op == IrOverflowOpShl) {
+ TypeTableEntry *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
+ dest_type->data.integral.bit_count - 1);
+ casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);
+ } else {
+ casted_op2 = ir_implicit_cast(ira, op2, dest_type);
+ }
if (type_is_invalid(casted_op2->value.type))
return ira->codegen->builtin_types.entry_invalid;