Skip to content

Commit

Permalink
[flang] Update PFTBuilder
Browse files Browse the repository at this point in the history
This patch update the PFTBuilder to be able to lower
the construct present in semantics.

This is a building block for other lowering patches that will be posted soon.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: PeteSteinfeld, schweitz

Differential Revision: https://reviews.llvm.org/D120336

Co-authored-by: Jean Perier <jperier@nvidia.com>
Co-authored-by: V Donaldson <vdonaldson@nvidia.com>
  • Loading branch information
3 people committed Feb 22, 2022
1 parent 88d66f6 commit 026a43f
Show file tree
Hide file tree
Showing 8 changed files with 741 additions and 283 deletions.
68 changes: 68 additions & 0 deletions flang/include/flang/Lower/HostAssociations.h
@@ -0,0 +1,68 @@
//===-- Lower/HostAssociations.h --------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_LOWER_HOSTASSOCIATIONS_H
#define FORTRAN_LOWER_HOSTASSOCIATIONS_H

#include "mlir/IR/Location.h"
#include "mlir/IR/Types.h"
#include "mlir/IR/Value.h"
#include "llvm/ADT/SetVector.h"

namespace Fortran {
namespace semantics {
class Symbol;
}

namespace lower {
class AbstractConverter;
class SymMap;

/// Internal procedures in Fortran may access variables declared in the host
/// procedure directly. We bundle these variables together in a tuple and pass
/// them as an extra argument.
class HostAssociations {
public:
/// Returns true iff there are no host associations.
bool empty() const { return symbols.empty(); }

/// Adds a set of Symbols that will be the host associated bindings for this
/// host procedure.
void addSymbolsToBind(
const llvm::SetVector<const Fortran::semantics::Symbol *> &s) {
assert(empty() && "symbol set must be initially empty");
symbols = s;
}

/// Code gen the FIR for the local bindings for the host associated symbols
/// for the host (parent) procedure using `builder`.
void hostProcedureBindings(AbstractConverter &converter, SymMap &symMap);

/// Code gen the FIR for the local bindings for the host associated symbols
/// for an internal (child) procedure using `builder`.
void internalProcedureBindings(AbstractConverter &converter, SymMap &symMap);

/// Return the type of the extra argument to add to each internal procedure.
mlir::Type getArgumentType(AbstractConverter &convert);

/// Is \p symbol host associated ?
bool isAssociated(const Fortran::semantics::Symbol &symbol) const {
return symbols.contains(&symbol);
}

private:
/// Canonical vector of host associated symbols.
llvm::SetVector<const Fortran::semantics::Symbol *> symbols;

/// The type of the extra argument to be added to each internal procedure.
mlir::Type argType;
};
} // namespace lower
} // namespace Fortran

#endif // FORTRAN_LOWER_HOSTASSOCIATIONS_H
109 changes: 109 additions & 0 deletions flang/include/flang/Lower/IntervalSet.h
@@ -0,0 +1,109 @@
//===-- IntervalSet.h -------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_LOWER_INTERVALSET_H
#define FORTRAN_LOWER_INTERVALSET_H

#include <cassert>
#include <map>

namespace Fortran::lower {

//===----------------------------------------------------------------------===//
// Interval set
//===----------------------------------------------------------------------===//

/// Interval set to keep track of intervals, merging them when they overlap one
/// another. Used to refine the pseudo-offset ranges of the front-end symbols
/// into groups of aliasing variables.
struct IntervalSet {
using MAP = std::map<std::size_t, std::size_t>;
using Iterator = MAP::const_iterator;

// Handles the merging of overlapping intervals correctly, efficiently.
void merge(std::size_t lo, std::size_t up) {
assert(lo <= up);
if (empty()) {
m.insert({lo, up});
return;
}
auto i = m.lower_bound(lo);
// i->first >= lo
if (i == begin()) {
if (up < i->first) {
// [lo..up] < i->first
m.insert({lo, up});
return;
}
// up >= i->first
if (i->second > up)
up = i->second;
fuse(lo, up, i);
return;
}
auto i1 = i;
if (i == end() || i->first > lo)
i = std::prev(i);
// i->first <= lo
if (i->second >= up) {
// i->first <= lo && up <= i->second, keep i
return;
}
// i->second < up
if (i->second < lo) {
if (i1 == end() || i1->first > up) {
// i < [lo..up] < i1
m.insert({lo, up});
return;
}
// i < [lo..up], i1->first <= up --> [lo..up] union [i1..?]
i = i1;
} else {
// i->first <= lo, lo <= i->second --> [i->first..up] union [i..?]
lo = i->first;
}
fuse(lo, up, i);
}

Iterator find(std::size_t pt) const {
auto i = m.lower_bound(pt);
if (i != end() && i->first == pt)
return i;
if (i == begin())
return end();
i = std::prev(i);
if (i->second < pt)
return end();
return i;
}

Iterator begin() const { return m.begin(); }
Iterator end() const { return m.end(); }
bool empty() const { return m.empty(); }
std::size_t size() const { return m.size(); }

private:
// Find and fuse overlapping sets.
void fuse(std::size_t lo, std::size_t up, Iterator i) {
auto j = m.upper_bound(up);
// up < j->first
std::size_t cu = std::prev(j)->second;
// cu < j->first
if (cu > up)
up = cu;
m.erase(i, j);
// merge [i .. j) with [i->first, max(up, cu)]
m.insert({lo, up});
}

MAP m{};
};

} // namespace Fortran::lower

#endif // FORTRAN_LOWER_INTERVALSET_H

0 comments on commit 026a43f

Please sign in to comment.