1 | //===- PtrTypes.cpp - Pointer dialect types ---------------------*- C++ -*-===// |
2 | // |
3 | // This file is licensed 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 | // This file defines the Ptr dialect types. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "mlir/Dialect/Ptr/IR/PtrTypes.h" |
14 | #include "mlir/Dialect/Ptr/IR/PtrAttrs.h" |
15 | #include "llvm/ADT/TypeSwitch.h" |
16 | |
17 | using namespace mlir; |
18 | using namespace mlir::ptr; |
19 | |
20 | //===----------------------------------------------------------------------===// |
21 | // Pointer type |
22 | //===----------------------------------------------------------------------===// |
23 | |
24 | constexpr const static unsigned kDefaultPointerSizeBits = 64; |
25 | constexpr const static unsigned kBitsInByte = 8; |
26 | constexpr const static unsigned kDefaultPointerAlignmentBits = 8; |
27 | |
28 | /// Searches the data layout for the pointer spec, returns nullptr if it is not |
29 | /// found. |
30 | static SpecAttr getPointerSpec(DataLayoutEntryListRef params, PtrType type, |
31 | MemorySpaceAttrInterface defaultMemorySpace) { |
32 | for (DataLayoutEntryInterface entry : params) { |
33 | if (!entry.isTypeEntry()) |
34 | continue; |
35 | if (cast<PtrType>(cast<Type>(entry.getKey())).getMemorySpace() == |
36 | type.getMemorySpace()) { |
37 | if (auto spec = dyn_cast<SpecAttr>(entry.getValue())) |
38 | return spec; |
39 | } |
40 | } |
41 | // If not found, and this is the pointer to the default memory space or if |
42 | // `defaultMemorySpace` is null, assume 64-bit pointers. `defaultMemorySpace` |
43 | // might be null if the data layout doesn't define the default memory space. |
44 | if (type.getMemorySpace() == defaultMemorySpace || |
45 | defaultMemorySpace == nullptr) |
46 | return SpecAttr::get(type.getContext(), kDefaultPointerSizeBits, |
47 | kDefaultPointerAlignmentBits, |
48 | kDefaultPointerAlignmentBits, kDefaultPointerSizeBits); |
49 | return nullptr; |
50 | } |
51 | |
52 | bool PtrType::areCompatible(DataLayoutEntryListRef oldLayout, |
53 | DataLayoutEntryListRef newLayout, |
54 | DataLayoutSpecInterface newSpec, |
55 | const DataLayoutIdentifiedEntryMap &map) const { |
56 | for (DataLayoutEntryInterface newEntry : newLayout) { |
57 | if (!newEntry.isTypeEntry()) |
58 | continue; |
59 | uint32_t size = kDefaultPointerSizeBits; |
60 | uint32_t abi = kDefaultPointerAlignmentBits; |
61 | auto newType = llvm::cast<PtrType>(llvm::cast<Type>(newEntry.getKey())); |
62 | const auto *it = |
63 | llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) { |
64 | if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) { |
65 | return llvm::cast<PtrType>(type).getMemorySpace() == |
66 | newType.getMemorySpace(); |
67 | } |
68 | return false; |
69 | }); |
70 | if (it == oldLayout.end()) { |
71 | Attribute defaultMemorySpace = mlir::detail::getDefaultMemorySpace( |
72 | map.lookup(newSpec.getDefaultMemorySpaceIdentifier(getContext()))); |
73 | it = llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) { |
74 | if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) { |
75 | auto ptrTy = llvm::cast<PtrType>(type); |
76 | return ptrTy.getMemorySpace() == defaultMemorySpace; |
77 | } |
78 | return false; |
79 | }); |
80 | } |
81 | if (it != oldLayout.end()) { |
82 | auto spec = llvm::cast<SpecAttr>(*it); |
83 | size = spec.getSize(); |
84 | abi = spec.getAbi(); |
85 | } |
86 | |
87 | auto newSpec = llvm::cast<SpecAttr>(newEntry.getValue()); |
88 | uint32_t newSize = newSpec.getSize(); |
89 | uint32_t newAbi = newSpec.getAbi(); |
90 | if (size != newSize || abi < newAbi || abi % newAbi != 0) |
91 | return false; |
92 | } |
93 | return true; |
94 | } |
95 | |
96 | uint64_t PtrType::getABIAlignment(const DataLayout &dataLayout, |
97 | DataLayoutEntryListRef params) const { |
98 | auto defaultMemorySpace = llvm::cast_if_present<MemorySpaceAttrInterface>( |
99 | dataLayout.getDefaultMemorySpace()); |
100 | if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace)) |
101 | return spec.getAbi() / kBitsInByte; |
102 | |
103 | return dataLayout.getTypeABIAlignment(get(defaultMemorySpace)); |
104 | } |
105 | |
106 | std::optional<uint64_t> |
107 | PtrType::getIndexBitwidth(const DataLayout &dataLayout, |
108 | DataLayoutEntryListRef params) const { |
109 | auto defaultMemorySpace = llvm::cast_if_present<MemorySpaceAttrInterface>( |
110 | dataLayout.getDefaultMemorySpace()); |
111 | if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace)) { |
112 | return spec.getIndex() == SpecAttr::kOptionalSpecValue ? spec.getSize() |
113 | : spec.getIndex(); |
114 | } |
115 | |
116 | return dataLayout.getTypeIndexBitwidth(get(defaultMemorySpace)); |
117 | } |
118 | |
119 | llvm::TypeSize PtrType::getTypeSizeInBits(const DataLayout &dataLayout, |
120 | DataLayoutEntryListRef params) const { |
121 | auto defaultMemorySpace = llvm::cast_if_present<MemorySpaceAttrInterface>( |
122 | dataLayout.getDefaultMemorySpace()); |
123 | if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace)) |
124 | return llvm::TypeSize::getFixed(spec.getSize()); |
125 | |
126 | // For other memory spaces, use the size of the pointer to the default memory |
127 | // space. |
128 | return dataLayout.getTypeSizeInBits(get(defaultMemorySpace)); |
129 | } |
130 | |
131 | uint64_t PtrType::getPreferredAlignment(const DataLayout &dataLayout, |
132 | DataLayoutEntryListRef params) const { |
133 | auto defaultMemorySpace = llvm::cast_if_present<MemorySpaceAttrInterface>( |
134 | dataLayout.getDefaultMemorySpace()); |
135 | if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace)) |
136 | return spec.getPreferred() / kBitsInByte; |
137 | |
138 | return dataLayout.getTypePreferredAlignment(get(defaultMemorySpace)); |
139 | } |
140 | |
141 | LogicalResult PtrType::verifyEntries(DataLayoutEntryListRef entries, |
142 | Location loc) const { |
143 | for (DataLayoutEntryInterface entry : entries) { |
144 | if (!entry.isTypeEntry()) |
145 | continue; |
146 | auto key = llvm::cast<Type>(entry.getKey()); |
147 | if (!llvm::isa<SpecAttr>(entry.getValue())) { |
148 | return emitError(loc) << "expected layout attribute for " << key |
149 | << " to be a #ptr.spec attribute" ; |
150 | } |
151 | } |
152 | return success(); |
153 | } |
154 | |