Skip to content

Commit 6c14e84

Browse files
committed
[flang][hlfir] Add codegen for vector subscripted LHS
This patch adds support for vector subscripted assignment left-hand side. It does not yet add support for the cases where the LHS must be saved because its evaluation could be impacted by the assignment. The implementation adds an hlfir::ElementalOpInterface to share the elemental inlining utility and some other tools between hlfir::ElementalOp and hlfir::ElelemntalAddrOp. It adds generateYieldedLHS() to allow retrieving the LHS value in lowering, whether or not it is vector subscripted. If it is vector subscripted, this utility creates a loop nest iterating over the elements and returns the address of an element. Differential Revision: https://reviews.llvm.org/D153759
1 parent 72c826c commit 6c14e84

File tree

7 files changed

+397
-93
lines changed

7 files changed

+397
-93
lines changed

flang/include/flang/Optimizer/Builder/HLFIRTools.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace hlfir {
3131

3232
class AssociateOp;
3333
class ElementalOp;
34+
class ElementalOpInterface;
3435
class ElementalAddrOp;
3536
class YieldElementOp;
3637

@@ -401,17 +402,16 @@ hlfir::YieldElementOp inlineElementalOp(mlir::Location loc,
401402
hlfir::ElementalOp elemental,
402403
mlir::ValueRange oneBasedIndices);
403404

404-
/// Inline the body of an hlfir.elemental without cloning the resulting
405-
/// hlfir.yield_element, and return the cloned operand of the
406-
/// hlfir.yield_element. The mapper must be provided to cover complex cases
407-
/// where the inlined elemental is not defined in the current context and uses
408-
/// values that have been cloned already.
409-
/// A callback is provided to indicate if an hlfir.apply inside the
410-
/// hlfir.elemental must be immediately replaced by the inlining of the
411-
/// applied hlfir.elemental.
405+
/// Inline the body of an hlfir.elemental or hlfir.elemental_addr without
406+
/// cloning the resulting hlfir.yield_element/hlfir.yield, and return the cloned
407+
/// operand of the hlfir.yield_element/hlfir.yield. The mapper must be provided
408+
/// to cover complex cases where the inlined elemental is not defined in the
409+
/// current context and uses values that have been cloned already. A callback is
410+
/// provided to indicate if an hlfir.apply inside the hlfir.elemental must be
411+
/// immediately replaced by the inlining of the applied hlfir.elemental.
412412
mlir::Value inlineElementalOp(
413413
mlir::Location loc, fir::FirOpBuilder &builder,
414-
hlfir::ElementalOp elemental, mlir::ValueRange oneBasedIndices,
414+
hlfir::ElementalOpInterface elemental, mlir::ValueRange oneBasedIndices,
415415
mlir::IRMapping &mapper,
416416
const std::function<bool(hlfir::ElementalOp)> &mustRecursivelyInline);
417417

flang/include/flang/Optimizer/HLFIR/HLFIROps.td

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,54 @@ def hlfir_NoReassocOp : hlfir_Op<"no_reassoc", [NoMemoryEffect, SameOperandsAndR
671671
let assemblyFormat = "$val attr-dict `:` type($val)";
672672
}
673673

674-
def hlfir_ElementalOp : hlfir_Op<"elemental", [RecursiveMemoryEffects]> {
674+
def hlfir_ElementalOpInterface : OpInterface<"ElementalOpInterface"> {
675+
let description = [{
676+
Interface for the operation holding a region with elemental computation.
677+
It is used as a common interface bewteen hlfir.elemental and hlfir.elemental_addr.
678+
}];
679+
680+
let methods = [
681+
InterfaceMethod<
682+
/*desc=*/"Return the one based elemental indices.",
683+
/*retTy=*/"mlir::Block::BlockArgListType",
684+
/*methodName=*/"getIndices",
685+
/*args=*/(ins),
686+
/*methodBody=*/[{}]
687+
>,
688+
InterfaceMethod<
689+
/*desc=*/"Return the element entity being computed",
690+
/*retTy=*/"mlir::Value",
691+
/*methodName=*/"getElementEntity",
692+
/*args=*/(ins),
693+
/*methodBody=*/[{}]
694+
>,
695+
InterfaceMethod<
696+
/*desc=*/"Get element cleanup region, if any.",
697+
/*retTy=*/"mlir::Region*",
698+
/*methodName=*/"getElementCleanup",
699+
/*args=*/(ins),
700+
/*methodBody=*/[{}]
701+
>,
702+
InterfaceMethod<
703+
/*desc=*/"Get elemental region.",
704+
/*retTy=*/"mlir::Region&",
705+
/*methodName=*/"getElementalRegion",
706+
/*args=*/(ins),
707+
/*methodBody=*/[{}]
708+
>,
709+
InterfaceMethod<
710+
/*desc=*/"Must this elemental operation be evaluated in order?",
711+
/*retTy=*/"bool",
712+
/*methodName=*/"isOrdered",
713+
/*args=*/(ins),
714+
/*methodBody=*/[{}]
715+
>,
716+
];
717+
718+
let cppNamespace = "hlfir";
719+
}
720+
721+
def hlfir_ElementalOp : hlfir_Op<"elemental", [RecursiveMemoryEffects, hlfir_ElementalOpInterface]> {
675722
let summary = "elemental expression";
676723
let description = [{
677724
Represent an elemental expression as a function of the indices.
@@ -726,6 +773,11 @@ def hlfir_ElementalOp : hlfir_Op<"elemental", [RecursiveMemoryEffects]> {
726773
mlir::Block::BlockArgListType getIndices() {
727774
return getBody()->getArguments();
728775
}
776+
/// ElementalOpInterface implementation.
777+
778+
mlir::Region& getElementalRegion() {return getRegion();}
779+
mlir::Value getElementEntity();
780+
mlir::Region* getElementCleanup() {return nullptr;}
729781

730782
/// Must this elemental be evaluated in order?
731783
/// TODO: add attribute and set it in lowering.
@@ -1117,7 +1169,7 @@ def hlfir_YieldOp : hlfir_Op<"yield", [Terminator, ParentOneOf<["RegionAssignOp"
11171169
let assemblyFormat = "$entity attr-dict `:` type($entity) custom<YieldOpCleanup>($cleanup)";
11181170
}
11191171

1120-
def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"RegionAssignOp">, RecursiveMemoryEffects, RecursivelySpeculatable]> {
1172+
def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"RegionAssignOp">, RecursiveMemoryEffects, RecursivelySpeculatable, hlfir_ElementalOpInterface]> {
11211173
let summary = "Yield the address of a vector subscripted variable inside an hlfir.region_assign";
11221174
let description = [{
11231175
Special terminator node for the left-hand side region of an hlfir.region_assign
@@ -1180,6 +1232,16 @@ def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"R
11801232
/// body. It yields the variable element address.
11811233
/// This should only be called once the ElementalAddrOp has been built.
11821234
hlfir::YieldOp getYieldOp();
1235+
1236+
/// ElementalOpInterface implementation.
1237+
1238+
mlir::Region& getElementalRegion() {return getBody();}
1239+
mlir::Value getElementEntity();
1240+
mlir::Region* getElementCleanup();
1241+
1242+
/// Must this elemental be evaluated in order?
1243+
/// TODO: add attribute and set it in lowering.
1244+
bool isOrdered() {return true;}
11831245
}];
11841246

11851247
let hasVerifier = 1;

flang/lib/Optimizer/Builder/HLFIRTools.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -776,36 +776,33 @@ hlfir::inlineElementalOp(mlir::Location loc, fir::FirOpBuilder &builder,
776776

777777
mlir::Value hlfir::inlineElementalOp(
778778
mlir::Location loc, fir::FirOpBuilder &builder,
779-
hlfir::ElementalOp elemental, mlir::ValueRange oneBasedIndices,
779+
hlfir::ElementalOpInterface elemental, mlir::ValueRange oneBasedIndices,
780780
mlir::IRMapping &mapper,
781781
const std::function<bool(hlfir::ElementalOp)> &mustRecursivelyInline) {
782-
mlir::Region &region = elemental.getRegion();
782+
mlir::Region &region = elemental.getElementalRegion();
783783
// hlfir.elemental region is a SizedRegion<1>.
784784
assert(region.hasOneBlock() && "elemental region must have one block");
785785
mapper.map(elemental.getIndices(), oneBasedIndices);
786-
mlir::Block::OpListType &ops = region.back().getOperations();
787-
assert(!ops.empty() && "elemental block cannot be empty");
788-
auto end = ops.end();
789-
for (auto opIt = ops.begin(); std::next(opIt) != end; ++opIt) {
790-
if (auto apply = mlir::dyn_cast<hlfir::ApplyOp>(*opIt))
786+
for (auto &op : region.front().without_terminator()) {
787+
if (auto apply = mlir::dyn_cast<hlfir::ApplyOp>(op))
791788
if (auto appliedElemental =
792789
apply.getExpr().getDefiningOp<hlfir::ElementalOp>())
793790
if (mustRecursivelyInline(appliedElemental)) {
794791
llvm::SmallVector<mlir::Value> clonedApplyIndices;
795792
for (auto indice : apply.getIndices())
796793
clonedApplyIndices.push_back(mapper.lookupOrDefault(indice));
797-
mlir::Value inlined = inlineElementalOp(
798-
loc, builder, appliedElemental, clonedApplyIndices, mapper,
799-
mustRecursivelyInline);
794+
hlfir::ElementalOpInterface elementalIface =
795+
mlir::cast<hlfir::ElementalOpInterface>(
796+
appliedElemental.getOperation());
797+
mlir::Value inlined = inlineElementalOp(loc, builder, elementalIface,
798+
clonedApplyIndices, mapper,
799+
mustRecursivelyInline);
800800
mapper.map(apply.getResult(), inlined);
801801
continue;
802802
}
803-
(void)builder.clone(*opIt, mapper);
803+
(void)builder.clone(op, mapper);
804804
}
805-
auto oldYield = mlir::dyn_cast_or_null<hlfir::YieldElementOp>(
806-
region.back().getOperations().back());
807-
assert(oldYield && "must terminate with yieldElementalOp");
808-
return mapper.lookupOrDefault(oldYield.getElementValue());
805+
return mapper.lookupOrDefault(elemental.getElementEntity());
809806
}
810807

811808
hlfir::LoopNest hlfir::genLoopNest(mlir::Location loc,

flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,10 @@ void hlfir::ElementalOp::build(mlir::OpBuilder &builder,
10431043
}
10441044
}
10451045

1046+
mlir::Value hlfir::ElementalOp::getElementEntity() {
1047+
return mlir::cast<hlfir::YieldElementOp>(getBody()->back()).getElementValue();
1048+
}
1049+
10461050
//===----------------------------------------------------------------------===//
10471051
// ApplyOp
10481052
//===----------------------------------------------------------------------===//
@@ -1297,6 +1301,15 @@ hlfir::YieldOp hlfir::ElementalAddrOp::getYieldOp() {
12971301
return yieldOp;
12981302
}
12991303

1304+
mlir::Value hlfir::ElementalAddrOp::getElementEntity() {
1305+
return getYieldOp().getEntity();
1306+
}
1307+
1308+
mlir::Region *hlfir::ElementalAddrOp::getElementCleanup() {
1309+
mlir::Region *cleanup = &getYieldOp().getCleanup();
1310+
return cleanup->empty() ? nullptr : cleanup;
1311+
}
1312+
13001313
//===----------------------------------------------------------------------===//
13011314
// OrderedAssignmentTreeOpInterface
13021315
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)