1//===- llvm/unittest/AsmParser/AsmParserTest.cpp - asm parser unittests ---===//
2//
3// Part of the LLVM Project, 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#include "llvm/ADT/StringRef.h"
10#include "llvm/AsmParser/Parser.h"
11#include "llvm/AsmParser/SlotMapping.h"
12#include "llvm/IR/Constants.h"
13#include "llvm/IR/DataLayout.h"
14#include "llvm/IR/LLVMContext.h"
15#include "llvm/IR/Module.h"
16#include "llvm/Support/Error.h"
17#include "llvm/Support/SourceMgr.h"
18#include "gtest/gtest.h"
19
20using namespace llvm;
21
22namespace {
23
24TEST(AsmParserTest, NullTerminatedInput) {
25 LLVMContext Ctx;
26 StringRef Source = "; Empty module \n";
27 SMDiagnostic Error;
28 auto Mod = parseAssemblyString(AsmString: Source, Err&: Error, Context&: Ctx);
29
30 EXPECT_TRUE(Mod != nullptr);
31 EXPECT_TRUE(Error.getMessage().empty());
32}
33
34#ifdef GTEST_HAS_DEATH_TEST
35#ifndef NDEBUG
36
37TEST(AsmParserTest, NonNullTerminatedInput) {
38 LLVMContext Ctx;
39 StringRef Source = "; Empty module \n\1\2";
40 SMDiagnostic Error;
41 std::unique_ptr<Module> Mod;
42 EXPECT_DEATH(Mod = parseAssemblyString(Source.substr(0, Source.size() - 2),
43 Error, Ctx),
44 "Buffer is not null terminated!");
45}
46
47#endif
48#endif
49
50TEST(AsmParserTest, SlotMappingTest) {
51 LLVMContext Ctx;
52 StringRef Source = "@0 = global i32 0\n !0 = !{}\n !42 = !{i32 42}";
53 SMDiagnostic Error;
54 SlotMapping Mapping;
55 auto Mod = parseAssemblyString(AsmString: Source, Err&: Error, Context&: Ctx, Slots: &Mapping);
56
57 EXPECT_TRUE(Mod != nullptr);
58 EXPECT_TRUE(Error.getMessage().empty());
59
60 ASSERT_EQ(Mapping.GlobalValues.getNext(), 1u);
61 EXPECT_TRUE(isa<GlobalVariable>(Mapping.GlobalValues.get(0)));
62
63 EXPECT_EQ(Mapping.MetadataNodes.size(), 2u);
64 EXPECT_EQ(Mapping.MetadataNodes.count(0), 1u);
65 EXPECT_EQ(Mapping.MetadataNodes.count(42), 1u);
66 EXPECT_EQ(Mapping.MetadataNodes.count(1), 0u);
67}
68
69TEST(AsmParserTest, TypeAndConstantValueParsing) {
70 LLVMContext Ctx;
71 SMDiagnostic Error;
72 StringRef Source = "define void @test() {\n entry:\n ret void\n}";
73 auto Mod = parseAssemblyString(AsmString: Source, Err&: Error, Context&: Ctx);
74 ASSERT_TRUE(Mod != nullptr);
75 auto &M = *Mod;
76
77 const Value *V;
78 V = parseConstantValue(Asm: "double 3.5", Err&: Error, M);
79 ASSERT_TRUE(V);
80 EXPECT_TRUE(V->getType()->isDoubleTy());
81 ASSERT_TRUE(isa<ConstantFP>(V));
82 EXPECT_TRUE(cast<ConstantFP>(V)->isExactlyValue(3.5));
83
84 V = parseConstantValue(Asm: "i32 42", Err&: Error, M);
85 ASSERT_TRUE(V);
86 EXPECT_TRUE(V->getType()->isIntegerTy());
87 ASSERT_TRUE(isa<ConstantInt>(V));
88 EXPECT_TRUE(cast<ConstantInt>(V)->equalsInt(42));
89
90 V = parseConstantValue(Asm: "<4 x i32> <i32 0, i32 1, i32 2, i32 3>", Err&: Error, M);
91 ASSERT_TRUE(V);
92 EXPECT_TRUE(V->getType()->isVectorTy());
93 ASSERT_TRUE(isa<ConstantDataVector>(V));
94
95 V = parseConstantValue(Asm: "i32 add (i32 1, i32 2)", Err&: Error, M);
96 ASSERT_TRUE(V);
97 ASSERT_TRUE(isa<ConstantInt>(V));
98
99 V = parseConstantValue(Asm: "ptr blockaddress(@test, %entry)", Err&: Error, M);
100 ASSERT_TRUE(V);
101 ASSERT_TRUE(isa<BlockAddress>(V));
102
103 V = parseConstantValue(Asm: "ptr undef", Err&: Error, M);
104 ASSERT_TRUE(V);
105 ASSERT_TRUE(isa<UndefValue>(V));
106
107 EXPECT_FALSE(parseConstantValue("duble 3.25", Error, M));
108 EXPECT_EQ(Error.getMessage(), "expected type");
109
110 EXPECT_FALSE(parseConstantValue("i32 3.25", Error, M));
111 EXPECT_EQ(Error.getMessage(), "floating point constant invalid for type");
112
113 EXPECT_FALSE(parseConstantValue("ptr @foo", Error, M));
114 EXPECT_EQ(Error.getMessage(), "expected a constant value");
115
116 EXPECT_FALSE(parseConstantValue("i32 3, ", Error, M));
117 EXPECT_EQ(Error.getMessage(), "expected end of string");
118}
119
120TEST(AsmParserTest, TypeAndConstantValueWithSlotMappingParsing) {
121 LLVMContext Ctx;
122 SMDiagnostic Error;
123 StringRef Source =
124 "%st = type { i32, i32 }\n"
125 "@v = common global [50 x %st] zeroinitializer, align 16\n"
126 "%0 = type { i32, i32, i32, i32 }\n"
127 "@g = common global [50 x %0] zeroinitializer, align 16\n"
128 "define void @marker4(i64 %d) {\n"
129 "entry:\n"
130 " %conv = trunc i64 %d to i32\n"
131 " store i32 %conv, ptr getelementptr inbounds "
132 " ([50 x %st], ptr @v, i64 0, i64 1, i32 0), align 16\n"
133 " store i32 %conv, ptr getelementptr inbounds "
134 " ([50 x %0], ptr @g, i64 0, i64 1, i32 0), align 16\n"
135 " ret void\n"
136 "}";
137 SlotMapping Mapping;
138 auto Mod = parseAssemblyString(AsmString: Source, Err&: Error, Context&: Ctx, Slots: &Mapping);
139 ASSERT_TRUE(Mod != nullptr);
140 auto &M = *Mod;
141
142 const Value *V;
143 V = parseConstantValue(Asm: "ptr getelementptr inbounds ([50 x %st], ptr "
144 "@v, i64 0, i64 1, i32 0)",
145 Err&: Error, M, Slots: &Mapping);
146 ASSERT_TRUE(V);
147 ASSERT_TRUE(isa<ConstantExpr>(V));
148
149 V = parseConstantValue(Asm: "ptr getelementptr inbounds ([50 x %0], ptr "
150 "@g, i64 0, i64 1, i32 0)",
151 Err&: Error, M, Slots: &Mapping);
152 ASSERT_TRUE(V);
153 ASSERT_TRUE(isa<ConstantExpr>(V));
154}
155
156TEST(AsmParserTest, TypeWithSlotMappingParsing) {
157 LLVMContext Ctx;
158 SMDiagnostic Error;
159 StringRef Source =
160 "%st = type { i32, i32 }\n"
161 "@v = common global [50 x %st] zeroinitializer, align 16\n"
162 "%0 = type { i32, i32, i32, i32 }\n"
163 "@g = common global [50 x %0] zeroinitializer, align 16\n"
164 "define void @marker4(i64 %d) {\n"
165 "entry:\n"
166 " %conv = trunc i64 %d to i32\n"
167 " store i32 %conv, ptr getelementptr inbounds "
168 " ([50 x %st], ptr @v, i64 0, i64 0, i32 0), align 16\n"
169 " store i32 %conv, ptr getelementptr inbounds "
170 " ([50 x %0], ptr @g, i64 0, i64 0, i32 0), align 16\n"
171 " ret void\n"
172 "}";
173 SlotMapping Mapping;
174 auto Mod = parseAssemblyString(AsmString: Source, Err&: Error, Context&: Ctx, Slots: &Mapping);
175 ASSERT_TRUE(Mod != nullptr);
176 auto &M = *Mod;
177
178 // Check we properly parse integer types.
179 Type *Ty;
180 Ty = parseType(Asm: "i32", Err&: Error, M, Slots: &Mapping);
181 ASSERT_TRUE(Ty);
182 ASSERT_TRUE(Ty->isIntegerTy());
183 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
184
185 // Check we properly parse integer types with exotic size.
186 Ty = parseType(Asm: "i13", Err&: Error, M, Slots: &Mapping);
187 ASSERT_TRUE(Ty);
188 ASSERT_TRUE(Ty->isIntegerTy());
189 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 13);
190
191 // Check we properly parse floating point types.
192 Ty = parseType(Asm: "float", Err&: Error, M, Slots: &Mapping);
193 ASSERT_TRUE(Ty);
194 ASSERT_TRUE(Ty->isFloatTy());
195
196 Ty = parseType(Asm: "double", Err&: Error, M, Slots: &Mapping);
197 ASSERT_TRUE(Ty);
198 ASSERT_TRUE(Ty->isDoubleTy());
199
200 // Check we properly parse struct types.
201 // Named struct.
202 Ty = parseType(Asm: "%st", Err&: Error, M, Slots: &Mapping);
203 ASSERT_TRUE(Ty);
204 ASSERT_TRUE(Ty->isStructTy());
205
206 // Check the details of the struct.
207 StructType *ST = cast<StructType>(Val: Ty);
208 ASSERT_TRUE(ST->getNumElements() == 2);
209 for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) {
210 Ty = ST->getElementType(N: i);
211 ASSERT_TRUE(Ty->isIntegerTy());
212 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
213 }
214
215 // Anonymous struct.
216 Ty = parseType(Asm: "%0", Err&: Error, M, Slots: &Mapping);
217 ASSERT_TRUE(Ty);
218 ASSERT_TRUE(Ty->isStructTy());
219
220 // Check the details of the struct.
221 ST = cast<StructType>(Val: Ty);
222 ASSERT_TRUE(ST->getNumElements() == 4);
223 for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) {
224 Ty = ST->getElementType(N: i);
225 ASSERT_TRUE(Ty->isIntegerTy());
226 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
227 }
228
229 // Check we properly parse vector types.
230 Ty = parseType(Asm: "<5 x i32>", Err&: Error, M, Slots: &Mapping);
231 ASSERT_TRUE(Ty);
232 ASSERT_TRUE(Ty->isVectorTy());
233
234 // Check the details of the vector.
235 auto *VT = cast<FixedVectorType>(Val: Ty);
236 ASSERT_TRUE(VT->getNumElements() == 5);
237 ASSERT_TRUE(VT->getPrimitiveSizeInBits().getFixedValue() == 160);
238 Ty = VT->getElementType();
239 ASSERT_TRUE(Ty->isIntegerTy());
240 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
241
242 // Opaque struct.
243 Ty = parseType(Asm: "%opaque", Err&: Error, M, Slots: &Mapping);
244 ASSERT_TRUE(Ty);
245 ASSERT_TRUE(Ty->isStructTy());
246
247 ST = cast<StructType>(Val: Ty);
248 ASSERT_TRUE(ST->isOpaque());
249
250 // Check we properly parse pointer types.
251 Ty = parseType(Asm: "ptr", Err&: Error, M, Slots: &Mapping);
252 ASSERT_TRUE(Ty);
253 ASSERT_TRUE(Ty->isPointerTy());
254
255 // Check that we reject types with garbage.
256 Ty = parseType(Asm: "i32 garbage", Err&: Error, M, Slots: &Mapping);
257 ASSERT_TRUE(!Ty);
258}
259
260TEST(AsmParserTest, TypeAtBeginningWithSlotMappingParsing) {
261 LLVMContext Ctx;
262 SMDiagnostic Error;
263 StringRef Source =
264 "%st = type { i32, i32 }\n"
265 "@v = common global [50 x %st] zeroinitializer, align 16\n"
266 "%0 = type { i32, i32, i32, i32 }\n"
267 "@g = common global [50 x %0] zeroinitializer, align 16\n"
268 "define void @marker4(i64 %d) {\n"
269 "entry:\n"
270 " %conv = trunc i64 %d to i32\n"
271 " store i32 %conv, ptr getelementptr inbounds "
272 " ([50 x %st], ptr @v, i64 0, i64 0, i32 0), align 16\n"
273 " store i32 %conv, ptr getelementptr inbounds "
274 " ([50 x %0], ptr @g, i64 0, i64 0, i32 0), align 16\n"
275 " ret void\n"
276 "}";
277 SlotMapping Mapping;
278 auto Mod = parseAssemblyString(AsmString: Source, Err&: Error, Context&: Ctx, Slots: &Mapping);
279 ASSERT_TRUE(Mod != nullptr);
280 auto &M = *Mod;
281 unsigned Read;
282
283 // Check we properly parse integer types.
284 Type *Ty;
285 Ty = parseTypeAtBeginning(Asm: "i32", Read, Err&: Error, M, Slots: &Mapping);
286 ASSERT_TRUE(Ty);
287 ASSERT_TRUE(Ty->isIntegerTy());
288 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
289 ASSERT_TRUE(Read == 3);
290
291 // Check we properly parse integer types with exotic size.
292 Ty = parseTypeAtBeginning(Asm: "i13", Read, Err&: Error, M, Slots: &Mapping);
293 ASSERT_TRUE(Ty);
294 ASSERT_TRUE(Ty->isIntegerTy());
295 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 13);
296 ASSERT_TRUE(Read == 3);
297
298 // Check we properly parse floating point types.
299 Ty = parseTypeAtBeginning(Asm: "float", Read, Err&: Error, M, Slots: &Mapping);
300 ASSERT_TRUE(Ty);
301 ASSERT_TRUE(Ty->isFloatTy());
302 ASSERT_TRUE(Read == 5);
303
304 Ty = parseTypeAtBeginning(Asm: "double", Read, Err&: Error, M, Slots: &Mapping);
305 ASSERT_TRUE(Ty);
306 ASSERT_TRUE(Ty->isDoubleTy());
307 ASSERT_TRUE(Read == 6);
308
309 // Check we properly parse struct types.
310 // Named struct.
311 Ty = parseTypeAtBeginning(Asm: "%st", Read, Err&: Error, M, Slots: &Mapping);
312 ASSERT_TRUE(Ty);
313 ASSERT_TRUE(Ty->isStructTy());
314 ASSERT_TRUE(Read == 3);
315
316 // Check the details of the struct.
317 StructType *ST = cast<StructType>(Val: Ty);
318 ASSERT_TRUE(ST->getNumElements() == 2);
319 for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) {
320 Ty = ST->getElementType(N: i);
321 ASSERT_TRUE(Ty->isIntegerTy());
322 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
323 }
324
325 // Anonymous struct.
326 Ty = parseTypeAtBeginning(Asm: "%0", Read, Err&: Error, M, Slots: &Mapping);
327 ASSERT_TRUE(Ty);
328 ASSERT_TRUE(Ty->isStructTy());
329 ASSERT_TRUE(Read == 2);
330
331 // Check the details of the struct.
332 ST = cast<StructType>(Val: Ty);
333 ASSERT_TRUE(ST->getNumElements() == 4);
334 for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) {
335 Ty = ST->getElementType(N: i);
336 ASSERT_TRUE(Ty->isIntegerTy());
337 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
338 }
339
340 // Check we properly parse vector types.
341 Ty = parseTypeAtBeginning(Asm: "<5 x i32>", Read, Err&: Error, M, Slots: &Mapping);
342 ASSERT_TRUE(Ty);
343 ASSERT_TRUE(Ty->isVectorTy());
344 ASSERT_TRUE(Read == 9);
345
346 // Check the details of the vector.
347 auto *VT = cast<FixedVectorType>(Val: Ty);
348 ASSERT_TRUE(VT->getNumElements() == 5);
349 ASSERT_TRUE(VT->getPrimitiveSizeInBits().getFixedValue() == 160);
350 Ty = VT->getElementType();
351 ASSERT_TRUE(Ty->isIntegerTy());
352 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
353
354 // Opaque struct.
355 Ty = parseTypeAtBeginning(Asm: "%opaque", Read, Err&: Error, M, Slots: &Mapping);
356 ASSERT_TRUE(Ty);
357 ASSERT_TRUE(Ty->isStructTy());
358 ASSERT_TRUE(Read == 7);
359
360 ST = cast<StructType>(Val: Ty);
361 ASSERT_TRUE(ST->isOpaque());
362
363 // Check we properly parse pointer types.
364 // One indirection.
365 Ty = parseTypeAtBeginning(Asm: "ptr", Read, Err&: Error, M, Slots: &Mapping);
366 ASSERT_TRUE(Ty);
367 ASSERT_TRUE(Ty->isPointerTy());
368 ASSERT_TRUE(Read == 3);
369
370 // Check that we reject types with garbage.
371 Ty = parseTypeAtBeginning(Asm: "i32 garbage", Read, Err&: Error, M, Slots: &Mapping);
372 ASSERT_TRUE(Ty);
373 ASSERT_TRUE(Ty->isIntegerTy());
374 ASSERT_TRUE(Ty->getPrimitiveSizeInBits() == 32);
375 // We go to the next token, i.e., we read "i32" + ' '.
376 ASSERT_TRUE(Read == 4);
377}
378
379TEST(AsmParserTest, InvalidDataLayoutStringCallback) {
380 LLVMContext Ctx;
381 SMDiagnostic Error;
382 // Note the invalid i8:7 part
383 // Overalign i32 as marker so we can check that indeed this DL was used,
384 // and not some default.
385 StringRef InvalidDLStr =
386 "e-m:e-p:64:64-i8:7-i16:16-i32:64-i64:64-f80:128-n8:16:32:64";
387 StringRef FixedDLStr =
388 "e-m:e-p:64:64-i8:8-i16:16-i32:64-i64:64-f80:128-n8:16:32:64";
389 Expected<DataLayout> ExpectedFixedDL = DataLayout::parse(LayoutDescription: FixedDLStr);
390 ASSERT_TRUE(!ExpectedFixedDL.takeError());
391 DataLayout FixedDL = ExpectedFixedDL.get();
392 std::string Source = ("target datalayout = \"" + InvalidDLStr + "\"\n").str();
393 MemoryBufferRef SourceBuffer(Source, "<string>");
394
395 // Check that we reject the source without a DL override.
396 SlotMapping Mapping1;
397 auto Mod1 = parseAssembly(F: SourceBuffer, Err&: Error, Context&: Ctx, Slots: &Mapping1);
398 EXPECT_TRUE(Mod1 == nullptr);
399
400 // Check that we pass the correct DL str to the callback,
401 // that fixing the DL str from the callback works,
402 // and that the resulting module has the correct DL.
403 SlotMapping Mapping2;
404 auto Mod2 = parseAssembly(
405 F: SourceBuffer, Err&: Error, Context&: Ctx, Slots: &Mapping2,
406 DataLayoutCallback: [&](StringRef Triple, StringRef DLStr) -> std::optional<std::string> {
407 EXPECT_EQ(DLStr, InvalidDLStr);
408 return std::string{FixedDLStr};
409 });
410 ASSERT_TRUE(Mod2 != nullptr);
411 EXPECT_EQ(Mod2->getDataLayout(), FixedDL);
412}
413
414} // end anonymous namespace
415

source code of llvm/unittests/AsmParser/AsmParserTest.cpp