Refactor the support for AffineMap and IntegerSet aliases in the parser into more general support for attribute aliases.

`#` alias `=` attribute-value

    This also allows for dialects to define aliases for attributes in the AsmPrinter. The printer supports two types of attribute aliases, 'direct' and 'kind'.

    * Direct aliases are synonymous with the current support for type aliases, i.e. this maps an alias to a specific instance of an attribute.

    // A direct alias ("foo_str") for the string attribute "foo".
    #foo_str = "foo"

    * Kind aliases generates unique names for all instances of a given attribute kind. The generated aliases are of the form: `alias[0-9]+`.

    // A kind alias ("strattr") for all string attributes could generate.
    #strattr0 = "foo"
    #strattr1 = "bar"
    ...
    #strattrN = "baz"

--

PiperOrigin-RevId: 246851916
This commit is contained in:
River Riddle 2019-05-06 10:36:32 -07:00 committed by Mehdi Amini
parent 3df7a80265
commit 94afc426e2
7 changed files with 209 additions and 306 deletions

View File

@ -95,15 +95,18 @@ public:
/// Registered hooks for getting identifier aliases for symbols. The
/// identifier is used in place of the symbol when printing textual IR.
///
/// Hook for defining AffineMap aliases.
virtual void getAffineMapAliases(
SmallVectorImpl<std::pair<StringRef, AffineMap>> &aliases) {}
/// Hook for defining IntegerSet aliases.
virtual void getIntegerSetAliases(
SmallVectorImpl<std::pair<StringRef, IntegerSet>> &aliases) {}
/// Hook for defining Attribute kind aliases. This will generate an alias for
/// all attributes of the given kind in the form : <alias>[0-9]+. These
/// aliases must not contain `.`.
virtual void getAttributeKindAliases(
SmallVectorImpl<std::pair<unsigned, StringRef>> &aliases) {}
/// Hook for defining Attribute aliases. These aliases must not contain `.` or
/// end with a numeric digit([0-9]+).
virtual void getAttributeAliases(
SmallVectorImpl<std::pair<Attribute, StringRef>> &aliases) {}
/// Hook for defining Type aliases.
virtual void
getTypeAliases(SmallVectorImpl<std::pair<StringRef, Type>> &aliases) {}
getTypeAliases(SmallVectorImpl<std::pair<Type, StringRef>> &aliases) {}
/// Verify an attribute from this dialect on the given function. Returns
/// failure if the verification failed, success otherwise.

View File

