From 1c99d1c06d1a8080ea0f2f81c035159dd607e4c5 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Wed, 24 May 2023 14:18:36 +0200 Subject: [PATCH] Take parameter kind into account when deciding function purity. --- hilti/toolchain/src/compiler/optimizer.cc | 19 +++++++++++++++ .../hilti.optimization.pure_function/opt.hlt | 24 +++++++++++++++++++ .../hilti.optimization.pure_function/output | 2 ++ tests/hilti/optimization/pure_function.hlt | 10 ++++++++ 4 files changed, 55 insertions(+) diff --git a/hilti/toolchain/src/compiler/optimizer.cc b/hilti/toolchain/src/compiler/optimizer.cc index b56e53c7e..577dd9700 100644 --- a/hilti/toolchain/src/compiler/optimizer.cc +++ b/hilti/toolchain/src/compiler/optimizer.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1987,6 +1988,24 @@ struct PureFunctionVisitor : OptimizerVisitor, visitor::PreOrder() ) { + // Reference provide interior mutability regardless of the + // mutability of the param so mark such accesses not as pure. + if ( type::isReferenceType(param->type()) ) + return {}; + + switch ( param->kind() ) { + // Access to `copy` or `in` parameters is side-effect free. + case declaration::parameter::Kind::Copy: [[fallthrough]]; + case declaration::parameter::Kind::In: + continue; + + // Any other access could have side-effects. + case declaration::parameter::Kind::InOut: [[fallthrough]]; + case declaration::parameter::Kind::Unknown: return {}; + } + } + else // Do not mark this function pure if it references any other kinds of IDs. return {}; diff --git a/tests/Baseline/hilti.optimization.pure_function/opt.hlt b/tests/Baseline/hilti.optimization.pure_function/opt.hlt index 126009b1e..9b5854613 100644 --- a/tests/Baseline/hilti.optimization.pure_function/opt.hlt +++ b/tests/Baseline/hilti.optimization.pure_function/opt.hlt @@ -37,6 +37,30 @@ method method void T::pure4() &pure { self; } +function void fn_pure5(uint<64> in_param) &pure { + in_param += 42; +} + +function void fn_pure6(copy uint<64> copy_param) &pure { + copy_param += 42; +} + +function void fn_not_pure2(inout uint<64> inout_param) { + inout_param += 42; +} + +function void fn_not_pure3(strong_ref> in_param) { + (*in_param) += 42; +} + +function void fn_not_pure4(copy strong_ref> copy_param) { + (*copy_param) += 42; +} + +function void fn_not_pure2(inout strong_ref> inout_param) { + (*inout_param) += 42; +} + t.pure4(); } diff --git a/tests/Baseline/hilti.optimization.pure_function/output b/tests/Baseline/hilti.optimization.pure_function/output index b2e19dfe9..78f15968c 100644 --- a/tests/Baseline/hilti.optimization.pure_function/output +++ b/tests/Baseline/hilti.optimization.pure_function/output @@ -4,4 +4,6 @@ [debug/optimizer] marking member 'pure' as pure (<...>/pure_function.hlt:31:5) [debug/optimizer] marking member 'pure2' as pure (<...>/pure_function.hlt:32:5) [debug/optimizer] marking member 'T::pure4' as pure (<...>/pure_function.hlt:43:7-46:2) +[debug/optimizer] marking function 'fn_pure5' as pure +[debug/optimizer] marking function 'fn_pure6' as pure [debug/optimizer] marking function 'fn_pure' as pure diff --git a/tests/hilti/optimization/pure_function.hlt b/tests/hilti/optimization/pure_function.hlt index 9ec4710dd..d759a06f0 100644 --- a/tests/hilti/optimization/pure_function.hlt +++ b/tests/hilti/optimization/pure_function.hlt @@ -48,4 +48,14 @@ method void T::pure4() { global T t; t.pure4(); +# Parameter access is side-effect free for `in` and `copy` parameters if they are not of reference type. +function void fn_pure5(uint<64> in_param) { in_param += 42; } +function void fn_pure6(copy uint<64> copy_param) { copy_param += 42; } +function void fn_not_pure2(inout uint<64> inout_param) { inout_param += 42; } + +function void fn_not_pure3(strong_ref> in_param) { *in_param += 42; } +function void fn_not_pure4(copy strong_ref> copy_param) { *copy_param += 42; } +function void fn_not_pure2(inout strong_ref> inout_param) { *inout_param += 42; } + + }