Jlm
Loading...
Searching...
No Matches
GetElementPtrTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2023 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
10#include <jlm/rvsdg/graph.hpp>
12
13namespace jlm::llvm
14{
15
16TEST(GetElemenPtrOperationTests, typeChecks)
17{
18 using namespace jlm::rvsdg;
19
20 // Assert
21 auto i32Type = BitType::Create(32);
22 auto i32FixedVectorType = FixedVectorType::Create(i32Type, 4);
23 auto i32ScalableVectorType = ScalableVectorType::Create(i32Type, 4);
24
25 auto pointerType = PointerType::Create();
26 auto ptrFixedVectorType = FixedVectorType::Create(pointerType, 4);
27 auto ptrScalableVectorType = ScalableVectorType::Create(pointerType, 4);
28
29 Graph graph;
30
31 auto & i32Import = GraphImport::Create(graph, i32Type, "");
32 auto & i32FixedVectorImport = GraphImport::Create(graph, i32FixedVectorType, "");
33 auto & i32ScalableVectorImport = GraphImport::Create(graph, i32ScalableVectorType, "");
34
35 auto & pointerImport = GraphImport::Create(graph, pointerType, "");
36 auto & ptrFixedVectorImport = GraphImport::Create(graph, ptrFixedVectorType, "");
37 auto & ptrScalableVectorImport = GraphImport::Create(graph, ptrScalableVectorType, "");
38
39 // Act & Assert
40 {
41 auto & gepNode = GetElementPtrOperation::createNode(pointerImport, {}, i32Type);
42 EXPECT_TRUE(is<PointerType>(gepNode.output(0)->Type()));
43 }
44
45 {
46 auto & gepNode = GetElementPtrOperation::createNode(ptrFixedVectorImport, {}, i32Type);
47 auto resultType = gepNode.output(0)->Type();
48 EXPECT_TRUE(is<FixedVectorType>(resultType));
49 EXPECT_TRUE(isVectorOf<PointerType>(*resultType));
50 }
51
52 {
53 auto & gepNode = GetElementPtrOperation::createNode(ptrScalableVectorImport, {}, i32Type);
54 auto resultType = gepNode.output(0)->Type();
55 EXPECT_TRUE(is<ScalableVectorType>(resultType));
56 EXPECT_TRUE(isVectorOf<PointerType>(*resultType));
57 }
58
59 {
60 // The base address must be a pointer or vector of pointers
61 EXPECT_THROW(GetElementPtrOperation::createNode(i32Import, {}, i32Type), std::logic_error);
62 }
63
64 {
65 auto & gepNode = GetElementPtrOperation::createNode(pointerImport, { &i32Import }, i32Type);
66 EXPECT_TRUE(is<PointerType>(gepNode.output(0)->Type()));
67 }
68
69 {
70 // One of the indices is a vector, so the result type must be a vector type
71 auto & gepNode =
72 GetElementPtrOperation::createNode(pointerImport, { &i32FixedVectorImport }, i32Type);
73 auto resultType = gepNode.output(0)->Type();
74 EXPECT_TRUE(is<FixedVectorType>(resultType));
75 EXPECT_TRUE(isVectorOf<PointerType>(*resultType));
76 }
77
78 {
79 // One of the indices is a vector, so the result type must be a vector type
80 auto & gepNode =
81 GetElementPtrOperation::createNode(pointerImport, { &i32ScalableVectorImport }, i32Type);
82 auto resultType = gepNode.output(0)->Type();
83 EXPECT_TRUE(is<ScalableVectorType>(resultType));
84 EXPECT_TRUE(isVectorOf<PointerType>(*resultType));
85 }
86}
87
88TEST(GetElementPtrOperationTests, TestOperationEquality)
89{
90 using namespace jlm::llvm;
91 using namespace jlm::rvsdg;
92
93 // Arrange
94 auto pointerType = PointerType::Create();
95 auto arrayType = ArrayType::Create(BitType::Create(8), 11);
96
97 auto structType1 = StructType::CreateLiteral({ BitType::Create(64), BitType::Create(64) }, false);
98 auto structType2 =
99 StructType::CreateIdentified("myStructType", { arrayType, BitType::Create(32) }, false);
100
102 pointerType,
103 { BitType::Create(32), BitType::Create(32) },
104 structType1);
105
107 pointerType,
108 { BitType::Create(32), BitType::Create(32) },
109 structType2);
110
111 // Assert
112 EXPECT_NE(operation1, operation2);
113
114 // Arrange 2: create a new type that is structurally identical to structType1
115 auto copyOfStructType1 =
116 StructType::CreateLiteral({ BitType::Create(64), BitType::Create(64) }, false);
118 pointerType,
119 { BitType::Create(32), BitType::Create(32) },
120 copyOfStructType1);
121
122 // Assert 2
123
124 // The struct types have distinct pointers
125 EXPECT_NE(structType1, copyOfStructType1);
126 // Yet the GEPs compare equal
127 EXPECT_EQ(*operation1, *operation3);
128}
129
130TEST(GetElementPtrTests, TryGetAsConstantTest)
131{
132 using namespace jlm::llvm;
133 using namespace jlm::rvsdg;
134
135 // Arrange
136 const auto bits8Type = BitType::Create(32);
137 const auto bits16Type = BitType::Create(32);
138 const auto bits32Type = BitType::Create(32);
139 const auto pointerType = PointerType::Create();
140
141 auto structType =
142 StructType::CreateIdentified("struct", { bits8Type, bits16Type, bits32Type }, false);
143 auto arrayType = ArrayType::Create(BitType::Create(32), 11);
144
145 Graph rvsdg;
146 auto & baseAddress = GraphImport::Create(rvsdg, pointerType, "base");
147 auto & i32 = GraphImport::Create(rvsdg, bits8Type, "i32");
148
149 auto & zeroNode = IntegerConstantOperation::Create(rvsdg.GetRootRegion(), 32, 0);
150 auto & oneNode = IntegerConstantOperation::Create(rvsdg.GetRootRegion(), 32, 1);
151
152 auto & gepNode0 = GetElementPtrOperation::createNode(
153 baseAddress,
154 { zeroNode.output(0), oneNode.output(0) },
155 structType);
156 auto & gepNode1 =
157 GetElementPtrOperation::createNode(baseAddress, { zeroNode.output(0), &i32 }, arrayType);
158 auto & gepNode2 = GetElementPtrOperation::createNode(baseAddress, { &i32, &i32 }, arrayType);
159
160 // Act
161 auto gepConstant0 = GetElementPtrOperation::tryGetAsConstant(gepNode0);
162 auto gepConstant1 = GetElementPtrOperation::tryGetAsConstant(gepNode1);
163 auto gepConstant2 = GetElementPtrOperation::tryGetAsConstant(gepNode2);
164
165 // Assert
166 // We expect gepConstant0 to be present as the \ref GetElementPtrOperation is statically
167 // completely known. All others should result in std::nullopt.
168 EXPECT_TRUE(gepConstant0.has_value());
169 EXPECT_EQ(gepConstant0.value().pointeeType, structType);
170 EXPECT_EQ(gepConstant0.value().indices, std::vector<uint64_t>({ 0, 1 }));
171
172 EXPECT_FALSE(gepConstant1.has_value());
173 EXPECT_FALSE(gepConstant2.has_value());
174}
175
176TEST(GetElementPtrTests, TestGetElementPtrOperationConstant_OffestInBytes)
177{
178 using namespace jlm::llvm;
179 using namespace jlm::rvsdg;
180
181 // Arrange
182 const auto bits8Type = BitType::Create(32);
183 const auto bits16Type = BitType::Create(32);
184 const auto bits32Type = BitType::Create(32);
185
186 auto structType =
187 StructType::CreateIdentified("struct", { bits8Type, bits16Type, bits32Type }, false);
188
189 auto arrayType1 = ArrayType::Create(bits32Type, 4);
190 auto arrayType2 = ArrayType::Create(structType, 4);
191
192 GetElementPtrOperation::Constant constant0{ structType, { 0, 0 } };
193 GetElementPtrOperation::Constant constant1{ structType, { 0, 2 } };
194 GetElementPtrOperation::Constant constant2{ structType, { 1, 2 } };
195 GetElementPtrOperation::Constant constant3{ arrayType1, { 0, 2 } };
196 GetElementPtrOperation::Constant constant4{ arrayType1, { 1, 1 } };
197 GetElementPtrOperation::Constant constant5{ arrayType2, { 0, 2, 2 } };
198
199 // Act & Assert
200 EXPECT_EQ(constant0.getOffsetInBytes(), 0u);
201 EXPECT_EQ(constant1.getOffsetInBytes(), 8u);
202 EXPECT_EQ(constant2.getOffsetInBytes(), 20u);
203 EXPECT_EQ(constant3.getOffsetInBytes(), 8u);
204 EXPECT_EQ(constant4.getOffsetInBytes(), 20u);
205 EXPECT_EQ(constant5.getOffsetInBytes(), 32u);
206}
207
208TEST(GetElementPtrTests, normalizeIdempotentReduction)
209{
210 using namespace jlm::rvsdg;
211
212 // Arrange
213 auto i32Type = BitType::Create(32);
214 auto pointerType = PointerType::Create();
215 auto structType = StructType::CreateLiteral({ i32Type, i32Type }, false);
216
217 Graph graph;
218
219 auto & pointerImport = GraphImport::Create(graph, pointerType, "");
220
221 auto & zero = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
222 auto & one = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 1);
223
224 auto & gepNode1 = GetElementPtrOperation::createNode(pointerImport, {}, i32Type);
225
226 auto & gepNode2 = GetElementPtrOperation::createNode(
227 pointerImport,
228 { zero.output(0), zero.output(0) },
229 structType);
230
231 auto & gepNode3 = GetElementPtrOperation::createNode(
232 pointerImport,
233 { zero.output(0), one.output(0) },
234 structType);
235
236 auto & x1 = GraphExport::Create(*gepNode1.output(0), "x1");
237 auto & x2 = GraphExport::Create(*gepNode2.output(0), "x2");
238 auto & x3 = GraphExport::Create(*gepNode3.output(0), "x3");
239
240 // Act
243 const auto successReductionGepNode3 = rvsdg::ReduceNode<GetElementPtrOperation>(
245 gepNode3);
246
247 // Assert
248 {
249 EXPECT_EQ(x1.origin(), &pointerImport);
250 }
251
252 {
253 EXPECT_EQ(x2.origin(), &pointerImport);
254 }
255
256 {
257 EXPECT_FALSE(successReductionGepNode3);
258 auto [gepNode, gepOperation] =
259 TryGetSimpleNodeAndOptionalOp<GetElementPtrOperation>(*x3.origin());
260 EXPECT_NE(gepOperation, nullptr);
261 }
262}
263
264}
static std::shared_ptr< const ArrayType > Create(std::shared_ptr< const Type > type, size_t nelements)
Definition types.hpp:98
static std::shared_ptr< const FixedVectorType > Create(std::shared_ptr< const rvsdg::Type > type, size_t size)
Definition types.hpp:413
static std::unique_ptr< GetElementPtrOperation > createOperation(const std::shared_ptr< const rvsdg::Type > &baseAddressType, const std::vector< std::shared_ptr< const rvsdg::Type > > &indexTypes, const std::shared_ptr< const rvsdg::Type > &gepType)
static std::optional< Constant > tryGetAsConstant(const rvsdg::SimpleNode &gepNode)
static rvsdg::SimpleNode & createNode(rvsdg::Output &baseAddress, const std::vector< rvsdg::Output * > &indices, const std::shared_ptr< const rvsdg::Type > &gepType)
static std::optional< std::vector< rvsdg::Output * > > normalizeIdempotent(const GetElementPtrOperation &operation, const std::vector< rvsdg::Output * > &operands)
static rvsdg::Node & Create(rvsdg::Region &region, IntegerValueRepresentation representation)
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
static std::shared_ptr< const ScalableVectorType > Create(std::shared_ptr< const rvsdg::Type > type, size_t size)
Definition types.hpp:438
static std::shared_ptr< const StructType > CreateLiteral(std::vector< std::shared_ptr< const Type > > types, bool isPacked)
Definition types.hpp:334
static std::shared_ptr< const StructType > CreateIdentified(const std::string &name, std::vector< std::shared_ptr< const Type > > types, bool isPacked)
Definition types.hpp:307
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
NodeOutput * output(size_t index) const noexcept
Global memory state passed between functions.
TEST(ControlOperationsTests, foldConstants)
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872