@ -35,6 +35,7 @@
#include "mlir/Support/STLExtras.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
@ -79,6 +80,9 @@ static llvm::cl::opt<bool>
namespace {
class ModuleState {
/// A special index constant used for non-kind attribute aliases.
static constexpr int kNonAttrKindAlias = -1;
public:
/// This is the current context if it is knowable, otherwise this is null.
MLIRContext *const context;
@ -88,51 +92,68 @@ public:
// Initializes module state, populating affine map state.
void initialize(Module *module);
StringRef getAffineMapAlias(AffineMap affineMap) const {
return affineMapToAlias.lookup(affineMap);
Twine getAttributeAlias(Attribute attr) const {
auto alias = attrToAlias.find(attr);
if (alias == attrToAlias.end())
return Twine();
// Return the alias for this attribute, along with the index if this was
// generated by a kind alias.
int kindIndex = alias->second.second;
return alias->second.first +
(kindIndex == kNonAttrKindAlias ? Twine() : Twine(kindIndex));
}
int getAffineMapId(AffineMap affineMap) const {
auto it = affineMapIds.find(affineMap);
if (it == affineMapIds.end()) {
return -1;
void printAttributeAliases(raw_ostream &os) const {
auto printAlias = [&](StringRef alias, Attribute attr, int index) {
os << '#' << alias;
if (index != kNonAttrKindAlias)
os << index;
os << " = " << attr << '\n';
};
// Print all of the attribute kind aliases.
for (auto &kindAlias : attrKindToAlias) {
for (unsigned i = 0, e = kindAlias.second.second.size(); i != e; ++i)
printAlias(kindAlias.second.first, kindAlias.second.second[i], i);
os << "\n";
}
return it->second;
}
ArrayRef<AffineMap> getAffineMapIds() const { return affineMapsById; }
StringRef getIntegerSetAlias(IntegerSet integerSet) const {
return integerSetToAlias.lookup(integerSet);
}
int getIntegerSetId(IntegerSet integerSet) const {
auto it = integerSetIds.find(integerSet);
if (it == integerSetIds.end()) {
return -1;
// In a second pass print all of the remaining attribute aliases that aren't
// kind aliases.
for (Attribute attr : usedAttributes) {
auto alias = attrToAlias.find(attr);
if (alias != attrToAlias.end() &&
alias->second.second == kNonAttrKindAlias)
printAlias(alias->second.first, attr, alias->second.second);
}
return it->second;
}
ArrayRef<IntegerSet> getIntegerSetIds() const { return integerSetsById; }
StringRef getTypeAlias(Type ty) const { return typeToAlias.lookup(ty); }
ArrayRef<Type> getTypeIds() const { return usedTypes.getArrayRef(); }
private:
void recordAffineMapReference(AffineMap affineMap) {
if (affineMapIds.count(affineMap) == 0) {
affineMapIds[affineMap] = affineMapsById.size();
affineMapsById.push_back(affineMap);
void printTypeAliases(raw_ostream &os) const {
for (Type type : usedTypes) {
auto alias = typeToAlias.find(type);
if (alias != typeToAlias.end())
os << '!' << alias->second << " = type " << type << '\n';
}
}
void recordIntegerSetReference(IntegerSet integerSet) {
if (integerSetIds.count(integerSet) == 0) {
integerSetIds[integerSet] = integerSetsById.size();
integerSetsById.push_back(integerSet);
}
private:
void recordAttributeReference(Attribute attr) {
// Don't recheck attributes that have already been seen or those that
// already have an alias.
if (!usedAttributes.insert(attr) || attrToAlias.count(attr))
return;
// If this attribute kind has an alias, then record one for this attribute.
auto alias = attrKindToAlias.find(static_cast<unsigned>(attr.getKind()));
if (alias == attrKindToAlias.end())
return;
std::pair<StringRef, int> attrAlias(alias->second.first,
alias->second.second.size());
attrToAlias.insert({attr, attrAlias});
alias->second.second.push_back(attr);
}
void recordTypeReference(Type ty) { usedTypes.insert(ty); }
@ -145,15 +166,23 @@ private:
// Initialize symbol aliases.
void initializeSymbolAliases();
DenseMap<AffineMap, int> affineMapIds;
std::vector<AffineMap> affineMapsById;
DenseMap<AffineMap, StringRef> affineMapToAlias;
/// Set of attributes known to be used within the module.
llvm::SetVector<Attribute> usedAttributes;
DenseMap<IntegerSet, int> integerSetIds;
std::vector<IntegerSet> integerSetsById;
DenseMap<IntegerSet, StringRef> integerSetToAlias;
/// Mapping between attribute and a pair comprised of a base alias name and a
/// count suffix. If the suffix is set to -1, it is not displayed.
llvm::MapVector<Attribute, std::pair<StringRef, int>> attrToAlias;
/// Mapping between attribute kind and a pair comprised of a base alias name
/// and a unique list of attributes belonging to this kind sorted by location
/// seen in the module.
llvm::MapVector<unsigned, std::pair<StringRef, std::vector<Attribute>>>
attrKindToAlias;
/// Set of types known to be used within the module.
llvm::SetVector<Type> usedTypes;
/// A mapping between a type and a given alias.
DenseMap<Type, StringRef> typeToAlias;
};
} // end anonymous namespace
@ -169,24 +198,18 @@ void ModuleState::visitType(Type type) {
visitType(result);
} else if (auto memref = type.dyn_cast<MemRefType>()) {
// Visit affine maps in memref type.
for (auto map : memref.getAffineMaps()) {
recordAffineMapReference(map);
}
for (auto map : memref.getAffineMaps())
recordAttributeReference(AffineMapAttr::get(map));
} else if (auto vecOrTensor = type.dyn_cast<VectorOrTensorType>()) {
visitType(vecOrTensor.getElementType());
}
}
void ModuleState::visitAttribute(Attribute attr) {
if (auto mapAttr = attr.dyn_cast<AffineMapAttr>()) {
recordAffineMapReference(mapAttr.getValue());
} else if (auto setAttr = attr.dyn_cast<IntegerSetAttr>()) {
recordIntegerSetReference(setAttr.getValue());
} else if (auto arrayAttr = attr.dyn_cast<ArrayAttr>()) {
for (auto elt : arrayAttr.getValue()) {
recordAttributeReference(attr);
if (auto arrayAttr = attr.dyn_cast<ArrayAttr>())
for (auto elt : arrayAttr.getValue())
visitAttribute(elt);
}
}
}
void ModuleState::visitOperation(Operation *op) {
@ -202,21 +225,14 @@ void ModuleState::visitOperation(Operation *op) {
}
// Utility to generate a function to register a symbol alias.
template <typename SymbolsInModuleSetTy, typename SymbolTy>
static void registerSymbolAlias(StringRef name, SymbolTy sym,
SymbolsInModuleSetTy &symbolsInModuleSet,
llvm::StringSet<> &usedAliases,
DenseMap<SymbolTy, StringRef> &symToAlias) {
static bool canRegisterAlias(StringRef name, llvm::StringSet<> &usedAliases) {
assert(!name.empty() && "expected alias name to be non-empty");
assert(sym && "expected alias symbol to be non-null");
// TODO(riverriddle) Assert that the provided alias name can be lexed as
// an identifier.
// Check if the symbol is not referenced by the module or the name is
// already used by another alias.
if (!symbolsInModuleSet.count(sym) || !usedAliases.insert(name).second)
return;
symToAlias.try_emplace(sym, name);
// Check that the alias doesn't contain a '.' character and the name is not
// already in use.
return !name.contains('.') && usedAliases.insert(name).second;
}
void ModuleState::initializeSymbolAliases() {
@ -228,53 +244,76 @@ void ModuleState::initializeSymbolAliases() {
auto dialects = context->getRegisteredDialects();
// Collect the set of aliases from each dialect.
SmallVector<std::pair<StringRef, AffineMap>, 8> affineMapAliases;
SmallVector<std::pair<StringRef, IntegerSet>, 8> integerSetAliases;
SmallVector<std::pair<StringRef, Type>, 16> typeAliases;
SmallVector<std::pair<unsigned, StringRef>, 8> attributeKindAliases;
SmallVector<std::pair<Attribute, StringRef>, 8> attributeAliases;
SmallVector<std::pair<Type, StringRef>, 16> typeAliases;
// AffineMap/Integer set have specific kind aliases.
attributeKindAliases.emplace_back(
static_cast<unsigned>(Attribute::Kind::AffineMap), "map");
attributeKindAliases.emplace_back(
static_cast<unsigned>(Attribute::Kind::IntegerSet), "set");
for (auto *dialect : dialects) {
dialect->getAffineMapAliases(affineMapAliases);
dialect->getIntegerSetAliases(integerSetAliases);
dialect->getAttributeKindAliases(attributeKindAliases);
dialect->getAttributeAliases(attributeAliases);
dialect->getTypeAliases(typeAliases);
}
// Register the affine aliases.
// Create a regex for the non-alias names of sets and maps, so that an alias
// is not registered with a conflicting name.
llvm::Regex reservedAffineNames("(set|map)[0-9]+");
// AffineMap aliases
for (auto &affineAliasPair : affineMapAliases) {
if (!reservedAffineNames.match(affineAliasPair.first))
registerSymbolAlias(affineAliasPair.first, affineAliasPair.second,
affineMapIds, usedAliases, affineMapToAlias);
// Setup the attribute kind aliases.
StringRef alias;
unsigned attrKind;
for (auto &attrAliasPair : attributeKindAliases) {
std::tie(attrKind, alias) = attrAliasPair;
assert(!alias.empty() && "expected non-empty alias string");
if (!usedAliases.count(alias) && !alias.contains('.'))
attrKindToAlias.insert({attrKind, {alias, {}}});
}
// IntegerSet aliases
for (auto &integerSetAliasPair : integerSetAliases) {
if (!reservedAffineNames.match(integerSetAliasPair.first))
registerSymbolAlias(integerSetAliasPair.first, integerSetAliasPair.second,
integerSetIds, usedAliases, integerSetToAlias);
// Clear the set of used identifiers so that the attribute kind aliases are
// just a prefix and not the full alias, i.e. there may be some overlap.
usedAliases.clear();
// Register the attribute aliases.
// Create a regex for the attribute kind alias names, these have a prefix with
// a counter appended to the end. We prevent normal aliases from having these
// names to avoid collisions.
llvm::Regex reservedAttrNames("[0-9]+$");
// Attribute value aliases.
Attribute attr;
for (auto &attrAliasPair : attributeAliases) {
std::tie(attr, alias) = attrAliasPair;
if (!reservedAttrNames.match(alias) && canRegisterAlias(alias, usedAliases))
attrToAlias.insert({attr, {alias, kNonAttrKindAlias}});
}
// Clear the set of used identifiers as types can have the same identifiers as
// affine structures.
usedAliases.clear();
// Type aliases.
for (auto &typeAliasPair : typeAliases)
registerSymbolAlias(typeAliasPair.first, typeAliasPair.second, usedTypes,
usedAliases, typeToAlias);
if (canRegisterAlias(typeAliasPair.second, usedAliases))
typeToAlias.insert(typeAliasPair);
}
// Initializes module state, populating affine map and integer set state.
void ModuleState::initialize(Module *module) {
// Initialize the symbol aliases.
initializeSymbolAliases();
// Walk the module and visit each operation.
for (auto &fn : *module) {
visitType(fn.getType());
for (auto attr : fn.getAttrs())
ModuleState::visitAttribute(attr.second);
for (auto attrList : fn.getAllArgAttrs())
for (auto attr : attrList.getAttrs())
ModuleState::visitAttribute(attr.second);
fn.walk([&](Operation *op) { ModuleState::visitOperation(op); });
}
// Initialize the symbol aliases.
initializeSymbolAliases();
}
//===----------------------------------------------------------------------===//
@ -318,12 +357,6 @@ protected:
void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
ArrayRef<StringRef> elidedAttrs = {});
void printAttributeOptionalType(Attribute attr, bool includeType);
void printAffineMapId(int affineMapId) const;
void printAffineMapReference(AffineMap affineMap);
void printAffineMapAlias(StringRef alias) const;
void printIntegerSetId(int integerSetId) const;
void printIntegerSetReference(IntegerSet integerSet);
void printIntegerSetAlias(StringRef alias) const;
void printTrailingLocation(Location loc);
void printLocationInternal(Location loc, bool pretty = false);
void printDenseElementsAttr(DenseElementsAttr attr);
@ -340,58 +373,6 @@ protected:
};
} // end anonymous namespace
// Prints affine map identifier.
void ModulePrinter::printAffineMapId(int affineMapId) const {
os << "#map" << affineMapId;
}
void ModulePrinter::printAffineMapAlias(StringRef alias) const {
os << '#' << alias;
}
void ModulePrinter::printAffineMapReference(AffineMap affineMap) {
// Check for an affine map alias.
auto alias = state.getAffineMapAlias(affineMap);
if (!alias.empty())
return printAffineMapAlias(alias);
int mapId = state.getAffineMapId(affineMap);
if (mapId >= 0) {
// Map will be printed at top of module so print reference to its id.
printAffineMapId(mapId);
} else {
// Map not in module state so print inline.
affineMap.print(os);
}
}
// Prints integer set identifier.
void ModulePrinter::printIntegerSetId(int integerSetId) const {
os << "#set" << integerSetId;
}
void ModulePrinter::printIntegerSetAlias(StringRef alias) const {
os << '#' << alias;
}
void ModulePrinter::printIntegerSetReference(IntegerSet integerSet) {
// Check for an integer set alias.
auto alias = state.getIntegerSetAlias(integerSet);
if (!alias.empty()) {
printIntegerSetAlias(alias);
return;
}
int setId;
if ((setId = state.getIntegerSetId(integerSet)) >= 0) {
// The set will be printed at top of module; so print reference to its id.
printIntegerSetId(setId);
} else {
// Set not in module state so print inline.
integerSet.print(os);
}
}
void ModulePrinter::printTrailingLocation(Location loc) {
// Check to see if we are printing debug information.
if (!shouldPrintDebugInfoOpt)
@ -463,31 +444,11 @@ void ModulePrinter::printLocationInternal(Location loc, bool pretty) {
}
void ModulePrinter::print(Module *module) {
for (const auto &map : state.getAffineMapIds()) {
StringRef alias = state.getAffineMapAlias(map);
if (!alias.empty())
printAffineMapAlias(alias);
else
printAffineMapId(state.getAffineMapId(map));
os << " = ";
map.print(os);
os << '\n';
}
for (const auto &set : state.getIntegerSetIds()) {
StringRef alias = state.getIntegerSetAlias(set);
if (!alias.empty())
printIntegerSetAlias(alias);
else
printIntegerSetId(state.getIntegerSetId(set));
os << " = ";
set.print(os);
os << '\n';
}
for (const auto &type : state.getTypeIds()) {
StringRef alias = state.getTypeAlias(type);
if (!alias.empty())
os << '!' << alias << " = type " << type << '\n';
}
// Output the aliases at the top level.
state.printAttributeAliases(os);
state.printTypeAliases(os);
// Print the module.
for (auto &fn : *module)
print(&fn);
}
@ -545,6 +506,13 @@ void ModulePrinter::printAttributeOptionalType(Attribute attr,
return;
}
// Check for an alias for this attribute.
Twine alias = state.getAttributeAlias(attr);
if (!alias.isTriviallyEmpty()) {
os << '#' << alias;
return;
}
switch (attr.getKind()) {
case Attribute::Kind::Unit:
os << "unit";
@ -587,10 +555,10 @@ void ModulePrinter::printAttributeOptionalType(Attribute attr,
os << ']';
break;
case Attribute::Kind::AffineMap:
printAffineMapReference(attr.cast<AffineMapAttr>().getValue());
attr.cast<AffineMapAttr>().getValue().print(os);
break;
case Attribute::Kind::IntegerSet:
printIntegerSetReference(attr.cast<IntegerSetAttr>().getValue());
attr.cast<IntegerSetAttr>().getValue().print(os);
break;
case Attribute::Kind::Type:
printType(attr.cast<TypeAttr>().getValue());
@ -889,7 +857,7 @@ void ModulePrinter::printType(Type type) {
printType(v.getElementType());
for (auto map : v.getAffineMaps()) {
os << ", ";
printAffineMapReference(map);
printAttribute(AffineMapAttr::get(map));
}
// Only print the memory space if it is the non-default one.
if (v.getMemorySpace())
@ -1303,12 +1271,12 @@ void FunctionPrinter::numberValueID(Value *value) {
Type type = op->getResult(0)->getType();
if (auto intCst = cst.dyn_cast<IntegerAttr>()) {
if (type.isIndex()) {
specialName << 'c' << intCst;
specialName << 'c' << intCst.getInt();
} else if (type.cast<IntegerType>().isInteger(1)) {
// i1 constants get special names.
specialName << (intCst.getInt() ? "true" : "false");
} else {
specialName << 'c' << intCst << '_' << type;
specialName << 'c' << intCst.getInt() << '_' << type;
}
} else if (cst.isa<FunctionAttr>()) {
specialName << 'f';
@ -1638,7 +1606,7 @@ void ModulePrinter::print(Function *fn) { FunctionPrinter(fn, *this).print(); }
void Attribute::print(raw_ostream &os) const {
ModuleState state(/*no context is known*/ nullptr);
ModulePrinter(os, state).printAttribute(*this);
ModulePrinter(os, state).printAttributeAndType(*this);
}
void Attribute::dump() const {

View File

@ -200,7 +200,8 @@ struct ArrayAttributeStorage : public AttributeStorage {
struct AffineMapAttributeStorage : public AttributeStorage {
using KeyTy = AffineMap;
AffineMapAttributeStorage(AffineMap value) : value(value) {}
AffineMapAttributeStorage(AffineMap value)
: AttributeStorage(IndexType::get(value.getContext())), value(value) {}
/// Key equality function.
bool operator==(const KeyTy &key) const { return key == value; }

View File

@ -244,7 +244,7 @@ Token Lexer::lexPrefixedIdentifier(const char *tokStart) {
switch (*tokStart) {
case '#':
kind = Token::hash_identifier;
errorKind = "invalid affine map name";
errorKind = "invalid attribute name";
break;
case '%':
kind = Token::percent_identifier;

View File

@ -68,11 +68,8 @@ public:
functionForwardRefs.clear();
}
// A map from affine map identifier to AffineMap.
llvm::StringMap<AffineMap> affineMapDefinitions;
// A map from integer set identifier to IntegerSet.
llvm::StringMap<IntegerSet> integerSetDefinitions;
// A map from attribute alias identifier to Attribute.
llvm::StringMap<Attribute> attributeAliasDefinitions;
// A map from type alias identifier to Type.
llvm::StringMap<Type> typeAliasDefinitions;
@ -204,8 +201,6 @@ public:
ParseResult parseAttributeDict(SmallVectorImpl<NamedAttribute> &attributes);
// Polyhedral structures.
AffineMap parseAffineMapReference();
IntegerSet parseIntegerSetReference();
ParseResult parseAffineMapOrIntegerSetReference(AffineMap &map,
IntegerSet &set);
DenseElementsAttr parseDenseElementsAttr(VectorOrTensorType type);
@ -761,10 +756,15 @@ Type Parser::parseMemRefType() {
// Parse affine map.
if (parsedMemorySpace)
return emitError("affine map after memory space in memref type");
auto affineMap = parseAffineMapReference();
auto affineMap = parseAttribute();
if (!affineMap)
return ParseFailure;
affineMapComposition.push_back(affineMap);
// Verify that the parsed attribute is an affine map.
if (auto affineMapAttr = affineMap.dyn_cast<AffineMapAttr>())
affineMapComposition.push_back(affineMapAttr.getValue());
else
return emitError("expected affine map in memref type");
}
return ParseSuccess;
};
@ -1033,6 +1033,25 @@ Function *Parser::resolveFunctionReference(StringRef nameStr, SMLoc nameLoc,
/// (tensor-type | vector-type) `,` hex-string-literal `>`
///
Attribute Parser::parseAttribute(Type type) {
// If this is a hash_identifier, we are parsing an attribute alias.
if (getToken().is(Token::hash_identifier)) {
StringRef id = getTokenSpelling().drop_front();
consumeToken(Token::hash_identifier);
// Check for an alias for this attribute.
auto aliasIt = state.attributeAliasDefinitions.find(id);
if (aliasIt == state.attributeAliasDefinitions.end())
return (emitError("undefined attribute alias id '" + id + "'"), nullptr);
// Ensure that the attribute alias has the same type as requested.
if (type && aliasIt->second.getType() != type) {
emitError("requested attribute type different then alias attribute type");
return nullptr;
}
return aliasIt->second;
}
switch (getToken().getKind()) {
case Token::kw_unit:
consumeToken(Token::kw_unit);
@ -1162,7 +1181,6 @@ Attribute Parser::parseAttribute(Type type) {
return nullptr;
return builder.getArrayAttr(elements);
}
case Token::hash_identifier:
case Token::l_paren: {
// Try to parse an affine map or an integer set reference.
AffineMap map;
@ -2071,8 +2089,8 @@ AffineParser::parseDimAndOptionalSymbolIdList(unsigned &numDims,
/// Parses an affine map definition inline.
///
/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
/// (`size` `(` dim-size (`,` dim-size)* `)`)?
/// affine-map ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
/// (`size` `(` dim-size (`,` dim-size)* `)`)?
/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
///
/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
@ -2095,9 +2113,7 @@ AffineMap AffineParser::parseAffineMapInline() {
/// Parses an integer set definition inline.
///
/// integer-set-inline
/// ::= dim-and-symbol-id-lists `:`
/// affine-constraint-conjunction
/// integer-set ::= dim-and-symbol-id-lists `:` affine-constraint-conjunction
/// affine-constraint-conjunction ::= /*empty*/
/// | affine-constraint (`,`
/// affine-constraint)*
@ -2149,8 +2165,8 @@ ParseResult AffineParser::parseAffineMapOrIntegerSetInline(AffineMap &map,
/// Parse the range and sizes affine map definition inline.
///
/// affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
/// (`size` `(` dim-size (`,` dim-size)* `)`)?
/// affine-map ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
/// (`size` `(` dim-size (`,` dim-size)* `)`)?
/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
///
/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
@ -2212,77 +2228,10 @@ AffineMap AffineParser::parseAffineMapRange(unsigned numDims,
return builder.getAffineMap(numDims, numSymbols, exprs, rangeSizes);
}
/// Parse a reference to an integer set.
/// integer-set ::= integer-set-id | integer-set-inline
/// integer-set-id ::= `#` suffix-id
///
IntegerSet Parser::parseIntegerSetReference() {
if (getToken().isNot(Token::hash_identifier)) {
// Try to parse inline integer set.
return AffineParser(state).parseIntegerSetInline();
}
// Parse integer set identifier and verify that it exists.
StringRef id = getTokenSpelling().drop_front();
if (getState().integerSetDefinitions.count(id) > 0) {
consumeToken(Token::hash_identifier);
return getState().integerSetDefinitions[id];
}
// The id isn't among any of the recorded definitions.
emitError("undefined integer set id '" + id + "'");
return IntegerSet();
}
/// Parse a reference to an affine map.
/// affine-map ::= affine-map-id | affine-map-inline
/// affine-map-id ::= `#` suffix-id
///
AffineMap Parser::parseAffineMapReference() {
if (getToken().isNot(Token::hash_identifier)) {
// Try to parse inline affine map.
return AffineParser(state).parseAffineMapInline();
}
// Parse affine map identifier and verify that it exists.
StringRef id = getTokenSpelling().drop_front();
if (getState().affineMapDefinitions.count(id) > 0) {
consumeToken(Token::hash_identifier);
return getState().affineMapDefinitions[id];
}
// The id isn't among any of the recorded definitions.
emitError("undefined affine map id '" + id + "'");
return AffineMap();
}
/// Parse an ambiguous reference to either and affine map or an integer set.
ParseResult Parser::parseAffineMapOrIntegerSetReference(AffineMap &map,
IntegerSet &set) {
if (getToken().isNot(Token::hash_identifier)) {
// Try to parse inline affine map.
return AffineParser(state).parseAffineMapOrIntegerSetInline(map, set);
}
// Parse affine map / integer set identifier and verify that it exists.
// Note that an id can't be in both affineMapDefinitions and
// integerSetDefinitions since they use the same sigil '#'.
StringRef id = getTokenSpelling().drop_front();
if (getState().affineMapDefinitions.count(id) > 0) {
consumeToken(Token::hash_identifier);
map = getState().affineMapDefinitions[id];
return ParseSuccess;
}
if (getState().integerSetDefinitions.count(id) > 0) {
consumeToken(Token::hash_identifier);
set = getState().integerSetDefinitions[id];
return ParseSuccess;
}
// The id isn't among any of the recorded definitions.
emitError("undefined affine map or integer set id '" + id + "'");
return ParseFailure;
return AffineParser(state).parseAffineMapOrIntegerSetInline(map, set);
}
//===----------------------------------------------------------------------===//
@ -3601,7 +3550,7 @@ public:
private:
ParseResult finalizeModule();
ParseResult parseAffineStructureDef();
ParseResult parseAttributeAliasDef();
ParseResult parseTypeAliasDef();
@ -3617,48 +3566,31 @@ private:
};
} // end anonymous namespace
/// Parses either an affine map declaration or an integer set declaration.
/// Parses an attribute alias declaration.
///
/// Affine map declaration.
/// attribute-alias-def ::= '#' alias-name `=` attribute-value
///
/// affine-map-def ::= affine-map-id `=` affine-map-inline
///
/// Integer set declaration.
///
/// integer-set-decl ::= integer-set-id `=` integer-set-inline
///
ParseResult ModuleParser::parseAffineStructureDef() {
ParseResult ModuleParser::parseAttributeAliasDef() {
assert(getToken().is(Token::hash_identifier));
StringRef affineStructureId = getTokenSpelling().drop_front();
StringRef attrId = getTokenSpelling().drop_front();
// Check for redefinitions.
if (getState().affineMapDefinitions.count(affineStructureId) > 0)
return emitError("redefinition of affine map id '" + affineStructureId +
"'");
if (getState().integerSetDefinitions.count(affineStructureId) > 0)
return emitError("redefinition of integer set id '" + affineStructureId +
"'");
if (getState().attributeAliasDefinitions.count(attrId) > 0)
return emitError("redefinition of attribute alias id '" + attrId + "'");
consumeToken(Token::hash_identifier);
// Parse the '='
if (parseToken(Token::equal,
"expected '=' in affine map outlined definition"))
if (parseToken(Token::equal, "expected '=' in attribute alias definition"))
return ParseFailure;
AffineMap map;
IntegerSet set;
if (AffineParser(getState()).parseAffineMapOrIntegerSetInline(map, set))
// Parse the attribute value.
Attribute attr = parseAttribute();
if (!attr)
return ParseFailure;
if (map) {
getState().affineMapDefinitions[affineStructureId] = map;
return ParseSuccess;
}
assert(set);
getState().integerSetDefinitions[affineStructureId] = set;
getState().attributeAliasDefinitions[attrId] = attr;
return ParseSuccess;
}
@ -3853,7 +3785,6 @@ ParseResult ModuleParser::parseFunc() {
/// Finish the end of module parsing - when the result is valid, do final
/// checking.
ParseResult ModuleParser::finalizeModule() {
// Resolve all forward references, building a remapping table of attributes.
DenseMap<Attribute, FunctionAttr> remappingTable;
for (auto forwardRef : getState().functionForwardRefs) {
@ -3906,7 +3837,7 @@ ParseResult ModuleParser::parseModule() {
return ParseFailure;
case Token::hash_identifier:
if (parseAffineStructureDef())
if (parseAttributeAliasDef())
return ParseFailure;
break;

View File

@ -14,7 +14,7 @@
#hello_world = (i, j) -> (, j) // expected-error {{expected affine expression}}
// -----
#hello_world (i, j) [s0] -> (i, j) // expected-error {{expected '=' in affine map outlined definition}}
#hello_world (i, j) [s0] -> (i, j) // expected-error {{expected '=' in attribute alias definition}}
// -----
#hello_world = (i, j) [s0] -> (2*i*, 3*j*i*2 + 5) // expected-error {{missing right operand of binary op}}
@ -118,4 +118,4 @@
// -----
#ABC = (i,j) -> (i+j)
#ABC = (i,j) -> (i+j) // expected-error {{redefinition of affine map id 'ABC'}}
#ABC = (i,j) -> (i+j) // expected-error {{redefinition of attribute alias id 'ABC'}}

View File

@ -34,17 +34,17 @@ func @memrefs(memref<2x4xi8, >) // expected-error {{expected list element}}
// -----
// Test non-existent map in memref type.
func @memrefs(memref<2x4xi8, #map7>) // expected-error {{undefined affine map id 'map7'}}
func @memrefs(memref<2x4xi8, #map7>) // expected-error {{undefined attribute alias id 'map7'}}
// -----
// Test non hash identifier in memref type.
func @memrefs(memref<2x4xi8, %map7>) // expected-error {{expected '(' at start of dimensional identifiers list}}
// Test non affine map in memref type.
func @memrefs(memref<2x4xi8, i8>) // expected-error {{expected affine map in memref type}}
// -----
// Test non-existent map in map composition of memref type.
#map0 = (d0, d1) -> (d0, d1)
func @memrefs(memref<2x4xi8, #map0, #map8>) // expected-error {{undefined affine map id 'map8'}}
func @memrefs(memref<2x4xi8, #map0, #map8>) // expected-error {{undefined attribute alias id 'map8'}}
// -----
// Test multiple memory space error.