Skip to content

Commit c2e7e75

Browse files
committed
Write a pass to annotate constant operands on FIR ops. This works
around the feature in MLIR's canonicalizer, which considers the semantics of constants differently based on how they are packaged and not their values and use. Add test. Reviewed By: clementval Differential Revision: https://reviews.llvm.org/D121625
1 parent 75d74d9 commit c2e7e75

File tree

5 files changed

+84
-0
lines changed

5 files changed

+84
-0
lines changed

flang/include/flang/Optimizer/Transforms/Passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ std::unique_ptr<mlir::Pass> createPromoteToAffinePass();
3737
std::unique_ptr<mlir::Pass> createMemoryAllocationPass();
3838
std::unique_ptr<mlir::Pass>
3939
createMemoryAllocationPass(bool dynOnHeap, std::size_t maxStackSize);
40+
std::unique_ptr<mlir::Pass> createAnnotateConstantOperandsPass();
4041

4142
// declarative passes
4243
#define GEN_PASS_REGISTRATION

flang/include/flang/Optimizer/Transforms/Passes.td

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,23 @@ def AffineDialectDemotion : Pass<"demote-affine", "::mlir::FuncOp"> {
7474
];
7575
}
7676

77+
def AnnotateConstantOperands : Pass<"annotate-constant"> {
78+
let summary = "Annotate constant operands to all FIR operations";
79+
let description = [{
80+
The MLIR canonicalizer makes a distinction between constants based on how
81+
they are packaged in the IR. A constant value is wrapped in an Attr and that
82+
Attr can be attached to an Op. There is a distinguished Op, ConstantOp, that
83+
merely has one of these Attr attached.
84+
85+
The MLIR canonicalizer treats constants referenced by an Op and constants
86+
referenced through a ConstantOp as having distinct semantics. This pass
87+
eliminates that distinction, so hashconsing of Ops, basic blocks, etc.
88+
behaves as one would expect.
89+
}];
90+
let constructor = "::fir::createAnnotateConstantOperandsPass()";
91+
let dependentDialects = [ "fir::FIROpsDialect" ];
92+
}
93+
7794
def ArrayValueCopy : Pass<"array-value-copy", "::mlir::FuncOp"> {
7895
let summary = "Convert array value operations to memory operations.";
7996
let description = [{
@@ -91,6 +108,7 @@ def ArrayValueCopy : Pass<"array-value-copy", "::mlir::FuncOp"> {
91108
This pass is required before code gen to the LLVM IR dialect.
92109
}];
93110
let constructor = "::fir::createArrayValueCopyPass()";
111+
let dependentDialects = [ "fir::FIROpsDialect" ];
94112
}
95113

96114
def CharacterConversion : Pass<"character-conversion"> {
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//===-- AnnotateConstant.cpp ----------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "PassDetail.h"
10+
#include "flang/Optimizer/Dialect/FIROps.h"
11+
#include "flang/Optimizer/Transforms/Passes.h"
12+
#include "mlir/IR/BuiltinAttributes.h"
13+
14+
#define DEBUG_TYPE "flang-annotate-constant"
15+
16+
using namespace fir;
17+
18+
namespace {
19+
struct AnnotateConstantOperands
20+
: AnnotateConstantOperandsBase<AnnotateConstantOperands> {
21+
void runOnOperation() override {
22+
auto *context = &getContext();
23+
mlir::Dialect *firDialect = context->getLoadedDialect("fir");
24+
getOperation()->walk([&](mlir::Operation *op) {
25+
// We filter out other dialects even though they may undergo merging of
26+
// non-equal constant values by the canonicalizer as well.
27+
if (op->getDialect() == firDialect) {
28+
llvm::SmallVector<mlir::Attribute> attrs;
29+
bool hasOneOrMoreConstOpnd = false;
30+
for (mlir::Value opnd : op->getOperands()) {
31+
if (auto constOp = mlir::dyn_cast_or_null<mlir::arith::ConstantOp>(
32+
opnd.getDefiningOp())) {
33+
attrs.push_back(constOp.getValue());
34+
hasOneOrMoreConstOpnd = true;
35+
} else if (auto addrOp = mlir::dyn_cast_or_null<fir::AddrOfOp>(
36+
opnd.getDefiningOp())) {
37+
attrs.push_back(addrOp.getSymbol());
38+
hasOneOrMoreConstOpnd = true;
39+
} else {
40+
attrs.push_back(mlir::UnitAttr::get(context));
41+
}
42+
}
43+
if (hasOneOrMoreConstOpnd)
44+
op->setAttr("canonicalize_constant_operands",
45+
mlir::ArrayAttr::get(context, attrs));
46+
}
47+
});
48+
}
49+
};
50+
51+
} // namespace
52+
53+
std::unique_ptr<mlir::Pass> fir::createAnnotateConstantOperandsPass() {
54+
return std::make_unique<AnnotateConstantOperands>();
55+
}

flang/lib/Optimizer/Transforms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_flang_library(FIRTransforms
22
AbstractResult.cpp
33
AffinePromotion.cpp
44
AffineDemotion.cpp
5+
AnnotateConstant.cpp
56
CharacterConversion.cpp
67
ArrayValueCopy.cpp
78
ExternalNameConversion.cpp

flang/test/Fir/annotate-constant.fir

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: fir-opt -annotate-constant %s | FileCheck %s
2+
3+
// CHECK-LABEL: func @annotate_test() -> !fir.ref<!fir.array<?xi32>> {
4+
func @annotate_test() -> !fir.ref<!fir.array<?xi32>> {
5+
%1 = arith.constant 5 : index
6+
// CHECK: %[[a:.*]] = fir.alloca !fir.array<?xi32>, %{{.*}} {canonicalize_constant_operands = [5 : index]}
7+
%2 = fir.alloca !fir.array<?xi32>, %1
8+
return %2 : !fir.ref<!fir.array<?xi32>>
9+
}

0 commit comments

Comments
 (0)