[flang] add hlfir.null to implement NULL()
authorJean Perier <jperier@nvidia.com>
Fri, 6 Jan 2023 08:57:08 +0000 (09:57 +0100)
committerJean Perier <jperier@nvidia.com>
Fri, 6 Jan 2023 08:57:15 +0000 (09:57 +0100)
In HLFIR, the address of a Fortran entity in lowering must be defined
by an operation that has the FortranVariableOpInterface (it is a sanity
requirement to ensure that the mlir::Value propagated in certain places
of lowering can be reasoned about).
fir.zero_bits does not have this interface and it makes little sense to
add it since it can "zero initialize" more types than just addresses.

Creating an hlfir.declare for null addresses is a bit too much (what
would be the name), and it would be noisy in the IR.

Instead add a small hlfir.null operation whose codegen is simply a
replacement by fir.zero_bits.

It may also later help dealing with the NULL(MOLD) cases in a nicer
way (the current lowering of this uses special handling it).

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

flang/include/flang/Optimizer/HLFIR/HLFIROps.td
flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
flang/test/HLFIR/null-codegen.fir [new file with mode: 0644]
flang/test/HLFIR/null.fir [new file with mode: 0644]

index b5e2a44..88acf78 100644 (file)
@@ -457,4 +457,29 @@ def hlfir_ApplyOp : hlfir_Op<"apply", [NoMemoryEffect, AttrSizedOperandSegments]
   ];
 }
 
+def hlfir_NullOp : hlfir_Op<"null", [NoMemoryEffect, fir_FortranVariableOpInterface]> {
+  let summary = "create a NULL() address";
+
+  let description = [{
+    Create a NULL() address.
+    So far is not intended to represent NULL(MOLD).
+  }];
+
+  let results = (outs AnyFortranVariable);
+  let builders = [OpBuilder<(ins)>];
+
+  let assemblyFormat = "type(results) attr-dict";
+  let extraClassDeclaration = [{
+    // Implement FortranVariableInterface interface.
+    std::optional<fir::FortranVariableFlagsEnum> getFortranAttrs() const {
+      return std::nullopt;
+    }
+    mlir::Value getShape() const {return mlir::Value{};}
+    mlir::OperandRange getExplicitTypeParams() const {
+      // Return an empty range.
+      return {(*this)->getOperands().begin(), (*this)->getOperands().begin()};
+    }
+  }];
+}
+
 #endif // FORTRAN_DIALECT_HLFIR_OPS
index 654414a..ba62f51 100644 (file)
@@ -503,5 +503,15 @@ void hlfir::ApplyOp::build(mlir::OpBuilder &builder,
   build(builder, odsState, resultType, expr, indices, typeparams);
 }
 
+//===----------------------------------------------------------------------===//
+// NullOp
+//===----------------------------------------------------------------------===//
+
+void hlfir::NullOp::build(mlir::OpBuilder &builder,
+                          mlir::OperationState &odsState) {
+  return build(builder, odsState,
+               fir::ReferenceType::get(builder.getNoneType()));
+}
+
 #define GET_OP_CLASSES
 #include "flang/Optimizer/HLFIR/HLFIROps.cpp.inc"
index a5c31b3..561f3e3 100644 (file)
@@ -291,6 +291,18 @@ public:
   }
 };
 
+class NullOpConversion : public mlir::OpRewritePattern<hlfir::NullOp> {
+public:
+  explicit NullOpConversion(mlir::MLIRContext *ctx) : OpRewritePattern{ctx} {}
+
+  mlir::LogicalResult
+  matchAndRewrite(hlfir::NullOp nullop,
+                  mlir::PatternRewriter &rewriter) const override {
+    rewriter.replaceOpWithNewOp<fir::ZeroOp>(nullop, nullop.getType());
+    return mlir::success();
+  }
+};
+
 class ConvertHLFIRtoFIR
     : public hlfir::impl::ConvertHLFIRtoFIRBase<ConvertHLFIRtoFIR> {
 public:
@@ -302,8 +314,9 @@ public:
     auto module = this->getOperation();
     auto *context = &getContext();
     mlir::RewritePatternSet patterns(context);
-    patterns.insert<AssignOpConversion, DeclareOpConversion,
-                    DesignateOpConversion, NoReassocOpConversion>(context);
+    patterns
+        .insert<AssignOpConversion, DeclareOpConversion, DesignateOpConversion,
+                NoReassocOpConversion, NullOpConversion>(context);
     mlir::ConversionTarget target(*context);
     target.addIllegalDialect<hlfir::hlfirDialect>();
     target.markUnknownOpDynamicallyLegal(
diff --git a/flang/test/HLFIR/null-codegen.fir b/flang/test/HLFIR/null-codegen.fir
new file mode 100644 (file)
index 0000000..4568c45
--- /dev/null
@@ -0,0 +1,9 @@
+// Test hlfir.null code generation to FIR
+
+// RUN: fir-opt %s -convert-hlfir-to-fir | FileCheck %s
+
+func.func @test() {
+  // CHECK: fir.zero_bits !fir.ref<none>
+  %0 = hlfir.null !fir.ref<none>
+  return
+}
diff --git a/flang/test/HLFIR/null.fir b/flang/test/HLFIR/null.fir
new file mode 100644 (file)
index 0000000..4614f2b
--- /dev/null
@@ -0,0 +1,9 @@
+// Test hlfir.null operation parse, verify (no errors), and unparse.
+
+// RUN: fir-opt %s | fir-opt | FileCheck %s
+
+func.func @test() {
+  // CHECK: hlfir.null !fir.ref<none>
+  %0 = hlfir.null !fir.ref<none>
+  return
+}