Jlm
Loading...
Searching...
No Matches
ConversionOperationsTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2017 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
15#include <jlm/rvsdg/view.hpp>
16
17namespace jlm::llvm
18{
19TEST(ConversionOperationsTests, SExtConstantFolding)
20{
21 using namespace jlm::rvsdg;
22
23 // Arrange
24 Graph graph;
25
26 auto & zero =
28 auto & one =
30
31 auto & node1 = SExtOperation::createNode(32, *zero.output(0));
32 auto & node2 = SExtOperation::createNode(32, *one.output(0));
33
34 auto & x1 = GraphExport::Create(*node1.output(0), "x1");
35 auto & x2 = GraphExport::Create(*node2.output(0), "x2");
36
37 view(graph, stdout);
38
39 // Act
40 ReduceNode<SExtOperation>(SExtOperation::foldConstant, node1);
41 ReduceNode<SExtOperation>(SExtOperation::foldConstant, node2);
42
43 graph.PruneNodes();
44
45 view(graph, stdout);
46
47 // Assert
48 {
49 auto [_, op] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*x1.origin());
50 EXPECT_TRUE(op);
51 EXPECT_EQ(op->Representation().to_uint(), 0u);
52 EXPECT_EQ(op->Representation().nbits(), 32u);
53 }
54
55 {
56 auto [_, op] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*x2.origin());
57 EXPECT_TRUE(op);
58 EXPECT_EQ(op->Representation().to_int(), -1);
59 EXPECT_EQ(op->Representation().nbits(), 32u);
60 }
61}
62
63TEST(ConversionOperationsTests, ZExtConstantFolding)
64{
65 using namespace jlm::rvsdg;
66
67 // Arrange
68 Graph graph;
69
70 auto & zero =
72 auto & one =
74
75 auto & node1 = ZExtOperation::createNode(32, *zero.output(0));
76 auto & node2 = ZExtOperation::createNode(32, *one.output(0));
77
78 auto & x1 = GraphExport::Create(*node1.output(0), "x1");
79 auto & x2 = GraphExport::Create(*node2.output(0), "x2");
80
81 view(graph, stdout);
82
83 // Act
84 ReduceNode<ZExtOperation>(ZExtOperation::foldConstant, node1);
85 ReduceNode<ZExtOperation>(ZExtOperation::foldConstant, node2);
86
87 graph.PruneNodes();
88
89 view(graph, stdout);
90
91 // Assert
92 {
93 auto [_, op] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*x1.origin());
94 EXPECT_TRUE(op);
95 EXPECT_EQ(op->Representation().to_uint(), 0u);
96 EXPECT_EQ(op->Representation().nbits(), 32u);
97 }
98
99 {
100 auto [_, op] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*x2.origin());
101 EXPECT_TRUE(op);
102 EXPECT_EQ(op->Representation().to_int(), 1);
103 EXPECT_EQ(op->Representation().nbits(), 32u);
104 }
105}
106
107TEST(ConversionOperationsTests, TruncConstantFolding)
108{
109 using namespace jlm::rvsdg;
110
111 // Arrange
112 auto i1Type = BitType::Create(1);
113
114 Graph graph;
115
116 auto & eight =
118 auto & one =
120
121 auto & node1 = TruncOperation::createNode(*eight.output(0), i1Type);
122 auto & node2 = TruncOperation::createNode(*one.output(0), i1Type);
123
124 auto & x1 = GraphExport::Create(*node1.output(0), "x1");
125 auto & x2 = GraphExport::Create(*node2.output(0), "x2");
126
127 view(graph, stdout);
128
129 // Act
130 ReduceNode<TruncOperation>(TruncOperation::foldConstant, node1);
131 ReduceNode<TruncOperation>(TruncOperation::foldConstant, node2);
132
133 graph.PruneNodes();
134
135 view(graph, stdout);
136
137 // Assert
138 {
139 auto [_, op] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*x1.origin());
140 EXPECT_TRUE(op);
141 EXPECT_EQ(op->Representation().to_uint(), 0u);
142 EXPECT_EQ(op->Representation().nbits(), 1u);
143 }
144
145 {
146 auto [_, op] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*x2.origin());
147 EXPECT_TRUE(op);
148 EXPECT_EQ(op->Representation().to_uint(), 1u);
149 EXPECT_EQ(op->Representation().nbits(), 1u);
150 }
151}
152
153TEST(ConversionOperationsTests, fpExtConstantFolding)
154{
155 using namespace jlm::rvsdg;
156
157 // Arrange
158 auto fpFltType = FloatingPointType::Create(fpsize::flt);
159 auto fpDblType = FloatingPointType::Create(fpsize::dbl);
160
161 Graph graph;
162
163 auto & eight = ConstantFP::createNode(graph.GetRootRegion(), fpsize::flt, ::llvm::APFloat(8.0));
164 auto & one = ConstantFP::createNode(graph.GetRootRegion(), fpsize::half, ::llvm::APFloat(1.0));
165
166 auto & node1 = FPExtOperation::createNode(*eight.output(0), fpDblType);
167 auto & node2 = FPExtOperation::createNode(*one.output(0), fpFltType);
168
169 auto & x1 = GraphExport::Create(*node1.output(0), "x1");
170 auto & x2 = GraphExport::Create(*node2.output(0), "x2");
171
172 view(graph, stdout);
173
174 // Act
175 ReduceNode<FPExtOperation>(FPExtOperation::foldConstant, node1);
176 ReduceNode<FPExtOperation>(FPExtOperation::foldConstant, node2);
177
178 graph.PruneNodes();
179
180 view(graph, stdout);
181
182 // Assert
183 {
184 auto [_, op] = TryGetSimpleNodeAndOptionalOp<ConstantFP>(*x1.origin());
185 EXPECT_TRUE(op);
186 EXPECT_EQ(&op->constant().getSemantics(), &::llvm::APFloat::IEEEdouble());
187 EXPECT_EQ(op->constant().convertToDouble(), 8.0);
188 }
189
190 {
191 auto [_, op] = TryGetSimpleNodeAndOptionalOp<ConstantFP>(*x2.origin());
192 EXPECT_TRUE(op);
193 EXPECT_EQ(&op->constant().getSemantics(), &::llvm::APFloat::IEEEsingle());
194 EXPECT_EQ(op->constant().convertToFloat(), 1.0);
195 }
196}
197
198TEST(ConversionOperationsTests, fpTruncConstantFolding)
199{
200 using namespace jlm::rvsdg;
201
202 // Arrange
203 auto fpFltType = FloatingPointType::Create(fpsize::flt);
204
205 Graph graph;
206
207 auto & eight = ConstantFP::createNode(graph.GetRootRegion(), fpsize::dbl, ::llvm::APFloat(8.0));
208
209 auto & node1 = FPTruncOperation::createNode(*eight.output(0), fpFltType);
210
211 auto & x1 = GraphExport::Create(*node1.output(0), "x1");
212
213 view(graph, stdout);
214
215 // Act
216 ReduceNode<FPTruncOperation>(FPTruncOperation::foldConstant, node1);
217
218 graph.PruneNodes();
219
220 view(graph, stdout);
221
222 // Assert
223 {
224 auto [_, op] = TryGetSimpleNodeAndOptionalOp<ConstantFP>(*x1.origin());
225 EXPECT_TRUE(op);
226 EXPECT_EQ(&op->constant().getSemantics(), &::llvm::APFloat::IEEEsingle());
227 EXPECT_EQ(op->constant().convertToDouble(), 8.0);
228 }
229}
230
231TEST(ConversionOperationsTests, FunctionToPointerInversion)
232{
233 using namespace jlm::rvsdg;
234
235 // Arrange
236 auto valueType = TestType::createValueType();
237 auto pointerType = PointerType::Create();
238 auto functionType = FunctionType::Create({ valueType }, { valueType });
239
240 Graph graph;
241
242 auto & i0 = GraphImport::Create(graph, pointerType, "i0");
243 auto & i1 = GraphImport::Create(graph, functionType, "i1");
244
245 auto & ptrToFnNode = rvsdg::CreateOpNode<PointerToFunctionOperation>({ &i0 }, functionType);
246
247 auto & fnToPtrNode1 =
248 rvsdg::CreateOpNode<FunctionToPointerOperation>({ ptrToFnNode.output(0) }, functionType);
249
250 auto & fnToPtrNode2 = rvsdg::CreateOpNode<FunctionToPointerOperation>({ &i1 }, functionType);
251
252 auto & x1 = GraphExport::Create(*fnToPtrNode1.output(0), "x1");
253 auto & x2 = GraphExport::Create(*fnToPtrNode2.output(0), "x2");
254
255 view(graph, stdout);
256
257 // Act
258 ReduceNode<FunctionToPointerOperation>(
260 fnToPtrNode1);
261
262 ReduceNode<FunctionToPointerOperation>(
264 fnToPtrNode2);
265
266 graph.PruneNodes();
267
268 view(graph, stdout);
269
270 // Assert
271 // The transformation should have been successful.
272 {
273 EXPECT_EQ(x1.origin(), &i0);
274 }
275
276 // The transformation should have failed.
277 {
278 auto [_, op] = TryGetSimpleNodeAndOptionalOp<FunctionToPointerOperation>(*x2.origin());
279 EXPECT_NE(op, nullptr);
280 }
281}
282
283TEST(ConversionOperationsTests, PointerToFunctionInversion)
284{
285 using namespace jlm::rvsdg;
286
287 // Arrange
288 auto stateType = TestType::createStateType();
289 auto valueType = TestType::createValueType();
290 auto pointerType = PointerType::Create();
291 auto functionType1 = FunctionType::Create({ valueType }, { valueType });
292 auto functionType2 = FunctionType::Create({ stateType }, { stateType });
293
294 Graph graph;
295
296 auto & i0 = GraphImport::Create(graph, functionType1, "i0");
297
298 auto & fnToPtrNode = rvsdg::CreateOpNode<FunctionToPointerOperation>({ &i0 }, functionType1);
299
300 auto & ptrToFnNode1 =
301 rvsdg::CreateOpNode<PointerToFunctionOperation>({ fnToPtrNode.output(0) }, functionType1);
302
303 auto & ptrToFnNode2 =
304 rvsdg::CreateOpNode<PointerToFunctionOperation>({ fnToPtrNode.output(0) }, functionType2);
305
306 auto & x1 = GraphExport::Create(*ptrToFnNode1.output(0), "x1");
307 auto & x2 = GraphExport::Create(*ptrToFnNode2.output(0), "x2");
308
309 view(graph, stdout);
310
311 // Act
312 ReduceNode<PointerToFunctionOperation>(
314 ptrToFnNode1);
315
316 ReduceNode<PointerToFunctionOperation>(
318 ptrToFnNode2);
319
320 graph.PruneNodes();
321
322 view(graph, stdout);
323
324 // Assert
325 // The transformation should have been successful.
326 {
327 EXPECT_EQ(x1.origin(), &i0);
328 }
329
330 // The transformation should have failed as the function types of the FunctionToPointer and
331 // PointerToFunction operations are different.
332 {
333 auto [_, op] = TryGetSimpleNodeAndOptionalOp<PointerToFunctionOperation>(*x2.origin());
334 EXPECT_NE(op, nullptr);
335 }
336}
337
338}
static rvsdg::Node & createNode(rvsdg::Region &region, fpsize size, const ::llvm::APFloat &constant)
static std::optional< std::vector< rvsdg::Output * > > foldConstant(const FPExtOperation &operation, const std::vector< rvsdg::Output * > &operands)
static rvsdg::SimpleNode & createNode(rvsdg::Output &operand, const std::shared_ptr< const rvsdg::Type > &resultType)
static std::optional< std::vector< rvsdg::Output * > > foldConstant(const FPTruncOperation &operation, const std::vector< rvsdg::Output * > &operands)
static rvsdg::SimpleNode & createNode(rvsdg::Output &operand, const std::shared_ptr< const rvsdg::Type > &resultType)
static std::shared_ptr< const FloatingPointType > Create(fpsize size)
Definition types.cpp:117
static std::optional< std::vector< rvsdg::Output * > > invertFunctionToPointer(const FunctionToPointerOperation &operation, const std::vector< rvsdg::Output * > &operands)
static rvsdg::Node & Create(rvsdg::Region &region, IntegerValueRepresentation representation)
static std::optional< std::vector< rvsdg::Output * > > invertPointerToFunction(const PointerToFunctionOperation &operation, const std::vector< rvsdg::Output * > &operands)
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
static std::optional< std::vector< rvsdg::Output * > > foldConstant(const SExtOperation &operation, const std::vector< rvsdg::Output * > &operands)
static rvsdg::SimpleNode & createNode(const size_t numResultBits, rvsdg::Output &operand)
static rvsdg::SimpleNode & createNode(rvsdg::Output &operand, std::shared_ptr< const rvsdg::Type > resultType)
static std::optional< std::vector< rvsdg::Output * > > foldConstant(const TruncOperation &operation, const std::vector< rvsdg::Output * > &operands)
static std::optional< std::vector< rvsdg::Output * > > foldConstant(const ZExtOperation &operation, const std::vector< rvsdg::Output * > &operands)
static rvsdg::SimpleNode & createNode(const size_t numResultBits, rvsdg::Output &operand)
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
void PruneNodes()
Definition graph.hpp:116
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