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 {
10451045 FnAnalStateSkipped,
10461046};
10471047
1048
1049enum WantPure {
1050 WantPureAuto,
1051 WantPureFalse,
1052 WantPureTrue,
1053};
1054
10481055struct FnTableEntry {
10491056 LLVMValueRef fn_value;
10501057 AstNode *proto_node;
......@@ -1060,6 +1067,7 @@ struct FnTableEntry {
10601067 bool is_extern;
10611068 bool is_test;
10621069 bool is_pure;
1070 WantPure want_pure;
10631071 bool safety_off;
10641072 bool is_noinline;
10651073 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
10601060 bool ok = resolve_const_expr_bool(g, import, import->block_context,
10611061 &directive_node->data.directive.expr, &enable);
10621062 if (!enable || !ok) {
1063 fn_table_entry->is_pure = false;
1063 fn_table_entry->want_pure = WantPureFalse;
10641064 }
10651065 // TODO cause compile error if enable is true and impure fn
10661066 }
......@@ -5153,7 +5153,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
51535153
51545154 FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
51555155 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) {
51575157 if (fn_table_entry->anal_state == FnAnalStateReady) {
51585158 analyze_fn_body(g, fn_table_entry);
51595159 }
......@@ -5167,7 +5167,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
51675167 }
51685168 }
51695169 }
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) {
51715171 // calling an impure fn is impure
51725172 mark_impure_fn(context);
51735173 }
src/codegen.cpp+7-1
......@@ -3885,6 +3885,7 @@ static void do_code_gen(CodeGen *g) {
38853885
38863886 TypeTableEntry *fn_type = fn_table_entry->type_entry;
38873887
3888 bool is_sret = false;
38883889 if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
38893890 // nothing to do
38903891 } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) {
......@@ -3893,7 +3894,12 @@ static void do_code_gen(CodeGen *g) {
38933894 LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
38943895 LLVMAddAttribute(first_arg, LLVMStructRetAttribute);
38953896 LLVMZigAddNonNullAttr(fn_table_entry->fn_value, 1);
3897 is_sret = true;
38963898 }
3899 if (fn_table_entry->is_pure && !is_sret) {
3900 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMReadOnlyAttribute);
3901 }
3902
38973903
38983904 // set parameter attributes
38993905 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) {
39143920 if (param_type->id == TypeTableEntryIdPointer && param_is_noalias) {
39153921 LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
39163922 }
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)) ||
39183924 is_byval)
39193925 {
39203926 LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);
test/run_tests.cpp+32-11
......@@ -1410,8 +1410,10 @@ fn baz(a: i32) {}
14101410 )SOURCE");
14111411
14121412 add_debug_safety_case("integer addition overflow", R"SOURCE(
1413error Whatever;
14131414pub fn main(args: [][]u8) -> %void {
1414 add(65530, 10);
1415 const x = add(65530, 10);
1416 if (x == 0) return error.Whatever;
14151417}
14161418#static_eval_enable(false)
14171419fn add(a: u16, b: u16) -> u16 {
......@@ -1420,8 +1422,10 @@ fn add(a: u16, b: u16) -> u16 {
14201422 )SOURCE");
14211423
14221424 add_debug_safety_case("integer subtraction overflow", R"SOURCE(
1425error Whatever;
14231426pub fn main(args: [][]u8) -> %void {
1424 sub(10, 20);
1427 const x = sub(10, 20);
1428 if (x == 0) return error.Whatever;
14251429}
14261430#static_eval_enable(false)
14271431fn sub(a: u16, b: u16) -> u16 {
......@@ -1430,8 +1434,10 @@ fn sub(a: u16, b: u16) -> u16 {
14301434 )SOURCE");
14311435
14321436 add_debug_safety_case("integer multiplication overflow", R"SOURCE(
1437error Whatever;
14331438pub fn main(args: [][]u8) -> %void {
1434 mul(300, 6000);
1439 const x = mul(300, 6000);
1440 if (x == 0) return error.Whatever;
14351441}
14361442#static_eval_enable(false)
14371443fn mul(a: u16, b: u16) -> u16 {
......@@ -1440,8 +1446,10 @@ fn mul(a: u16, b: u16) -> u16 {
14401446 )SOURCE");
14411447
14421448 add_debug_safety_case("integer negation overflow", R"SOURCE(
1449error Whatever;
14431450pub fn main(args: [][]u8) -> %void {
1444 neg(-32768);
1451 const x = neg(-32768);
1452 if (x == 0) return error.Whatever;
14451453}
14461454#static_eval_enable(false)
14471455fn neg(a: i16) -> i16 {
......@@ -1450,8 +1458,10 @@ fn neg(a: i16) -> i16 {
14501458 )SOURCE");
14511459
14521460 add_debug_safety_case("signed shift left overflow", R"SOURCE(
1461error Whatever;
14531462pub fn main(args: [][]u8) -> %void {
1454 shl(-16385, 1);
1463 const x = shl(-16385, 1);
1464 if (x == 0) return error.Whatever;
14551465}
14561466#static_eval_enable(false)
14571467fn shl(a: i16, b: i16) -> i16 {
......@@ -1460,8 +1470,10 @@ fn shl(a: i16, b: i16) -> i16 {
14601470 )SOURCE");
14611471
14621472 add_debug_safety_case("unsigned shift left overflow", R"SOURCE(
1473error Whatever;
14631474pub fn main(args: [][]u8) -> %void {
1464 shl(0b0010111111111111, 3);
1475 const x = shl(0b0010111111111111, 3);
1476 if (x == 0) return error.Whatever;
14651477}
14661478#static_eval_enable(false)
14671479fn shl(a: u16, b: u16) -> u16 {
......@@ -1470,8 +1482,9 @@ fn shl(a: u16, b: u16) -> u16 {
14701482 )SOURCE");
14711483
14721484 add_debug_safety_case("integer division by zero", R"SOURCE(
1485error Whatever;
14731486pub fn main(args: [][]u8) -> %void {
1474 div0(999, 0);
1487 const x = div0(999, 0);
14751488}
14761489#static_eval_enable(false)
14771490fn div0(a: i32, b: i32) -> i32 {
......@@ -1480,8 +1493,10 @@ fn div0(a: i32, b: i32) -> i32 {
14801493 )SOURCE");
14811494
14821495 add_debug_safety_case("exact division failure", R"SOURCE(
1496error Whatever;
14831497pub fn main(args: [][]u8) -> %void {
1484 div_exact(10, 3);
1498 const x = div_exact(10, 3);
1499 if (x == 0) return error.Whatever;
14851500}
14861501#static_eval_enable(false)
14871502fn div_exact(a: i32, b: i32) -> i32 {
......@@ -1490,8 +1505,10 @@ fn div_exact(a: i32, b: i32) -> i32 {
14901505 )SOURCE");
14911506
14921507 add_debug_safety_case("cast []u8 to bigger slice of wrong size", R"SOURCE(
1508error Whatever;
14931509pub 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;
14951512}
14961513#static_eval_enable(false)
14971514fn widen_slice(slice: []u8) -> []i32 {
......@@ -1500,8 +1517,10 @@ fn widen_slice(slice: []u8) -> []i32 {
15001517 )SOURCE");
15011518
15021519 add_debug_safety_case("value does not fit in shortening cast", R"SOURCE(
1520error Whatever;
15031521pub fn main(args: [][]u8) -> %void {
1504 shorten_cast(200);
1522 const x = shorten_cast(200);
1523 if (x == 0) return error.Whatever;
15051524}
15061525#static_eval_enable(false)
15071526fn shorten_cast(x: i32) -> i8 {
......@@ -1510,8 +1529,10 @@ fn shorten_cast(x: i32) -> i8 {
15101529 )SOURCE");
15111530
15121531 add_debug_safety_case("signed integer not fitting in cast to unsigned integer", R"SOURCE(
1532error Whatever;
15131533pub fn main(args: [][]u8) -> %void {
1514 unsigned_cast(-10);
1534 const x = unsigned_cast(-10);
1535 if (x == 0) return error.Whatever;
15151536}
15161537#static_eval_enable(false)
15171538fn unsigned_cast(x: i32) -> u32 {