1 //===- llvm/unittests/MC/SystemZ/SystemZAsmLexerTest.cpp ----------------===//
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 #include "llvm/MC/MCAsmInfo.h"
9 #include "llvm/MC/MCContext.h"
10 #include "llvm/MC/MCObjectFileInfo.h"
11 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
12 #include "llvm/MC/MCRegisterInfo.h"
13 #include "llvm/MC/MCStreamer.h"
14 #include "llvm/Support/MemoryBuffer.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "llvm/Support/TargetRegistry.h"
17 #include "llvm/Support/TargetSelect.h"
18 
19 #include "gtest/gtest.h"
20 
21 using namespace llvm;
22 
23 namespace {
24 
25 // Come up with our hacked version of MCAsmInfo.
26 // This hacked version derives from the main MCAsmInfo instance.
27 // Here, we're free to override whatever we want, without polluting
28 // the main MCAsmInfo interface.
29 class MockedUpMCAsmInfo : public MCAsmInfo {
30 public:
31   void setRestrictCommentStringToStartOfStatement(bool Value) {
32     RestrictCommentStringToStartOfStatement = Value;
33   }
34   void setCommentString(StringRef Value) { CommentString = Value; }
35   void setAllowAdditionalComments(bool Value) {
36     AllowAdditionalComments = Value;
37   }
38 };
39 
40 // Setup a testing class that the GTest framework can call.
41 class SystemZAsmLexerTest : public ::testing::Test {
42 protected:
43   static void SetUpTestCase() {
44     LLVMInitializeSystemZTargetInfo();
45     LLVMInitializeSystemZTargetMC();
46   }
47 
48   std::unique_ptr<MCRegisterInfo> MRI;
49   std::unique_ptr<MockedUpMCAsmInfo> MUPMAI;
50   std::unique_ptr<const MCInstrInfo> MII;
51   std::unique_ptr<MCStreamer> Str;
52   std::unique_ptr<MCAsmParser> Parser;
53   std::unique_ptr<MCContext> Ctx;
54 
55   SourceMgr SrcMgr;
56   std::string TripleName;
57   llvm::Triple Triple;
58   const Target *TheTarget;
59 
60   const MCTargetOptions MCOptions;
61   MCObjectFileInfo MOFI;
62 
63   SystemZAsmLexerTest() {
64     // We will use the SystemZ triple, because of missing
65     // Object File and Streamer support for the z/OS target.
66     TripleName = "s390x-ibm-linux";
67     Triple = llvm::Triple(TripleName);
68 
69     std::string Error;
70     TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
71     EXPECT_NE(TheTarget, nullptr);
72 
73     MRI.reset(TheTarget->createMCRegInfo(TripleName));
74     EXPECT_NE(MRI, nullptr);
75 
76     std::unique_ptr<MCAsmInfo> MAI;
77     MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
78     EXPECT_NE(MAI, nullptr);
79 
80     // Now we cast to our mocked up version of MCAsmInfo.
81     MUPMAI.reset(static_cast<MockedUpMCAsmInfo *>(MAI.release()));
82     // MUPMAI should "hold" MAI.
83     EXPECT_NE(MUPMAI, nullptr);
84     // After releasing, MAI should now be null.
85     EXPECT_EQ(MAI, nullptr);
86   }
87 
88   void setupCallToAsmParser(StringRef AsmStr) {
89     std::unique_ptr<MemoryBuffer> Buffer(MemoryBuffer::getMemBuffer(AsmStr));
90     SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
91     EXPECT_EQ(Buffer, nullptr);
92 
93     Ctx.reset(
94         new MCContext(MUPMAI.get(), MRI.get(), &MOFI, &SrcMgr, &MCOptions));
95     MOFI.InitMCObjectFileInfo(Triple, false, *Ctx, false);
96 
97     Str.reset(TheTarget->createNullStreamer(*Ctx));
98 
99     Parser.reset(createMCAsmParser(SrcMgr, *Ctx, *Str, *MUPMAI));
100   }
101 
102   void lexAndCheckTokens(StringRef AsmStr,
103                          SmallVector<AsmToken::TokenKind> ExpectedTokens) {
104     // Get reference to AsmLexer.
105     MCAsmLexer &Lexer = Parser->getLexer();
106     // Loop through all expected tokens checking one by one.
107     for (size_t I = 0; I < ExpectedTokens.size(); ++I) {
108       EXPECT_EQ(Lexer.getTok().getKind(), ExpectedTokens[I]);
109       Lexer.Lex();
110     }
111   }
112 
113   void lexAndCheckIntegerTokensAndValues(StringRef AsmStr,
114                                          SmallVector<int64_t> ExpectedValues) {
115     // Get reference to AsmLexer.
116     MCAsmLexer &Lexer = Parser->getLexer();
117     // Loop through all expected tokens and expected values.
118     for (size_t I = 0; I < ExpectedValues.size(); ++I) {
119       // Skip any EndOfStatement tokens, we're not concerned with them.
120       if (Lexer.getTok().getKind() == AsmToken::EndOfStatement)
121         continue;
122       EXPECT_EQ(Lexer.getTok().getKind(), AsmToken::Integer);
123       EXPECT_EQ(Lexer.getTok().getIntVal(), ExpectedValues[I]);
124       Lexer.Lex();
125     }
126   }
127 };
128 
129 TEST_F(SystemZAsmLexerTest, CheckDontRestrictCommentStringToStartOfStatement) {
130   StringRef AsmStr = "jne #-4";
131 
132   // Setup.
133   setupCallToAsmParser(AsmStr);
134 
135   // Lex initially to get the string.
136   Parser->getLexer().Lex();
137 
138   SmallVector<AsmToken::TokenKind> ExpectedTokens(
139       {AsmToken::Identifier, AsmToken::EndOfStatement});
140   lexAndCheckTokens(AsmStr /* "jne #-4" */, ExpectedTokens);
141 }
142 
143 // Testing MCAsmInfo's RestrictCommentStringToStartOfStatement attribute.
144 TEST_F(SystemZAsmLexerTest, CheckRestrictCommentStringToStartOfStatement) {
145   StringRef AsmStr = "jne #-4";
146 
147   // Setup.
148   MUPMAI->setRestrictCommentStringToStartOfStatement(true);
149   setupCallToAsmParser(AsmStr);
150 
151   // Lex initially to get the string.
152   Parser->getLexer().Lex();
153 
154   // When we are restricting the comment string to only the start of the
155   // statement, The sequence of tokens we are expecting are: Identifier - "jne"
156   // Hash - '#'
157   // Minus - '-'
158   // Integer - '4'
159   SmallVector<AsmToken::TokenKind> ExpectedTokens(
160       {AsmToken::Identifier, AsmToken::Hash, AsmToken::Minus,
161        AsmToken::Integer});
162   lexAndCheckTokens(AsmStr /* "jne #-4" */, ExpectedTokens);
163 }
164 
165 // Test HLASM Comment Syntax ('*')
166 TEST_F(SystemZAsmLexerTest, CheckHLASMComment) {
167   StringRef AsmStr = "* lhi 1,10";
168 
169   // Setup.
170   MUPMAI->setCommentString("*");
171   setupCallToAsmParser(AsmStr);
172 
173   // Lex initially to get the string.
174   Parser->getLexer().Lex();
175 
176   SmallVector<AsmToken::TokenKind> ExpectedTokens(
177       {AsmToken::EndOfStatement, AsmToken::Eof});
178   lexAndCheckTokens(AsmStr /* "* lhi 1,10" */, ExpectedTokens);
179 }
180 
181 TEST_F(SystemZAsmLexerTest, CheckHashDefault) {
182   StringRef AsmStr = "lh#123";
183 
184   // Setup.
185   setupCallToAsmParser(AsmStr);
186 
187   // Lex initially to get the string.
188   Parser->getLexer().Lex();
189 
190   // "lh" -> Identifier
191   // "#123" -> EndOfStatement (Lexed as a comment since CommentString is "#")
192   SmallVector<AsmToken::TokenKind> ExpectedTokens(
193       {AsmToken::Identifier, AsmToken::EndOfStatement, AsmToken::Eof});
194   lexAndCheckTokens(AsmStr, ExpectedTokens);
195 }
196 
197 // Test if "#" is accepted as an Identifier
198 TEST_F(SystemZAsmLexerTest, CheckAllowHashInIdentifier) {
199   StringRef AsmStr = "lh#123";
200 
201   // Setup.
202   setupCallToAsmParser(AsmStr);
203   Parser->getLexer().setAllowHashInIdentifier(true);
204 
205   // Lex initially to get the string.
206   Parser->getLexer().Lex();
207 
208   // "lh123" -> Identifier
209   SmallVector<AsmToken::TokenKind> ExpectedTokens(
210       {AsmToken::Identifier, AsmToken::EndOfStatement, AsmToken::Eof});
211   lexAndCheckTokens(AsmStr, ExpectedTokens);
212 }
213 
214 TEST_F(SystemZAsmLexerTest, CheckAllowHashInIdentifier2) {
215   StringRef AsmStr = "lh#12*3";
216 
217   // Setup.
218   MUPMAI->setCommentString("*");
219   MUPMAI->setRestrictCommentStringToStartOfStatement(true);
220   setupCallToAsmParser(AsmStr);
221   Parser->getLexer().setAllowHashInIdentifier(true);
222 
223   // Lex initially to get the string.
224   Parser->getLexer().Lex();
225 
226   // "lh#12" -> Identifier
227   // "*" -> Star
228   // "3" -> Integer
229   SmallVector<AsmToken::TokenKind> ExpectedTokens(
230       {AsmToken::Identifier, AsmToken::Star, AsmToken::Integer,
231        AsmToken::EndOfStatement, AsmToken::Eof});
232   lexAndCheckTokens(AsmStr, ExpectedTokens);
233 }
234 
235 TEST_F(SystemZAsmLexerTest, DontCheckStrictCommentString) {
236   StringRef AsmStr = "# abc\n/* def *///  xyz";
237 
238   // Setup.
239   setupCallToAsmParser(AsmStr);
240 
241   // Lex initially to get the string.
242   Parser->getLexer().Lex();
243 
244   SmallVector<AsmToken::TokenKind> ExpectedTokens(
245       {AsmToken::EndOfStatement, AsmToken::Comment, AsmToken::EndOfStatement,
246        AsmToken::Eof});
247   lexAndCheckTokens(AsmStr, ExpectedTokens);
248 }
249 
250 TEST_F(SystemZAsmLexerTest, DontCheckStrictCommentString2) {
251   StringRef AsmStr = "# abc\n/* def *///  xyz\n* rst";
252 
253   // Setup.
254   MUPMAI->setCommentString("*");
255   setupCallToAsmParser(AsmStr);
256 
257   // Lex initially to get the string.
258   Parser->getLexer().Lex();
259 
260   SmallVector<AsmToken::TokenKind> ExpectedTokens(
261       {AsmToken::EndOfStatement, AsmToken::Comment, AsmToken::EndOfStatement,
262        AsmToken::EndOfStatement, AsmToken::Eof});
263   lexAndCheckTokens(AsmStr, ExpectedTokens);
264 }
265 
266 TEST_F(SystemZAsmLexerTest, CheckStrictCommentString) {
267   StringRef AsmStr = "# abc\n/* def *///  xyz";
268 
269   // Setup.
270   MUPMAI->setAllowAdditionalComments(false);
271   setupCallToAsmParser(AsmStr);
272 
273   // Lex initially to get the string.
274   Parser->getLexer().Lex();
275 
276   // "# abc" -> still treated as a comment, since CommentString
277   //            is set to "#"
278   SmallVector<AsmToken::TokenKind> ExpectedTokens;
279   ExpectedTokens.push_back(AsmToken::EndOfStatement); // "# abc\n"
280   ExpectedTokens.push_back(AsmToken::Slash);          // "/"
281   ExpectedTokens.push_back(AsmToken::Star);           // "*"
282   ExpectedTokens.push_back(AsmToken::Identifier);     // "def"
283   ExpectedTokens.push_back(AsmToken::Star);           // "*"
284   ExpectedTokens.push_back(AsmToken::Slash);          // "/"
285   ExpectedTokens.push_back(AsmToken::Slash);          // "/"
286   ExpectedTokens.push_back(AsmToken::Slash);          // "/"
287   ExpectedTokens.push_back(AsmToken::Identifier);     // "xyz"
288   ExpectedTokens.push_back(AsmToken::EndOfStatement);
289   ExpectedTokens.push_back(AsmToken::Eof);
290 
291   lexAndCheckTokens(AsmStr, ExpectedTokens);
292 }
293 
294 TEST_F(SystemZAsmLexerTest, CheckStrictCommentString2) {
295   StringRef AsmStr = "// abc";
296 
297   // Setup.
298   MUPMAI->setAllowAdditionalComments(false);
299   MUPMAI->setCommentString("//");
300   setupCallToAsmParser(AsmStr);
301 
302   // Lex initially to get the string.
303   Parser->getLexer().Lex();
304 
305   // "// abc" -> will still be treated as a comment because "//" is the
306   //             CommentString
307   SmallVector<AsmToken::TokenKind> ExpectedTokens(
308       {AsmToken::EndOfStatement, AsmToken::Eof});
309   lexAndCheckTokens(AsmStr /* "// abc" */, ExpectedTokens);
310 }
311 
312 TEST_F(SystemZAsmLexerTest, CheckStrictCommentString3) {
313   StringRef AsmStr = "/* abc */";
314 
315   // Setup.
316   MUPMAI->setAllowAdditionalComments(false);
317   setupCallToAsmParser(AsmStr);
318 
319   // Lex initially to get the string.
320   Parser->getLexer().Lex();
321 
322   SmallVector<AsmToken::TokenKind> ExpectedTokens;
323   ExpectedTokens.push_back(AsmToken::Slash);
324   ExpectedTokens.push_back(AsmToken::Star);
325   ExpectedTokens.push_back(AsmToken::Identifier);
326   ExpectedTokens.push_back(AsmToken::Star);
327   ExpectedTokens.push_back(AsmToken::Slash);
328   ExpectedTokens.push_back(AsmToken::EndOfStatement);
329   ExpectedTokens.push_back(AsmToken::Eof);
330 
331   lexAndCheckTokens(AsmStr, ExpectedTokens);
332 }
333 
334 TEST_F(SystemZAsmLexerTest, CheckStrictCommentString4) {
335   StringRef AsmStr = "# abc\n/* def *///  xyz";
336 
337   // Setup.
338   MUPMAI->setCommentString("*");
339   MUPMAI->setAllowAdditionalComments(false);
340   MUPMAI->setRestrictCommentStringToStartOfStatement(true);
341   setupCallToAsmParser(AsmStr);
342 
343   // Lex initially to get the string.
344   Parser->getLexer().Lex();
345 
346   SmallVector<AsmToken::TokenKind> ExpectedTokens;
347   ExpectedTokens.push_back(AsmToken::Hash);           // "#"
348   ExpectedTokens.push_back(AsmToken::Identifier);     // "abc"
349   ExpectedTokens.push_back(AsmToken::EndOfStatement); // "\n"
350   ExpectedTokens.push_back(AsmToken::Slash);          // "/"
351   ExpectedTokens.push_back(AsmToken::Star);           // "*"
352   ExpectedTokens.push_back(AsmToken::Identifier);     // "def"
353   ExpectedTokens.push_back(AsmToken::Star);           // "*"
354   ExpectedTokens.push_back(AsmToken::Slash);          // "/"
355   ExpectedTokens.push_back(AsmToken::Slash);          // "/"
356   ExpectedTokens.push_back(AsmToken::Slash);          // "/"
357   ExpectedTokens.push_back(AsmToken::Identifier);     // "xyz"
358   ExpectedTokens.push_back(AsmToken::EndOfStatement);
359   ExpectedTokens.push_back(AsmToken::Eof);
360 
361   lexAndCheckTokens(AsmStr, ExpectedTokens);
362 }
363 
364 TEST_F(SystemZAsmLexerTest, CheckStrictCommentString5) {
365   StringRef AsmStr = "#abc\n/* def */// xyz";
366 
367   // Setup.
368   MUPMAI->setCommentString("*");
369   MUPMAI->setAllowAdditionalComments(false);
370   setupCallToAsmParser(AsmStr);
371 
372   // Lex initially to get the string.
373   Parser->getLexer().Lex();
374 
375   SmallVector<AsmToken::TokenKind> ExpectedTokens;
376   ExpectedTokens.push_back(AsmToken::Hash);           // "#"
377   ExpectedTokens.push_back(AsmToken::Identifier);     // "abc"
378   ExpectedTokens.push_back(AsmToken::EndOfStatement); // "\n"
379   ExpectedTokens.push_back(AsmToken::Slash);          // "/"
380   ExpectedTokens.push_back(AsmToken::EndOfStatement); // "* def */// xyz"
381   ExpectedTokens.push_back(AsmToken::Eof);
382 
383   lexAndCheckTokens(AsmStr, ExpectedTokens);
384 }
385 
386 TEST_F(SystemZAsmLexerTest, CheckValidHLASMIntegers) {
387   StringRef AsmStr = "123\n000123\n1999\n007\n12300\n12021\n";
388   // StringRef AsmStr = "123";
389   // Setup.
390   setupCallToAsmParser(AsmStr);
391   Parser->getLexer().setLexHLASMIntegers(true);
392 
393   // Lex initially to get the string.
394   Parser->getLexer().Lex();
395 
396   // SmallVector<int64_t> ExpectedValues({123});
397   SmallVector<int64_t> ExpectedValues({123, 123, 1999, 7, 12300, 12021});
398   lexAndCheckIntegerTokensAndValues(AsmStr, ExpectedValues);
399 }
400 
401 TEST_F(SystemZAsmLexerTest, CheckInvalidHLASMIntegers) {
402   StringRef AsmStr = "0b0101\n0xDEADBEEF\nfffh\n.133\n";
403 
404   // Setup.
405   setupCallToAsmParser(AsmStr);
406   Parser->getLexer().setLexHLASMIntegers(true);
407 
408   // Lex initially to get the string.
409   Parser->getLexer().Lex();
410 
411   SmallVector<AsmToken::TokenKind> ExpectedTokens;
412   ExpectedTokens.push_back(AsmToken::Integer);        // "0"
413   ExpectedTokens.push_back(AsmToken::Identifier);     // "b0101"
414   ExpectedTokens.push_back(AsmToken::EndOfStatement); // "\n"
415   ExpectedTokens.push_back(AsmToken::Integer);        // "0"
416   ExpectedTokens.push_back(AsmToken::Identifier);     // "xDEADBEEF"
417   ExpectedTokens.push_back(AsmToken::EndOfStatement); // "\n"
418   ExpectedTokens.push_back(AsmToken::Identifier);     // "fffh"
419   ExpectedTokens.push_back(AsmToken::EndOfStatement); // "\n"
420   ExpectedTokens.push_back(AsmToken::Real);           // ".133"
421   ExpectedTokens.push_back(AsmToken::EndOfStatement); // "\n"
422   ExpectedTokens.push_back(AsmToken::Eof);
423   lexAndCheckTokens(AsmStr, ExpectedTokens);
424 }
425 
426 TEST_F(SystemZAsmLexerTest, CheckDefaultIntegers) {
427   StringRef AsmStr = "0b0101\n0xDEADBEEF\nfffh\n";
428 
429   // Setup.
430   setupCallToAsmParser(AsmStr);
431 
432   // Lex initially to get the string.
433   Parser->getLexer().Lex();
434 
435   SmallVector<int64_t> ExpectedValues({5, 0xDEADBEEF, 0xFFF});
436   lexAndCheckIntegerTokensAndValues(AsmStr, ExpectedValues);
437 }
438 
439 TEST_F(SystemZAsmLexerTest, CheckDefaultFloats) {
440   StringRef AsmStr = "0.333\n1.3\n2.5\n3.0\n";
441 
442   // Setup.
443   setupCallToAsmParser(AsmStr);
444 
445   // Lex initially to get the string.
446   Parser->getLexer().Lex();
447 
448   SmallVector<AsmToken::TokenKind> ExpectedTokens;
449 
450   for (int I = 0; I < 4; ++I)
451     ExpectedTokens.insert(ExpectedTokens.begin(),
452                           {AsmToken::Real, AsmToken::EndOfStatement});
453 
454   ExpectedTokens.push_back(AsmToken::Eof);
455   lexAndCheckTokens(AsmStr, ExpectedTokens);
456 }
457 } // end anonymous namespace
458