| // RUN: fir-opt --function-attr="set-readonly=true" %s | FileCheck %s --check-prefix=CHECK | |
| // RUN: fir-opt --function-attr="set-readonly=true set-nocapture=true set-noalias=true" %s | FileCheck %s --check-prefix=ALL | |
| // RUN: fir-opt --function-attr="set-readonly=false" %s | FileCheck %s --check-prefix=OFF | |
| // Test translation of the FIR marker placed on INTENT(IN) by-reference dummy | |
| // arguments to the LLVM dialect argument attribute. | |
| // CHECK-LABEL: func.func private @test_ref( | |
| // CHECK-SAME: %{{.*}}: !fir.ref<i32> {fir.read_only, llvm.readonly}) { | |
| // ALL-LABEL: func.func private @test_ref( | |
| // ALL-SAME: %{{.*}}: !fir.ref<i32> {fir.read_only, llvm.noalias, llvm.nocapture, llvm.readonly}) { | |
| // OFF-LABEL: func.func private @test_ref( | |
| // OFF-SAME: %{{.*}}: !fir.ref<i32> {fir.read_only}) { | |
| func.func private @test_ref(%arg0: !fir.ref<i32> {fir.read_only}) { | |
| return | |
| } | |
| // An unmarked reference is not read-only. | |
| // CHECK-LABEL: func.func private @test_unmarked_ref( | |
| // CHECK-SAME: %{{.*}}: !fir.ref<i32>) { | |
| func.func private @test_unmarked_ref(%arg0: !fir.ref<i32>) { | |
| return | |
| } | |
| // TARGET prevents noalias and nocapture, but it does not prevent readonly. | |
| // Match the complete argument attribute dictionary under the ALL run so an | |
| // accidental llvm.noalias or llvm.nocapture addition makes the test fail. | |
| // CHECK-LABEL: func.func private @test_target( | |
| // CHECK-SAME: %{{.*}}: !fir.ref<i32> {fir.read_only, fir.target, llvm.readonly}) { | |
| // ALL-LABEL: func.func private @test_target( | |
| // ALL-SAME: %{{.*}}: !fir.ref<i32> {fir.read_only, fir.target, llvm.readonly}) { | |
| func.func private @test_target(%arg0: !fir.ref<i32> {fir.read_only, fir.target}) { | |
| return | |
| } | |
| // FunctionAttr mechanically translates an explicit marker on any reference. | |
| // This is independent of which source-level dummies CallInterface marks. | |
| // CHECK-LABEL: func.func private @test_derived( | |
| // CHECK-SAME: %{{.*}}: !fir.ref<!fir.type<_QFtest_derivedTt{p:!fir.box<!fir.ptr<i32>>}>> {fir.read_only, llvm.readonly}) { | |
| func.func private @test_derived(%arg0: !fir.ref<!fir.type<_QFtest_derivedTt{p:!fir.box<!fir.ptr<i32>>}>> {fir.read_only}) { | |
| return | |
| } | |
| // On a reference to a descriptor, readonly protects the descriptor storage, | |
| // not the data address stored in the descriptor. | |
| // CHECK-LABEL: func.func private @test_pointer_descriptor( | |
| // CHECK-SAME: %{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>> {fir.read_only, llvm.readonly}) { | |
| // ALL-LABEL: func.func private @test_pointer_descriptor( | |
| // ALL-SAME: %{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>> {fir.read_only, llvm.nocapture, llvm.readonly}) { | |
| func.func private @test_pointer_descriptor(%arg0: !fir.ref<!fir.box<!fir.ptr<i32>>> {fir.read_only}) { | |
| return | |
| } | |
| // CHECK-LABEL: func.func private @test_allocatable_descriptor( | |
| // CHECK-SAME: %{{.*}}: !fir.ref<!fir.box<!fir.heap<i32>>> {fir.read_only, llvm.readonly}) { | |
| func.func private @test_allocatable_descriptor(%arg0: !fir.ref<!fir.box<!fir.heap<i32>>> {fir.read_only}) { | |
| return | |
| } | |
| // A Fortran BIND(C) definition must obey INTENT(IN), so readonly is valid. | |
| // Unlike ordinary definitions, it must not receive noalias or nocapture. | |
| // CHECK-LABEL: func.func @test_bindc_definition( | |
| // CHECK-SAME: %{{.*}}: !fir.ref<i32> {fir.read_only, llvm.readonly}) attributes | |
| // ALL-LABEL: func.func @test_bindc_definition( | |
| // ALL-SAME: %{{.*}}: !fir.ref<i32> {fir.read_only, llvm.readonly}) attributes | |
| func.func @test_bindc_definition(%arg0: !fir.ref<i32> {fir.read_only}) attributes {fir.bindc_name = "test_bindc_definition", fir.proc_attrs = #fir.proc_attrs<bind_c>} { | |
| return | |
| } | |
| // Do not apply readonly to a declaration of an external C procedure: its body | |
| // is not constrained by the Fortran INTENT appearing in the local interface. | |
| // Use a module-style FIR name so this exercises the BIND(C)-declaration check, | |
| // rather than the generic check that skips non-module declarations. | |
| // CHECK-LABEL: func.func private @_QMreadonly_modPbindc_declaration( | |
| // CHECK-SAME: !fir.ref<i32> {fir.read_only}) attributes | |
| func.func private @_QMreadonly_modPbindc_declaration(!fir.ref<i32> {fir.read_only}) attributes {fir.bindc_name = "bindc_declaration", fir.proc_attrs = #fir.proc_attrs<bind_c>} | |
| // A declaration of a Fortran module procedure carries the Fortran contract. | |
| // CHECK-LABEL: func.func private @_QMreadonly_modPfortran_declaration( | |
| // CHECK-SAME: !fir.ref<i32> {fir.read_only, llvm.readonly}) | |
| func.func private @_QMreadonly_modPfortran_declaration(!fir.ref<i32> {fir.read_only}) | |
| // A fir.box passed by value is not a ReferenceType, so FunctionAttr does not | |
| // translate its marker. This is distinct from POINTER and ALLOCATABLE dummies, | |
| // whose descriptors are passed by reference and are covered above. | |
| // CHECK-LABEL: func.func private @test_box( | |
| // CHECK-SAME: %{{.*}}: !fir.box<!fir.array<?xi32>> {fir.read_only}) { | |
| func.func private @test_box(%arg0: !fir.box<!fir.array<?xi32>> {fir.read_only}) { | |
| return | |
| } |