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