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
17using namespace mlir;
18using namespace mlir::ptr;
19
20//===----------------------------------------------------------------------===//
21// Pointer type
22//===----------------------------------------------------------------------===//
23
24constexpr const static unsigned kDefaultPointerSizeBits = 64;
25constexpr const static unsigned kBitsInByte = 8;
26constexpr const static unsigned kDefaultPointerAlignmentBits = 8;
27
28/// Searches the data layout for the pointer spec, returns nullptr if it is not
29/// found.
30static 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
52bool 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
96uint64_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
106std::optional<uint64_t>
107PtrType::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
119llvm::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
131uint64_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
141LogicalResult 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

source code of mlir/lib/Dialect/Ptr/IR/PtrTypes.cpp