Jlm
Loading...
Searching...
No Matches
GetElementPtr.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
9
10namespace jlm::llvm
11{
12
14
15bool
16GetElementPtrOperation::operator==(const Operation & other) const noexcept
17{
18 auto operation = dynamic_cast<const GetElementPtrOperation *>(&other);
19
20 if (operation == nullptr || *getPointeeType() != *operation->getPointeeType()
21 || narguments() != operation->narguments())
22 {
23 return false;
24 }
25
26 for (size_t n = 0; n < narguments(); n++)
27 {
28 if (*operation->argument(n) != *argument(n))
29 {
30 return false;
31 }
32 }
33
34 return true;
35}
36
37std::string
39{
40 return "GetElementPtr";
41}
42
43std::unique_ptr<rvsdg::Operation>
45{
46 return std::make_unique<GetElementPtrOperation>(*this);
47}
48
49std::optional<GetElementPtrOperation::Constant>
51{
52 const auto gepOperation = dynamic_cast<const GetElementPtrOperation *>(&gepNode.GetOperation());
53 if (!gepOperation)
54 return std::nullopt;
55
56 std::vector<uint64_t> indices;
57 for (auto & input : gepOperation->indices(gepNode))
58 {
59 if (auto indexOpt = tryGetConstantSignedInteger(*input.origin()))
60 {
61 indices.push_back(indexOpt.value());
62 }
63 else
64 {
65 return std::nullopt;
66 }
67 }
68
69 return Constant{ gepOperation->getPointeeType(), indices };
70}
71
72int64_t
74{
75 JLM_ASSERT(indices.size() >= 1);
76
77 std::function<uint64_t(size_t, const rvsdg::Type &)> computeIntraTypeOffset =
78 [&](const size_t index, const rvsdg::Type & type)
79 {
80 if (index >= indices.size())
81 return static_cast<int64_t>(0);
82
83 const auto indexValue = indices[index];
84 if (const auto arrayType = dynamic_cast<const ArrayType *>(&type))
85 {
86 const auto & elementType = *arrayType->GetElementType();
87 int64_t offsetInBytes = indexValue * GetTypeAllocSize(elementType);
88 offsetInBytes += computeIntraTypeOffset(index + 1, elementType);
89 return offsetInBytes;
90 }
91
92 if (const auto structType = dynamic_cast<const StructType *>(&type))
93 {
94 const auto & fieldType = *structType->getElementType(indexValue);
95 int64_t offsetInBytes = structType->GetFieldOffset(indexValue);
96 offsetInBytes += computeIntraTypeOffset(index + 1, fieldType);
97 return offsetInBytes;
98 }
99
100 throw std::logic_error("Unknown GetElementPtr type");
101 };
102
103 const auto wholeTypeIndex = indices[0];
104 int64_t offsetInBytes = wholeTypeIndex * GetTypeAllocSize(*pointeeType);
105 offsetInBytes += computeIntraTypeOffset(1, *pointeeType);
106 return offsetInBytes;
107}
108
109std::shared_ptr<const rvsdg::Type>
111 const std::shared_ptr<const rvsdg::Type> & gepType,
112 const std::vector<rvsdg::Output *> & indices)
113{
114 if (indices.empty())
115 return gepType;
116
117 auto currentType = gepType;
118
119 // We skip the first index as it always just steps through the container
120 for (size_t n = 1; n < indices.size(); ++n)
121 {
122 if (auto structType = std::dynamic_pointer_cast<const StructType>(currentType))
123 {
124 auto index = indices[n];
125 auto & tracedIndex = llvm::traceOutput(*index);
126 auto [constantNode, constantOperation] =
128 if (!constantOperation)
129 {
130 return nullptr;
131 }
132
133 if (constantOperation->Representation().nbits() != 32)
134 return nullptr;
135
136 auto idx = constantOperation->Representation().to_uint();
137 if (idx > structType->numElements())
138 return nullptr;
139
140 currentType = structType->getElementType(idx);
141 }
142 else if (const auto arrayType = std::dynamic_pointer_cast<const ArrayType>(currentType))
143 {
144 currentType = arrayType->GetElementType();
145 }
146 else if (const auto vectorType = std::dynamic_pointer_cast<const VectorType>(currentType))
147 {
148 currentType = vectorType->Type();
149 }
150 else
151 {
152 return nullptr;
153 }
154 }
155
156 return currentType;
157}
158
159std::optional<std::vector<rvsdg::Output *>>
162 const std::vector<rvsdg::Output *> & operands)
163{
164 JLM_ASSERT(operands.size() >= 1);
165 auto baseAddress = operands[0];
166
167 for (size_t n = 1; n < operands.size(); ++n)
168 {
169 auto intOpt = tryGetConstantSignedInteger(*operands[n]);
170 if (!intOpt.has_value() || intOpt.value() != 0)
171 return std::nullopt;
172 }
173
174 // At this point we know that either there are no index operands or that all indices are zero. We
175 // can just return the base address.
176 return std::vector({ baseAddress });
177}
178
179}
std::string debug_string() const override
static std::shared_ptr< const rvsdg::Type > getIndexedType(const std::shared_ptr< const rvsdg::Type > &gepType, const std::vector< rvsdg::Output * > &indices)
static rvsdg::Node::InputConstIteratorRange indices(const rvsdg::Node &node) noexcept
static std::optional< Constant > tryGetAsConstant(const rvsdg::SimpleNode &gepNode)
~GetElementPtrOperation() noexcept override
static std::optional< std::vector< rvsdg::Output * > > normalizeIdempotent(const GetElementPtrOperation &operation, const std::vector< rvsdg::Output * > &operands)
std::unique_ptr< Operation > copy() const override
StructType class.
Definition types.hpp:184
const SimpleOperation & GetOperation() const noexcept override
#define JLM_ASSERT(x)
Definition common.hpp:16
Global memory state passed between functions.
size_t GetTypeAllocSize(const rvsdg::Type &type)
Definition types.cpp:473
rvsdg::Output & traceOutput(rvsdg::Output &output, const rvsdg::Region *withinRegion)
Definition Trace.cpp:62
std::optional< int64_t > tryGetConstantSignedInteger(const rvsdg::Output &output)
Definition Trace.cpp:70
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
std::shared_ptr< const rvsdg::Type > pointeeType