Skip to content

Commit 54b4bd5

Browse files
authored
[flang][AliasAnalysis] Cray pointers/pointees might alias with anything (#170900)
The LOC intrinsic allows a cray pointer to alias with ordinary variables with no other attribute. See the new test for an example. This is not enabled by default. The functionality can be used with `-mmlir -funsafe-cray-pointers`. First part of the un-revert of #169544. That will handle TBAA.
1 parent f8580c9 commit 54b4bd5

File tree

11 files changed

+169
-42
lines changed

11 files changed

+169
-42
lines changed

flang/docs/Aliasing.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,18 @@ print *, target
281281
end
282282
```
283283

284-
Optimizations assume that Cray pointers do not alias any other variables.
285-
In the above example, it is assumed that `handle` and `target` do not alias,
286-
and optimizations will treat them as separate entities.
284+
By default, optimizations assume that Cray pointers do not alias any other
285+
variables. In the above example, it is assumed that `handle` and `target` do
286+
not alias, and optimizations will treat them as separate entities.
287287

288288
In order to disable optimizations that assume that there is no aliasing between
289289
Cray pointer targets and entities they alias with, add the TARGET attribute to
290290
variables aliasing with a Cray pointer (the `target` variable in this example).
291291

292+
There is also a flag `-mmlir -funsafe-cray-pointers` which causes the compiler
293+
to assume that cray pointers alias with all data whether or not it has the
294+
TARGET attribute.
295+
292296
## Type considerations
293297

294298
Pointers with distinct types may alias so long as their types are

flang/include/flang/Optimizer/Analysis/AliasAnalysis.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct AliasAnalysis {
4545
Unknown);
4646

4747
/// Attributes of the memory source object.
48-
ENUM_CLASS(Attribute, Target, Pointer, IntentIn);
48+
ENUM_CLASS(Attribute, Target, Pointer, IntentIn, CrayPointer, CrayPointee);
4949

5050
// See
5151
// https://discourse.llvm.org/t/rfc-distinguish-between-data-and-non-data-in-fir-alias-analysis/78759/1
@@ -161,6 +161,15 @@ struct AliasAnalysis {
161161
/// Return true, if Pointer attribute is set.
162162
bool isPointer() const;
163163

164+
/// Return true, if CrayPointer attribute is set.
165+
bool isCrayPointer() const;
166+
167+
/// Return true, if CrayPointee attribute is set.
168+
bool isCrayPointee() const;
169+
170+
/// Return true, if CrayPointer or CrayPointee attribute is set.
171+
bool isCrayPointerOrPointee() const;
172+
164173
bool isDummyArgument() const;
165174
bool isData() const;
166175
bool isBoxData() const;

flang/include/flang/Optimizer/Dialect/FIRAttr.td

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,17 @@ def FIRvolatile : I32BitEnumAttrCaseBit<"fortran_volatile", 12, "volatile">;
3636
def FIRHostAssoc : I32BitEnumAttrCaseBit<"host_assoc", 13>;
3737
// Used inside parent procedure to flag variables host associated in internal procedure.
3838
def FIRInternalAssoc : I32BitEnumAttrCaseBit<"internal_assoc", 14>;
39+
// Used by alias analysis
40+
def FIRcray_pointer : I32BitEnumAttrCaseBit<"cray_pointer", 15>;
41+
def FIRcray_pointee : I32BitEnumAttrCaseBit<"cray_pointee", 16>;
3942

4043
def fir_FortranVariableFlagsEnum : I32BitEnumAttr<
4144
"FortranVariableFlagsEnum",
4245
"Fortran variable attributes",
4346
[FIRnoAttributes, FIRallocatable, FIRasynchronous, FIRbind_c, FIRcontiguous,
4447
FIRintent_in, FIRintent_inout, FIRintent_out, FIRoptional, FIRparameter,
45-
FIRpointer, FIRtarget, FIRvalue, FIRvolatile, FIRHostAssoc, FIRInternalAssoc]> {
48+
FIRpointer, FIRtarget, FIRvalue, FIRvolatile, FIRHostAssoc, FIRInternalAssoc,
49+
FIRcray_pointer, FIRcray_pointee]> {
4650
let separator = ", ";
4751
let cppNamespace = "::fir";
4852
let printBitEnumPrimaryGroups = 1;

flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,20 @@ def fir_FortranVariableOpInterface : OpInterface<"FortranVariableOpInterface"> {
114114
fir::FortranVariableFlagsEnum::pointer);
115115
}
116116

117+
/// Is this variable a Cray pointer?
118+
bool isCrayPointer() {
119+
auto attrs = getFortranAttrs();
120+
return attrs && bitEnumContainsAny(*attrs,
121+
fir::FortranVariableFlagsEnum::cray_pointer);
122+
}
123+
124+
/// Is this variable a Cray pointee?
125+
bool isCrayPointee() {
126+
auto attrs = getFortranAttrs();
127+
return attrs && bitEnumContainsAny(*attrs,
128+
fir::FortranVariableFlagsEnum::cray_pointee);
129+
}
130+
117131
/// Is this variable a Fortran allocatable?
118132
bool isAllocatable() {
119133
auto attrs = getFortranAttrs();

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,6 +1806,9 @@ fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
18061806
if (sym.test(Fortran::semantics::Symbol::Flag::CrayPointee)) {
18071807
// CrayPointee are represented as pointers.
18081808
flags = flags | fir::FortranVariableFlagsEnum::pointer;
1809+
// Still use the CrayPointee flag so that AliasAnalysis can handle these
1810+
// separately.
1811+
flags = flags | fir::FortranVariableFlagsEnum::cray_pointee;
18091812
return fir::FortranVariableFlagsAttr::get(mlirContext, flags);
18101813
}
18111814
const auto &attrs = sym.attrs();
@@ -1835,6 +1838,8 @@ fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
18351838
flags = flags | fir::FortranVariableFlagsEnum::value;
18361839
if (attrs.test(Fortran::semantics::Attr::VOLATILE))
18371840
flags = flags | fir::FortranVariableFlagsEnum::fortran_volatile;
1841+
if (sym.test(Fortran::semantics::Symbol::Flag::CrayPointer))
1842+
flags = flags | fir::FortranVariableFlagsEnum::cray_pointer;
18381843
if (flags == fir::FortranVariableFlagsEnum::None)
18391844
return {};
18401845
return fir::FortranVariableFlagsAttr::get(mlirContext, flags);

flang/lib/Optimizer/Analysis/AliasAnalysis.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,18 @@
2121
#include "mlir/Interfaces/SideEffectInterfaces.h"
2222
#include "llvm/ADT/TypeSwitch.h"
2323
#include "llvm/Support/Casting.h"
24+
#include "llvm/Support/CommandLine.h"
2425
#include "llvm/Support/Debug.h"
2526

2627
using namespace mlir;
2728

2829
#define DEBUG_TYPE "fir-alias-analysis"
2930

31+
llvm::cl::opt<bool> supportCrayPointers(
32+
"funsafe-cray-pointers",
33+
llvm::cl::desc("Support Cray POINTERs that ALIAS with non-TARGET data"),
34+
llvm::cl::init(false));
35+
3036
// Inspect for value-scoped Allocate effects and determine whether
3137
// 'candidate' is a new allocation. Returns SourceKind::Allocate if a
3238
// MemAlloc effect is attached
@@ -60,6 +66,10 @@ getAttrsFromVariable(fir::FortranVariableOpInterface var) {
6066
attrs.set(fir::AliasAnalysis::Attribute::Pointer);
6167
if (var.isIntentIn())
6268
attrs.set(fir::AliasAnalysis::Attribute::IntentIn);
69+
if (var.isCrayPointer())
70+
attrs.set(fir::AliasAnalysis::Attribute::CrayPointer);
71+
if (var.isCrayPointee())
72+
attrs.set(fir::AliasAnalysis::Attribute::CrayPointee);
6373

6474
return attrs;
6575
}
@@ -138,6 +148,18 @@ bool AliasAnalysis::Source::isPointer() const {
138148
return attributes.test(Attribute::Pointer);
139149
}
140150

151+
bool AliasAnalysis::Source::isCrayPointee() const {
152+
return attributes.test(Attribute::CrayPointee);
153+
}
154+
155+
bool AliasAnalysis::Source::isCrayPointer() const {
156+
return attributes.test(Attribute::CrayPointer);
157+
}
158+
159+
bool AliasAnalysis::Source::isCrayPointerOrPointee() const {
160+
return isCrayPointer() || isCrayPointee();
161+
}
162+
141163
bool AliasAnalysis::Source::isDummyArgument() const {
142164
if (auto v = origin.u.dyn_cast<mlir::Value>()) {
143165
return fir::isDummyArgument(v);
@@ -224,6 +246,15 @@ AliasResult AliasAnalysis::alias(Source lhsSrc, Source rhsSrc, mlir::Value lhs,
224246
return AliasResult::MayAlias;
225247
}
226248

249+
// Cray pointers/pointees can alias with anything via LOC.
250+
if (supportCrayPointers) {
251+
if (lhsSrc.isCrayPointerOrPointee() || rhsSrc.isCrayPointerOrPointee()) {
252+
LLVM_DEBUG(llvm::dbgs()
253+
<< " aliasing because of Cray pointer/pointee\n");
254+
return AliasResult::MayAlias;
255+
}
256+
}
257+
227258
if (lhsSrc.kind == rhsSrc.kind) {
228259
// If the kinds and origins are the same, then lhs and rhs must alias unless
229260
// either source is approximate. Approximate sources are for parts of the
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Check that cray pointers might alias with everything.
2+
3+
// RUN: fir-opt %s -funsafe-cray-pointers -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' -mlir-disable-threading 2>&1 | FileCheck %s
4+
// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' -mlir-disable-threading 2>&1 | FileCheck --check-prefix=DEFAULT %s
5+
6+
// Fortran source:
7+
// subroutine test()
8+
// real :: a, b
9+
// pointer(p, a)
10+
// p = loc(b)
11+
// end subroutine
12+
13+
// CHECK-LABEL: Testing : "_QPtest"
14+
// CHECK-DAG: p#0 <-> b#0: MayAlias
15+
// CHECK-DAG: p#1 <-> b#0: MayAlias
16+
// CHECK-DAG: p#0 <-> b#1: MayAlias
17+
// CHECK-DAG: p#1 <-> b#1: MayAlias
18+
// CHECK-DAG: p#0 <-> a#0: MayAlias
19+
// CHECK-DAG: p#1 <-> a#0: MayAlias
20+
// CHECK-DAG: b#0 <-> a#0: MayAlias
21+
// CHECK-DAG: b#1 <-> a#0: MayAlias
22+
// CHECK-DAG: p#0 <-> a#1: MayAlias
23+
// CHECK-DAG: p#1 <-> a#1: MayAlias
24+
// CHECK-DAG: b#0 <-> a#1: MayAlias
25+
// CHECK-DAG: b#1 <-> a#1: MayAlias
26+
27+
// By default, alias analysis assumes that cray pointers do not alias with
28+
// non-target data. See flang/docs/Aliasing.md.
29+
// DEFAULT-LABEL: Testing : "_QPtest"
30+
// DEFAULT-DAG: p#0 <-> b#0: NoAlias
31+
// DEFAULT-DAG: p#1 <-> b#0: NoAlias
32+
// DEFAULT-DAG: p#0 <-> b#1: NoAlias
33+
// DEFAULT-DAG: p#1 <-> b#1: NoAlias
34+
// DEFAULT-DAG: p#0 <-> a#0: NoAlias
35+
// DEFAULT-DAG: p#1 <-> a#0: NoAlias
36+
// DEFAULT-DAG: b#0 <-> a#0: NoAlias
37+
// DEFAULT-DAG: b#1 <-> a#0: NoAlias
38+
// DEFAULT-DAG: p#0 <-> a#1: NoAlias
39+
// DEFAULT-DAG: p#1 <-> a#1: NoAlias
40+
// DEFAULT-DAG: b#0 <-> a#1: NoAlias
41+
// DEFAULT-DAG: b#1 <-> a#1: NoAlias
42+
43+
func.func @_QPtest() {
44+
%0 = fir.alloca !fir.box<!fir.ptr<f32>>
45+
%1 = fir.dummy_scope : !fir.dscope
46+
%2 = fir.alloca i64 {bindc_name = "p", uniq_name = "_QFtestEp"}
47+
%3:2 = hlfir.declare %2 {test.ptr = "p", fortran_attrs = #fir.var_attrs<cray_pointer>, uniq_name = "_QFtestEp"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
48+
%4 = fir.alloca f32 {bindc_name = "b", uniq_name = "_QFtestEb"}
49+
%5:2 = hlfir.declare %4 {test.ptr = "b", uniq_name = "_QFtestEb"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
50+
%6:2 = hlfir.declare %0 {test.ptr = "a", fortran_attrs = #fir.var_attrs<pointer, cray_pointee>, uniq_name = "_QFtestEa"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)
51+
%7 = fir.zero_bits !fir.ptr<f32>
52+
%8 = fir.embox %7 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>
53+
fir.store %8 to %6#0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
54+
%9 = fir.embox %5#0 : (!fir.ref<f32>) -> !fir.box<f32>
55+
%10 = fir.box_addr %9 : (!fir.box<f32>) -> !fir.ref<f32>
56+
%11 = fir.convert %10 : (!fir.ref<f32>) -> i64
57+
hlfir.assign %11 to %3#0 : i64, !fir.ref<i64>
58+
return
59+
}
60+

0 commit comments

Comments
 (0)