[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:
parent
bc7f3240e6
commit
bc0342383d
@ -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
|
||||
|
||||
@ -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
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user