authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-06 15:46:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-06 15:46:38-07:00
log100802cdc0a898b948d30b464ac2348be1928080
tree00aea62fb0d7a5b63637fc7a73f3f3be47f70fc8
parent0c96920172dee530f445e4ef304954d0fe233bfa

add debug safety for left shifting

See #46

4 files changed, 79 insertions(+), 5 deletions(-)

src/codegen.cpp+41-2
...@@ -440,7 +440,7 @@ static LLVMValueRef gen_cmp_exchange(CodeGen *g, AstNode *node) {...@@ -440,7 +440,7 @@ static LLVMValueRef gen_cmp_exchange(CodeGen *g, AstNode *node) {
440 LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering((AtomicOrder)failure_order_val->data.x_enum.tag);440 LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering((AtomicOrder)failure_order_val->data.x_enum.tag);
441441
442 LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,442 LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
443 success_order, failure_order, "");443 success_order, failure_order);
444444
445 return LLVMBuildExtractValue(g->builder, result_val, 1, "");445 return LLVMBuildExtractValue(g->builder, result_val, 1, "");
446}446}
...@@ -1309,6 +1309,36 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS...@@ -1309,6 +1309,36 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS
1309 return result;1309 return result;
1310}1310}
13111311
1312static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
1313 LLVMValueRef val1, LLVMValueRef val2)
1314{
1315 // for unsigned left shifting, we do the wrapping shift, then logically shift
1316 // right the same number of bits
1317 // if the values don't match, we have an overflow
1318 // for signed left shifting we do the same except arithmetic shift right
1319
1320 assert(type_entry->id == TypeTableEntryIdInt);
1321
1322 LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
1323 LLVMValueRef orig_val;
1324 if (type_entry->data.integral.is_signed) {
1325 orig_val = LLVMBuildAShr(g->builder, result, val2, "");
1326 } else {
1327 orig_val = LLVMBuildLShr(g->builder, result, val2, "");
1328 }
1329 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
1330
1331 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
1332 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
1333 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
1334
1335 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1336 gen_debug_safety_crash(g);
1337
1338 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1339 return result;
1340}
1341
1312static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {1342static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
1313 assert(node->type == NodeTypePrefixOpExpr);1343 assert(node->type == NodeTypePrefixOpExpr);
1314 assert(node->data.prefix_op_expr.primary_expr);1344 assert(node->data.prefix_op_expr.primary_expr);
...@@ -1484,7 +1514,16 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,...@@ -1484,7 +1514,16 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
1484 case BinOpTypeBitShiftLeft:1514 case BinOpTypeBitShiftLeft:
1485 case BinOpTypeAssignBitShiftLeft:1515 case BinOpTypeAssignBitShiftLeft:
1486 set_debug_source_node(g, source_node);1516 set_debug_source_node(g, source_node);
1487 return LLVMBuildShl(g->builder, val1, val2, "");1517 assert(op1_type->id == TypeTableEntryIdInt);
1518 if (op1_type->data.integral.is_wrapping) {
1519 return LLVMBuildShl(g->builder, val1, val2, "");
1520 } else if (want_debug_safety(g, source_node)) {
1521 return gen_overflow_shl_op(g, op1_type, val1, val2);
1522 } else if (op1_type->data.integral.is_signed) {
1523 return ZigLLVMBuildNSWShl(g->builder, val1, val2, "");
1524 } else {
1525 return ZigLLVMBuildNUWShl(g->builder, val1, val2, "");
1526 }
1488 case BinOpTypeBitShiftRight:1527 case BinOpTypeBitShiftRight:
1489 case BinOpTypeAssignBitShiftRight:1528 case BinOpTypeAssignBitShiftRight:
1490 assert(op1_type->id == TypeTableEntryIdInt);1529 assert(op1_type->id == TypeTableEntryIdInt);
src/zig_llvm.cpp+13-2
...@@ -661,14 +661,25 @@ static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {...@@ -661,14 +661,25 @@ static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {
661661
662LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,662LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
663 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,663 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
664 LLVMAtomicOrdering failure_ordering,664 LLVMAtomicOrdering failure_ordering)
665 const char *name)
666{665{
667 return wrap(unwrap(builder)->CreateAtomicCmpXchg(unwrap(ptr), unwrap(cmp), unwrap(new_val),666 return wrap(unwrap(builder)->CreateAtomicCmpXchg(unwrap(ptr), unwrap(cmp), unwrap(new_val),
668 mapFromLLVMOrdering(success_ordering), mapFromLLVMOrdering(failure_ordering),667 mapFromLLVMOrdering(success_ordering), mapFromLLVMOrdering(failure_ordering),
669 CrossThread));668 CrossThread));
670}669}
671670
671LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
672 const char *name)
673{
674 return wrap(unwrap(builder)->CreateShl(unwrap(LHS), unwrap(RHS), name, false, true));
675}
676
677LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
678 const char *name)
679{
680 return wrap(unwrap(builder)->CreateShl(unwrap(LHS), unwrap(RHS), name, false, true));
681}
682
672683
673//------------------------------------684//------------------------------------
674685
src/zig_llvm.hpp+5-1
...@@ -41,7 +41,11 @@ LLVMValueRef LLVMZigBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *A...@@ -41,7 +41,11 @@ LLVMValueRef LLVMZigBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *A
4141
42LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,42LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
43 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,43 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
44 LLVMAtomicOrdering failure_ordering,44 LLVMAtomicOrdering failure_ordering);
45
46LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
47 const char *name);
48LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
45 const char *name);49 const char *name);
4650
47// 0 is return value, 1 is first arg51// 0 is return value, 1 is first arg
test/run_tests.cpp+20
...@@ -1363,6 +1363,26 @@ fn neg(a: i16) -> i16 {...@@ -1363,6 +1363,26 @@ fn neg(a: i16) -> i16 {
1363}1363}
1364 )SOURCE");1364 )SOURCE");
13651365
1366 add_debug_safety_case("signed shift left overflow", R"SOURCE(
1367pub fn main(args: [][]u8) -> %void {
1368 shl(-16385, 1);
1369}
1370#static_eval_enable(false)
1371fn shl(a: i16, b: i16) -> i16 {
1372 a << b
1373}
1374 )SOURCE");
1375
1376 add_debug_safety_case("unsigned shift left overflow", R"SOURCE(
1377pub fn main(args: [][]u8) -> %void {
1378 shl(0b0010111111111111, 3);
1379}
1380#static_eval_enable(false)
1381fn shl(a: u16, b: u16) -> u16 {
1382 a << b
1383}
1384 )SOURCE");
1385
1366}1386}
13671387
1368//////////////////////////////////////////////////////////////////////////////1388//////////////////////////////////////////////////////////////////////////////