1 //===-- FIRAttr.cpp -------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "flang/Optimizer/Dialect/FIRAttr.h" 10 #include "flang/Optimizer/Dialect/FIRDialect.h" 11 #include "flang/Optimizer/Dialect/FIRType.h" 12 #include "flang/Optimizer/Support/KindMapping.h" 13 #include "mlir/IR/AttributeSupport.h" 14 #include "mlir/IR/Diagnostics.h" 15 #include "mlir/IR/DialectImplementation.h" 16 #include "mlir/IR/Types.h" 17 #include "mlir/Parser.h" 18 #include "llvm/ADT/SmallString.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/ADT/Twine.h" 21 22 using namespace fir; 23 24 namespace fir { 25 namespace detail { 26 27 struct RealAttributeStorage : public mlir::AttributeStorage { 28 using KeyTy = std::pair<int, llvm::APFloat>; 29 30 RealAttributeStorage(int kind, const llvm::APFloat &value) 31 : kind(kind), value(value) {} 32 RealAttributeStorage(const KeyTy &key) 33 : RealAttributeStorage(key.first, key.second) {} 34 35 static unsigned hashKey(const KeyTy &key) { return llvm::hash_value(key); } 36 37 bool operator==(const KeyTy &key) const { 38 return key.first == kind && 39 key.second.compare(value) == llvm::APFloatBase::cmpEqual; 40 } 41 42 static RealAttributeStorage * 43 construct(mlir::AttributeStorageAllocator &allocator, const KeyTy &key) { 44 return new (allocator.allocate<RealAttributeStorage>()) 45 RealAttributeStorage(key); 46 } 47 48 int getFKind() const { return kind; } 49 llvm::APFloat getValue() const { return value; } 50 51 private: 52 int kind; 53 llvm::APFloat value; 54 }; 55 56 /// An attribute representing a reference to a type. 57 struct TypeAttributeStorage : public mlir::AttributeStorage { 58 using KeyTy = mlir::Type; 59 60 TypeAttributeStorage(mlir::Type value) : value(value) { 61 assert(value && "must not be of Type null"); 62 } 63 64 /// Key equality function. 65 bool operator==(const KeyTy &key) const { return key == value; } 66 67 /// Construct a new storage instance. 68 static TypeAttributeStorage * 69 construct(mlir::AttributeStorageAllocator &allocator, KeyTy key) { 70 return new (allocator.allocate<TypeAttributeStorage>()) 71 TypeAttributeStorage(key); 72 } 73 74 mlir::Type getType() const { return value; } 75 76 private: 77 mlir::Type value; 78 }; 79 } // namespace detail 80 81 ExactTypeAttr ExactTypeAttr::get(mlir::Type value) { 82 return Base::get(value.getContext(), FIR_EXACTTYPE, value); 83 } 84 85 mlir::Type ExactTypeAttr::getType() const { return getImpl()->getType(); } 86 87 SubclassAttr SubclassAttr::get(mlir::Type value) { 88 return Base::get(value.getContext(), FIR_SUBCLASS, value); 89 } 90 91 mlir::Type SubclassAttr::getType() const { return getImpl()->getType(); } 92 93 using AttributeUniquer = mlir::detail::AttributeUniquer; 94 95 ClosedIntervalAttr ClosedIntervalAttr::get(mlir::MLIRContext *ctxt) { 96 return AttributeUniquer::get<ClosedIntervalAttr>(ctxt, getId()); 97 } 98 99 UpperBoundAttr UpperBoundAttr::get(mlir::MLIRContext *ctxt) { 100 return AttributeUniquer::get<UpperBoundAttr>(ctxt, getId()); 101 } 102 103 LowerBoundAttr LowerBoundAttr::get(mlir::MLIRContext *ctxt) { 104 return AttributeUniquer::get<LowerBoundAttr>(ctxt, getId()); 105 } 106 107 PointIntervalAttr PointIntervalAttr::get(mlir::MLIRContext *ctxt) { 108 return AttributeUniquer::get<PointIntervalAttr>(ctxt, getId()); 109 } 110 111 // RealAttr 112 113 RealAttr RealAttr::get(mlir::MLIRContext *ctxt, 114 const RealAttr::ValueType &key) { 115 return Base::get(ctxt, getId(), key); 116 } 117 118 int RealAttr::getFKind() const { return getImpl()->getFKind(); } 119 120 llvm::APFloat RealAttr::getValue() const { return getImpl()->getValue(); } 121 122 // FIR attribute parsing 123 124 namespace { 125 mlir::Attribute parseFirRealAttr(FIROpsDialect *dialect, 126 mlir::DialectAsmParser &parser, 127 mlir::Type type) { 128 int kind = 0; 129 if (parser.parseLess() || parser.parseInteger(kind) || parser.parseComma()) { 130 parser.emitError(parser.getNameLoc(), "expected '<' kind ','"); 131 return {}; 132 } 133 KindMapping kindMap(dialect->getContext()); 134 llvm::APFloat value(0.); 135 if (parser.parseOptionalKeyword("i")) { 136 // `i` not present, so literal float must be present 137 double dontCare; 138 if (parser.parseFloat(dontCare) || parser.parseGreater()) { 139 parser.emitError(parser.getNameLoc(), "expected real constant '>'"); 140 return {}; 141 } 142 auto fltStr = parser.getFullSymbolSpec() 143 .drop_until([](char c) { return c == ','; }) 144 .drop_front() 145 .drop_while([](char c) { return c == ' ' || c == '\t'; }) 146 .take_until([](char c) { 147 return c == '>' || c == ' ' || c == '\t'; 148 }); 149 value = llvm::APFloat(kindMap.getFloatSemantics(kind), fltStr); 150 } else { 151 // `i` is present, so literal bitstring (hex) must be present 152 llvm::StringRef hex; 153 if (parser.parseKeyword(&hex) || parser.parseGreater()) { 154 parser.emitError(parser.getNameLoc(), "expected real constant '>'"); 155 return {}; 156 } 157 auto bits = llvm::APInt(kind * 8, hex.drop_front(), 16); 158 value = llvm::APFloat(kindMap.getFloatSemantics(kind), bits); 159 } 160 return RealAttr::get(dialect->getContext(), {kind, value}); 161 } 162 } // namespace 163 164 mlir::Attribute parseFirAttribute(FIROpsDialect *dialect, 165 mlir::DialectAsmParser &parser, 166 mlir::Type type) { 167 auto loc = parser.getNameLoc(); 168 llvm::StringRef attrName; 169 if (parser.parseKeyword(&attrName)) { 170 parser.emitError(loc, "expected an attribute name"); 171 return {}; 172 } 173 174 if (attrName == ExactTypeAttr::getAttrName()) { 175 mlir::Type type; 176 if (parser.parseLess() || parser.parseType(type) || parser.parseGreater()) { 177 parser.emitError(loc, "expected a type"); 178 return {}; 179 } 180 return ExactTypeAttr::get(type); 181 } 182 if (attrName == SubclassAttr::getAttrName()) { 183 mlir::Type type; 184 if (parser.parseLess() || parser.parseType(type) || parser.parseGreater()) { 185 parser.emitError(loc, "expected a subtype"); 186 return {}; 187 } 188 return SubclassAttr::get(type); 189 } 190 if (attrName == PointIntervalAttr::getAttrName()) 191 return PointIntervalAttr::get(dialect->getContext()); 192 if (attrName == LowerBoundAttr::getAttrName()) 193 return LowerBoundAttr::get(dialect->getContext()); 194 if (attrName == UpperBoundAttr::getAttrName()) 195 return UpperBoundAttr::get(dialect->getContext()); 196 if (attrName == ClosedIntervalAttr::getAttrName()) 197 return ClosedIntervalAttr::get(dialect->getContext()); 198 if (attrName == RealAttr::getAttrName()) 199 return parseFirRealAttr(dialect, parser, type); 200 201 parser.emitError(loc, "unknown FIR attribute: ") << attrName; 202 return {}; 203 } 204 205 // FIR attribute pretty printer 206 207 void printFirAttribute(FIROpsDialect *dialect, mlir::Attribute attr, 208 mlir::DialectAsmPrinter &p) { 209 auto &os = p.getStream(); 210 if (auto exact = attr.dyn_cast<fir::ExactTypeAttr>()) { 211 os << fir::ExactTypeAttr::getAttrName() << '<'; 212 p.printType(exact.getType()); 213 os << '>'; 214 } else if (auto sub = attr.dyn_cast<fir::SubclassAttr>()) { 215 os << fir::SubclassAttr::getAttrName() << '<'; 216 p.printType(sub.getType()); 217 os << '>'; 218 } else if (attr.dyn_cast_or_null<fir::PointIntervalAttr>()) { 219 os << fir::PointIntervalAttr::getAttrName(); 220 } else if (attr.dyn_cast_or_null<fir::ClosedIntervalAttr>()) { 221 os << fir::ClosedIntervalAttr::getAttrName(); 222 } else if (attr.dyn_cast_or_null<fir::LowerBoundAttr>()) { 223 os << fir::LowerBoundAttr::getAttrName(); 224 } else if (attr.dyn_cast_or_null<fir::UpperBoundAttr>()) { 225 os << fir::UpperBoundAttr::getAttrName(); 226 } else if (auto a = attr.dyn_cast_or_null<fir::RealAttr>()) { 227 os << fir::RealAttr::getAttrName() << '<' << a.getFKind() << ", i x"; 228 llvm::SmallString<40> ss; 229 a.getValue().bitcastToAPInt().toStringUnsigned(ss, 16); 230 os << ss << '>'; 231 } else { 232 llvm_unreachable("attribute pretty-printer is not implemented"); 233 } 234 } 235 236 } // namespace fir 237