[flang-commits] [flang] bc03423 - [flang] Upstream recent work on FIR to llvm-project.
Eric Schweitz via flang-commits
flang-commits at lists.llvm.org
Mon Apr 27 17:49:16 PDT 2020
Author: Eric Schweitz
Date: 2020-04-27T17:48:57-07:00
New Revision: bc0342383dde329ab2bb07085900a533f0c053db
URL: https://github.com/llvm/llvm-project/commit/bc0342383dde329ab2bb07085900a533f0c053db
DIFF: https://github.com/llvm/llvm-project/commit/bc0342383dde329ab2bb07085900a533f0c053db.diff
LOG: [flang] Upstream recent work on FIR to llvm-project.
Summary:
Reviewers: DavidTruby, sscalpone, jeanPerier
Subscribers: mgorny, aartbik, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78835
Added:
Modified:
flang/include/flang/Optimizer/Dialect/FIRDialect.h
flang/include/flang/Optimizer/Dialect/FIROps.h
flang/include/flang/Optimizer/Dialect/FIROps.td
flang/include/flang/Optimizer/Dialect/FIRType.h
flang/lib/Optimizer/Dialect/FIRAttr.cpp
flang/lib/Optimizer/Dialect/FIRDialect.cpp
flang/lib/Optimizer/Dialect/FIROps.cpp
flang/lib/Optimizer/Dialect/FIRType.cpp
flang/test/Fir/fir-ops.fir
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/Dialect/FIRDialect.h b/flang/include/flang/Optimizer/Dialect/FIRDialect.h
index 7a8fc18937fc..92fd23b5044f 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRDialect.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRDialect.h
@@ -13,20 +13,6 @@
#include "mlir/InitAllDialects.h"
#include "mlir/InitAllPasses.h"
-namespace llvm {
-class raw_ostream;
-class StringRef;
-} // namespace llvm
-
-namespace mlir {
-class Attribute;
-class DialectAsmParser;
-class DialectAsmPrinter;
-class Location;
-class MLIRContext;
-class Type;
-} // namespace mlir
-
namespace fir {
/// FIR dialect
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.h b/flang/include/flang/Optimizer/Dialect/FIROps.h
index f5763693f7bb..992fe48d539c 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.h
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.h
@@ -10,6 +10,8 @@
#define OPTIMIZER_DIALECT_FIROPS_H
#include "mlir/Dialect/StandardOps/IR/Ops.h"
+#include "mlir/Interfaces/LoopLikeInterface.h"
+#include "mlir/Interfaces/SideEffects.h"
using namespace mlir;
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 15d1bbf89001..8ecb1711c7e0 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -16,6 +16,7 @@
include "mlir/IR/SymbolInterfaces.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
+include "mlir/Interfaces/LoopLikeInterface.td"
include "mlir/Interfaces/SideEffects.td"
def fir_Dialect : Dialect {
@@ -195,8 +196,9 @@ class fir_AllocatableBaseOp<string mnemonic, list<OpTrait> traits = []> :
);
}
-class fir_AllocatableOp<string mnemonic, list<OpTrait> traits =[]> :
- fir_AllocatableBaseOp<mnemonic, !listconcat([NoSideEffect], traits)>,
+class fir_AllocatableOp<string mnemonic, list<OpTrait> traits = []> :
+ fir_AllocatableBaseOp<mnemonic,
+ !listconcat(traits, [MemoryEffects<[MemAlloc]>])>,
fir_TwoBuilders<fir_AllocateOpBuilder, fir_NamedAllocateOpBuilder>,
Arguments<(ins TypeAttr:$in_type, Variadic<AnyIntegerType>:$args)> {
@@ -263,18 +265,27 @@ class fir_AllocatableOp<string mnemonic, list<OpTrait> traits =[]> :
static constexpr llvm::StringRef inType() { return "in_type"; }
static constexpr llvm::StringRef lenpName() { return "len_param_count"; }
mlir::Type getAllocatedType();
+
bool hasLenParams() { return bool{getAttr(lenpName())}; }
+
unsigned numLenParams() {
if (auto val = getAttrOfType<mlir::IntegerAttr>(lenpName()))
return val.getInt();
return 0;
}
+
operand_range getLenParams() {
return {operand_begin(), operand_begin() + numLenParams()};
}
+
+ unsigned numShapeOperands() {
+ return operand_end() - operand_begin() + numLenParams();
+ }
+
operand_range getShapeOperands() {
return {operand_begin() + numLenParams(), operand_end()};
}
+
static mlir::Type getRefTy(mlir::Type ty);
/// Get the input type of the allocation
@@ -286,14 +297,16 @@ class fir_AllocatableOp<string mnemonic, list<OpTrait> traits =[]> :
// Verify checks common to all allocation operations
string allocVerify = [{
llvm::SmallVector<llvm::StringRef, 8> visited;
- if (verifyInType(getInType(), visited))
+ if (verifyInType(getInType(), visited, numShapeOperands()))
return emitOpError("invalid type for allocation");
if (verifyRecordLenParams(getInType(), numLenParams()))
return emitOpError("LEN params do not correspond to type");
}];
}
+//===----------------------------------------------------------------------===//
// Memory SSA operations
+//===----------------------------------------------------------------------===//
def fir_AllocaOp : fir_AllocatableOp<"alloca"> {
let summary = "allocate storage for a temporary on the stack given a type";
@@ -338,7 +351,7 @@ def fir_AllocaOp : fir_AllocatableOp<"alloca"> {
}];
}
-def fir_LoadOp : fir_OneResultOp<"load", []> {
+def fir_LoadOp : fir_OneResultOp<"load", [MemoryEffects<[MemRead]>]> {
let summary = "load a value from a memory reference";
let description = [{
Load a value from a memory reference into an ssa-value (virtual register).
@@ -396,7 +409,7 @@ def fir_LoadOp : fir_OneResultOp<"load", []> {
}];
}
-def fir_StoreOp : fir_Op<"store", []> {
+def fir_StoreOp : fir_Op<"store", [MemoryEffects<[MemWrite]>]> {
let summary = "store an SSA-value to a memory location";
let description = [{
@@ -473,8 +486,7 @@ def fir_UndefOp : fir_OneResultOp<"undefined", [NoSideEffect]> {
let assemblyFormat = "type($intype) attr-dict";
let verifier = [{
- if (auto ref = getType().dyn_cast<fir::ReferenceType>())
- return emitOpError("undefined values of type !fir.ref not allowed");
+ // allow `undef : ref<T>` since it is a possible from transformations
return mlir::success();
}];
}
@@ -508,7 +520,7 @@ def fir_AllocMemOp : fir_AllocatableOp<"allocmem"> {
}];
}
-def fir_FreeMemOp : fir_Op<"freemem", []> {
+def fir_FreeMemOp : fir_Op<"freemem", [MemoryEffects<[MemFree]>]> {
let summary = "free a heap object";
let description = [{
@@ -530,7 +542,8 @@ def fir_FreeMemOp : fir_Op<"freemem", []> {
let assemblyFormat = "$heapref attr-dict `:` type($heapref)";
}
-//===----------------------------------------------------------------------===//// Terminator operations
+//===----------------------------------------------------------------------===//
+// Terminator operations
//===----------------------------------------------------------------------===//
class fir_SwitchTerminatorOp<string mnemonic, list<OpTrait> traits = []> :
@@ -547,29 +560,15 @@ class fir_SwitchTerminatorOp<string mnemonic, list<OpTrait> traits = []> :
let successors = (successor VariadicSuccessor<AnySuccessor>:$targets);
- let builders = [OpBuilder<
- "Builder *, OperationState &result, Value selector,"
- "ValueRange properOperands, ArrayRef<Block *> destinations,"
- "ArrayRef<ValueRange> operands = {},"
- "ArrayRef<NamedAttribute> attributes = {}",
- [{
- result.addOperands(selector);
- result.addOperands(properOperands);
- for (auto kvp : llvm::zip(destinations, operands)) {
- result.addSuccessors(std::get<0>(kvp));
- result.addOperands(std::get<1>(kvp));
- }
- result.addAttributes(attributes);
- }]
- >];
-
string extraSwitchClassDeclaration = [{
using Conditions = mlir::Value;
static constexpr llvm::StringRef getCasesAttr() { return "case_tags"; }
// The number of destination conditions that may be tested
- unsigned getNumConditions() { return getNumDest(); }
+ unsigned getNumConditions() {
+ return getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).size();
+ }
// The selector is the value being tested to determine the destination
mlir::Value getSelector() { return selector(); }
@@ -596,12 +595,51 @@ class fir_SwitchTerminatorOp<string mnemonic, list<OpTrait> traits = []> :
else
p.printSuccessor(succ);
}
+
+ unsigned targetOffsetSize();
}];
}
class fir_IntegralSwitchTerminatorOp<string mnemonic,
list<OpTrait> traits = []> : fir_SwitchTerminatorOp<mnemonic, traits> {
+ let skipDefaultBuilders = 1;
+ let builders = [OpBuilder<
+ "Builder *builder, OperationState &result, Value selector,"
+ "ArrayRef<int64_t> compareOperands, ArrayRef<Block *> destinations,"
+ "ArrayRef<ValueRange> destOperands = {},"
+ "ArrayRef<NamedAttribute> attributes = {}",
+ [{
+ result.addOperands(selector);
+ llvm::SmallVector<mlir::Attribute, 8> ivalues;
+ for (auto iv : compareOperands)
+ ivalues.push_back(builder->getI64IntegerAttr(iv));
+ ivalues.push_back(builder->getUnitAttr());
+ result.addAttribute(getCasesAttr(), builder->getArrayAttr(ivalues));
+ const auto count = destinations.size();
+ for (auto d : destinations)
+ result.addSuccessors(d);
+ const auto opCount = destOperands.size();
+ llvm::SmallVector<int32_t, 8> argOffs;
+ int32_t sumArgs = 0;
+ for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
+ if (i < opCount) {
+ result.addOperands(destOperands[i]);
+ const auto argSz = destOperands[i].size();
+ argOffs.push_back(argSz);
+ sumArgs += argSz;
+ } else {
+ argOffs.push_back(0);
+ }
+ }
+ result.addAttribute(getOperandSegmentSizeAttr(),
+ builder->getI32VectorAttr({1, 0, sumArgs}));
+ result.addAttribute(getTargetOffsetAttr(),
+ builder->getI32VectorAttr(argOffs));
+ result.addAttributes(attributes);
+ }]
+ >];
+
let parser = [{
mlir::OpAsmParser::OperandType selector;
mlir::Type type;
@@ -674,14 +712,17 @@ class fir_IntegralSwitchTerminatorOp<string mnemonic,
getSelector().getType().isa<fir::IntType>()))
return emitOpError("must be an integer");
auto cases = getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
- auto count = getNumConditions();
+ auto count = getNumDest();
+ if (count == 0)
+ return emitOpError("must have at least one successor");
+ if (getNumConditions() != count)
+ return emitOpError("number of cases and targets don't match");
+ if (targetOffsetSize() != count)
+ return emitOpError("incorrect number of successor operand groups");
for (decltype(count) i = 0; i != count; ++i) {
auto &attr = cases[i];
- if (attr.isa<mlir::IntegerAttr>() || attr.isa<mlir::UnitAttr>()) {
- // ok
- } else {
+ if (!(attr.isa<mlir::IntegerAttr>() || attr.isa<mlir::UnitAttr>()))
return emitOpError("invalid case alternative");
- }
}
return mlir::success();
}];
@@ -750,6 +791,17 @@ def fir_SelectCaseOp : fir_SwitchTerminatorOp<"select_case"> {
```
}];
+ let skipDefaultBuilders = 1;
+ let builders = [
+ OpBuilder<"Builder *builder, OperationState &result, Value selector,"
+ "ArrayRef<mlir::Attribute> compareAttrs, ArrayRef<ValueRange> cmpOperands,"
+ "ArrayRef<Block *> destinations, ArrayRef<ValueRange> destOperands = {},"
+ "ArrayRef<NamedAttribute> attributes = {}">,
+ OpBuilder<"Builder *builder, OperationState &result, Value selector,"
+ "ArrayRef<mlir::Attribute> compareAttrs, ArrayRef<Value> cmpOpList,"
+ "ArrayRef<Block *> destinations, ArrayRef<ValueRange> destOperands = {},"
+ "ArrayRef<NamedAttribute> attributes = {}">];
+
let parser = "return parseSelectCase(parser, result);";
let printer = [{
@@ -786,23 +838,30 @@ def fir_SelectCaseOp : fir_SwitchTerminatorOp<"select_case"> {
getSelector().getType().isa<fir::CharacterType>()))
return emitOpError("must be an integer, character, or logical");
auto cases = getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
- auto count = getNumConditions();
+ auto count = getNumDest();
+ if (count == 0)
+ return emitOpError("must have at least one successor");
+ if (getNumConditions() != count)
+ return emitOpError("number of conditions and successors don't match");
+ if (compareOffsetSize() != count)
+ return emitOpError("incorrect number of compare operand groups");
+ if (targetOffsetSize() != count)
+ return emitOpError("incorrect number of successor operand groups");
for (decltype(count) i = 0; i != count; ++i) {
auto &attr = cases[i];
- if (attr.isa<fir::PointIntervalAttr>() ||
- attr.isa<fir::LowerBoundAttr>() ||
- attr.isa<fir::UpperBoundAttr>() ||
- attr.isa<fir::ClosedIntervalAttr>() ||
- attr.isa<mlir::UnitAttr>()) {
- // ok
- } else {
+ if (!(attr.isa<fir::PointIntervalAttr>() ||
+ attr.isa<fir::LowerBoundAttr>() ||
+ attr.isa<fir::UpperBoundAttr>() ||
+ attr.isa<fir::ClosedIntervalAttr>() ||
+ attr.isa<mlir::UnitAttr>()))
return emitOpError("incorrect select case attribute type");
- }
}
return mlir::success();
}];
- let extraClassDeclaration = extraSwitchClassDeclaration;
+ let extraClassDeclaration = extraSwitchClassDeclaration#[{
+ unsigned compareOffsetSize();
+ }];
}
def fir_SelectTypeOp : fir_SwitchTerminatorOp<"select_type"> {
@@ -825,6 +884,39 @@ def fir_SelectTypeOp : fir_SwitchTerminatorOp<"select_type"> {
```
}];
+ let skipDefaultBuilders = 1;
+ let builders = [OpBuilder<
+ "Builder *builder, OperationState &result, Value selector,"
+ "ArrayRef<mlir::Attribute> typeOperands,"
+ "ArrayRef<Block *> destinations, ArrayRef<ValueRange> destOperands = {},"
+ "ArrayRef<NamedAttribute> attributes = {}",
+ [{
+ result.addOperands(selector);
+ result.addAttribute(getCasesAttr(), builder->getArrayAttr(typeOperands));
+ const auto count = destinations.size();
+ for (auto d : destinations)
+ result.addSuccessors(d);
+ const auto opCount = destOperands.size();
+ llvm::SmallVector<int32_t, 8> argOffs;
+ int32_t sumArgs = 0;
+ for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
+ if (i < opCount) {
+ result.addOperands(destOperands[i]);
+ const auto argSz = destOperands[i].size();
+ argOffs.push_back(argSz);
+ sumArgs += argSz;
+ } else {
+ argOffs.push_back(0);
+ }
+ }
+ result.addAttribute(getOperandSegmentSizeAttr(),
+ builder->getI32VectorAttr({1, 0, sumArgs}));
+ result.addAttribute(getTargetOffsetAttr(),
+ builder->getI32VectorAttr(argOffs));
+ result.addAttributes(attributes);
+ }]
+ >];
+
let parser = "return parseSelectType(parser, result);";
let printer = [{
@@ -848,15 +940,18 @@ def fir_SelectTypeOp : fir_SwitchTerminatorOp<"select_type"> {
if (!(getSelector().getType().isa<fir::BoxType>()))
return emitOpError("must be a boxed type");
auto cases = getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
- auto count = getNumConditions();
+ auto count = getNumDest();
+ if (count == 0)
+ return emitOpError("must have at least one successor");
+ if (getNumConditions() != count)
+ return emitOpError("number of conditions and successors don't match");
+ if (targetOffsetSize() != count)
+ return emitOpError("incorrect number of successor operand groups");
for (decltype(count) i = 0; i != count; ++i) {
auto &attr = cases[i];
- if (attr.isa<fir::ExactTypeAttr>() || attr.isa<fir::SubclassAttr>() ||
- attr.isa<mlir::UnitAttr>()) {
- // ok
- } else {
+ if (!(attr.isa<fir::ExactTypeAttr>() || attr.isa<fir::SubclassAttr>() ||
+ attr.isa<mlir::UnitAttr>()))
return emitOpError("invalid type-case alternative");
- }
}
return mlir::success();
}];
@@ -1016,9 +1111,6 @@ def fir_EmboxOp : fir_Op<"embox", [NoSideEffect]> {
}
def fir_EmboxCharOp : fir_Op<"emboxchar", [NoSideEffect]> {
- let arguments = (ins AnyReferenceLike:$memref, AnyIntegerLike:$len);
- let results = (outs fir_BoxCharType);
-
let summary = "boxes a given CHARACTER reference and its LEN parameter";
let description = [{
@@ -1040,6 +1132,10 @@ def fir_EmboxCharOp : fir_Op<"emboxchar", [NoSideEffect]> {
This buffer and its LEN value (10) are wrapped into a pair in `%6`.
}];
+ let arguments = (ins AnyReferenceLike:$memref, AnyIntegerLike:$len);
+
+ let results = (outs fir_BoxCharType);
+
let assemblyFormat = [{
$memref `,` $len attr-dict `:` functional-type(operands, results)
}];
@@ -1053,7 +1149,6 @@ def fir_EmboxCharOp : fir_Op<"emboxchar", [NoSideEffect]> {
}
def fir_EmboxProcOp : fir_Op<"emboxproc", [NoSideEffect]> {
-
let summary = "boxes a given procedure and optional host context";
let description = [{
@@ -1232,6 +1327,8 @@ def fir_BoxAddrOp : fir_SimpleOneResultOp<"box_addr", [NoSideEffect]> {
let arguments = (ins fir_BoxType:$val);
let results = (outs AnyReferenceLike);
+
+ let hasFolder = 1;
}
def fir_BoxCharLenOp : fir_SimpleOp<"boxchar_len", [NoSideEffect]> {
@@ -1249,6 +1346,8 @@ def fir_BoxCharLenOp : fir_SimpleOp<"boxchar_len", [NoSideEffect]> {
let arguments = (ins fir_BoxCharType:$val);
let results = (outs AnyIntegerLike);
+
+ let hasFolder = 1;
}
def fir_BoxDimsOp : fir_Op<"box_dims", [NoSideEffect]> {
@@ -1445,8 +1544,8 @@ def fir_CoordinateOp : fir_Op<"coordinate_of", [NoSideEffect]> {
```mlir
%i = ... : index
- %h = ... : !fir.heap<!fir.array<?:f32>>
- %p = fir.coordinate_of %h, %i : (!fir.heap<!fir.array<?:f32>>, index) -> !fir.ref<f32>
+ %h = ... : !fir.heap<!fir.array<100 x f32>>
+ %p = fir.coordinate_of %h, %i : (!fir.heap<!fir.array<100 x f32>>, index) -> !fir.ref<f32>
```
In the example, `%p` will be a pointer to the `%i`-th f32 value in the
@@ -1457,11 +1556,27 @@ def fir_CoordinateOp : fir_Op<"coordinate_of", [NoSideEffect]> {
let results = (outs fir_ReferenceType);
- let assemblyFormat = [{
- operands attr-dict `:` functional-type(operands, results)
- }];
+ let parser = "return parseCoordinateOp(parser, result);";
+ let printer = [{
+ p << getOperationName() << ' ' << getOperation()->getOperands();
+ p.printOptionalAttrDict(getAttrs(), /*elidedAttrs=*/{baseType()});
+ p << " : ";
+ p.printFunctionalType(getOperation()->getOperandTypes(),
+ getOperation()->getResultTypes());
+ }];
+
let verifier = [{
+ auto refTy = ref().getType();
+ if (fir::isa_ref_type(refTy)) {
+ auto eleTy = fir::dyn_cast_ptrEleTy(refTy);
+ if (auto arrTy = eleTy.dyn_cast<fir::SequenceType>()) {
+ if (arrTy.hasUnknownShape())
+ return emitOpError("cannot find coordinate in unknown shape");
+ if (arrTy.getConstantRows() < arrTy.getDimension() - 1)
+ return emitOpError("cannot find coordinate with unknown extents");
+ }
+ }
// Recovering a LEN type parameter only makes sense from a boxed value
for (auto co : coor())
if (dyn_cast_or_null<LenParamIndexOp>(co.getDefiningOp())) {
@@ -1470,8 +1585,28 @@ def fir_CoordinateOp : fir_Op<"coordinate_of", [NoSideEffect]> {
if (!ref().getType().dyn_cast<BoxType>())
return emitOpError("len_param_index must be used on box type");
}
+ if (auto attr = getAttr(CoordinateOp::baseType())) {
+ if (!attr.isa<mlir::TypeAttr>())
+ return emitOpError("improperly constructed");
+ } else {
+ return emitOpError("must have base type");
+ }
return mlir::success();
}];
+
+ let skipDefaultBuilders = 1;
+ let builders = [
+ OpBuilder<"mlir::Builder *builder, OperationState &result,"
+ "Type type, Value ref, ValueRange coor,"
+ "ArrayRef<NamedAttribute> attrs = {}">,
+ OpBuilder<"mlir::Builder *builder, OperationState &result,"
+ "Type type, ValueRange operands,"
+ "ArrayRef<NamedAttribute> attrs = {}">];
+
+ let extraClassDeclaration = [{
+ static constexpr llvm::StringRef baseType() { return "base_type"; }
+ mlir::Type getBaseType();
+ }];
}
def fir_ExtractValueOp : fir_OneResultOp<"extract_value", [NoSideEffect]> {
@@ -1602,7 +1737,7 @@ def fir_GenDimsOp : fir_OneResultOp<"gendims", [NoSideEffect]> {
stride must not be zero.
```mlir
- %d = fir.gendims %l, %u, %s : (index, index, index) -> !fir.dims<1>
+ %d = fir.gendims %lo, %ext, %str : (index, index, index) -> !fir.dims<1>
```
}];
@@ -1713,20 +1848,52 @@ def fir_LenParamIndexOp : fir_OneResultOp<"len_param_index", [NoSideEffect]> {
}];
}
+//===----------------------------------------------------------------------===//
// Fortran loops
+//===----------------------------------------------------------------------===//
-def ImplicitFirTerminator : SingleBlockImplicitTerminator<"FirEndOp">;
+def fir_ResultOp : fir_Op<"result", [NoSideEffect, ReturnLike, Terminator]> {
+ let summary = "special terminator for use in fir region operations";
+
+ let description = [{
+ Result takes a list of ssa-values produced in the block and forwards them
+ as a result to the operation that owns the region of the block. The
+ operation can retain the values or return them to its parent block
+ depending upon its semantics.
+ }];
+
+ let arguments = (ins Variadic<AnyType>:$results);
+ let builders = [
+ OpBuilder<"Builder *builder, OperationState &result", "/* do nothing */">
+ ];
+
+ let assemblyFormat = "($results^ `:` type($results))? attr-dict";
+
+ let verifier = [{ return ::verify(*this); }];
+}
-def fir_LoopOp : fir_Op<"loop", [ImplicitFirTerminator]> {
+def FirRegionTerminator : SingleBlockImplicitTerminator<"ResultOp">;
+
+class region_Op<string mnemonic, list<OpTrait> traits = []> :
+ fir_Op<mnemonic,
+ !listconcat(traits, [FirRegionTerminator, RecursiveSideEffects])> {
+ let printer = [{ return ::print(p, *this); }];
+ let verifier = [{ return ::verify(*this); }];
+ let parser = [{ return ::parse$cppClass(parser, result); }];
+}
+
+def fir_LoopOp : region_Op<"do_loop",
+ [DeclareOpInterfaceMethods<LoopLikeOpInterface>]> {
let summary = "generalized loop operation";
let description = [{
Generalized high-level looping construct. This operation is similar to
- MLIR's `loop.for`. An ordered loop will return the final value of `%i`.
+ MLIR's `loop.for`.
```mlir
%l = constant 0 : index
%u = constant 9 : index
- fir.loop %i = %l to %u unordered {
+ %s = constant 1 : index
+ fir.do_loop %i = %l to %u step %s unordered {
%x = fir.convert %i : (index) -> i32
%v = fir.call @compute(%x) : (i32) -> f32
%p = fir.coordinate_of %A, %i : (!fir.ref<f32>, index) -> !fir.ref<f32>
@@ -1741,143 +1908,100 @@ def fir_LoopOp : fir_Op<"loop", [ImplicitFirTerminator]> {
let arguments = (ins
Index:$lowerBound,
Index:$upperBound,
- Variadic<Index>:$optStep,
- OptionalAttr<I64Attr>:$constantStep,
+ Index:$step,
+ Variadic<AnyType>:$initArgs,
OptionalAttr<UnitAttr>:$unordered
);
-
- let results = (outs Variadic<Index>:$lastVal);
-
+ let results = (outs
+ Variadic<AnyType>:$results
+ );
let regions = (region SizedRegion<1>:$region);
let skipDefaultBuilders = 1;
let builders = [
OpBuilder<"mlir::Builder *builder, OperationState &result,"
"mlir::Value lowerBound, mlir::Value upperBound,"
- "ValueRange step = {}, ArrayRef<NamedAttribute> attributes = {}">
+ "mlir::Value step, bool unordered = false,"
+ "ValueRange iterArgs = llvm::None,"
+ "ArrayRef<NamedAttribute> attributes = {}">
];
- let parser = "return parseLoopOp(parser, result);";
-
- let printer = [{
- p << getOperationName() << ' ' << getInductionVar() << " = "
- << lowerBound() << " to " << upperBound();
- auto s = optStep();
- if (s.begin() != s.end()) {
- p << " step ";
- p.printOperand(*s.begin());
- }
- if (unordered())
- p << " unordered";
- p.printRegion(region(), /*printEntryBlockArgs=*/false,
- /*printBlockTerminators=*/false);
- p.printOptionalAttrDict(getAttrs(), {unorderedAttrName(), stepAttrName()});
- }];
-
- let verifier = [{
- auto step = optStep();
- if (step.begin() != step.end()) {
- // FIXME: size of step must be 1
- auto *s = (*step.begin()).getDefiningOp();
- if (auto cst = dyn_cast_or_null<mlir::ConstantIndexOp>(s))
- if (cst.getValue() == 0)
- return emitOpError("constant step operand must be nonzero");
- }
-
- // Check that the body defines as single block argument for the induction
- // variable.
- auto *body = getBody();
- if (body->getNumArguments() != 1 ||
- !body->getArgument(0).getType().isIndex())
- return emitOpError("expected body to have a single index argument for "
- "the induction variable");
- if (lastVal().size() > 1)
- return emitOpError("can only return one final value of iterator");
- return mlir::success();
- }];
-
let extraClassDeclaration = [{
- static constexpr const char *unorderedAttrName() { return "unordered"; }
- static constexpr const char *stepAttrName() { return "step"; }
-
- /// Is this an unordered loop?
- bool isUnordered() { return getAttr(unorderedAttrName()).isa<UnitAttr>(); }
+ static constexpr llvm::StringRef unorderedAttrName() { return "unordered"; }
- /// Does loop set (and return) the final value of the control variable?
- bool hasLastValue() { return lastVal().size(); }
-
- /// Get the block argument corresponding to the loop control value (PHI)
mlir::Value getInductionVar() { return getBody()->getArgument(0); }
-
- void setLowerBound(mlir::Value bound) {
- getOperation()->setOperand(0, bound);
+ mlir::OpBuilder getBodyBuilder() {
+ return OpBuilder(getBody(), std::prev(getBody()->end()));
+ }
+ mlir::Block::BlockArgListType getRegionIterArgs() {
+ return getBody()->getArguments().drop_front();
}
+ mlir::Operation::operand_range getIterOperands() {
+ return getOperands().drop_front(getNumControlOperands());
+ }
+
+ void setLowerBound(Value bound) { getOperation()->setOperand(0, bound); }
+ void setUpperBound(Value bound) { getOperation()->setOperand(1, bound); }
+ void setStep(Value step) { getOperation()->setOperand(2, step); }
- void setUpperBound(mlir::Value bound) {
- getOperation()->setOperand(1, bound);
+ /// Number of region arguments for loop-carried values
+ unsigned getNumRegionIterArgs() {
+ return getBody()->getNumArguments() - 1;
+ }
+ /// Number of operands controlling the loop: lb, ub, step
+ unsigned getNumControlOperands() { return 3; }
+ /// Does the operation hold operands for loop-carried values
+ bool hasIterOperands() {
+ return getOperation()->getNumOperands() > getNumControlOperands();
+ }
+ /// Get Number of loop-carried values
+ unsigned getNumIterOperands() {
+ return getOperation()->getNumOperands() - getNumControlOperands();
}
- void setStep(mlir::Value step) {
- getOperation()->setOperand(2, step);
+ /// Get the body of the loop
+ mlir::Block *getBody() { return ®ion().front(); }
+
+ void setUnordered() {
+ getOperation()->setAttr(unorderedAttrName(),
+ mlir::UnitAttr::get(getContext()));
}
}];
}
-def fir_WhereOp : fir_Op<"where", [ImplicitFirTerminator]> {
- let summary = "generalized conditional operation";
+def fir_WhereOp : region_Op<"if"> {
+ let summary = "if-then-else conditional operation";
let description = [{
- To conditionally execute operations (typically) within the body of a
- `fir.loop` operation. This operation is similar to `loop.if`.
+ Used to conditionally execute operations. This operation is the FIR
+ dialect's version of `loop.if`.
```mlir
%56 = ... : i1
%78 = ... : !fir.ref<!T>
- fir.where %56 {
+ fir.if %56 {
fir.store %76 to %78 : !fir.ref<!T>
- } otherwise {
+ } else {
fir.store %77 to %78 : !fir.ref<!T>
}
```
}];
let arguments = (ins I1:$condition);
+ let results = (outs Variadic<AnyType>:$results);
- let regions = (region SizedRegion<1>:$whereRegion, AnyRegion:$otherRegion);
+ let regions = (region
+ SizedRegion<1>:$whereRegion,
+ AnyRegion:$otherRegion
+ );
let skipDefaultBuilders = 1;
let builders = [
OpBuilder<"Builder *builder, OperationState &result, "
- "Value cond, bool withOtherRegion">
+ "Value cond, bool withOtherRegion">,
+ OpBuilder<"Builder *builder, OperationState &result, "
+ "TypeRange resultTypes, Value cond, bool withOtherRegion">
];
- let parser = [{ return parseWhereOp(parser, result); }];
-
- let printer = [{
- p << getOperationName() << ' ' << condition();
- p.printRegion(whereRegion(), /*printEntryBlockArgs=*/false,
- /*printBlockTerminators=*/false);
-
- // Print the 'else' regions if it exists and has a block.
- auto &otherReg = otherRegion();
- if (!otherReg.empty()) {
- p << " otherwise";
- p.printRegion(otherReg, /*printEntryBlockArgs=*/false,
- /*printBlockTerminators=*/false);
- }
- p.printOptionalAttrDict(getAttrs());
- }];
-
- let verifier = [{
- for (auto ®ion : getOperation()->getRegions()) {
- if (region.empty())
- continue;
- for (auto &b : region)
- if (b.getNumArguments() != 0)
- return emitOpError("requires that child entry blocks have no args");
- }
- return mlir::success();
- }];
-
let extraClassDeclaration = [{
mlir::OpBuilder getWhereBodyBuilder() {
assert(!whereRegion().empty() && "Unexpected empty 'where' region.");
@@ -1892,9 +2016,81 @@ def fir_WhereOp : fir_Op<"where", [ImplicitFirTerminator]> {
}];
}
+def fir_IterWhileOp : region_Op<"iterate_while",
+ [DeclareOpInterfaceMethods<LoopLikeOpInterface>]> {
+ let summary = "DO loop with early exit condition";
+ let description = [{
+ This construct is useful for lowering implied-DO loops. It is very similar
+ to `fir::LoopOp` with the addition that it requires a single loop-carried
+ bool value that signals an early exit condition to the operation. A `true`
+ disposition means the next loop iteration should proceed. A `false`
+ indicates that the `fir.iterate_while` operation should terminate and
+ return its iteration arguments.
+ }];
+
+ let arguments = (ins
+ Index:$lowerBound,
+ Index:$upperBound,
+ Index:$step,
+ I1:$iterateIn,
+ Variadic<AnyType>:$initArgs
+ );
+ let results = (outs
+ I1:$iterateResult,
+ Variadic<AnyType>:$results
+ );
+ let regions = (region SizedRegion<1>:$region);
+
+ let skipDefaultBuilders = 1;
+ let builders = [
+ OpBuilder<"mlir::Builder *builder, OperationState &result,"
+ "mlir::Value lowerBound, mlir::Value upperBound,"
+ "mlir::Value step, mlir::Value iterate,"
+ "ValueRange iterArgs = llvm::None,"
+ "ArrayRef<NamedAttribute> attributes = {}">
+ ];
+
+ let extraClassDeclaration = [{
+ mlir::Block *getBody() { return ®ion().front(); }
+ mlir::Value getIterateVar() { return getBody()->getArgument(1); }
+ mlir::Value getInductionVar() { return getBody()->getArgument(0); }
+ mlir::OpBuilder getBodyBuilder() {
+ return mlir::OpBuilder(getBody(), std::prev(getBody()->end()));
+ }
+ mlir::Block::BlockArgListType getRegionIterArgs() {
+ return getBody()->getArguments().drop_front();
+ }
+ mlir::Operation::operand_range getIterOperands() {
+ return getOperands().drop_front(getNumControlOperands());
+ }
+
+ void setLowerBound(Value bound) { getOperation()->setOperand(0, bound); }
+ void setUpperBound(Value bound) { getOperation()->setOperand(1, bound); }
+ void setStep(mlir::Value step) { getOperation()->setOperand(2, step); }
+
+ /// Number of region arguments for loop-carried values
+ unsigned getNumRegionIterArgs() {
+ return getBody()->getNumArguments() - 1;
+ }
+ /// Number of operands controlling the loop
+ unsigned getNumControlOperands() { return 3; }
+ /// Does the operation hold operands for loop-carried values
+ bool hasIterOperands() {
+ return getOperation()->getNumOperands() > getNumControlOperands();
+ }
+ /// Get Number of loop-carried values
+ unsigned getNumIterOperands() {
+ return getOperation()->getNumOperands() - getNumControlOperands();
+ }
+ }];
+}
+
+//===----------------------------------------------------------------------===//
// Procedure call operations
+//===----------------------------------------------------------------------===//
-def fir_CallOp : fir_Op<"call", []> {
+def fir_CallOp : fir_Op<"call",
+ [MemoryEffects<[MemAlloc, MemFree, MemRead, MemWrite]>]> {
let summary = "call a procedure";
let description = [{
@@ -1924,7 +2120,8 @@ def fir_CallOp : fir_Op<"call", []> {
}];
}
-def fir_DispatchOp : fir_Op<"dispatch", []> {
+def fir_DispatchOp : fir_Op<"dispatch",
+ [MemoryEffects<[MemAlloc, MemFree, MemRead, MemWrite]>]> {
let summary = "call a type-bound procedure";
let description = [{
@@ -2025,7 +2222,8 @@ def fir_StringLitOp : fir_Op<"string_lit", [NoSideEffect]> {
else if (auto v = val.dyn_cast<mlir::ArrayAttr>())
result.attributes.push_back(builder.getNamedAttr(xlist(), v));
else
- return mlir::failure();
+ return parser.emitError(parser.getCurrentLocation(),
+ "found an invalid constant");
mlir::IntegerAttr sz;
mlir::Type type;
if (parser.parseLParen() ||
@@ -2033,9 +2231,11 @@ def fir_StringLitOp : fir_Op<"string_lit", [NoSideEffect]> {
parser.parseRParen() ||
parser.parseColonType(type))
return mlir::failure();
+ if (!(type.isa<fir::CharacterType>() || type.isa<mlir::IntegerType>()))
+ return parser.emitError(parser.getCurrentLocation(),
+ "must have character type");
type = fir::SequenceType::get({sz.getInt()}, type);
- if (!type ||
- parser.addTypesToList(type, result.types))
+ if (!type || parser.addTypesToList(type, result.types))
return mlir::failure();
return mlir::success();
}];
@@ -2084,7 +2284,7 @@ def fir_StringLitOp : fir_Op<"string_lit", [NoSideEffect]> {
class fir_ArithmeticOp<string mnemonic, list<OpTrait> traits = []> :
fir_Op<mnemonic,
- !listconcat(traits, [NoSideEffect, SameOperandsAndResultType])>,
+ !listconcat(traits, [NoSideEffect, SameOperandsAndResultType])>,
Results<(outs AnyType)> {
let parser = [{
return impl::parseOneResultSameOperandTypeOp(parser, result);
@@ -2095,7 +2295,7 @@ class fir_ArithmeticOp<string mnemonic, list<OpTrait> traits = []> :
class fir_UnaryArithmeticOp<string mnemonic, list<OpTrait> traits = []> :
fir_Op<mnemonic,
- !listconcat(traits, [NoSideEffect, SameOperandsAndResultType])>,
+ !listconcat(traits, [NoSideEffect, SameOperandsAndResultType])>,
Results<(outs AnyType)> {
let parser = [{
return impl::parseOneResultSameOperandTypeOp(parser, result);
@@ -2140,9 +2340,15 @@ class RealArithmeticOp<string mnemonic, list<OpTrait> traits = []> :
fir_ArithmeticOp<mnemonic, traits>,
Arguments<(ins AnyRealLike:$lhs, AnyRealLike:$rhs)>;
-def fir_AddfOp : RealArithmeticOp<"addf", [Commutative]>;
-def fir_SubfOp : RealArithmeticOp<"subf">;
-def fir_MulfOp : RealArithmeticOp<"mulf", [Commutative]>;
+def fir_AddfOp : RealArithmeticOp<"addf", [Commutative]> {
+ let hasFolder = 1;
+}
+def fir_SubfOp : RealArithmeticOp<"subf"> {
+ let hasFolder = 1;
+}
+def fir_MulfOp : RealArithmeticOp<"mulf", [Commutative]> {
+ let hasFolder = 1;
+}
def fir_DivfOp : RealArithmeticOp<"divf">;
def fir_ModfOp : RealArithmeticOp<"modf">;
// Pow is a builtin call and not a primitive
@@ -2183,8 +2389,7 @@ def fir_CmpfOp : fir_Op<"cmpf",
}];
}
-def fir_ConstcOp : fir_Op<"constc", [NoSideEffect]>,
- Results<(outs fir_ComplexType)> {
+def fir_ConstcOp : fir_Op<"constc", [NoSideEffect]> {
let summary = "create a complex constant";
let description = [{
@@ -2193,6 +2398,8 @@ def fir_ConstcOp : fir_Op<"constc", [NoSideEffect]>,
the standard dialect.
}];
+ let results = (outs fir_ComplexType);
+
let parser = [{
fir::RealAttr realp;
fir::RealAttr imagp;
@@ -2290,6 +2497,7 @@ def fir_CmpcOp : fir_Op<"cmpc",
def fir_AddrOfOp : fir_OneResultOp<"address_of", [NoSideEffect]> {
let summary = "convert a symbol to an SSA value";
+
let description = [{
Convert a symbol (a function or global reference) to an SSA-value to be
used in other Operations.
@@ -2308,6 +2516,7 @@ def fir_AddrOfOp : fir_OneResultOp<"address_of", [NoSideEffect]> {
def fir_ConvertOp : fir_OneResultOp<"convert", [NoSideEffect]> {
let summary = "encapsulates all Fortran scalar type conversions";
+
let description = [{
Generalized type conversion. Convert the ssa value from type T to type U.
Not all pairs of types have conversions. When types T and U are the same
@@ -2326,6 +2535,32 @@ def fir_ConvertOp : fir_OneResultOp<"convert", [NoSideEffect]> {
let assemblyFormat = [{
$value attr-dict `:` functional-type($value, results)
}];
+
+ let hasFolder = 1;
+
+ let verifier = [{
+ auto inType = value().getType();
+ auto outType = getType();
+ if (inType == outType)
+ return mlir::success();
+ if ((isPointerCompatible(inType) && isPointerCompatible(outType)) ||
+ (isIntegerCompatible(inType) && isIntegerCompatible(outType)) ||
+ (isIntegerCompatible(inType) && isFloatCompatible(outType)) ||
+ (isFloatCompatible(inType) && isIntegerCompatible(outType)) ||
+ (isFloatCompatible(inType) && isFloatCompatible(outType)) ||
+ (isIntegerCompatible(inType) && isPointerCompatible(outType)) ||
+ (isPointerCompatible(inType) && isIntegerCompatible(outType)) ||
+ (inType.isa<fir::BoxType>() && outType.isa<fir::BoxType>()) ||
+ (fir::isa_complex(inType) && fir::isa_complex(outType)))
+ return mlir::success();
+ return emitOpError("invalid type conversion");
+ }];
+
+ let extraClassDeclaration = [{
+ static bool isIntegerCompatible(mlir::Type ty);
+ static bool isFloatCompatible(mlir::Type ty);
+ static bool isPointerCompatible(mlir::Type ty);
+ }];
}
def FortranTypeAttr : Attr<And<[CPred<"$_self.isa<TypeAttr>()">,
@@ -2396,7 +2631,7 @@ def fir_GenTypeDescOp : fir_OneResultOp<"gentypedesc", [NoSideEffect]> {
}
def fir_NoReassocOp : fir_OneResultOp<"no_reassoc",
- [SameOperandsAndResultType]> {
+ [NoSideEffect, SameOperandsAndResultType]> {
let summary = "synthetic op to prevent reassociation";
let description = [{
Primitive operation meant to intrusively prevent operator reassociation.
@@ -2440,101 +2675,86 @@ def fir_GlobalOp : fir_Op<"global", [IsolatedFromAbove, Symbol]> {
%z = constant 0 : index
%o = constant 1 : index
%4 = fir.insert_value %3, %1, %z : (tuple<i32, f32>, i32, index) -> tuple<i32, f32>
- %5 = fir.insert_value %4, %1, %o : (tuple<i32, f32>, f32, index) -> tuple<i32, f32>
- return %5
+ %5 = fir.insert_value %4, %2, %o : (tuple<i32, f32>, f32, index) -> tuple<i32, f32>
+ fir.has_value %5 : tuple<i32, f32>
}
```
}];
let arguments = (ins
StrAttr:$sym_name,
- OptionalAttr<AnyAttr>:$initval,
- UnitAttr:$constant,
- TypeAttr:$type
+ SymbolRefAttr:$symref,
+ TypeAttr:$type,
+ OptionalAttr<AnyAttr>:$initVal,
+ OptionalAttr<UnitAttr>:$constant,
+ OptionalAttr<StrAttr>:$linkName
);
let regions = (region AtMostRegion<1>:$region);
- let parser = [{
- // Parse the name as a symbol reference attribute.
- SymbolRefAttr nameAttr;
- if (parser.parseAttribute(nameAttr, mlir::SymbolTable::getSymbolAttrName(),
- result.attributes))
- return failure();
-
- auto &builder = parser.getBuilder();
- auto name = nameAttr.getRootReference();
- result.attributes.back().second = builder.getStringAttr(name);
-
- bool simpleInitializer = false;
- if (!parser.parseOptionalLParen()) {
- Attribute attr;
- if (parser.parseAttribute(attr, initValAttrName(), result.attributes) ||
- parser.parseRParen())
- return failure();
- simpleInitializer = true;
- }
-
- if (succeeded(parser.parseOptionalKeyword(constantAttrName()))) {
- // if "constant" keyword then mark this as a constant, not a variable
- result.addAttribute(constantAttrName(), builder.getUnitAttr());
- }
-
- mlir::Type globalType;
- if (parser.parseColonType(globalType))
- return failure();
-
- result.addAttribute(typeAttrName(), mlir::TypeAttr::get(globalType));
-
- if (!simpleInitializer) {
- // Parse the optional initializer body.
- if (parser.parseRegion(*result.addRegion(), llvm::None, llvm::None))
- return failure();
- }
-
- return success();
- }];
+ let parser = "return parseGlobalOp(parser, result);";
let printer = [{
- auto varName = getAttrOfType<StringAttr>(
- mlir::SymbolTable::getSymbolAttrName()).getValue();
- p << getOperationName() << " @" << varName;
- if (auto iv = initval().getValueOr(Attribute())) {
- p << '(';
- p.printAttribute(iv);
- p << ')';
- }
+ p << getOperationName();
+ if (linkName().hasValue())
+ p << ' ' << linkName().getValue();
+ p << ' ';
+ p.printAttributeWithoutType(getAttr(symbolAttrName()));
+ if (auto val = getValueOrNull())
+ p << '(' << val << ')';
if (getAttr(constantAttrName()))
- p << ' ' << constantAttrName();
+ p << " constant";
p << " : ";
p.printType(getType());
- Region &body = getOperation()->getRegion(0);
- if (!body.empty())
- p.printRegion(body, /*printEntryBlockArgs=*/false,
- /*printBlockTerminators=*/true);
+ if (hasInitializationBody())
+ p.printRegion(getOperation()->getRegion(0), /*printEntryBlockArgs=*/false,
+ /*printBlockTerminators=*/true);
}];
let skipDefaultBuilders = 1;
let builders = [
OpBuilder<"mlir::Builder *builder, OperationState &result,"
- "StringRef name, Type type, ArrayRef<NamedAttribute> attrs = {}",
- [{
- result.addAttribute(typeAttrName(), mlir::TypeAttr::get(type));
- result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
- builder->getStringAttr(name));
- result.addAttributes(attrs);
- }]>
+ "StringRef name, Type type, ArrayRef<NamedAttribute> attrs = {}">,
+ OpBuilder<"mlir::Builder *builder, OperationState &result,"
+ "StringRef name, bool isConstant, Type type,"
+ "ArrayRef<NamedAttribute> attrs = {}">,
+ OpBuilder<"mlir::Builder *builder, OperationState &result,"
+ "StringRef name, Type type, StringAttr linkage = {},"
+ "ArrayRef<NamedAttribute> attrs = {}">,
+ OpBuilder<"mlir::Builder *builder, OperationState &result,"
+ "StringRef name, bool isConstant, Type type,"
+ "StringAttr linkage = {},"
+ "ArrayRef<NamedAttribute> attrs = {}">,
+ OpBuilder<"mlir::Builder *builder, OperationState &result,"
+ "StringRef name, Type type, Attribute initVal,"
+ "StringAttr linkage = {},"
+ "ArrayRef<NamedAttribute> attrs = {}">,
+ OpBuilder<"mlir::Builder *builder, OperationState &result,"
+ "StringRef name, bool isConstant, Type type,"
+ "Attribute initVal, StringAttr linkage = {},"
+ "ArrayRef<NamedAttribute> attrs = {}">,
];
let extraClassDeclaration = [{
+ static constexpr llvm::StringRef symbolAttrName() { return "symref"; }
static constexpr llvm::StringRef constantAttrName() { return "constant"; }
- static constexpr llvm::StringRef initValAttrName() { return "initval"; }
+ static constexpr llvm::StringRef initValAttrName() { return "initVal"; }
+ static constexpr llvm::StringRef linkageAttrName() { return "linkName"; }
static constexpr llvm::StringRef typeAttrName() { return "type"; }
+ /// The printable type of the global
mlir::Type getType() {
return getAttrOfType<TypeAttr>(typeAttrName()).getValue();
}
+ /// The semantic type of the global
+ mlir::Type resultType() {
+ return fir::AllocaOp::wrapResultType(getType());
+ }
+
+ /// Return the initializer attribute if it exists, or a null attribute.
+ Attribute getValueOrNull() { return initVal().getValueOr(Attribute()); }
+
/// Append the next initializer value to the `GlobalOp` to construct
/// the variable's initial value.
void appendInitialValue(mlir::Operation *op);
@@ -2544,6 +2764,19 @@ def fir_GlobalOp : fir_Op<"global", [IsolatedFromAbove, Symbol]> {
/// A GlobalOp has one block.
mlir::Block &getBlock() { return getRegion().front(); }
+
+ /// Determine if `linkage` is a supported keyword
+ static mlir::ParseResult verifyValidLinkage(StringRef linkage);
+
+ bool hasInitializationBody() {
+ return (getOperation()->getNumRegions() == 1) && !getRegion().empty() &&
+ !isa<fir::FirEndOp>(getBlock().front());
+ }
+
+ mlir::FlatSymbolRefAttr getSymbol() {
+ return mlir::FlatSymbolRefAttr::get(getAttrOfType<mlir::StringAttr>(
+ mlir::SymbolTable::getSymbolAttrName()).getValue(), getContext());
+ }
}];
}
@@ -2594,8 +2827,10 @@ def fir_GlobalLenOp : fir_Op<"global_len", []> {
}];
}
-def fir_DispatchTableOp : fir_Op<"dispatch_table", [IsolatedFromAbove, Symbol,
- ImplicitFirTerminator]> {
+def ImplicitFirTerminator : SingleBlockImplicitTerminator<"FirEndOp">;
+
+def fir_DispatchTableOp : fir_Op<"dispatch_table",
+ [IsolatedFromAbove, Symbol, ImplicitFirTerminator]> {
let summary = "Dispatch table definition";
let description = [{
diff --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h
index 73174371718a..3749c87b9e94 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRType.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRType.h
@@ -24,6 +24,8 @@ class hash_code;
namespace mlir {
class DialectAsmParser;
class DialectAsmPrinter;
+class ComplexType;
+class FloatType;
} // namespace mlir
namespace fir {
@@ -89,6 +91,19 @@ bool isa_fir_or_std_type(mlir::Type t);
/// Is `t` a FIR dialect type that implies a memory (de)reference?
bool isa_ref_type(mlir::Type t);
+/// Is `t` a type that is always trivially pass-by-reference?
+bool isa_passbyref_type(mlir::Type t);
+
+/// Is `t` a boxed type?
+bool isa_box_type(mlir::Type t);
+
+/// Is `t` a type that can conform to be pass-by-reference? Depending on the
+/// context, these types may simply demote to pass-by-reference or a reference
+/// to them may have to be passed instead.
+inline bool conformsWithPassByRef(mlir::Type t) {
+ return isa_ref_type(t) || isa_box_type(t);
+}
+
/// Is `t` a FIR dialect aggregate type?
bool isa_aggregate(mlir::Type t);
@@ -127,6 +142,10 @@ class CplxType : public mlir::Type::TypeBase<CplxType, mlir::Type,
public:
using Base::Base;
static CplxType get(mlir::MLIRContext *ctxt, KindTy kind);
+
+ /// Get the corresponding fir.real<k> type.
+ mlir::Type getElementType() const;
+
KindTy getFKind() const;
};
@@ -324,6 +343,21 @@ class SequenceType : public mlir::Type::TypeBase<SequenceType, mlir::Type,
/// The number of dimensions of the sequence
unsigned getDimension() const { return getShape().size(); }
+ /// Number of rows of constant extent
+ unsigned getConstantRows() const;
+
+ /// Is the shape of the sequence constant?
+ bool hasConstantShape() const { return getConstantRows() == getDimension(); }
+
+ /// Does the sequence have unknown shape? (`array<* x T>`)
+ bool hasUnknownShape() const { return getShape().empty(); }
+
+ /// Is the interior of the sequence constant? Check if the array is
+ /// one of constant shape (`array<C...xCxT>`), unknown shape
+ /// (`array<*xT>`), or rows with shape and ending with column(s) of
+ /// unknown extent (`array<C...xCx?...x?xT>`).
+ bool hasConstantInterior() const;
+
/// The value `-1` represents an unknown extent for a dimension
static constexpr Extent getUnknownExtent() { return -1; }
@@ -394,6 +428,20 @@ mlir::Type parseFirType(FIROpsDialect *, mlir::DialectAsmParser &parser);
void printFirType(FIROpsDialect *, mlir::Type ty, mlir::DialectAsmPrinter &p);
+/// Guarantee `type` is a scalar integral type (standard Integer, standard
+/// Index, or FIR Int). Aborts execution if condition is false.
+void verifyIntegralType(mlir::Type type);
+
+/// Is `t` a FIR Real or MLIR Float type?
+inline bool isa_real(mlir::Type t) {
+ return t.isa<fir::RealType>() || t.isa<mlir::FloatType>();
+}
+
+/// Is `t` a FIR or MLIR Complex type?
+inline bool isa_complex(mlir::Type t) {
+ return t.isa<fir::CplxType>() || t.isa<mlir::ComplexType>();
+}
+
} // namespace fir
#endif // OPTIMIZER_DIALECT_FIRTYPE_H
diff --git a/flang/lib/Optimizer/Dialect/FIRAttr.cpp b/flang/lib/Optimizer/Dialect/FIRAttr.cpp
index 76cccbfb06d3..09780d306fb8 100644
--- a/flang/lib/Optimizer/Dialect/FIRAttr.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRAttr.cpp
@@ -8,16 +8,11 @@
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
-#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/Support/KindMapping.h"
#include "mlir/IR/AttributeSupport.h"
-#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/DialectImplementation.h"
#include "mlir/IR/Types.h"
-#include "mlir/Parser.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
using namespace fir;
diff --git a/flang/lib/Optimizer/Dialect/FIRDialect.cpp b/flang/lib/Optimizer/Dialect/FIRDialect.cpp
index 9a56c6bc403e..6364c24137f2 100644
--- a/flang/lib/Optimizer/Dialect/FIRDialect.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRDialect.cpp
@@ -10,8 +10,6 @@
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
-#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
-#include "mlir/IR/StandardTypes.h"
using namespace fir;
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index f62e1c4ced18..d8ef6f6f8515 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -10,28 +10,35 @@
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Dialect/FIRType.h"
+#include "mlir/Dialect/CommonFolders.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/Function.h"
+#include "mlir/IR/Matchers.h"
#include "mlir/IR/Module.h"
-#include "mlir/IR/StandardTypes.h"
-#include "mlir/IR/SymbolTable.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/TypeSwitch.h"
using namespace fir;
-/// return true if the sequence type is abstract or the record type is malformed
-/// or contains an abstract sequence type
+/// Return true if a sequence type is of some incomplete size or a record type
+/// is malformed or contains an incomplete sequence type. An incomplete sequence
+/// type is one with more unknown extents in the type than have been provided
+/// via `dynamicExtents`. Sequence types with an unknown rank are incomplete by
+/// definition.
static bool verifyInType(mlir::Type inType,
- llvm::SmallVectorImpl<llvm::StringRef> &visited) {
+ llvm::SmallVectorImpl<llvm::StringRef> &visited,
+ unsigned dynamicExtents = 0) {
if (auto st = inType.dyn_cast<fir::SequenceType>()) {
auto shape = st.getShape();
if (shape.size() == 0)
return true;
- for (auto ext : shape)
- if (ext < 0)
+ for (std::size_t i = 0, end{shape.size()}; i < end; ++i) {
+ if (shape[i] != fir::SequenceType::getUnknownExtent())
+ continue;
+ if (dynamicExtents-- == 0)
return true;
+ }
} else if (auto rt = inType.dyn_cast<fir::RecordType>()) {
// don't recurse if we're already visiting this one
if (llvm::is_contained(visited, rt.getName()))
@@ -57,6 +64,15 @@ static bool verifyRecordLenParams(mlir::Type inType, unsigned numLenParams) {
return false;
}
+//===----------------------------------------------------------------------===//
+// AddfOp
+//===----------------------------------------------------------------------===//
+
+mlir::OpFoldResult fir::AddfOp::fold(llvm::ArrayRef<mlir::Attribute> opnds) {
+ return mlir::constFoldBinaryOp<FloatAttr>(
+ opnds, [](APFloat a, APFloat b) { return a + b; });
+}
+
//===----------------------------------------------------------------------===//
// AllocaOp
//===----------------------------------------------------------------------===//
@@ -100,6 +116,33 @@ mlir::Type fir::AllocMemOp::wrapResultType(mlir::Type intype) {
return HeapType::get(intype);
}
+//===----------------------------------------------------------------------===//
+// BoxAddrOp
+//===----------------------------------------------------------------------===//
+
+mlir::OpFoldResult fir::BoxAddrOp::fold(llvm::ArrayRef<mlir::Attribute> opnds) {
+ if (auto v = val().getDefiningOp()) {
+ if (auto box = dyn_cast<fir::EmboxOp>(v))
+ return box.memref();
+ if (auto box = dyn_cast<fir::EmboxCharOp>(v))
+ return box.memref();
+ }
+ return {};
+}
+
+//===----------------------------------------------------------------------===//
+// BoxCharLenOp
+//===----------------------------------------------------------------------===//
+
+mlir::OpFoldResult
+fir::BoxCharLenOp::fold(llvm::ArrayRef<mlir::Attribute> opnds) {
+ if (auto v = val().getDefiningOp()) {
+ if (auto box = dyn_cast<fir::EmboxCharOp>(v))
+ return box.len();
+ }
+ return {};
+}
+
//===----------------------------------------------------------------------===//
// BoxDimsOp
//===----------------------------------------------------------------------===//
@@ -267,6 +310,103 @@ mlir::ParseResult fir::parseCmpcOp(mlir::OpAsmParser &parser,
return parseCmpOp<fir::CmpcOp>(parser, result);
}
+//===----------------------------------------------------------------------===//
+// ConvertOp
+//===----------------------------------------------------------------------===//
+
+mlir::OpFoldResult fir::ConvertOp::fold(llvm::ArrayRef<mlir::Attribute> opnds) {
+ if (value().getType() == getType())
+ return value();
+ if (matchPattern(value(), m_Op<fir::ConvertOp>())) {
+ auto inner = cast<fir::ConvertOp>(value().getDefiningOp());
+ // (convert (convert 'a : logical -> i1) : i1 -> logical) ==> forward 'a
+ if (auto toTy = getType().dyn_cast<fir::LogicalType>())
+ if (auto fromTy = inner.value().getType().dyn_cast<fir::LogicalType>())
+ if (inner.getType().isa<mlir::IntegerType>() && (toTy == fromTy))
+ return inner.value();
+ // (convert (convert 'a : i1 -> logical) : logical -> i1) ==> forward 'a
+ if (auto toTy = getType().dyn_cast<mlir::IntegerType>())
+ if (auto fromTy = inner.value().getType().dyn_cast<mlir::IntegerType>())
+ if (inner.getType().isa<fir::LogicalType>() && (toTy == fromTy) &&
+ (fromTy.getWidth() == 1))
+ return inner.value();
+ }
+ return {};
+}
+
+bool fir::ConvertOp::isIntegerCompatible(mlir::Type ty) {
+ return ty.isa<mlir::IntegerType>() || ty.isa<mlir::IndexType>() ||
+ ty.isa<fir::IntType>() || ty.isa<fir::LogicalType>() ||
+ ty.isa<fir::CharacterType>();
+}
+
+bool fir::ConvertOp::isFloatCompatible(mlir::Type ty) {
+ return ty.isa<mlir::FloatType>() || ty.isa<fir::RealType>();
+}
+
+bool fir::ConvertOp::isPointerCompatible(mlir::Type ty) {
+ return ty.isa<fir::ReferenceType>() || ty.isa<fir::PointerType>() ||
+ ty.isa<fir::HeapType>() || ty.isa<mlir::MemRefType>() ||
+ ty.isa<fir::TypeDescType>();
+}
+
+//===----------------------------------------------------------------------===//
+// CoordinateOp
+//===----------------------------------------------------------------------===//
+
+static mlir::ParseResult parseCoordinateOp(mlir::OpAsmParser &parser,
+ mlir::OperationState &result) {
+ llvm::ArrayRef<mlir::Type> allOperandTypes;
+ llvm::ArrayRef<mlir::Type> allResultTypes;
+ llvm::SMLoc allOperandLoc = parser.getCurrentLocation();
+ llvm::SmallVector<mlir::OpAsmParser::OperandType, 4> allOperands;
+ if (parser.parseOperandList(allOperands))
+ return failure();
+ if (parser.parseOptionalAttrDict(result.attributes))
+ return failure();
+ if (parser.parseColon())
+ return failure();
+
+ mlir::FunctionType funcTy;
+ if (parser.parseType(funcTy))
+ return failure();
+ allOperandTypes = funcTy.getInputs();
+ allResultTypes = funcTy.getResults();
+ result.addTypes(allResultTypes);
+ if (parser.resolveOperands(allOperands, allOperandTypes, allOperandLoc,
+ result.operands))
+ return failure();
+ if (funcTy.getNumInputs()) {
+ // No inputs handled by verify
+ result.addAttribute(fir::CoordinateOp::baseType(),
+ mlir::TypeAttr::get(funcTy.getInput(0)));
+ }
+ return success();
+}
+
+mlir::Type fir::CoordinateOp::getBaseType() {
+ return getAttr(CoordinateOp::baseType()).cast<mlir::TypeAttr>().getValue();
+}
+
+void fir::CoordinateOp::build(Builder *, OperationState &result,
+ mlir::Type resType, ValueRange operands,
+ ArrayRef<NamedAttribute> attrs) {
+ assert(operands.size() >= 1u && "mismatched number of parameters");
+ result.addOperands(operands);
+ result.addAttribute(fir::CoordinateOp::baseType(),
+ mlir::TypeAttr::get(operands[0].getType()));
+ result.attributes.append(attrs.begin(), attrs.end());
+ result.addTypes({resType});
+}
+
+void fir::CoordinateOp::build(Builder *builder, OperationState &result,
+ mlir::Type resType, mlir::Value ref,
+ ValueRange coor, ArrayRef<NamedAttribute> attrs) {
+ llvm::SmallVector<mlir::Value, 16> operands{ref};
+ operands.append(coor.begin(), coor.end());
+ build(builder, result, resType, operands, attrs);
+}
+
//===----------------------------------------------------------------------===//
// DispatchOp
//===----------------------------------------------------------------------===//
@@ -341,10 +481,289 @@ void fir::GenTypeDescOp::build(Builder *, OperationState &result,
// GlobalOp
//===----------------------------------------------------------------------===//
+static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) {
+ // Parse the optional linkage
+ llvm::StringRef linkage;
+ auto &builder = parser.getBuilder();
+ if (mlir::succeeded(parser.parseOptionalKeyword(&linkage))) {
+ if (fir::GlobalOp::verifyValidLinkage(linkage))
+ return failure();
+ mlir::StringAttr linkAttr = builder.getStringAttr(linkage);
+ result.addAttribute(fir::GlobalOp::linkageAttrName(), linkAttr);
+ }
+
+ // Parse the name as a symbol reference attribute.
+ mlir::SymbolRefAttr nameAttr;
+ if (parser.parseAttribute(nameAttr, fir::GlobalOp::symbolAttrName(),
+ result.attributes))
+ return failure();
+ result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
+ builder.getStringAttr(nameAttr.getRootReference()));
+
+ bool simpleInitializer = false;
+ if (mlir::succeeded(parser.parseOptionalLParen())) {
+ Attribute attr;
+ if (parser.parseAttribute(attr, fir::GlobalOp::initValAttrName(),
+ result.attributes) ||
+ parser.parseRParen())
+ return failure();
+ simpleInitializer = true;
+ }
+
+ if (succeeded(parser.parseOptionalKeyword("constant"))) {
+ // if "constant" keyword then mark this as a constant, not a variable
+ result.addAttribute(fir::GlobalOp::constantAttrName(),
+ builder.getUnitAttr());
+ }
+
+ mlir::Type globalType;
+ if (parser.parseColonType(globalType))
+ return failure();
+
+ result.addAttribute(fir::GlobalOp::typeAttrName(),
+ mlir::TypeAttr::get(globalType));
+
+ if (simpleInitializer) {
+ result.addRegion();
+ } else {
+ // Parse the optional initializer body.
+ if (parser.parseRegion(*result.addRegion(), llvm::None, llvm::None))
+ return failure();
+ }
+
+ return success();
+}
+
void fir::GlobalOp::appendInitialValue(mlir::Operation *op) {
getBlock().getOperations().push_back(op);
}
+void fir::GlobalOp::build(mlir::Builder *builder, OperationState &result,
+ StringRef name, bool isConstant, Type type,
+ Attribute initialVal, StringAttr linkage,
+ ArrayRef<NamedAttribute> attrs) {
+ result.addRegion();
+ result.addAttribute(typeAttrName(), mlir::TypeAttr::get(type));
+ result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
+ builder->getStringAttr(name));
+ result.addAttribute(symbolAttrName(), builder->getSymbolRefAttr(name));
+ if (isConstant)
+ result.addAttribute(constantAttrName(), builder->getUnitAttr());
+ if (initialVal)
+ result.addAttribute(initValAttrName(), initialVal);
+ if (linkage)
+ result.addAttribute(linkageAttrName(), linkage);
+ result.attributes.append(attrs.begin(), attrs.end());
+}
+
+void fir::GlobalOp::build(mlir::Builder *builder, OperationState &result,
+ StringRef name, Type type, Attribute initialVal,
+ StringAttr linkage, ArrayRef<NamedAttribute> attrs) {
+ build(builder, result, name, /*isConstant=*/false, type, {}, linkage, attrs);
+}
+
+void fir::GlobalOp::build(mlir::Builder *builder, OperationState &result,
+ StringRef name, bool isConstant, Type type,
+ StringAttr linkage, ArrayRef<NamedAttribute> attrs) {
+ build(builder, result, name, isConstant, type, {}, linkage, attrs);
+}
+
+void fir::GlobalOp::build(mlir::Builder *builder, OperationState &result,
+ StringRef name, Type type, StringAttr linkage,
+ ArrayRef<NamedAttribute> attrs) {
+ build(builder, result, name, /*isConstant=*/false, type, {}, linkage, attrs);
+}
+
+void fir::GlobalOp::build(mlir::Builder *builder, OperationState &result,
+ StringRef name, bool isConstant, Type type,
+ ArrayRef<NamedAttribute> attrs) {
+ build(builder, result, name, isConstant, type, StringAttr{}, attrs);
+}
+
+void fir::GlobalOp::build(mlir::Builder *builder, OperationState &result,
+ StringRef name, Type type,
+ ArrayRef<NamedAttribute> attrs) {
+ build(builder, result, name, /*isConstant=*/false, type, attrs);
+}
+
+mlir::ParseResult fir::GlobalOp::verifyValidLinkage(StringRef linkage) {
+ // Supporting only a subset of the LLVM linkage types for now
+ static const llvm::SmallVector<const char *, 3> validNames = {
+ "internal", "common", "weak"};
+ return mlir::success(llvm::is_contained(validNames, linkage));
+}
+
+//===----------------------------------------------------------------------===//
+// IterWhileOp
+//===----------------------------------------------------------------------===//
+
+void fir::IterWhileOp::build(mlir::Builder *builder,
+ mlir::OperationState &result, mlir::Value lb,
+ mlir::Value ub, mlir::Value step,
+ mlir::Value iterate, mlir::ValueRange iterArgs,
+ llvm::ArrayRef<mlir::NamedAttribute> attributes) {
+ result.addOperands({lb, ub, step, iterate});
+ result.addTypes(iterate.getType());
+ result.addOperands(iterArgs);
+ for (auto v : iterArgs)
+ result.addTypes(v.getType());
+ mlir::Region *bodyRegion = result.addRegion();
+ bodyRegion->push_back(new Block{});
+ bodyRegion->front().addArgument(builder->getIndexType());
+ bodyRegion->front().addArgument(iterate.getType());
+ for (auto v : iterArgs)
+ bodyRegion->front().addArgument(v.getType());
+ result.addAttributes(attributes);
+}
+
+static mlir::ParseResult parseIterWhileOp(mlir::OpAsmParser &parser,
+ mlir::OperationState &result) {
+ auto &builder = parser.getBuilder();
+ mlir::OpAsmParser::OperandType inductionVariable, lb, ub, step;
+ if (parser.parseLParen() || parser.parseRegionArgument(inductionVariable) ||
+ parser.parseEqual())
+ return mlir::failure();
+
+ // Parse loop bounds.
+ auto indexType = builder.getIndexType();
+ auto i1Type = builder.getIntegerType(1);
+ if (parser.parseOperand(lb) ||
+ parser.resolveOperand(lb, indexType, result.operands) ||
+ parser.parseKeyword("to") || parser.parseOperand(ub) ||
+ parser.resolveOperand(ub, indexType, result.operands) ||
+ parser.parseKeyword("step") || parser.parseOperand(step) ||
+ parser.parseRParen() ||
+ parser.resolveOperand(step, indexType, result.operands))
+ return mlir::failure();
+
+ mlir::OpAsmParser::OperandType iterateVar, iterateInput;
+ if (parser.parseKeyword("and") || parser.parseLParen() ||
+ parser.parseRegionArgument(iterateVar) || parser.parseEqual() ||
+ parser.parseOperand(iterateInput) || parser.parseRParen() ||
+ parser.resolveOperand(iterateInput, i1Type, result.operands))
+ return mlir::failure();
+
+ // Parse the initial iteration arguments.
+ llvm::SmallVector<mlir::OpAsmParser::OperandType, 4> regionArgs;
+ // Induction variable.
+ regionArgs.push_back(inductionVariable);
+ regionArgs.push_back(iterateVar);
+ result.addTypes(i1Type);
+
+ if (mlir::succeeded(parser.parseOptionalKeyword("iter_args"))) {
+ llvm::SmallVector<mlir::OpAsmParser::OperandType, 4> operands;
+ llvm::SmallVector<mlir::Type, 4> regionTypes;
+ // Parse assignment list and results type list.
+ if (parser.parseAssignmentList(regionArgs, operands) ||
+ parser.parseArrowTypeList(regionTypes))
+ return mlir::failure();
+ // Resolve input operands.
+ for (auto operand_type : llvm::zip(operands, regionTypes))
+ if (parser.resolveOperand(std::get<0>(operand_type),
+ std::get<1>(operand_type), result.operands))
+ return mlir::failure();
+ result.addTypes(regionTypes);
+ }
+
+ if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
+ return mlir::failure();
+
+ llvm::SmallVector<mlir::Type, 4> argTypes;
+ // Induction variable (hidden)
+ argTypes.push_back(indexType);
+ // Loop carried variables (including iterate)
+ argTypes.append(result.types.begin(), result.types.end());
+ // Parse the body region.
+ auto *body = result.addRegion();
+ if (regionArgs.size() != argTypes.size())
+ return parser.emitError(
+ parser.getNameLoc(),
+ "mismatch in number of loop-carried values and defined values");
+
+ if (parser.parseRegion(*body, regionArgs, argTypes))
+ return failure();
+
+ fir::IterWhileOp::ensureTerminator(*body, builder, result.location);
+
+ return mlir::success();
+}
+
+static mlir::LogicalResult verify(fir::IterWhileOp op) {
+ if (auto cst = dyn_cast_or_null<ConstantIndexOp>(op.step().getDefiningOp()))
+ if (cst.getValue() <= 0)
+ return op.emitOpError("constant step operand must be positive");
+
+ // Check that the body defines as single block argument for the induction
+ // variable.
+ auto *body = op.getBody();
+ if (!body->getArgument(1).getType().isInteger(1))
+ return op.emitOpError(
+ "expected body second argument to be an index argument for "
+ "the induction variable");
+ if (!body->getArgument(0).getType().isIndex())
+ return op.emitOpError(
+ "expected body first argument to be an index argument for "
+ "the induction variable");
+
+ auto opNumResults = op.getNumResults();
+ if (opNumResults == 0)
+ return mlir::failure();
+ if (op.getNumIterOperands() != opNumResults)
+ return op.emitOpError(
+ "mismatch in number of loop-carried values and defined values");
+ if (op.getNumRegionIterArgs() != opNumResults)
+ return op.emitOpError(
+ "mismatch in number of basic block args and defined values");
+ auto iterOperands = op.getIterOperands();
+ auto iterArgs = op.getRegionIterArgs();
+ auto opResults = op.getResults();
+ unsigned i = 0;
+ for (auto e : llvm::zip(iterOperands, iterArgs, opResults)) {
+ if (std::get<0>(e).getType() != std::get<2>(e).getType())
+ return op.emitOpError() << "types mismatch between " << i
+ << "th iter operand and defined value";
+ if (std::get<1>(e).getType() != std::get<2>(e).getType())
+ return op.emitOpError() << "types mismatch between " << i
+ << "th iter region arg and defined value";
+
+ i++;
+ }
+ return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::IterWhileOp op) {
+ p << fir::IterWhileOp::getOperationName() << " (" << op.getInductionVar()
+ << " = " << op.lowerBound() << " to " << op.upperBound() << " step "
+ << op.step() << ") and (";
+ assert(op.hasIterOperands());
+ auto regionArgs = op.getRegionIterArgs();
+ auto operands = op.getIterOperands();
+ p << regionArgs.front() << " = " << *operands.begin() << ")";
+ if (regionArgs.size() > 1) {
+ p << " iter_args(";
+ llvm::interleaveComma(
+ llvm::zip(regionArgs.drop_front(), operands.drop_front()), p,
+ [&](auto it) { p << std::get<0>(it) << " = " << std::get<1>(it); });
+ p << ") -> (" << op.getResultTypes().drop_front() << ')';
+ }
+ p.printOptionalAttrDictWithKeyword(op.getAttrs(), {});
+ p.printRegion(op.region(), /*printEntryBlockArgs=*/false,
+ /*printBlockTerminators=*/true);
+}
+
+mlir::Region &fir::IterWhileOp::getLoopBody() { return region(); }
+
+bool fir::IterWhileOp::isDefinedOutsideOfLoop(mlir::Value value) {
+ return !region().isAncestor(value.getParentRegion());
+}
+
+mlir::LogicalResult
+fir::IterWhileOp::moveOutOfLoop(llvm::ArrayRef<mlir::Operation *> ops) {
+ for (auto op : ops)
+ op->moveBefore(*this);
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// LoadOp
//===----------------------------------------------------------------------===//
@@ -367,65 +786,84 @@ mlir::ParseResult fir::LoadOp::getElementOf(mlir::Type &ele, mlir::Type ref) {
// LoopOp
//===----------------------------------------------------------------------===//
-void fir::LoopOp::build(mlir::Builder *builder, OperationState &result,
- mlir::Value lb, mlir::Value ub, ValueRange step,
- ArrayRef<NamedAttribute> attributes) {
- if (step.empty())
- result.addOperands({lb, ub});
- else
- result.addOperands({lb, ub, step[0]});
+void fir::LoopOp::build(mlir::Builder *builder, mlir::OperationState &result,
+ mlir::Value lb, mlir::Value ub, mlir::Value step,
+ bool unordered, mlir::ValueRange iterArgs,
+ llvm::ArrayRef<mlir::NamedAttribute> attributes) {
+ result.addOperands({lb, ub, step});
+ result.addOperands(iterArgs);
+ for (auto v : iterArgs)
+ result.addTypes(v.getType());
mlir::Region *bodyRegion = result.addRegion();
- LoopOp::ensureTerminator(*bodyRegion, *builder, result.location);
+ bodyRegion->push_back(new Block{});
+ if (iterArgs.empty())
+ LoopOp::ensureTerminator(*bodyRegion, *builder, result.location);
bodyRegion->front().addArgument(builder->getIndexType());
+ for (auto v : iterArgs)
+ bodyRegion->front().addArgument(v.getType());
+ if (unordered)
+ result.addAttribute(unorderedAttrName(), builder->getUnitAttr());
result.addAttributes(attributes);
- NamedAttributeList attrs(attributes);
- if (!attrs.get(unorderedAttrName()))
- result.addTypes(builder->getIndexType());
}
static mlir::ParseResult parseLoopOp(mlir::OpAsmParser &parser,
mlir::OperationState &result) {
auto &builder = parser.getBuilder();
- OpAsmParser::OperandType inductionVariable, lb, ub, step;
+ mlir::OpAsmParser::OperandType inductionVariable, lb, ub, step;
// Parse the induction variable followed by '='.
if (parser.parseRegionArgument(inductionVariable) || parser.parseEqual())
return mlir::failure();
// Parse loop bounds.
- mlir::Type indexType = builder.getIndexType();
+ auto indexType = builder.getIndexType();
if (parser.parseOperand(lb) ||
parser.resolveOperand(lb, indexType, result.operands) ||
parser.parseKeyword("to") || parser.parseOperand(ub) ||
- parser.resolveOperand(ub, indexType, result.operands))
- return mlir::failure();
+ parser.resolveOperand(ub, indexType, result.operands) ||
+ parser.parseKeyword("step") || parser.parseOperand(step) ||
+ parser.resolveOperand(step, indexType, result.operands))
+ return failure();
- if (parser.parseOptionalKeyword(fir::LoopOp::stepAttrName())) {
- result.addAttribute(fir::LoopOp::stepAttrName(),
- builder.getIntegerAttr(builder.getIndexType(), 1));
- } else if (parser.parseOperand(step) ||
- parser.resolveOperand(step, indexType, result.operands)) {
- return mlir::failure();
+ if (mlir::succeeded(parser.parseOptionalKeyword("unordered")))
+ result.addAttribute(fir::LoopOp::unorderedAttrName(),
+ builder.getUnitAttr());
+
+ // Parse the optional initial iteration arguments.
+ llvm::SmallVector<mlir::OpAsmParser::OperandType, 4> regionArgs, operands;
+ llvm::SmallVector<mlir::Type, 4> argTypes;
+ regionArgs.push_back(inductionVariable);
+
+ if (succeeded(parser.parseOptionalKeyword("iter_args"))) {
+ // Parse assignment list and results type list.
+ if (parser.parseAssignmentList(regionArgs, operands) ||
+ parser.parseArrowTypeList(result.types))
+ return failure();
+ // Resolve input operands.
+ for (auto operand_type : llvm::zip(operands, result.types))
+ if (parser.resolveOperand(std::get<0>(operand_type),
+ std::get<1>(operand_type), result.operands))
+ return failure();
}
- // Parse the optional `unordered` keyword
- bool isUnordered = false;
- if (!parser.parseOptionalKeyword(LoopOp::unorderedAttrName())) {
- result.addAttribute(LoopOp::unorderedAttrName(), builder.getUnitAttr());
- isUnordered = true;
- }
+ if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
+ return mlir::failure();
+ // Induction variable.
+ argTypes.push_back(indexType);
+ // Loop carried variables
+ argTypes.append(result.types.begin(), result.types.end());
// Parse the body region.
- mlir::Region *body = result.addRegion();
- if (parser.parseRegion(*body, inductionVariable, indexType))
- return mlir::failure();
+ auto *body = result.addRegion();
+ if (regionArgs.size() != argTypes.size())
+ return parser.emitError(
+ parser.getNameLoc(),
+ "mismatch in number of loop-carried values and defined values");
+
+ if (parser.parseRegion(*body, regionArgs, argTypes))
+ return failure();
fir::LoopOp::ensureTerminator(*body, builder, result.location);
- // Parse the optional attribute list.
- if (parser.parseOptionalAttrDict(result.attributes))
- return mlir::failure();
- if (!isUnordered)
- result.addTypes(builder.getIndexType());
return mlir::success();
}
@@ -438,6 +876,115 @@ fir::LoopOp fir::getForInductionVarOwner(mlir::Value val) {
return dyn_cast_or_null<fir::LoopOp>(containingInst);
}
+// Lifted from loop.loop
+static mlir::LogicalResult verify(fir::LoopOp op) {
+ if (auto cst = dyn_cast_or_null<ConstantIndexOp>(op.step().getDefiningOp()))
+ if (cst.getValue() <= 0)
+ return op.emitOpError("constant step operand must be positive");
+
+ // Check that the body defines as single block argument for the induction
+ // variable.
+ auto *body = op.getBody();
+ if (!body->getArgument(0).getType().isIndex())
+ return op.emitOpError(
+ "expected body first argument to be an index argument for "
+ "the induction variable");
+
+ auto opNumResults = op.getNumResults();
+ if (opNumResults == 0)
+ return success();
+ if (op.getNumIterOperands() != opNumResults)
+ return op.emitOpError(
+ "mismatch in number of loop-carried values and defined values");
+ if (op.getNumRegionIterArgs() != opNumResults)
+ return op.emitOpError(
+ "mismatch in number of basic block args and defined values");
+ auto iterOperands = op.getIterOperands();
+ auto iterArgs = op.getRegionIterArgs();
+ auto opResults = op.getResults();
+ unsigned i = 0;
+ for (auto e : llvm::zip(iterOperands, iterArgs, opResults)) {
+ if (std::get<0>(e).getType() != std::get<2>(e).getType())
+ return op.emitOpError() << "types mismatch between " << i
+ << "th iter operand and defined value";
+ if (std::get<1>(e).getType() != std::get<2>(e).getType())
+ return op.emitOpError() << "types mismatch between " << i
+ << "th iter region arg and defined value";
+
+ i++;
+ }
+ return success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::LoopOp op) {
+ bool printBlockTerminators = false;
+ p << fir::LoopOp::getOperationName() << ' ' << op.getInductionVar() << " = "
+ << op.lowerBound() << " to " << op.upperBound() << " step " << op.step();
+ if (op.unordered())
+ p << " unordered";
+ if (op.hasIterOperands()) {
+ p << " iter_args(";
+ auto regionArgs = op.getRegionIterArgs();
+ auto operands = op.getIterOperands();
+ llvm::interleaveComma(llvm::zip(regionArgs, operands), p, [&](auto it) {
+ p << std::get<0>(it) << " = " << std::get<1>(it);
+ });
+ p << ") -> (" << op.getResultTypes() << ')';
+ printBlockTerminators = true;
+ }
+ p.printOptionalAttrDictWithKeyword(op.getAttrs(),
+ {fir::LoopOp::unorderedAttrName()});
+ p.printRegion(op.region(), /*printEntryBlockArgs=*/false,
+ printBlockTerminators);
+}
+
+mlir::Region &fir::LoopOp::getLoopBody() { return region(); }
+
+bool fir::LoopOp::isDefinedOutsideOfLoop(mlir::Value value) {
+ return !region().isAncestor(value.getParentRegion());
+}
+
+mlir::LogicalResult
+fir::LoopOp::moveOutOfLoop(llvm::ArrayRef<mlir::Operation *> ops) {
+ for (auto op : ops)
+ op->moveBefore(*this);
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// MulfOp
+//===----------------------------------------------------------------------===//
+
+mlir::OpFoldResult fir::MulfOp::fold(llvm::ArrayRef<mlir::Attribute> opnds) {
+ return mlir::constFoldBinaryOp<FloatAttr>(
+ opnds, [](APFloat a, APFloat b) { return a * b; });
+}
+
+//===----------------------------------------------------------------------===//
+// ResultOp
+//===----------------------------------------------------------------------===//
+
+static mlir::LogicalResult verify(fir::ResultOp op) {
+ auto parentOp = op.getParentOp();
+ auto results = parentOp->getResults();
+ auto operands = op.getOperands();
+
+ if (isa<fir::WhereOp>(parentOp) || isa<fir::LoopOp>(parentOp) ||
+ isa<fir::IterWhileOp>(parentOp)) {
+ if (parentOp->getNumResults() != op.getNumOperands())
+ return op.emitOpError() << "parent of result must have same arity";
+ for (auto e : llvm::zip(results, operands)) {
+ if (std::get<0>(e).getType() != std::get<1>(e).getType())
+ return op.emitOpError()
+ << "types mismatch between result op and its parent";
+ }
+ } else {
+ return op.emitOpError()
+ << "result only terminates if, do_loop, or iterate_while regions";
+ }
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// SelectOp
//===----------------------------------------------------------------------===//
@@ -460,6 +1007,10 @@ static A getSubOperands(unsigned pos, A allArgs,
return {std::next(allArgs.begin(), start), std::next(allArgs.begin(), end)};
}
+static unsigned denseElementsSize(mlir::DenseIntElementsAttr attr) {
+ return attr.getNumElements();
+}
+
llvm::Optional<mlir::OperandRange> fir::SelectOp::getCompareOperands(unsigned) {
return {};
}
@@ -486,6 +1037,11 @@ fir::SelectOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
bool fir::SelectOp::canEraseSuccessorOperand() { return true; }
+unsigned fir::SelectOp::targetOffsetSize() {
+ return denseElementsSize(
+ getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr()));
+}
+
//===----------------------------------------------------------------------===//
// SelectCaseOp
//===----------------------------------------------------------------------===//
@@ -596,6 +1152,95 @@ static mlir::ParseResult parseSelectCase(mlir::OpAsmParser &parser,
return mlir::success();
}
+unsigned fir::SelectCaseOp::compareOffsetSize() {
+ return denseElementsSize(
+ getAttrOfType<mlir::DenseIntElementsAttr>(getCompareOffsetAttr()));
+}
+
+unsigned fir::SelectCaseOp::targetOffsetSize() {
+ return denseElementsSize(
+ getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr()));
+}
+
+void fir::SelectCaseOp::build(mlir::Builder *builder,
+ mlir::OperationState &result,
+ mlir::Value selector,
+ llvm::ArrayRef<mlir::Attribute> compareAttrs,
+ llvm::ArrayRef<mlir::ValueRange> cmpOperands,
+ llvm::ArrayRef<mlir::Block *> destinations,
+ llvm::ArrayRef<mlir::ValueRange> destOperands,
+ llvm::ArrayRef<mlir::NamedAttribute> attributes) {
+ result.addOperands(selector);
+ result.addAttribute(getCasesAttr(), builder->getArrayAttr(compareAttrs));
+ llvm::SmallVector<int32_t, 8> operOffs;
+ int32_t operSize = 0;
+ for (auto attr : compareAttrs) {
+ if (attr.isa<fir::ClosedIntervalAttr>()) {
+ operOffs.push_back(2);
+ operSize += 2;
+ } else if (attr.isa<mlir::UnitAttr>()) {
+ operOffs.push_back(0);
+ } else {
+ operOffs.push_back(1);
+ ++operSize;
+ }
+ }
+ for (auto ops : cmpOperands)
+ result.addOperands(ops);
+ result.addAttribute(getCompareOffsetAttr(),
+ builder->getI32VectorAttr(operOffs));
+ const auto count = destinations.size();
+ for (auto d : destinations)
+ result.addSuccessors(d);
+ const auto opCount = destOperands.size();
+ llvm::SmallVector<int32_t, 8> argOffs;
+ int32_t sumArgs = 0;
+ for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
+ if (i < opCount) {
+ result.addOperands(destOperands[i]);
+ const auto argSz = destOperands[i].size();
+ argOffs.push_back(argSz);
+ sumArgs += argSz;
+ } else {
+ argOffs.push_back(0);
+ }
+ }
+ result.addAttribute(getOperandSegmentSizeAttr(),
+ builder->getI32VectorAttr({1, operSize, sumArgs}));
+ result.addAttribute(getTargetOffsetAttr(),
+ builder->getI32VectorAttr(argOffs));
+ result.addAttributes(attributes);
+}
+
+/// This builder has a slightly simplified interface in that the list of
+/// operands need not be partitioned by the builder. Instead the operands are
+/// partitioned here, before being passed to the default builder. This
+/// partitioning is unchecked, so can go awry on bad input.
+void fir::SelectCaseOp::build(mlir::Builder *builder,
+ mlir::OperationState &result,
+ mlir::Value selector,
+ llvm::ArrayRef<mlir::Attribute> compareAttrs,
+ llvm::ArrayRef<mlir::Value> cmpOpList,
+ llvm::ArrayRef<mlir::Block *> destinations,
+ llvm::ArrayRef<mlir::ValueRange> destOperands,
+ llvm::ArrayRef<mlir::NamedAttribute> attributes) {
+ llvm::SmallVector<mlir::ValueRange, 16> cmpOpers;
+ auto iter = cmpOpList.begin();
+ for (auto &attr : compareAttrs) {
+ if (attr.isa<fir::ClosedIntervalAttr>()) {
+ cmpOpers.push_back(mlir::ValueRange({iter, iter + 2}));
+ iter += 2;
+ } else if (attr.isa<UnitAttr>()) {
+ cmpOpers.push_back(mlir::ValueRange{});
+ } else {
+ cmpOpers.push_back(mlir::ValueRange({iter, iter + 1}));
+ ++iter;
+ }
+ }
+ build(builder, result, selector, compareAttrs, cmpOpers, destinations,
+ destOperands, attributes);
+}
+
//===----------------------------------------------------------------------===//
// SelectRankOp
//===----------------------------------------------------------------------===//
@@ -627,6 +1272,11 @@ fir::SelectRankOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
bool fir::SelectRankOp::canEraseSuccessorOperand() { return true; }
+unsigned fir::SelectRankOp::targetOffsetSize() {
+ return denseElementsSize(
+ getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr()));
+}
+
//===----------------------------------------------------------------------===//
// SelectTypeOp
//===----------------------------------------------------------------------===//
@@ -703,6 +1353,11 @@ static ParseResult parseSelectType(OpAsmParser &parser,
return mlir::success();
}
+unsigned fir::SelectTypeOp::targetOffsetSize() {
+ return denseElementsSize(
+ getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr()));
+}
+
//===----------------------------------------------------------------------===//
// StoreOp
//===----------------------------------------------------------------------===//
@@ -726,6 +1381,15 @@ bool fir::StringLitOp::isWideValue() {
return eleTy.cast<fir::CharacterType>().getFKind() != 1;
}
+//===----------------------------------------------------------------------===//
+// SubfOp
+//===----------------------------------------------------------------------===//
+
+mlir::OpFoldResult fir::SubfOp::fold(llvm::ArrayRef<mlir::Attribute> opnds) {
+ return mlir::constFoldBinaryOp<FloatAttr>(
+ opnds, [](APFloat a, APFloat b) { return a - b; });
+}
+
//===----------------------------------------------------------------------===//
// WhereOp
//===----------------------------------------------------------------------===//
@@ -758,7 +1422,7 @@ static mlir::ParseResult parseWhereOp(OpAsmParser &parser,
WhereOp::ensureTerminator(*thenRegion, parser.getBuilder(), result.location);
- if (!parser.parseOptionalKeyword("otherwise")) {
+ if (!parser.parseOptionalKeyword("else")) {
if (parser.parseRegion(*elseRegion, {}, {}))
return mlir::failure();
WhereOp::ensureTerminator(*elseRegion, parser.getBuilder(),
@@ -772,6 +1436,43 @@ static mlir::ParseResult parseWhereOp(OpAsmParser &parser,
return mlir::success();
}
+static LogicalResult verify(fir::WhereOp op) {
+ // Verify that the entry of each child region does not have arguments.
+ for (auto ®ion : op.getOperation()->getRegions()) {
+ if (region.empty())
+ continue;
+
+ for (auto &b : region)
+ if (b.getNumArguments() != 0)
+ return op.emitOpError(
+ "requires that child entry blocks have no arguments");
+ }
+ if (op.getNumResults() != 0 && op.otherRegion().empty())
+ return op.emitOpError("must have an else block if defining values");
+
+ return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::WhereOp op) {
+ bool printBlockTerminators = false;
+ p << fir::WhereOp::getOperationName() << ' ' << op.condition();
+ if (!op.results().empty()) {
+ p << " -> (" << op.getResultTypes() << ')';
+ printBlockTerminators = true;
+ }
+ p.printRegion(op.whereRegion(), /*printEntryBlockArgs=*/false,
+ printBlockTerminators);
+
+ // Print the 'else' regions if it exists and has a block.
+ auto &otherReg = op.otherRegion();
+ if (!otherReg.empty()) {
+ p << " else";
+ p.printRegion(otherReg, /*printEntryBlockArgs=*/false,
+ printBlockTerminators);
+ }
+ p.printOptionalAttrDict(op.getAttrs());
+}
+
//===----------------------------------------------------------------------===//
mlir::ParseResult fir::isValidCaseAttr(mlir::Attribute attr) {
@@ -840,6 +1541,7 @@ mlir::FuncOp fir::createFuncOp(mlir::Location loc, mlir::ModuleOp module,
if (auto f = module.lookupSymbol<mlir::FuncOp>(name))
return f;
mlir::OpBuilder modBuilder(module.getBodyRegion());
+ modBuilder.setInsertionPoint(module.getBody()->getTerminator());
return modBuilder.create<mlir::FuncOp>(loc, name, type, attrs);
}
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 1fedd00e5da3..97d169de7e77 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -8,15 +8,12 @@
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
-#include "mlir/IR/Builders.h"
#include "mlir/IR/Diagnostics.h"
-#include "mlir/IR/Dialect.h"
#include "mlir/IR/DialectImplementation.h"
-#include "mlir/IR/StandardTypes.h"
-#include "mlir/Parser.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace fir;
@@ -181,7 +178,7 @@ SequenceType parseSequence(mlir::DialectAsmParser &parser, mlir::Location) {
return SequenceType::get(shape, eleTy, map);
}
-bool verifyIntegerType(mlir::Type ty) {
+static bool verifyIntegerType(mlir::Type ty) {
return ty.isa<mlir::IntegerType>() || ty.isa<IntType>();
}
@@ -842,6 +839,14 @@ bool isa_ref_type(mlir::Type t) {
return t.isa<ReferenceType>() || t.isa<PointerType>() || t.isa<HeapType>();
}
+bool isa_box_type(mlir::Type t) {
+ return t.isa<BoxType>() || t.isa<BoxCharType>() || t.isa<BoxProcType>();
+}
+
+bool isa_passbyref_type(mlir::Type t) {
+ return t.isa<ReferenceType>() || isa_box_type(t);
+}
+
bool isa_aggregate(mlir::Type t) {
return t.isa<SequenceType>() || t.isa<RecordType>();
}
@@ -905,6 +910,10 @@ CplxType fir::CplxType::get(mlir::MLIRContext *ctxt, KindTy kind) {
return Base::get(ctxt, FIR_COMPLEX, kind);
}
+mlir::Type fir::CplxType::getElementType() const {
+ return fir::RealType::get(getContext(), getFKind());
+}
+
KindTy fir::CplxType::getFKind() const { return getImpl()->getFKind(); }
// REAL
@@ -1061,6 +1070,34 @@ SequenceType::Shape fir::SequenceType::getShape() const {
return getImpl()->getShape();
}
+unsigned fir::SequenceType::getConstantRows() const {
+ auto shape = getShape();
+ unsigned count = 0;
+ for (auto d : shape) {
+ if (d < 0)
+ break;
+ ++count;
+ }
+ return count;
+}
+
+// This test helps us determine if we can degenerate an array to a
+// pointer to some interior section (possibly a single element) of the
+// sequence. This is used to determine if we can lower to the LLVM IR.
+bool fir::SequenceType::hasConstantInterior() const {
+ if (hasUnknownShape())
+ return true;
+ auto rows = getConstantRows();
+ auto dim = getDimension();
+ if (rows == dim)
+ return true;
+ auto shape = getShape();
+ for (unsigned i{rows}, size{dim}; i < size; ++i)
+ if (shape[i] != getUnknownExtent())
+ return false;
+ return true;
+}
+
mlir::LogicalResult fir::SequenceType::verifyConstructionInvariants(
mlir::Location loc, const SequenceType::Shape &shape, mlir::Type eleTy,
mlir::AffineMapAttr map) {
@@ -1178,6 +1215,12 @@ llvm::SmallPtrSet<detail::RecordTypeStorage const *, 4> recordTypeVisited;
} // namespace
+void fir::verifyIntegralType(mlir::Type type) {
+ if (verifyIntegerType(type) || type.isa<mlir::IndexType>())
+ return;
+ llvm_unreachable("expected integral type");
+}
+
void fir::printFirType(FIROpsDialect *, mlir::Type ty,
mlir::DialectAsmPrinter &p) {
auto &os = p.getStream();
diff --git a/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir
index bdadf5cd6f58..5821b7f29132 100644
--- a/flang/test/Fir/fir-ops.fir
+++ b/flang/test/Fir/fir-ops.fir
@@ -4,129 +4,174 @@
// UNSUPPORTED: !fir
// CHECK-LABEL: func @it1() -> !fir.int<4>
+// CHECK: func @box1() -> !fir.boxchar<2>
+// CHECK: func @box2() -> !fir.boxproc<(i32, i32) -> i64>
+// CHECK: func @box3() -> !fir.box<!fir.type<derived3{f:f32}>>
func @it1() -> !fir.int<4>
-// CHECK-LABEL: func @box1() -> !fir.boxchar<2>
func @box1() -> !fir.boxchar<2>
-// CHECK-LABEL: func @box2() -> !fir.boxproc<(i32, i32) -> i64>
func @box2() -> !fir.boxproc<(i32, i32) -> i64>
-// CHECK-LABEL: func @box3() -> !fir.box<!fir.type<derived3{f:f32}>>
func @box3() -> !fir.box<!fir.type<derived3{f:f32}>>
// Fortran SUBROUTINE and FUNCTION
// CHECK-LABEL: func @print_index3(index, index, index)
-// CHECK-LABEL: func @user_i64(i64)
-// CHECK-LABEL: func @user_tdesc(!fir.tdesc<!fir.type<x>>)
+// CHECK: func @user_i64(i64)
+// CHECK: func @user_tdesc(!fir.tdesc<!fir.type<x>>)
func @print_index3(index, index, index)
func @user_i64(i64)
func @user_tdesc(!fir.tdesc<!fir.type<x>>)
// expect the void return to be omitted
// CHECK-LABEL: func @store_tuple(tuple<!fir.type<qq1{f1:i32}>>)
+// CHECK: func @get_method_box() -> !fir.box<!fir.type<derived3{f:f32}>>
+// CHECK: func @method_impl(!fir.box<!fir.type<derived3{f:f32}>>)
func @store_tuple(tuple<!fir.type<qq1{f1:i32}>>) -> ()
-
-// CHECK-LABEL: func @get_method_box() -> !fir.box<!fir.type<derived3{f:f32}>>
-// CHECK-LABEL: func @method_impl(!fir.box<!fir.type<derived3{f:f32}>>)
func @get_method_box() -> !fir.box<!fir.type<derived3{f:f32}>>
func @method_impl(!fir.box<!fir.type<derived3{f:f32}>>)
// CHECK-LABEL: func @nop()
-func @nop()
-
// CHECK-LABEL: func @get_func() -> (() -> ())
+func @nop()
func @get_func() -> (() -> ())
-// CHECK-LABEL: @instructions
+// CHECK-LABEL: func @instructions() {
func @instructions() {
- // CHECK: %[[A0:.*]] = fir.alloca !fir.array<10xi32>
+// CHECK: [[VAL_0:%.*]] = fir.alloca !fir.array<10xi32>
+// CHECK: [[VAL_1:%.*]] = fir.load [[VAL_0]] : !fir.ref<!fir.array<10xi32>>
+// CHECK: [[VAL_2:%.*]] = fir.alloca i32
+// CHECK: [[VAL_3:%.*]] = constant 22 : i32
%0 = fir.alloca !fir.array<10xi32>
- // CHECK: fir.load %[[A0]] : !fir.ref<!fir.array<10xi32>>
%1 = fir.load %0 : !fir.ref<!fir.array<10xi32>>
%2 = fir.alloca i32
%3 = constant 22 : i32
- // CHECK: fir.store %{{.*}} to %{{.*}} : !fir.ref<i32>
+
+// CHECK: fir.store [[VAL_3]] to [[VAL_2]] : !fir.ref<i32>
+// CHECK: [[VAL_4:%.*]] = fir.undefined i32
+// CHECK: [[VAL_5:%.*]] = fir.allocmem !fir.array<100xf32>
+// CHECK: [[VAL_6:%.*]] = fir.embox [[VAL_5]] : (!fir.heap<!fir.array<100xf32>>) -> !fir.box<!fir.array<100xf32>>
fir.store %3 to %2 : !fir.ref<i32>
- // CHECK: fir.undefined i32
%4 = fir.undefined i32
- // CHECK: %[[A5:.*]] = fir.allocmem !fir.array<100xf32>
%5 = fir.allocmem !fir.array<100xf32>
- // CHECK: %[[A6:.*]] = fir.embox %[[A5]] : (!fir.heap<!fir.array<100xf32>>) -> !fir.box<!fir.array<100xf32>>
%6 = fir.embox %5 : (!fir.heap<!fir.array<100xf32>>) -> !fir.box<!fir.array<100xf32>>
- // CHECK: fir.box_addr %{{.*}} : (!fir.box<!fir.array<100xf32>>) -> !fir.ref<!fir.array<100xf32>>
+
+// CHECK: [[VAL_7:%.*]] = fir.box_addr [[VAL_6]] : (!fir.box<!fir.array<100xf32>>) -> !fir.ref<!fir.array<100xf32>>
+// CHECK: [[VAL_8:%.*]] = constant 0 : index
+// CHECK: [[VAL_9:%.*]]:3 = fir.box_dims [[VAL_6]], [[VAL_8]] : (!fir.box<!fir.array<100xf32>>, index) -> (index, index, index)
+// CHECK: fir.call @print_index3([[VAL_9]]#0, [[VAL_9]]#1, [[VAL_9]]#2) : (index, index, index) -> ()
+// CHECK: [[VAL_10:%.*]] = fir.call @it1() : () -> !fir.int<4>
%7 = fir.box_addr %6 : (!fir.box<!fir.array<100xf32>>) -> !fir.ref<!fir.array<100xf32>>
%c0 = constant 0 : index
- // CHECK: %[[A8:.*]]:3 = fir.box_dims %{{.*}}, %{{.*}} : (!fir.box<!fir.array<100xf32>>, index) -> (index, index, index)
%d1:3 = fir.box_dims %6, %c0 : (!fir.box<!fir.array<100xf32>>, index) -> (index, index, index)
- // CHECK: fir.call @print_index3(%[[A8]]#0, %[[A8]]#1, %[[A8]]#2) : (index, index, index)
fir.call @print_index3(%d1#0, %d1#1, %d1#2) : (index, index, index) -> ()
%8 = fir.call @it1() : () -> !fir.int<4>
- // CHECK: fir.box_elesize %[[A6]] : (!fir.box<!fir.array<100xf32>>) -> i64
+
+// CHECK: [[VAL_11:%.*]] = fir.box_elesize [[VAL_6]] : (!fir.box<!fir.array<100xf32>>) -> i64
+// CHECK: [[VAL_12:%.*]] = fir.box_isalloc [[VAL_6]] : (!fir.box<!fir.array<100xf32>>) -> i1
+// CHECK: [[VAL_13:%.*]] = fir.box_isarray [[VAL_6]] : (!fir.box<!fir.array<100xf32>>) -> i1
+// CHECK: [[VAL_14:%.*]] = fir.box_isptr [[VAL_6]] : (!fir.box<!fir.array<100xf32>>) -> i1
+// CHECK: [[VAL_15:%.*]] = fir.box_rank [[VAL_6]] : (!fir.box<!fir.array<100xf32>>) -> i64
%9 = fir.box_elesize %6 : (!fir.box<!fir.array<100xf32>>) -> i64
- // CHECK: fir.box_isalloc %[[A6]] : (!fir.box<!fir.array<100xf32>>) -> i1
%10 = fir.box_isalloc %6 : (!fir.box<!fir.array<100xf32>>) -> i1
- // CHECK: fir.box_isarray %[[A6]] : (!fir.box<!fir.array<100xf32>>) -> i1
%11 = fir.box_isarray %6 : (!fir.box<!fir.array<100xf32>>) -> i1
- // CHECK: fir.box_isptr %[[A6]] : (!fir.box<!fir.array<100xf32>>) -> i1
%12 = fir.box_isptr %6 : (!fir.box<!fir.array<100xf32>>) -> i1
- // CHECK: fir.box_rank %[[A6]] : (!fir.box<!fir.array<100xf32>>) -> i64
%13 = fir.box_rank %6 : (!fir.box<!fir.array<100xf32>>) -> i64
- // CHECK: fir.box_tdesc %[[A6]] : (!fir.box<!fir.array<100xf32>>) -> !fir.tdesc<!fir.array<100xf32>>
+
+// CHECK: [[VAL_16:%.*]] = fir.box_tdesc [[VAL_6]] : (!fir.box<!fir.array<100xf32>>) -> !fir.tdesc<!fir.array<100xf32>>
+// CHECK: [[VAL_17:%.*]] = fir.call @box1() : () -> !fir.boxchar<2>
+// CHECK: [[VAL_18:%.*]] = fir.boxchar_len [[VAL_17]] : (!fir.boxchar<2>) -> i32
+// CHECK: [[VAL_19:%.*]] = fir.call @box2() : () -> !fir.boxproc<(i32, i32) -> i64>
+// CHECK: [[VAL_20:%.*]] = fir.boxproc_host [[VAL_19]] : (!fir.boxproc<(i32, i32) -> i64>) -> !fir.ref<i32>
%14 = fir.box_tdesc %6 : (!fir.box<!fir.array<100xf32>>) -> !fir.tdesc<!fir.array<100xf32>>
%15 = fir.call @box1() : () -> !fir.boxchar<2>
- // CHECK: fir.boxchar_len %{{.*}} : (!fir.boxchar<2>) -> i32
%16 = fir.boxchar_len %15 : (!fir.boxchar<2>) -> i32
%17 = fir.call @box2() : () -> !fir.boxproc<(i32, i32) -> i64>
- // CHECK: fir.boxproc_host %{{.*}} : (!fir.boxproc<(i32, i32) -> i64>) -> !fir.ref<i32>
%18 = fir.boxproc_host %17 : (!fir.boxproc<(i32, i32) -> i64>) -> !fir.ref<i32>
+
+// CHECK: [[VAL_21:%.*]] = constant 10 : i32
+// CHECK: [[VAL_22:%.*]] = fir.coordinate_of [[VAL_5]], [[VAL_21]] : (!fir.heap<!fir.array<100xf32>>, i32) -> !fir.ref<f32>
+// CHECK: [[VAL_23:%.*]] = fir.field_index f, !fir.type<derived{f:f32}>
+// CHECK: [[VAL_24:%.*]] = fir.undefined !fir.type<derived{f:f32}>
+// CHECK: [[VAL_25:%.*]] = fir.extract_value [[VAL_24]], [[VAL_23]] : (!fir.type<derived{f:f32}>, !fir.field) -> f32
%19 = constant 10 : i32
- // CHECK: fir.coordinate_of %{{.*}}, %{{.*}} : (!fir.heap<!fir.array<100xf32>>, i32) -> !fir.ref<f32>
%20 = fir.coordinate_of %5, %19 : (!fir.heap<!fir.array<100xf32>>, i32) -> !fir.ref<f32>
- // CHECK: fir.field_index f, !fir.type<derived{f:f32}>
%21 = fir.field_index f, !fir.type<derived{f:f32}>
- // CHECK: fir.undefined !fir.type<derived{f:f32}>
%22 = fir.undefined !fir.type<derived{f:f32}>
- // CHECK: fir.extract_value %{{.*}}, %{{.*}} : (!fir.type<derived{f:f32}>, !fir.field) -> f32
%23 = fir.extract_value %22, %21 : (!fir.type<derived{f:f32}>, !fir.field) -> f32
+
+// CHECK: [[VAL_26:%.*]] = constant 1 : i32
+// CHECK: [[VAL_27:%.*]] = fir.gendims [[VAL_26]], [[VAL_21]], [[VAL_26]] : (i32, i32, i32) -> !fir.dims<1>
+// CHECK: [[VAL_28:%.*]] = constant 1.0
+// CHECK: [[VAL_29:%.*]] = fir.insert_value [[VAL_24]], [[VAL_28]], [[VAL_23]] : (!fir.type<derived{f:f32}>, f32, !fir.field) -> !fir.type<derived{f:f32}>
+// CHECK: [[VAL_30:%.*]] = fir.len_param_index f, !fir.type<derived3{f:f32}>
%c1 = constant 1 : i32
- // CHECK: fir.gendims %{{.*}}, %{{.*}}, %{{.*}} : (i32, i32, i32) -> !fir.dims<1>
%24 = fir.gendims %c1, %19, %c1 : (i32, i32, i32) -> !fir.dims<1>
%cf1 = constant 1.0 : f32
- // CHECK: fir.insert_value %{{.*}}, %{{.*}}, %{{.*}} : (!fir.type<derived{f:f32}>, f32, !fir.field) -> !fir.type<derived{f:f32}>
%25 = fir.insert_value %22, %cf1, %21 : (!fir.type<derived{f:f32}>, f32, !fir.field) -> !fir.type<derived{f:f32}>
- // CHECK: fir.len_param_index f, !fir.type<derived3{f:f32}>
%26 = fir.len_param_index f, !fir.type<derived3{f:f32}>
+
+// CHECK: [[VAL_31:%.*]] = fir.call @box3() : () -> !fir.box<!fir.type<derived3{f:f32}>>
+// CHECK: [[VAL_32:%.*]] = fir.dispatch "method"([[VAL_31]]) : (!fir.box<!fir.type<derived3{f:f32}>>) -> i32
+// CHECK: [[VAL_33:%.*]] = fir.convert [[VAL_32]] : (i32) -> i64
+// CHECK: [[VAL_34:%.*]] = fir.gentypedesc !fir.type<x>
+// CHECK: fir.call @user_tdesc([[VAL_34]]) : (!fir.tdesc<!fir.type<x>>) -> ()
+// CHECK: [[VAL_35:%.*]] = fir.no_reassoc [[VAL_33]] : i64
%27 = fir.call @box3() : () -> !fir.box<!fir.type<derived3{f:f32}>>
- // CHECK: fir.dispatch "method"(%{{.*}}) : (!fir.box<!fir.type<derived3{f:f32}>>) -> i32
%28 = fir.dispatch "method"(%27) : (!fir.box<!fir.type<derived3{f:f32}>>) -> i32
- // CHECK: fir.convert %{{.*}} : (i32) -> i64
%29 = fir.convert %28 : (i32) -> i64
- // CHECK: fir.gentypedesc !fir.type<x>
%30 = fir.gentypedesc !fir.type<x>
fir.call @user_tdesc(%30) : (!fir.tdesc<!fir.type<x>>) -> ()
- // CHECK: fir.no_reassoc %{{.*}} : i64
%31 = fir.no_reassoc %29 : i64
+
+// CHECK: fir.call @user_i64([[VAL_35]]) : (i64) -> ()
+// CHECK: fir.freemem [[VAL_5]] : !fir.heap<!fir.array<100xf32>>
+// CHECK: [[VAL_36:%.*]] = fir.call @get_func() : () -> (() -> ())
+// CHECK: fir.call [[VAL_36]]() : () -> ()
+// CHECK: [[VAL_37:%.*]] = fir.address_of(@it1) : !fir.ref<() -> !fir.int<4>>
+// CHECK: return
+// CHECK: }
fir.call @user_i64(%31) : (i64) -> ()
- // CHECK: fir.freemem %{{.*}} : !fir.heap<!fir.array<100xf32>>
fir.freemem %5 : !fir.heap<!fir.array<100xf32>>
%32 = fir.call @get_func() : () -> (() -> ())
fir.call %32() : () -> ()
- // CHECK: fir.address_of(@it1) : !fir.ref<() -> !fir.int<4>>
%33 = fir.address_of (@it1) : !fir.ref<() -> !fir.int<4>>
return
}
-// CHECK-LABEL: @boxing_match
+// CHECK-LABEL: func @boxing_match() {
func @boxing_match() {
+// CHECK: [[VAL_38:%.*]] = fir.alloca i32
+// CHECK: [[VAL_39:%.*]] = fir.alloca !fir.type<qq2{f1:i32,f2:f64}>
+// CHECK: [[VAL_40:%.*]] = fir.alloca !fir.char<1>
+// CHECK: [[VAL_41:%.*]] = fir.alloca tuple<i32, f64>
+// CHECK: [[VAL_42:%.*]] = fir.embox [[VAL_38]] : (!fir.ref<i32>) -> !fir.box<i32>
+// CHECK: [[VAL_43:%.*]]:6 = fir.unbox [[VAL_42]] : (!fir.box<i32>) -> (!fir.ref<i32>, i32, i32, !fir.tdesc<i32>, i32, !fir.dims<0>)
+// CHECK: [[VAL_44:%.*]] = constant 8 : i32
+// CHECK: [[VAL_45:%.*]] = fir.undefined !fir.char<1>
+// CHECK: [[VAL_46:%.*]] = fir.emboxchar [[VAL_40]], [[VAL_44]] : (!fir.ref<!fir.char<1>>, i32) -> !fir.boxchar<1>
+// CHECK: [[VAL_47:%.*]]:2 = fir.unboxchar [[VAL_46]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1>>, i32)
+// CHECK: [[VAL_48:%.*]] = fir.undefined !fir.type<qq2{f1:i32,f2:f64}>
+// CHECK: [[VAL_49:%.*]] = constant 0 : i32
+// CHECK: [[VAL_50:%.*]] = constant 12 : i32
+// CHECK: [[VAL_51:%.*]] = fir.insert_value [[VAL_48]], [[VAL_50]], [[VAL_49]] : (!fir.type<qq2{f1:i32,f2:f64}>, i32, i32) -> !fir.type<qq2{f1:i32,f2:f64}>
+// CHECK: [[VAL_52:%.*]] = constant 1 : i32
+// CHECK: [[VAL_53:%.*]] = constant 4.213000e+01 : f64
+// CHECK: [[VAL_54:%.*]] = fir.insert_value [[VAL_48]], [[VAL_53]], [[VAL_52]] : (!fir.type<qq2{f1:i32,f2:f64}>, f64, i32) -> !fir.type<qq2{f1:i32,f2:f64}>
+// CHECK: fir.store [[VAL_54]] to [[VAL_39]] : !fir.ref<!fir.type<qq2{f1:i32,f2:f64}>>
+// CHECK: [[VAL_55:%.*]] = fir.emboxproc @method_impl, [[VAL_41]] : ((!fir.box<!fir.type<derived3{f:f32}>>) -> (), !fir.ref<tuple<i32, f64>>) -> !fir.boxproc<(!fir.box<!fir.type<derived3{f:f32}>>) -> ()>
+// CHECK: [[VAL_56:%.*]], [[VAL_57:%.*]] = fir.unboxproc [[VAL_55]] : (!fir.boxproc<(!fir.box<!fir.type<derived3{f:f32}>>) -> ()>) -> ((!fir.box<!fir.type<derived3{f:f32}>>) -> (), !fir.ref<tuple<!fir.type<qq2{f1:i32,f2:f64}>>>)
+// CHECK: [[VAL_58:%.*]] = fir.call @box2() : () -> !fir.boxproc<(i32, i32) -> i64>
+// CHECK: [[VAL_59:%.*]], [[VAL_60:%.*]] = fir.unboxproc [[VAL_58]] : (!fir.boxproc<(i32, i32) -> i64>) -> ((i32, i32) -> i64, !fir.ref<tuple<!fir.type<qq1{f1:i32}>>>)
+// CHECK: [[VAL_61:%.*]] = fir.load [[VAL_60]] : !fir.ref<tuple<!fir.type<qq1{f1:i32}>>>
+// CHECK: fir.call @store_tuple([[VAL_61]]) : (tuple<!fir.type<qq1{f1:i32}>>) -> ()
+// CHECK: return
+// CHECK: }
%0 = fir.alloca i32
%d6 = fir.alloca !fir.type<qq2{f1:i32,f2:f64}>
%d3 = fir.alloca !fir.char<1>
%e6 = fir.alloca tuple<i32,f64>
%1 = fir.embox %0 : (!fir.ref<i32>) -> !fir.box<i32>
- // CHECK: fir.unbox %{{.*}} : (!fir.box<i32>) -> (!fir.ref<i32>, i32, i32, !fir.tdesc<i32>, i32, !fir.dims<0>)
%2:6 = fir.unbox %1 : (!fir.box<i32>) -> (!fir.ref<i32>,i32,i32,!fir.tdesc<i32>,i32,!fir.dims<0>)
%c8 = constant 8 : i32
%3 = fir.undefined !fir.char<1>
- // CHECK: fir.emboxchar %{{.*}}, %{{.*}} : (!fir.ref<!fir.char<1>>, i32) -> !fir.boxchar<1>
- // CHECK: fir.unboxchar %{{.*}} : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1>>, i32)
%4 = fir.emboxchar %d3, %c8 : (!fir.ref<!fir.char<1>>, i32) -> !fir.boxchar<1>
%5:2 = fir.unboxchar %4 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1>>, i32)
%6 = fir.undefined !fir.type<qq2{f1:i32,f2:f64}>
@@ -139,8 +184,6 @@ func @boxing_match() {
fir.store %a3 to %d6 : !fir.ref<!fir.type<qq2{f1:i32,f2:f64}>>
%7 = fir.emboxproc @method_impl, %e6 : ((!fir.box<!fir.type<derived3{f:f32}>>) -> (), !fir.ref<tuple<i32,f64>>) -> !fir.boxproc<(!fir.box<!fir.type<derived3{f:f32}>>) -> ()>
%8:2 = fir.unboxproc %7 : (!fir.boxproc<(!fir.box<!fir.type<derived3{f:f32}>>) -> ()>) -> ((!fir.box<!fir.type<derived3{f:f32}>>) -> (), !fir.ref<tuple<!fir.type<qq2{f1:i32,f2:f64}>>>)
- // CHECK: fir.emboxproc @method_impl, %{{.*}} : ((!fir.box<!fir.type<derived3{f:f32}>>) -> (), !fir.ref<tuple<i32, f64>>) -> !fir.boxproc<(!fir.box<!fir.type<derived3{f:f32}>>) -> ()>
- // CHECK: fir.unboxproc %{{.*}} : (!fir.boxproc<(!fir.box<!fir.type<derived3{f:f32}>>) -> ()>) -> ((!fir.box<!fir.type<derived3{f:f32}>>) -> (), !fir.ref<tuple<!fir.type<qq2{f1:i32,f2:f64}>>>)
%9 = fir.call @box2() : () -> !fir.boxproc<(i32, i32) -> i64>
%10:2 = fir.unboxproc %9 : (!fir.boxproc<(i32, i32) -> i64>) -> ((i32, i32) -> i64, !fir.ref<tuple<!fir.type<qq1{f1:i32}>>>)
%11 = fir.load %10#1 : !fir.ref<tuple<!fir.type<qq1{f1:i32}>>>
@@ -148,32 +191,61 @@ func @boxing_match() {
return
}
-// CHECK-LABEL: @loop
+// CHECK-LABEL: func @loop() {
func @loop() {
+// CHECK: [[VAL_62:%.*]] = constant 1 : index
+// CHECK: [[VAL_63:%.*]] = constant 10 : index
+// CHECK: [[VAL_64:%.*]] = constant true
%c1 = constant 1 : index
%c10 = constant 10 : index
%ct = constant true
- // CHECK: fir.loop %{{.*}} = %{{.*}} to %{{.*}} {
- %i = fir.loop %i = %c1 to %c10 {
- // CHECK: fir.where %{{.*}} {
- fir.where %ct {
+
+// CHECK: fir.do_loop [[VAL_65:%.*]] = [[VAL_62]] to [[VAL_63]] step [[VAL_62]] {
+// CHECK: fir.if [[VAL_64]] {
+// CHECK: fir.call @nop() : () -> ()
+// CHECK: } else {
+// CHECK: fir.call @nop() : () -> ()
+// CHECK: }
+// CHECK: }
+// CHECK: fir.unreachable
+// CHECK: }
+ fir.do_loop %i = %c1 to %c10 step %c1 {
+ fir.if %ct {
fir.call @nop() : () -> ()
- // CHECK: } otherwise {
- } otherwise {
+ } else {
fir.call @nop() : () -> ()
}
}
- // CHECK: fir.unreachable
fir.unreachable
}
-// CHECK-LABEL: @bar_select
+// CHECK: func @bar_select([[VAL_66:%.*]]: i32, [[VAL_67:%.*]]: i32) -> i32 {
func @bar_select(%arg : i32, %arg2 : i32) -> i32 {
+// CHECK: [[VAL_68:%.*]] = constant 1 : i32
+// CHECK: [[VAL_69:%.*]] = constant 2 : i32
+// CHECK: [[VAL_70:%.*]] = constant 3 : i32
+// CHECK: [[VAL_71:%.*]] = constant 4 : i32
%0 = constant 1 : i32
%1 = constant 2 : i32
%2 = constant 3 : i32
%3 = constant 4 : i32
- // CHECK: fir.select %{{.*}} : i32 [1, ^bb1(%{{.*}} : i32), 2, ^bb2(%{{.*}}, %{{.*}}, %{{.*}} : i32, i32, i32), -3, ^bb3(%{{.*}}, %{{.*}} : i32, i32), 4, ^bb4(%{{.*}} : i32), unit, ^bb5]
+
+// CHECK: fir.select [[VAL_66]] : i32 [1, ^bb1([[VAL_68]] : i32), 2, ^bb2([[VAL_70]], [[VAL_66]], [[VAL_67]] : i32, i32, i32), -3, ^bb3([[VAL_67]], [[VAL_70]] : i32, i32), 4, ^bb4([[VAL_69]] : i32), unit, ^bb5]
+// CHECK: ^bb1([[VAL_72:%.*]]: i32):
+// CHECK: return [[VAL_72]] : i32
+// CHECK: ^bb2([[VAL_73:%.*]]: i32, [[VAL_74:%.*]]: i32, [[VAL_75:%.*]]: i32):
+// CHECK: [[VAL_76:%.*]] = addi [[VAL_73]], [[VAL_74]] : i32
+// CHECK: [[VAL_77:%.*]] = addi [[VAL_76]], [[VAL_75]] : i32
+// CHECK: return [[VAL_77]] : i32
+// CHECK: ^bb3([[VAL_78:%.*]]: i32, [[VAL_79:%.*]]: i32):
+// CHECK: [[VAL_80:%.*]] = addi [[VAL_78]], [[VAL_79]] : i32
+// CHECK: return [[VAL_80]] : i32
+// CHECK: ^bb4([[VAL_81:%.*]]: i32):
+// CHECK: return [[VAL_81]] : i32
+// CHECK: ^bb5:
+// CHECK: [[VAL_82:%.*]] = constant 0 : i32
+// CHECK: return [[VAL_82]] : i32
+// CHECK: }
fir.select %arg:i32 [ 1,^bb1(%0:i32), 2,^bb2(%2,%arg,%arg2:i32,i32,i32), -3,^bb3(%arg2,%2:i32,i32), 4,^bb4(%1:i32), unit,^bb5 ]
^bb1(%a : i32) :
return %a : i32
@@ -191,13 +263,25 @@ func @bar_select(%arg : i32, %arg2 : i32) -> i32 {
return %zero : i32
}
-// CHECK-LABEL: @bar_select_rank
+// CHECK-LABEL: func @bar_select_rank(
+// CHECK-SAME: [[VAL_83:%.*]]: i32, [[VAL_84:%.*]]: i32) -> i32 {
func @bar_select_rank(%arg : i32, %arg2 : i32) -> i32 {
+// CHECK: [[VAL_85:%.*]] = constant 1 : i32
+// CHECK: [[VAL_86:%.*]] = constant 2 : i32
+// CHECK: [[VAL_87:%.*]] = constant 3 : i32
+// CHECK: [[VAL_88:%.*]] = constant 4 : i32
%0 = constant 1 : i32
%1 = constant 2 : i32
%2 = constant 3 : i32
%3 = constant 4 : i32
- // CHECK: fir.select_rank %{{.*}} : i32 [1, ^bb1(%{{.*}} : i32), 2, ^bb2(%{{.*}}, %{{.*}}, %{{.*}} : i32, i32, i32), 3, ^bb3(%{{.*}}, %{{.*}} : i32, i32), -1, ^bb4(%{{.*}} : i32), unit, ^bb5]
+
+// CHECK: fir.select_rank [[VAL_83]] : i32 [1, ^bb1([[VAL_85]] : i32), 2, ^bb2([[VAL_87]], [[VAL_83]], [[VAL_84]] : i32, i32, i32), 3, ^bb3([[VAL_84]], [[VAL_87]] : i32, i32), -1, ^bb4([[VAL_86]] : i32), unit, ^bb5]
+// CHECK: ^bb1([[VAL_89:%.*]]: i32):
+// CHECK: return [[VAL_89]] : i32
+// CHECK: ^bb2([[VAL_90:%.*]]: i32, [[VAL_91:%.*]]: i32, [[VAL_92:%.*]]: i32):
+// CHECK: [[VAL_93:%.*]] = addi [[VAL_90]], [[VAL_91]] : i32
+// CHECK: [[VAL_94:%.*]] = addi [[VAL_93]], [[VAL_92]] : i32
+// CHECK: return [[VAL_94]] : i32
fir.select_rank %arg:i32 [ 1,^bb1(%0:i32), 2,^bb2(%2,%arg,%arg2:i32,i32,i32), 3,^bb3(%arg2,%2:i32,i32), -1,^bb4(%1:i32), unit,^bb5 ]
^bb1(%a : i32) :
return %a : i32
@@ -205,26 +289,56 @@ func @bar_select_rank(%arg : i32, %arg2 : i32) -> i32 {
%4 = addi %b, %b2 : i32
%5 = addi %4, %b3 : i32
return %5 : i32
+
+// CHECK: ^bb3([[VAL_95:%.*]]: i32, [[VAL_96:%.*]]: i32):
+// CHECK: [[VAL_97:%.*]] = addi [[VAL_95]], [[VAL_96]] : i32
+// CHECK: return [[VAL_97]] : i32
+// CHECK: ^bb4([[VAL_98:%.*]]: i32):
+// CHECK: return [[VAL_98]] : i32
^bb3(%c:i32, %c2:i32) :
%6 = addi %c, %c2 : i32
return %6 : i32
^bb4(%d : i32) :
return %d : i32
+
+// CHECK: ^bb5:
+// CHECK: [[VAL_99:%.*]] = constant 0 : i32
+// CHECK: [[VAL_100:%.*]] = fir.call @get_method_box() : () -> !fir.box<!fir.type<derived3{f:f32}>>
+// CHECK: fir.dispatch "method"([[VAL_100]]) : (!fir.box<!fir.type<derived3{f:f32}>>) -> ()
^bb5 :
%zero = constant 0 : i32
%7 = fir.call @get_method_box() : () -> !fir.box<!fir.type<derived3{f:f32}>>
fir.dispatch method(%7) : (!fir.box<!fir.type<derived3{f:f32}>>) -> ()
+
+// CHECK: return [[VAL_99]] : i32
+// CHECK: }
return %zero : i32
}
-// CHECK-LABEL: @bar_select_type
+// CHECK-LABEL: func @bar_select_type(
+// CHECK-SAME: [[VAL_101:%.*]]: !fir.box<!fir.type<name(param1:i32){fld:!fir.char<1>}>>) -> i32 {
func @bar_select_type(%arg : !fir.box<!fir.type<name(param1:i32){fld:!fir.char<1>}>>) -> i32 {
+
+// CHECK: [[VAL_102:%.*]] = constant 1 : i32
+// CHECK: [[VAL_103:%.*]] = constant 2 : i32
+// CHECK: [[VAL_104:%.*]] = constant 3 : i32
+// CHECK: [[VAL_105:%.*]] = constant 4 : i32
%0 = constant 1 : i32
%1 = constant 2 : i32
%2 = constant 3 : i32
%3 = constant 4 : i32
- // CHECK: fir.select_type %{{.*}} : !fir.box<!fir.type<name(param1:i32){fld:!fir.char<1>}>> [#fir.instance<!fir.int<4>>, ^bb1(%{{.*}} : i32), #fir.instance<!fir.int<8>>, ^bb2(%{{.*}} : i32), #fir.subsumed<!fir.int<2>>, ^bb3(%{{.*}} : i32), #fir.instance<!fir.int<1>>, ^bb4(%{{.*}} : i32), unit, ^bb5]
+
+// CHECK: fir.select_type [[VAL_101]] : !fir.box<!fir.type<name(param1:i32){fld:!fir.char<1>}>> [#fir.instance<!fir.int<4>>, ^bb1([[VAL_102]] : i32), #fir.instance<!fir.int<8>>, ^bb2([[VAL_104]] : i32), #fir.subsumed<!fir.int<2>>, ^bb3([[VAL_104]] : i32), #fir.instance<!fir.int<1>>, ^bb4([[VAL_103]] : i32), unit, ^bb5]
fir.select_type %arg : !fir.box<!fir.type<name(param1:i32){fld:!fir.char<1>}>> [ #fir.instance<!fir.int<4>>,^bb1(%0:i32), #fir.instance<!fir.int<8>>,^bb2(%2:i32), #fir.subsumed<!fir.int<2>>,^bb3(%2:i32), #fir.instance<!fir.int<1>>,^bb4(%1:i32), unit,^bb5 ]
+
+// CHECK: ^bb1([[VAL_106:%.*]]: i32):
+// CHECK: return [[VAL_106]] : i32
+// CHECK: ^bb2([[VAL_107:%.*]]: i32):
+// CHECK: return [[VAL_107]] : i32
+// CHECK: ^bb3([[VAL_108:%.*]]: i32):
+// CHECK: return [[VAL_108]] : i32
+// CHECK: ^bb4([[VAL_109:%.*]]: i32):
+// CHECK: return [[VAL_109]] : i32
^bb1(%a : i32) :
return %a : i32
^bb2(%b : i32) :
@@ -233,19 +347,43 @@ func @bar_select_type(%arg : !fir.box<!fir.type<name(param1:i32){fld:!fir.char<1
return %c : i32
^bb4(%d : i32) :
return %d : i32
+
+// CHECK: ^bb5:
+// CHECK: [[VAL_110:%.*]] = constant 0 : i32
+// CHECK: return [[VAL_110]] : i32
+// CHECK: }
^bb5 :
%zero = constant 0 : i32
return %zero : i32
}
-// CHECK-LABEL: @bar_select_case
+// CHECK-LABEL: func @bar_select_case(
+// CHECK-SAME: [[VAL_111:%.*]]: i32, [[VAL_112:%.*]]: i32) -> i32 {
+// CHECK: [[VAL_113:%.*]] = constant 1 : i32
+// CHECK: [[VAL_114:%.*]] = constant 2 : i32
+// CHECK: [[VAL_115:%.*]] = constant 3 : i32
+// CHECK: [[VAL_116:%.*]] = constant 4 : i32
func @bar_select_case(%arg : i32, %arg2 : i32) -> i32 {
%0 = constant 1 : i32
%1 = constant 2 : i32
%2 = constant 3 : i32
%3 = constant 4 : i32
- // CHECK: fir.select_case %{{.*}} : i32 [#fir.point, %{{.*}}, ^bb1(%{{.*}} : i32), #fir.lower, %{{.*}}, ^bb2(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}} : i32, i32, i32, i32), #fir.interval, %{{.*}}, %{{.*}}, ^bb3(%{{.*}}, %{{.*}} : i32, i32), #fir.upper, %{{.*}}, ^bb4(%{{.*}} : i32), unit, ^bb5]
+
+// CHECK: fir.select_case [[VAL_111]] : i32 [#fir.point, [[VAL_113]], ^bb1([[VAL_113]] : i32), #fir.lower, [[VAL_114]], ^bb2([[VAL_115]], [[VAL_111]], [[VAL_112]], [[VAL_114]] : i32, i32, i32, i32), #fir.interval, [[VAL_115]], [[VAL_116]], ^bb3([[VAL_115]], [[VAL_112]] : i32, i32), #fir.upper, [[VAL_111]], ^bb4([[VAL_114]] : i32), unit, ^bb5]
fir.select_case %arg : i32 [#fir.point, %0, ^bb1(%0:i32), #fir.lower, %1, ^bb2(%2,%arg,%arg2,%1:i32,i32,i32,i32), #fir.interval, %2, %3, ^bb3(%2,%arg2:i32,i32), #fir.upper, %arg, ^bb4(%1:i32), unit, ^bb5]
+
+// CHECK: ^bb1([[VAL_117:%.*]]: i32):
+// CHECK: return [[VAL_117]] : i32
+// CHECK: ^bb2([[VAL_118:%.*]]: i32, [[VAL_119:%.*]]: i32, [[VAL_120:%.*]]: i32, [[VAL_121:%.*]]: i32):
+// CHECK: [[VAL_122:%.*]] = addi [[VAL_118]], [[VAL_119]] : i32
+// CHECK: [[VAL_123:%.*]] = muli [[VAL_122]], [[VAL_120]] : i32
+// CHECK: [[VAL_124:%.*]] = addi [[VAL_123]], [[VAL_121]] : i32
+// CHECK: return [[VAL_124]] : i32
+// CHECK: ^bb3([[VAL_125:%.*]]: i32, [[VAL_126:%.*]]: i32):
+// CHECK: [[VAL_127:%.*]] = addi [[VAL_125]], [[VAL_126]] : i32
+// CHECK: return [[VAL_127]] : i32
+// CHECK: ^bb4([[VAL_128:%.*]]: i32):
+// CHECK: return [[VAL_128]] : i32
^bb1(%a : i32) :
return %a : i32
^bb2(%b : i32, %b2:i32, %b3:i32, %b4:i32) :
@@ -258,146 +396,211 @@ func @bar_select_case(%arg : i32, %arg2 : i32) -> i32 {
return %7 : i32
^bb4(%d : i32) :
return %d : i32
+
+// CHECK: ^bb5:
+// CHECK: [[VAL_129:%.*]] = constant 0 : i32
+// CHECK: return [[VAL_129]] : i32
+// CHECK: }
^bb5 :
%zero = constant 0 : i32
return %zero : i32
}
-// CHECK-LABEL: @global_var
+// CHECK-LABEL: fir.global @global_var : i32 {
+// CHECK: [[VAL_130:%.*]] = constant 1 : i32
+// CHECK: fir.has_value [[VAL_130]] : i32
+// CHECK: }
fir.global @global_var : i32 {
%0 = constant 1 : i32
fir.has_value %0 : i32
}
-// CHECK-LABEL: @global_constant
+// CHECK-LABEL: fir.global @global_constant constant : i32 {
+// CHECK: [[VAL_131:%.*]] = constant 934 : i32
+// CHECK: fir.has_value [[VAL_131]] : i32
+// CHECK: }
fir.global @global_constant constant : i32 {
%0 = constant 934 : i32
fir.has_value %0 : i32
}
-// CHECK-LABEL: @global_derived
+// CHECK-LABEL: fir.global @global_derived : !fir.type<minez(f:i32)> {
+// CHECK: fir.global_len "f", 1 : i32
+// CHECK: [[VAL_132:%.*]] = fir.undefined !fir.type<minez(f:i32)>
+// CHECK: fir.has_value [[VAL_132]] : !fir.type<minez(f:i32)>
+// CHECK: }
fir.global @global_derived : !fir.type<minez(f:i32)> {
- // CHECK: fir.global_len "f", 1 : i32
fir.global_len f, 1 : i32
%0 = fir.undefined !fir.type<minez>
fir.has_value %0 : !fir.type<minez>
}
-// CHECK-LABEL: @dispatch_tbl
+// CHECK-LABEL: fir.dispatch_table @dispatch_tbl {
+// CHECK: fir.dt_entry "method", @method_impl
+// CHECK: }
fir.dispatch_table @dispatch_tbl {
- // CHECK: fir.dt_entry "method", @method_impl
fir.dt_entry "method", @method_impl
}
-// CHECK-LABEL: @compare_real
+// CHECK-LABEL: func @compare_real(
+// CHECK-SAME: [[VAL_133:%.*]]: !fir.real<16>, [[VAL_134:%.*]]: !fir.real<16>) {
func @compare_real(%a : !fir.real<16>, %b : !fir.real<16>) {
- // CHECK: fir.cmpf "false", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "oeq", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "ogt", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "oge", %{{.*}}, %{{.*}} : !fir.real<16>
+
+// CHECK: [[VAL_135:%.*]] = fir.cmpf "false", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_136:%.*]] = fir.cmpf "oeq", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_137:%.*]] = fir.cmpf "ogt", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_138:%.*]] = fir.cmpf "oge", [[VAL_133]], [[VAL_134]] : !fir.real<16>
%d0 = fir.cmpf "false", %a, %b : !fir.real<16>
%d1 = fir.cmpf "oeq", %a, %b : !fir.real<16>
%d2 = fir.cmpf "ogt", %a, %b : !fir.real<16>
%d3 = fir.cmpf "oge", %a, %b : !fir.real<16>
- // CHECK: fir.cmpf "olt", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "ole", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "one", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "ord", %{{.*}}, %{{.*}} : !fir.real<16>
+
+// CHECK: [[VAL_139:%.*]] = fir.cmpf "olt", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_140:%.*]] = fir.cmpf "ole", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_141:%.*]] = fir.cmpf "one", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_142:%.*]] = fir.cmpf "ord", [[VAL_133]], [[VAL_134]] : !fir.real<16>
%a0 = fir.cmpf "olt", %a, %b : !fir.real<16>
%a1 = fir.cmpf "ole", %a, %b : !fir.real<16>
%a2 = fir.cmpf "one", %a, %b : !fir.real<16>
%a3 = fir.cmpf "ord", %a, %b : !fir.real<16>
- // CHECK: fir.cmpf "ueq", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "ugt", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "uge", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "ult", %{{.*}}, %{{.*}} : !fir.real<16>
+
+// CHECK: [[VAL_143:%.*]] = fir.cmpf "ueq", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_144:%.*]] = fir.cmpf "ugt", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_145:%.*]] = fir.cmpf "uge", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_146:%.*]] = fir.cmpf "ult", [[VAL_133]], [[VAL_134]] : !fir.real<16>
%b0 = fir.cmpf "ueq", %a, %b : !fir.real<16>
%b1 = fir.cmpf "ugt", %a, %b : !fir.real<16>
%b2 = fir.cmpf "uge", %a, %b : !fir.real<16>
%b3 = fir.cmpf "ult", %a, %b : !fir.real<16>
- // CHECK: fir.cmpf "ule", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "une", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "uno", %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.cmpf "true", %{{.*}}, %{{.*}} : !fir.real<16>
+
+// CHECK: [[VAL_147:%.*]] = fir.cmpf "ule", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_148:%.*]] = fir.cmpf "une", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_149:%.*]] = fir.cmpf "uno", [[VAL_133]], [[VAL_134]] : !fir.real<16>
+// CHECK: [[VAL_150:%.*]] = fir.cmpf "true", [[VAL_133]], [[VAL_134]] : !fir.real<16>
%c0 = fir.cmpf "ule", %a, %b : !fir.real<16>
%c1 = fir.cmpf "une", %a, %b : !fir.real<16>
%c2 = fir.cmpf "uno", %a, %b : !fir.real<16>
%c3 = fir.cmpf "true", %a, %b : !fir.real<16>
+
+// CHECK: return
+// CHECK: }
return
}
-// CHECK-LABEL: @compare_complex
+// CHECK-LABEL: func @compare_complex(
+// CHECK-SAME: [[VAL_151:%.*]]: !fir.complex<16>, [[VAL_152:%.*]]: !fir.complex<16>) {
func @compare_complex(%a : !fir.complex<16>, %b : !fir.complex<16>) {
- // CHECK: fir.cmpc "false", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "oeq", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "ogt", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "oge", %{{.*}}, %{{.*}} : !fir.complex<16>
+
+// CHECK: [[VAL_153:%.*]] = fir.cmpc "false", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_154:%.*]] = fir.cmpc "oeq", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_155:%.*]] = fir.cmpc "ogt", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_156:%.*]] = fir.cmpc "oge", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
%d0 = fir.cmpc "false", %a, %b : !fir.complex<16>
%d1 = fir.cmpc "oeq", %a, %b : !fir.complex<16>
%d2 = fir.cmpc "ogt", %a, %b : !fir.complex<16>
%d3 = fir.cmpc "oge", %a, %b : !fir.complex<16>
- // CHECK: fir.cmpc "olt", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "ole", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "one", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "ord", %{{.*}}, %{{.*}} : !fir.complex<16>
+
+// CHECK: [[VAL_157:%.*]] = fir.cmpc "olt", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_158:%.*]] = fir.cmpc "ole", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_159:%.*]] = fir.cmpc "one", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_160:%.*]] = fir.cmpc "ord", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
%a0 = fir.cmpc "olt", %a, %b : !fir.complex<16>
%a1 = fir.cmpc "ole", %a, %b : !fir.complex<16>
%a2 = fir.cmpc "one", %a, %b : !fir.complex<16>
%a3 = fir.cmpc "ord", %a, %b : !fir.complex<16>
- // CHECK: fir.cmpc "ueq", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "ugt", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "uge", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "ult", %{{.*}}, %{{.*}} : !fir.complex<16>
+
+// CHECK: [[VAL_161:%.*]] = fir.cmpc "ueq", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_162:%.*]] = fir.cmpc "ugt", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_163:%.*]] = fir.cmpc "uge", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_164:%.*]] = fir.cmpc "ult", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
%b0 = fir.cmpc "ueq", %a, %b : !fir.complex<16>
%b1 = fir.cmpc "ugt", %a, %b : !fir.complex<16>
%b2 = fir.cmpc "uge", %a, %b : !fir.complex<16>
%b3 = fir.cmpc "ult", %a, %b : !fir.complex<16>
- // CHECK: fir.cmpc "ule", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "une", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "uno", %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.cmpc "true", %{{.*}}, %{{.*}} : !fir.complex<16>
+
+// CHECK: [[VAL_165:%.*]] = fir.cmpc "ule", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_166:%.*]] = fir.cmpc "une", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_167:%.*]] = fir.cmpc "uno", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
+// CHECK: [[VAL_168:%.*]] = fir.cmpc "true", [[VAL_151]], [[VAL_152]] : !fir.complex<16>
%c0 = fir.cmpc "ule", %a, %b : !fir.complex<16>
%c1 = fir.cmpc "une", %a, %b : !fir.complex<16>
%c2 = fir.cmpc "uno", %a, %b : !fir.complex<16>
%c3 = fir.cmpc "true", %a, %b : !fir.complex<16>
+// CHECK: return
+// CHECK: }
return
}
-// CHECK-LABEL: @arith_real
+// CHECK-LABEL: func @arith_real(
+// CHECK-SAME: [[VAL_169:%.*]]: !fir.real<16>, [[VAL_170:%.*]]: !fir.real<16>) -> !fir.real<16> {
func @arith_real(%a : !fir.real<16>, %b : !fir.real<16>) -> !fir.real<16> {
+
+// CHECK: [[VAL_171:%.*]] = constant 1.0
+// CHECK: [[VAL_172:%.*]] = fir.convert [[VAL_171]] : (f32) -> !fir.real<16>
+// CHECK: [[VAL_173:%.*]] = fir.negf [[VAL_169]] : !fir.real<16>
+// CHECK: [[VAL_174:%.*]] = fir.addf [[VAL_172]], [[VAL_173]] : !fir.real<16>
+// CHECK: [[VAL_175:%.*]] = fir.subf [[VAL_174]], [[VAL_170]] : !fir.real<16>
+// CHECK: [[VAL_176:%.*]] = fir.mulf [[VAL_173]], [[VAL_175]] : !fir.real<16>
+// CHECK: [[VAL_177:%.*]] = fir.divf [[VAL_176]], [[VAL_169]] : !fir.real<16>
%c1 = constant 1.0 : f32
%0 = fir.convert %c1 : (f32) -> !fir.real<16>
- // CHECK: %[[R1:.*]] = fir.negf %{{.*}} : !fir.real<16>
- // CHECK: fir.addf %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: %[[R3:.*]] = fir.subf %{{.*}}, %{{.*}} : !fir.real<16>
- // CHECK: fir.mulf %[[R1]], %[[R3]] : !fir.real<16>
- // CHECK: fir.divf %{{.*}}, %{{.*}} : !fir.real<16>
%1 = fir.negf %a : !fir.real<16>
%2 = fir.addf %0, %1 : !fir.real<16>
%3 = fir.subf %2, %b : !fir.real<16>
%4 = fir.mulf %1, %3 : !fir.real<16>
%5 = fir.divf %4, %a : !fir.real<16>
+// CHECK: return [[VAL_177]] : !fir.real<16>
+// CHECK: }
return %5 : !fir.real<16>
}
-// CHECK-LABEL: @arith_complex
+// CHECK-LABEL: func @arith_complex(
+// CHECK-SAME: [[VAL_178:%.*]]: !fir.complex<16>, [[VAL_179:%.*]]: !fir.complex<16>) -> !fir.complex<16> {
func @arith_complex(%a : !fir.complex<16>, %b : !fir.complex<16>) -> !fir.complex<16> {
- // CHECK: fir.negc %{{.*}} : !fir.complex<16>
- // CHECK: fir.addc %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.subc %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.mulc %{{.*}}, %{{.*}} : !fir.complex<16>
- // CHECK: fir.divc %{{.*}}, %{{.*}} : !fir.complex<16>
+// CHECK: [[VAL_180:%.*]] = fir.negc [[VAL_178]] : !fir.complex<16>
+// CHECK: [[VAL_181:%.*]] = fir.addc [[VAL_179]], [[VAL_180]] : !fir.complex<16>
+// CHECK: [[VAL_182:%.*]] = fir.subc [[VAL_181]], [[VAL_179]] : !fir.complex<16>
+// CHECK: [[VAL_183:%.*]] = fir.mulc [[VAL_180]], [[VAL_182]] : !fir.complex<16>
+// CHECK: [[VAL_184:%.*]] = fir.divc [[VAL_183]], [[VAL_178]] : !fir.complex<16>
%1 = fir.negc %a : !fir.complex<16>
%2 = fir.addc %b, %1 : !fir.complex<16>
%3 = fir.subc %2, %b : !fir.complex<16>
%4 = fir.mulc %1, %3 : !fir.complex<16>
%5 = fir.divc %4, %a : !fir.complex<16>
+// CHECK: return [[VAL_184]] : !fir.complex<16>
+// CHECK: }
return %5 : !fir.complex<16>
}
-// CHECK-LABEL: @character_literal
+// CHECK-LABEL: func @character_literal() -> !fir.array<13x!fir.char<1>> {
func @character_literal() -> !fir.array<13 x !fir.char<1>> {
- // CHECK: fir.string_lit "Hello, World!"(13) : !fir.char<1>
+// CHECK: [[VAL_185:%.*]] = fir.string_lit "Hello, World!"(13) : !fir.char<1>
%0 = fir.string_lit "Hello, World!"(13) : !fir.char<1>
+// CHECK: return [[VAL_185]] : !fir.array<13x!fir.char<1>>
return %0 : !fir.array<13 x !fir.char<1>>
+// CHECK: }
+}
+
+// CHECK-LABEL: func @earlyexit2(i32) -> i1
+func @earlyexit2(%a : i32) -> i1
+
+// CHECK-LABEL: func @early_exit(
+// CHECK-SAME: [[VAL_186:%.*]]: i1, [[VAL_187:%.*]]: i32) -> i1 {
+func @early_exit(%ok : i1, %k : i32) -> i1 {
+// CHECK: [[VAL_188:%.*]] = constant 1 : index
+// CHECK: [[VAL_189:%.*]] = constant 100 : index
+ %c1 = constant 1 : index
+ %c100 = constant 100 : index
+
+// CHECK: [[VAL_190:%.*]], [[VAL_191:%.*]] = fir.iterate_while ([[VAL_192:%.*]] = [[VAL_188]] to [[VAL_189]] step [[VAL_188]]) and ([[VAL_193:%.*]] = [[VAL_186]]) iter_args([[VAL_194:%.*]] = [[VAL_187]]) -> (i32) {
+// CHECK: [[VAL_195:%.*]] = call @earlyexit2([[VAL_194]]) : (i32) -> i1
+// CHECK: fir.result [[VAL_195]], [[VAL_194]] : i1, i32
+// CHECK: }
+ %newOk:2 = fir.iterate_while (%i = %c1 to %c100 step %c1) and (%ok_ = %ok) iter_args(%v = %k) -> (i32) {
+ %stop = call @earlyexit2(%v) : (i32) -> i1
+ fir.result %stop, %v : i1, i32
+ }
+// CHECK: return [[VAL_190]] : i1
+// CHECK: }
+ return %newOk#0 : i1
}
More information about the flang-commits
mailing list