[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
This commit is contained in:
Eric Schweitz 2020-04-24 15:24:20 -07:00
parent bc7f3240e6
commit bc0342383d
9 changed files with 1637 additions and 425 deletions

View File

@ -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

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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 @@ public:
/// 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

View File

@ -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;

View File

@ -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;

View File

@ -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 &region : 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);
}

View File

@ -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();

View File

@ -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
}