authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-11 15:58:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-11 15:58:00-07:00
log1eafc85f1f0643ca2594247615a14b7a34343a14
treed72e400d60d3ef09aaf60b54ba69b15fe7ee3ae4
parent26718a619c572602c21c83b1588e50723447709a

add readonly attribute to relevant functions and parameters


4 files changed, 50 insertions(+), 15 deletions(-)

src/all_types.hpp+8
...@@ -1045,6 +1045,13 @@ enum FnAnalState {...@@ -1045,6 +1045,13 @@ enum FnAnalState {
1045 FnAnalStateSkipped,1045 FnAnalStateSkipped,
1046};1046};
10471047
1048
1049enum WantPure {
1050 WantPureAuto,
1051 WantPureFalse,
1052 WantPureTrue,
1053};
1054
1048struct FnTableEntry {1055struct FnTableEntry {
1049 LLVMValueRef fn_value;1056 LLVMValueRef fn_value;
1050 AstNode *proto_node;1057 AstNode *proto_node;
...@@ -1060,6 +1067,7 @@ struct FnTableEntry {...@@ -1060,6 +1067,7 @@ struct FnTableEntry {
1060 bool is_extern;1067 bool is_extern;
1061 bool is_test;1068 bool is_test;
1062 bool is_pure;1069 bool is_pure;
1070 WantPure want_pure;
1063 bool safety_off;1071 bool safety_off;
1064 bool is_noinline;1072 bool is_noinline;
1065 BlockContext *parent_block_context;1073 BlockContext *parent_block_context;
src/analyze.cpp+3-3
...@@ -1060,7 +1060,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -1060,7 +1060,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
1060 bool ok = resolve_const_expr_bool(g, import, import->block_context,1060 bool ok = resolve_const_expr_bool(g, import, import->block_context,
1061 &directive_node->data.directive.expr, &enable);1061 &directive_node->data.directive.expr, &enable);
1062 if (!enable || !ok) {1062 if (!enable || !ok) {
1063 fn_table_entry->is_pure = false;1063 fn_table_entry->want_pure = WantPureFalse;
1064 }1064 }
1065 // TODO cause compile error if enable is true and impure fn1065 // TODO cause compile error if enable is true and impure fn
1066 }1066 }
...@@ -5153,7 +5153,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,...@@ -5153,7 +5153,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
51535153
5154 FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;5154 FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
5155 ConstExprValue *result_val = &get_resolved_expr(node)->const_val;5155 ConstExprValue *result_val = &get_resolved_expr(node)->const_val;
5156 if (ok_invocation && fn_table_entry && fn_table_entry->is_pure) {5156 if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) {
5157 if (fn_table_entry->anal_state == FnAnalStateReady) {5157 if (fn_table_entry->anal_state == FnAnalStateReady) {
5158 analyze_fn_body(g, fn_table_entry);5158 analyze_fn_body(g, fn_table_entry);
5159 }5159 }
...@@ -5167,7 +5167,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,...@@ -5167,7 +5167,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
5167 }5167 }
5168 }5168 }
5169 }5169 }
5170 if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure) {5170 if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure || fn_table_entry->want_pure == WantPureFalse) {
5171 // calling an impure fn is impure5171 // calling an impure fn is impure
5172 mark_impure_fn(context);5172 mark_impure_fn(context);
5173 }5173 }
src/codegen.cpp+7-1
...@@ -3885,6 +3885,7 @@ static void do_code_gen(CodeGen *g) {...@@ -3885,6 +3885,7 @@ static void do_code_gen(CodeGen *g) {
38853885
3886 TypeTableEntry *fn_type = fn_table_entry->type_entry;3886 TypeTableEntry *fn_type = fn_table_entry->type_entry;
38873887
3888 bool is_sret = false;
3888 if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {3889 if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
3889 // nothing to do3890 // nothing to do
3890 } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) {3891 } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) {
...@@ -3893,7 +3894,12 @@ static void do_code_gen(CodeGen *g) {...@@ -3893,7 +3894,12 @@ static void do_code_gen(CodeGen *g) {
3893 LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);3894 LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
3894 LLVMAddAttribute(first_arg, LLVMStructRetAttribute);3895 LLVMAddAttribute(first_arg, LLVMStructRetAttribute);
3895 LLVMZigAddNonNullAttr(fn_table_entry->fn_value, 1);3896 LLVMZigAddNonNullAttr(fn_table_entry->fn_value, 1);
3897 is_sret = true;
3896 }3898 }
3899 if (fn_table_entry->is_pure && !is_sret) {
3900 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMReadOnlyAttribute);
3901 }
3902
38973903
3898 // set parameter attributes3904 // set parameter attributes
3899 for (int param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) {3905 for (int param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) {
...@@ -3914,7 +3920,7 @@ static void do_code_gen(CodeGen *g) {...@@ -3914,7 +3920,7 @@ static void do_code_gen(CodeGen *g) {
3914 if (param_type->id == TypeTableEntryIdPointer && param_is_noalias) {3920 if (param_type->id == TypeTableEntryIdPointer && param_is_noalias) {
3915 LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);3921 LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
3916 }3922 }
3917 if ((param_type->id == TypeTableEntryIdPointer && param_type->data.pointer.is_const) ||3923 if ((param_type->id == TypeTableEntryIdPointer && (param_type->data.pointer.is_const || fn_table_entry->is_pure)) ||
3918 is_byval)3924 is_byval)
3919 {3925 {
3920 LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);3926 LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);
test/run_tests.cpp+32-11
...@@ -1410,8 +1410,10 @@ fn baz(a: i32) {}...@@ -1410,8 +1410,10 @@ fn baz(a: i32) {}
1410 )SOURCE");1410 )SOURCE");
14111411
1412 add_debug_safety_case("integer addition overflow", R"SOURCE(1412 add_debug_safety_case("integer addition overflow", R"SOURCE(
1413error Whatever;
1413pub fn main(args: [][]u8) -> %void {1414pub fn main(args: [][]u8) -> %void {
1414 add(65530, 10);1415 const x = add(65530, 10);
1416 if (x == 0) return error.Whatever;
1415}1417}
1416#static_eval_enable(false)1418#static_eval_enable(false)
1417fn add(a: u16, b: u16) -> u16 {1419fn add(a: u16, b: u16) -> u16 {
...@@ -1420,8 +1422,10 @@ fn add(a: u16, b: u16) -> u16 {...@@ -1420,8 +1422,10 @@ fn add(a: u16, b: u16) -> u16 {
1420 )SOURCE");1422 )SOURCE");
14211423
1422 add_debug_safety_case("integer subtraction overflow", R"SOURCE(1424 add_debug_safety_case("integer subtraction overflow", R"SOURCE(
1425error Whatever;
1423pub fn main(args: [][]u8) -> %void {1426pub fn main(args: [][]u8) -> %void {
1424 sub(10, 20);1427 const x = sub(10, 20);
1428 if (x == 0) return error.Whatever;
1425}1429}
1426#static_eval_enable(false)1430#static_eval_enable(false)
1427fn sub(a: u16, b: u16) -> u16 {1431fn sub(a: u16, b: u16) -> u16 {
...@@ -1430,8 +1434,10 @@ fn sub(a: u16, b: u16) -> u16 {...@@ -1430,8 +1434,10 @@ fn sub(a: u16, b: u16) -> u16 {
1430 )SOURCE");1434 )SOURCE");
14311435
1432 add_debug_safety_case("integer multiplication overflow", R"SOURCE(1436 add_debug_safety_case("integer multiplication overflow", R"SOURCE(
1437error Whatever;
1433pub fn main(args: [][]u8) -> %void {1438pub fn main(args: [][]u8) -> %void {
1434 mul(300, 6000);1439 const x = mul(300, 6000);
1440 if (x == 0) return error.Whatever;
1435}1441}
1436#static_eval_enable(false)1442#static_eval_enable(false)
1437fn mul(a: u16, b: u16) -> u16 {1443fn mul(a: u16, b: u16) -> u16 {
...@@ -1440,8 +1446,10 @@ fn mul(a: u16, b: u16) -> u16 {...@@ -1440,8 +1446,10 @@ fn mul(a: u16, b: u16) -> u16 {
1440 )SOURCE");1446 )SOURCE");
14411447
1442 add_debug_safety_case("integer negation overflow", R"SOURCE(1448 add_debug_safety_case("integer negation overflow", R"SOURCE(
1449error Whatever;
1443pub fn main(args: [][]u8) -> %void {1450pub fn main(args: [][]u8) -> %void {
1444 neg(-32768);1451 const x = neg(-32768);
1452 if (x == 0) return error.Whatever;
1445}1453}
1446#static_eval_enable(false)1454#static_eval_enable(false)
1447fn neg(a: i16) -> i16 {1455fn neg(a: i16) -> i16 {
...@@ -1450,8 +1458,10 @@ fn neg(a: i16) -> i16 {...@@ -1450,8 +1458,10 @@ fn neg(a: i16) -> i16 {
1450 )SOURCE");1458 )SOURCE");
14511459
1452 add_debug_safety_case("signed shift left overflow", R"SOURCE(1460 add_debug_safety_case("signed shift left overflow", R"SOURCE(
1461error Whatever;
1453pub fn main(args: [][]u8) -> %void {1462pub fn main(args: [][]u8) -> %void {
1454 shl(-16385, 1);1463 const x = shl(-16385, 1);
1464 if (x == 0) return error.Whatever;
1455}1465}
1456#static_eval_enable(false)1466#static_eval_enable(false)
1457fn shl(a: i16, b: i16) -> i16 {1467fn shl(a: i16, b: i16) -> i16 {
...@@ -1460,8 +1470,10 @@ fn shl(a: i16, b: i16) -> i16 {...@@ -1460,8 +1470,10 @@ fn shl(a: i16, b: i16) -> i16 {
1460 )SOURCE");1470 )SOURCE");
14611471
1462 add_debug_safety_case("unsigned shift left overflow", R"SOURCE(1472 add_debug_safety_case("unsigned shift left overflow", R"SOURCE(
1473error Whatever;
1463pub fn main(args: [][]u8) -> %void {1474pub fn main(args: [][]u8) -> %void {
1464 shl(0b0010111111111111, 3);1475 const x = shl(0b0010111111111111, 3);
1476 if (x == 0) return error.Whatever;
1465}1477}
1466#static_eval_enable(false)1478#static_eval_enable(false)
1467fn shl(a: u16, b: u16) -> u16 {1479fn shl(a: u16, b: u16) -> u16 {
...@@ -1470,8 +1482,9 @@ fn shl(a: u16, b: u16) -> u16 {...@@ -1470,8 +1482,9 @@ fn shl(a: u16, b: u16) -> u16 {
1470 )SOURCE");1482 )SOURCE");
14711483
1472 add_debug_safety_case("integer division by zero", R"SOURCE(1484 add_debug_safety_case("integer division by zero", R"SOURCE(
1485error Whatever;
1473pub fn main(args: [][]u8) -> %void {1486pub fn main(args: [][]u8) -> %void {
1474 div0(999, 0);1487 const x = div0(999, 0);
1475}1488}
1476#static_eval_enable(false)1489#static_eval_enable(false)
1477fn div0(a: i32, b: i32) -> i32 {1490fn div0(a: i32, b: i32) -> i32 {
...@@ -1480,8 +1493,10 @@ fn div0(a: i32, b: i32) -> i32 {...@@ -1480,8 +1493,10 @@ fn div0(a: i32, b: i32) -> i32 {
1480 )SOURCE");1493 )SOURCE");
14811494
1482 add_debug_safety_case("exact division failure", R"SOURCE(1495 add_debug_safety_case("exact division failure", R"SOURCE(
1496error Whatever;
1483pub fn main(args: [][]u8) -> %void {1497pub fn main(args: [][]u8) -> %void {
1484 div_exact(10, 3);1498 const x = div_exact(10, 3);
1499 if (x == 0) return error.Whatever;
1485}1500}
1486#static_eval_enable(false)1501#static_eval_enable(false)
1487fn div_exact(a: i32, b: i32) -> i32 {1502fn div_exact(a: i32, b: i32) -> i32 {
...@@ -1490,8 +1505,10 @@ fn div_exact(a: i32, b: i32) -> i32 {...@@ -1490,8 +1505,10 @@ fn div_exact(a: i32, b: i32) -> i32 {
1490 )SOURCE");1505 )SOURCE");
14911506
1492 add_debug_safety_case("cast []u8 to bigger slice of wrong size", R"SOURCE(1507 add_debug_safety_case("cast []u8 to bigger slice of wrong size", R"SOURCE(
1508error Whatever;
1493pub fn main(args: [][]u8) -> %void {1509pub fn main(args: [][]u8) -> %void {
1494 widen_slice([]u8{1, 2, 3, 4, 5});1510 const x = widen_slice([]u8{1, 2, 3, 4, 5});
1511 if (x.len == 0) return error.Whatever;
1495}1512}
1496#static_eval_enable(false)1513#static_eval_enable(false)
1497fn widen_slice(slice: []u8) -> []i32 {1514fn widen_slice(slice: []u8) -> []i32 {
...@@ -1500,8 +1517,10 @@ fn widen_slice(slice: []u8) -> []i32 {...@@ -1500,8 +1517,10 @@ fn widen_slice(slice: []u8) -> []i32 {
1500 )SOURCE");1517 )SOURCE");
15011518
1502 add_debug_safety_case("value does not fit in shortening cast", R"SOURCE(1519 add_debug_safety_case("value does not fit in shortening cast", R"SOURCE(
1520error Whatever;
1503pub fn main(args: [][]u8) -> %void {1521pub fn main(args: [][]u8) -> %void {
1504 shorten_cast(200);1522 const x = shorten_cast(200);
1523 if (x == 0) return error.Whatever;
1505}1524}
1506#static_eval_enable(false)1525#static_eval_enable(false)
1507fn shorten_cast(x: i32) -> i8 {1526fn shorten_cast(x: i32) -> i8 {
...@@ -1510,8 +1529,10 @@ fn shorten_cast(x: i32) -> i8 {...@@ -1510,8 +1529,10 @@ fn shorten_cast(x: i32) -> i8 {
1510 )SOURCE");1529 )SOURCE");
15111530
1512 add_debug_safety_case("signed integer not fitting in cast to unsigned integer", R"SOURCE(1531 add_debug_safety_case("signed integer not fitting in cast to unsigned integer", R"SOURCE(
1532error Whatever;
1513pub fn main(args: [][]u8) -> %void {1533pub fn main(args: [][]u8) -> %void {
1514 unsigned_cast(-10);1534 const x = unsigned_cast(-10);
1535 if (x == 0) return error.Whatever;
1515}1536}
1516#static_eval_enable(false)1537#static_eval_enable(false)
1517fn unsigned_cast(x: i32) -> u32 {1538fn unsigned_cast(x: i32) -> u32 {