1 //===- SubElementInterfaces.cpp - Attr and Type SubElement Interfaces -----===//
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 "mlir/IR/SubElementInterfaces.h"
10 
11 #include "llvm/ADT/DenseSet.h"
12 
13 using namespace mlir;
14 
15 //===----------------------------------------------------------------------===//
16 // SubElementInterface
17 //===----------------------------------------------------------------------===//
18 
19 //===----------------------------------------------------------------------===//
20 // WalkSubElements
21 
22 template <typename InterfaceT>
walkSubElementsImpl(InterfaceT interface,function_ref<void (Attribute)> walkAttrsFn,function_ref<void (Type)> walkTypesFn,DenseSet<Attribute> & visitedAttrs,DenseSet<Type> & visitedTypes)23 static void walkSubElementsImpl(InterfaceT interface,
24                                 function_ref<void(Attribute)> walkAttrsFn,
25                                 function_ref<void(Type)> walkTypesFn,
26                                 DenseSet<Attribute> &visitedAttrs,
27                                 DenseSet<Type> &visitedTypes) {
28   interface.walkImmediateSubElements(
29       [&](Attribute attr) {
30         // Guard against potentially null inputs. This removes the need for the
31         // derived attribute/type to do it.
32         if (!attr)
33           return;
34 
35         // Avoid infinite recursion when visiting sub attributes later, if this
36         // is a mutable attribute.
37         if (LLVM_UNLIKELY(attr.hasTrait<AttributeTrait::IsMutable>())) {
38           if (!visitedAttrs.insert(attr).second)
39             return;
40         }
41 
42         // Walk any sub elements first.
43         if (auto interface = attr.dyn_cast<SubElementAttrInterface>())
44           walkSubElementsImpl(interface, walkAttrsFn, walkTypesFn, visitedAttrs,
45                               visitedTypes);
46 
47         // Walk this attribute.
48         walkAttrsFn(attr);
49       },
50       [&](Type type) {
51         // Guard against potentially null inputs. This removes the need for the
52         // derived attribute/type to do it.
53         if (!type)
54           return;
55 
56         // Avoid infinite recursion when visiting sub types later, if this
57         // is a mutable type.
58         if (LLVM_UNLIKELY(type.hasTrait<TypeTrait::IsMutable>())) {
59           if (!visitedTypes.insert(type).second)
60             return;
61         }
62 
63         // Walk any sub elements first.
64         if (auto interface = type.dyn_cast<SubElementTypeInterface>())
65           walkSubElementsImpl(interface, walkAttrsFn, walkTypesFn, visitedAttrs,
66                               visitedTypes);
67 
68         // Walk this type.
69         walkTypesFn(type);
70       });
71 }
72 
walkSubElements(function_ref<void (Attribute)> walkAttrsFn,function_ref<void (Type)> walkTypesFn)73 void SubElementAttrInterface::walkSubElements(
74     function_ref<void(Attribute)> walkAttrsFn,
75     function_ref<void(Type)> walkTypesFn) {
76   assert(walkAttrsFn && walkTypesFn && "expected valid walk functions");
77   DenseSet<Attribute> visitedAttrs;
78   DenseSet<Type> visitedTypes;
79   walkSubElementsImpl(*this, walkAttrsFn, walkTypesFn, visitedAttrs,
80                       visitedTypes);
81 }
82 
walkSubElements(function_ref<void (Attribute)> walkAttrsFn,function_ref<void (Type)> walkTypesFn)83 void SubElementTypeInterface::walkSubElements(
84     function_ref<void(Attribute)> walkAttrsFn,
85     function_ref<void(Type)> walkTypesFn) {
86   assert(walkAttrsFn && walkTypesFn && "expected valid walk functions");
87   DenseSet<Attribute> visitedAttrs;
88   DenseSet<Type> visitedTypes;
89   walkSubElementsImpl(*this, walkAttrsFn, walkTypesFn, visitedAttrs,
90                       visitedTypes);
91 }
92 
93 //===----------------------------------------------------------------------===//
94 // ReplaceSubElements
95 
96 /// Return if the given element is mutable.
isMutable(Attribute attr)97 static bool isMutable(Attribute attr) {
98   return attr.hasTrait<AttributeTrait::IsMutable>();
99 }
isMutable(Type type)100 static bool isMutable(Type type) {
101   return type.hasTrait<TypeTrait::IsMutable>();
102 }
103 
104 template <typename InterfaceT, typename T, typename ReplaceSubElementFnT>
updateSubElementImpl(T element,function_ref<T (T)> walkFn,DenseMap<T,T> & visited,SmallVectorImpl<T> & newElements,FailureOr<bool> & changed,ReplaceSubElementFnT && replaceSubElementFn)105 static void updateSubElementImpl(T element, function_ref<T(T)> walkFn,
106                                  DenseMap<T, T> &visited,
107                                  SmallVectorImpl<T> &newElements,
108                                  FailureOr<bool> &changed,
109                                  ReplaceSubElementFnT &&replaceSubElementFn) {
110   // Bail early if we failed at any point.
111   if (failed(changed))
112     return;
113   newElements.push_back(element);
114 
115   // Guard against potentially null inputs. We always map null to null.
116   if (!element)
117     return;
118 
119   // Check for an existing mapping for this element, and walk it if we haven't
120   // yet.
121   T &mappedElement = visited[element];
122   if (!mappedElement) {
123     // Try walking this element.
124     if (!(mappedElement = walkFn(element))) {
125       changed = failure();
126       return;
127     }
128 
129     // Handle replacing sub-elements if this element is also a container.
130     if (auto interface = mappedElement.template dyn_cast<InterfaceT>()) {
131       if (!(mappedElement = replaceSubElementFn(interface))) {
132         changed = failure();
133         return;
134       }
135     }
136   }
137 
138   // Update to the mapped element.
139   if (mappedElement != element) {
140     newElements.back() = mappedElement;
141     changed = true;
142   }
143 }
144 
145 template <typename InterfaceT>
146 static typename InterfaceT::ValueType
replaceSubElementsImpl(InterfaceT interface,function_ref<Attribute (Attribute)> walkAttrsFn,function_ref<Type (Type)> walkTypesFn,DenseMap<Attribute,Attribute> & visitedAttrs,DenseMap<Type,Type> & visitedTypes)147 replaceSubElementsImpl(InterfaceT interface,
148                        function_ref<Attribute(Attribute)> walkAttrsFn,
149                        function_ref<Type(Type)> walkTypesFn,
150                        DenseMap<Attribute, Attribute> &visitedAttrs,
151                        DenseMap<Type, Type> &visitedTypes) {
152   // Walk the current sub-elements, replacing them as necessary.
153   SmallVector<Attribute, 16> newAttrs;
154   SmallVector<Type, 16> newTypes;
155   FailureOr<bool> changed = false;
156   auto replaceSubElementFn = [&](auto subInterface) {
157     return replaceSubElementsImpl(subInterface, walkAttrsFn, walkTypesFn,
158                                   visitedAttrs, visitedTypes);
159   };
160   interface.walkImmediateSubElements(
161       [&](Attribute element) {
162         updateSubElementImpl<SubElementAttrInterface>(
163             element, walkAttrsFn, visitedAttrs, newAttrs, changed,
164             replaceSubElementFn);
165       },
166       [&](Type element) {
167         updateSubElementImpl<SubElementTypeInterface>(
168             element, walkTypesFn, visitedTypes, newTypes, changed,
169             replaceSubElementFn);
170       });
171   if (failed(changed))
172     return {};
173 
174   // If the sub-elements didn't change, just return the original value.
175   if (!*changed)
176     return interface;
177 
178   // If this element is mutable, we don't support changing its sub elements, the
179   // sub element walk doesn't give us a valid ordering for what we need here. If
180   // we want to support mutable elements, we'll need something more.
181   if (isMutable(interface))
182     return {};
183 
184   // Use the new elements during the replacement.
185   return interface.replaceImmediateSubElements(newAttrs, newTypes);
186 }
187 
replaceSubElements(function_ref<Attribute (Attribute)> replaceAttrFn,function_ref<Type (Type)> replaceTypeFn)188 Attribute SubElementAttrInterface::replaceSubElements(
189     function_ref<Attribute(Attribute)> replaceAttrFn,
190     function_ref<Type(Type)> replaceTypeFn) {
191   assert(replaceAttrFn && replaceTypeFn && "expected valid replace functions");
192   DenseMap<Attribute, Attribute> visitedAttrs;
193   DenseMap<Type, Type> visitedTypes;
194   return replaceSubElementsImpl(*this, replaceAttrFn, replaceTypeFn,
195                                 visitedAttrs, visitedTypes);
196 }
197 
replaceSubElements(function_ref<Attribute (Attribute)> replaceAttrFn,function_ref<Type (Type)> replaceTypeFn)198 Type SubElementTypeInterface::replaceSubElements(
199     function_ref<Attribute(Attribute)> replaceAttrFn,
200     function_ref<Type(Type)> replaceTypeFn) {
201   assert(replaceAttrFn && replaceTypeFn && "expected valid replace functions");
202   DenseMap<Attribute, Attribute> visitedAttrs;
203   DenseMap<Type, Type> visitedTypes;
204   return replaceSubElementsImpl(*this, replaceAttrFn, replaceTypeFn,
205                                 visitedAttrs, visitedTypes);
206 }
207 
208 //===----------------------------------------------------------------------===//
209 // SubElementInterface Tablegen definitions
210 //===----------------------------------------------------------------------===//
211 
212 #include "mlir/IR/SubElementAttrInterfaces.cpp.inc"
213 #include "mlir/IR/SubElementTypeInterfaces.cpp.inc"
214