Skip to content

Commit 43d729d

Browse files
committed
[flang][HLFIR] add more memory effects interfaces
Anything that produces a hlfir.expr should have an allocation side effect so that it is not removed by CSE (which would result in two hlfir.destroy operations for the same expression). Similarly for hlfir.associate, which has hlfir.end_associate. Also adds read effects on arguments which are pointer-like or boxes. I see no regressions from this change when running llvm-testsuite with optimization enabled, or from SPEC2017 rate benchmarks. To test this, I have added MLIR's pass for testing side effect interfaces to fir-opt. Differential Revision: https://reviews.llvm.org/D158662
1 parent c5fabac commit 43d729d

File tree

6 files changed

+376
-28
lines changed

6 files changed

+376
-28
lines changed

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

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@ def hlfir_ParentComponentOp : hlfir_Op<"parent_comp", [AttrSizedOperandSegments,
319319
let hasVerifier = 1;
320320
}
321321

322-
def hlfir_ConcatOp : hlfir_Op<"concat", []> {
322+
def hlfir_ConcatOp : hlfir_Op<"concat",
323+
[DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
323324
let summary = "concatenate characters";
324325
let description = [{
325326
Concatenate two or more character strings of a same character kind.
@@ -340,7 +341,7 @@ def hlfir_ConcatOp : hlfir_Op<"concat", []> {
340341
let hasVerifier = 1;
341342
}
342343

343-
def hlfir_AllOp : hlfir_Op<"all", []> {
344+
def hlfir_AllOp : hlfir_Op<"all", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
344345
let summary = "ALL transformational intrinsic";
345346
let description = [{
346347
Takes a logical array MASK as argument, optionally along a particular dimension,
@@ -361,7 +362,7 @@ def hlfir_AllOp : hlfir_Op<"all", []> {
361362
let hasVerifier = 1;
362363
}
363364

364-
def hlfir_AnyOp : hlfir_Op<"any", []> {
365+
def hlfir_AnyOp : hlfir_Op<"any", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
365366
let summary = "ANY transformational intrinsic";
366367
let description = [{
367368
Takes a logical array MASK as argument, optionally along a particular dimension,
@@ -382,7 +383,7 @@ def hlfir_AnyOp : hlfir_Op<"any", []> {
382383
let hasVerifier = 1;
383384
}
384385

385-
def hlfir_CountOp : hlfir_Op<"count", [AttrSizedOperandSegments]> {
386+
def hlfir_CountOp : hlfir_Op<"count", [AttrSizedOperandSegments, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
386387
let summary = "COUNT transformational intrinsic";
387388
let description = [{
388389
Takes a logical and counts the number of true values.
@@ -403,9 +404,9 @@ def hlfir_CountOp : hlfir_Op<"count", [AttrSizedOperandSegments]> {
403404
let hasVerifier = 1;
404405
}
405406

406-
407407
def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments,
408-
DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
408+
DeclareOpInterfaceMethods<ArithFastMathInterface>,
409+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
409410
let summary = "PRODUCT transformational intrinsic";
410411
let description = [{
411412
Multiplies the elements of an array, optionally along a particular dimension,
@@ -429,7 +430,8 @@ def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments,
429430
let hasVerifier = 1;
430431
}
431432

432-
def hlfir_SetLengthOp : hlfir_Op<"set_length", []> {
433+
def hlfir_SetLengthOp : hlfir_Op<"set_length",
434+
[DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
433435
let summary = "change the length of a character entity";
434436
let description = [{
435437
Change the length of character entity. This trims or pads the
@@ -468,7 +470,8 @@ def hlfir_GetLengthOp : hlfir_Op<"get_length", [Pure]> {
468470
}
469471

470472
def hlfir_SumOp : hlfir_Op<"sum", [AttrSizedOperandSegments,
471-
DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
473+
DeclareOpInterfaceMethods<ArithFastMathInterface>,
474+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
472475
let summary = "SUM transformational intrinsic";
473476
let description = [{
474477
Sums the elements of an array, optionally along a particular dimension,
@@ -493,7 +496,8 @@ def hlfir_SumOp : hlfir_Op<"sum", [AttrSizedOperandSegments,
493496
}
494497

495498
def hlfir_DotProductOp : hlfir_Op<"dot_product",
496-
[DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
499+
[DeclareOpInterfaceMethods<ArithFastMathInterface>,
500+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
497501
let summary = "DOT_PRODUCT transformational intrinsic";
498502
let description = [{
499503
Dot product of two vectors
@@ -516,7 +520,8 @@ def hlfir_DotProductOp : hlfir_Op<"dot_product",
516520
}
517521

518522
def hlfir_MatmulOp : hlfir_Op<"matmul",
519-
[DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
523+
[DeclareOpInterfaceMethods<ArithFastMathInterface>,
524+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
520525
let summary = "MATMUL transformational intrinsic";
521526
let description = [{
522527
Matrix multiplication
@@ -541,7 +546,8 @@ def hlfir_MatmulOp : hlfir_Op<"matmul",
541546
let hasVerifier = 1;
542547
}
543548

544-
def hlfir_TransposeOp : hlfir_Op<"transpose", []> {
549+
def hlfir_TransposeOp : hlfir_Op<"transpose",
550+
[DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
545551
let summary = "TRANSPOSE transformational intrinsic";
546552
let description = [{
547553
Transpose a rank 2 array
@@ -559,7 +565,8 @@ def hlfir_TransposeOp : hlfir_Op<"transpose", []> {
559565
}
560566

561567
def hlfir_MatmulTransposeOp : hlfir_Op<"matmul_transpose",
562-
[DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
568+
[DeclareOpInterfaceMethods<ArithFastMathInterface>,
569+
DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
563570
let summary = "Optimized MATMUL(TRANSPOSE(...), ...)";
564571
let description = [{
565572
Matrix multiplication where the left hand side is transposed
@@ -581,8 +588,12 @@ def hlfir_MatmulTransposeOp : hlfir_Op<"matmul_transpose",
581588
let hasVerifier = 1;
582589
}
583590

591+
// An allocation effect is needed because the value produced by the associate
592+
// is "deallocated" by hlfir.end_associate (the end_associate must not be
593+
// removed, and there must be only one hlfir.end_associate).
584594
def hlfir_AssociateOp : hlfir_Op<"associate", [AttrSizedOperandSegments,
585-
DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>]> {
595+
DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>,
596+
MemoryEffects<[MemAlloc]>]> {
586597
let summary = "Create a variable from an expression value";
587598
let description = [{
588599
Create a variable from an expression value.
@@ -635,7 +646,7 @@ def hlfir_AssociateOp : hlfir_Op<"associate", [AttrSizedOperandSegments,
635646
}];
636647
}
637648

638-
def hlfir_EndAssociateOp : hlfir_Op<"end_associate", []> {
649+
def hlfir_EndAssociateOp : hlfir_Op<"end_associate", [MemoryEffects<[MemFree]>]> {
639650
let summary = "Mark the end of life of a variable associated to an expression";
640651

641652
let description = [{
@@ -652,7 +663,8 @@ def hlfir_EndAssociateOp : hlfir_Op<"end_associate", []> {
652663
let builders = [OpBuilder<(ins "hlfir::AssociateOp":$associate)>];
653664
}
654665

655-
def hlfir_AsExprOp : hlfir_Op<"as_expr", []> {
666+
def hlfir_AsExprOp : hlfir_Op<"as_expr",
667+
[DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
656668
let summary = "Take the value of an array, character or derived variable";
657669

658670
let description = [{
@@ -934,7 +946,7 @@ def hlfir_DestroyOp : hlfir_Op<"destroy", [MemoryEffects<[MemFree]>]> {
934946
let assemblyFormat = "$expr attr-dict `:` qualified(type($expr))";
935947
}
936948

937-
def hlfir_CopyInOp : hlfir_Op<"copy_in", []> {
949+
def hlfir_CopyInOp : hlfir_Op<"copy_in", [MemoryEffects<[MemAlloc]>]> {
938950
let summary = "copy a variable into a contiguous temporary if it is not contiguous";
939951
let description = [{
940952
Copy a variable into a contiguous temporary if the variable is not
@@ -954,7 +966,7 @@ def hlfir_CopyInOp : hlfir_Op<"copy_in", []> {
954966
is true and, when it is false, the original value will be returned instead.
955967
}];
956968

957-
let arguments = (ins fir_BaseBoxType:$var,
969+
let arguments = (ins Arg<fir_BaseBoxType, "", [MemRead]>:$var,
958970
Optional<I1>:$var_is_present);
959971

960972
let results = (outs fir_BaseBoxType, I1);
@@ -981,7 +993,7 @@ def hlfir_CopyInOp : hlfir_Op<"copy_in", []> {
981993
}];
982994
}
983995

984-
def hlfir_CopyOutOp : hlfir_Op<"copy_out", []> {
996+
def hlfir_CopyOutOp : hlfir_Op<"copy_out", [MemoryEffects<[MemFree]>]> {
985997
let summary = "copy out a variable after a copy in";
986998
let description = [{
987999
If the variable was copied in a temporary in the related hlfir.copy_in,
@@ -992,9 +1004,9 @@ def hlfir_CopyOutOp : hlfir_Op<"copy_out", []> {
9921004
The deallocation of $temp is done if $was_copied is true.
9931005
}];
9941006

995-
let arguments = (ins fir_BaseBoxType:$temp,
1007+
let arguments = (ins Arg<fir_BaseBoxType, "", [MemRead]>:$temp,
9961008
I1:$was_copied,
997-
Optional<fir_BaseBoxType>:$var);
1009+
Arg<Optional<fir_BaseBoxType>, "", [MemWrite]>:$var);
9981010

9991011
let assemblyFormat = [{
10001012
$temp `,` $was_copied (`to` $var^)?
@@ -1546,7 +1558,8 @@ def hlfir_ForallIndexOp : hlfir_Op<"forall_index", [fir_FortranVariableOpInterfa
15461558
let hasCanonicalizeMethod = 1;
15471559
}
15481560

1549-
def hlfir_CharExtremumOp : hlfir_Op<"char_extremum", []> {
1561+
def hlfir_CharExtremumOp : hlfir_Op<"char_extremum",
1562+
[DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
15501563
let summary = "Find max/min from given character strings";
15511564
let description = [{
15521565
Find the lexicographical minimum or maximum of two or more character

0 commit comments

Comments
 (0)