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 };
36 
37 // Setup a testing class that the GTest framework can call.
38 class SystemZAsmLexerTest : public ::testing::Test {
39 protected:
40   static void SetUpTestCase() {
41     LLVMInitializeSystemZTargetInfo();
42     LLVMInitializeSystemZTargetMC();
43   }
44 
45   std::unique_ptr<MCRegisterInfo> MRI;
46   std::unique_ptr<MockedUpMCAsmInfo> MUPMAI;
47   std::unique_ptr<const MCInstrInfo> MII;
48   std::unique_ptr<MCStreamer> Str;
49   std::unique_ptr<MCAsmParser> Parser;
50   std::unique_ptr<MCContext> Ctx;
51 
52   SourceMgr SrcMgr;
53   std::string TripleName;
54   llvm::Triple Triple;
55   const Target *TheTarget;
56 
57   const MCTargetOptions MCOptions;
58   MCObjectFileInfo MOFI;
59 
60   SystemZAsmLexerTest() {
61     // We will use the SystemZ triple, because of missing
62     // Object File and Streamer support for the z/OS target.
63     TripleName = "s390x-ibm-linux";
64     Triple = llvm::Triple(TripleName);
65 
66     std::string Error;
67     TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
68     EXPECT_NE(TheTarget, nullptr);
69 
70     MRI.reset(TheTarget->createMCRegInfo(TripleName));
71     EXPECT_NE(MRI, nullptr);
72 
73     std::unique_ptr<MCAsmInfo> MAI;
74     MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
75     EXPECT_NE(MAI, nullptr);
76 
77     // Now we cast to our mocked up version of MCAsmInfo.
78     MUPMAI.reset(static_cast<MockedUpMCAsmInfo *>(MAI.release()));
79     // MUPMAI should "hold" MAI.
80     EXPECT_NE(MUPMAI, nullptr);
81     // After releasing, MAI should now be null.
82     EXPECT_EQ(MAI, nullptr);
83   }
84 
85   void setupCallToAsmParser(StringRef AsmStr) {
86     std::unique_ptr<MemoryBuffer> Buffer(MemoryBuffer::getMemBuffer(AsmStr));
87     SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
88     EXPECT_EQ(Buffer, nullptr);
89 
90     Ctx.reset(
91         new MCContext(MUPMAI.get(), MRI.get(), &MOFI, &SrcMgr, &MCOptions));
92     MOFI.InitMCObjectFileInfo(Triple, false, *Ctx, false);
93 
94     Str.reset(TheTarget->createNullStreamer(*Ctx));
95 
96     Parser.reset(createMCAsmParser(SrcMgr, *Ctx, *Str, *MUPMAI));
97   }
98 
99   void lexAndCheckTokens(StringRef AsmStr,
100                          SmallVector<AsmToken::TokenKind> ExpectedTokens) {
101     // Get reference to AsmLexer.
102     MCAsmLexer &Lexer = Parser->getLexer();
103     // Loop through all expected tokens checking one by one.
104     for (size_t I = 0; I < ExpectedTokens.size(); ++I) {
105       EXPECT_EQ(Lexer.getTok().getKind(), ExpectedTokens[I]);
106       Lexer.Lex();
107     }
108   }
109 };
110 
111 TEST_F(SystemZAsmLexerTest, CheckDontRestrictCommentStringToStartOfStatement) {
112   StringRef AsmStr = "jne #-4";
113 
114   // Setup.
115   setupCallToAsmParser(AsmStr);
116 
117   // Lex initially to get the string.
118   Parser->getLexer().Lex();
119 
120   SmallVector<AsmToken::TokenKind> ExpectedTokens(
121       {AsmToken::Identifier, AsmToken::EndOfStatement});
122   lexAndCheckTokens(AsmStr /* "jne #-4" */, ExpectedTokens);
123 }
124 
125 // Testing MCAsmInfo's RestrictCommentStringToStartOfStatement attribute.
126 TEST_F(SystemZAsmLexerTest, CheckRestrictCommentStringToStartOfStatement) {
127   StringRef AsmStr = "jne #-4";
128 
129   // Setup.
130   MUPMAI->setRestrictCommentStringToStartOfStatement(true);
131   setupCallToAsmParser(AsmStr);
132 
133   // Lex initially to get the string.
134   Parser->getLexer().Lex();
135 
136   // When we are restricting the comment string to only the start of the
137   // statement, The sequence of tokens we are expecting are: Identifier - "jne"
138   // Hash - '#'
139   // Minus - '-'
140   // Integer - '4'
141   SmallVector<AsmToken::TokenKind> ExpectedTokens(
142       {AsmToken::Identifier, AsmToken::Hash, AsmToken::Minus,
143        AsmToken::Integer});
144   lexAndCheckTokens(AsmStr /* "jne #-4" */, ExpectedTokens);
145 }
146 
147 // Test HLASM Comment Syntax ('*')
148 TEST_F(SystemZAsmLexerTest, CheckHLASMComment) {
149   StringRef AsmStr = "* lhi 1,10";
150 
151   // Setup.
152   MUPMAI->setCommentString("*");
153   setupCallToAsmParser(AsmStr);
154 
155   // Lex initially to get the string.
156   Parser->getLexer().Lex();
157 
158   SmallVector<AsmToken::TokenKind> ExpectedTokens(
159       {AsmToken::EndOfStatement, AsmToken::Eof});
160   lexAndCheckTokens(AsmStr /* "* lhi 1,10" */, ExpectedTokens);
161 }
162 
163 TEST_F(SystemZAsmLexerTest, CheckHashDefault) {
164   StringRef AsmStr = "lh#123";
165 
166   // Setup.
167   setupCallToAsmParser(AsmStr);
168 
169   // Lex initially to get the string.
170   Parser->getLexer().Lex();
171 
172   // "lh" -> Identifier
173   // "#123" -> EndOfStatement (Lexed as a comment since CommentString is "#")
174   SmallVector<AsmToken::TokenKind> ExpectedTokens(
175       {AsmToken::Identifier, AsmToken::EndOfStatement, AsmToken::Eof});
176   lexAndCheckTokens(AsmStr, ExpectedTokens);
177 }
178 
179 // Test if "#" is accepted as an Identifier
180 TEST_F(SystemZAsmLexerTest, CheckAllowHashInIdentifier) {
181   StringRef AsmStr = "lh#123";
182 
183   // Setup.
184   setupCallToAsmParser(AsmStr);
185   Parser->getLexer().setAllowHashInIdentifier(true);
186 
187   // Lex initially to get the string.
188   Parser->getLexer().Lex();
189 
190   // "lh123" -> Identifier
191   SmallVector<AsmToken::TokenKind> ExpectedTokens(
192       {AsmToken::Identifier, AsmToken::EndOfStatement, AsmToken::Eof});
193   lexAndCheckTokens(AsmStr, ExpectedTokens);
194 }
195 
196 TEST_F(SystemZAsmLexerTest, CheckAllowHashInIdentifier2) {
197   StringRef AsmStr = "lh#12*3";
198 
199   // Setup.
200   MUPMAI->setCommentString("*");
201   MUPMAI->setRestrictCommentStringToStartOfStatement(true);
202   setupCallToAsmParser(AsmStr);
203   Parser->getLexer().setAllowHashInIdentifier(true);
204 
205   // Lex initially to get the string.
206   Parser->getLexer().Lex();
207 
208   // "lh#12" -> Identifier
209   // "*" -> Star
210   // "3" -> Integer
211   SmallVector<AsmToken::TokenKind> ExpectedTokens(
212       {AsmToken::Identifier, AsmToken::Star, AsmToken::Integer,
213        AsmToken::EndOfStatement, AsmToken::Eof});
214   lexAndCheckTokens(AsmStr, ExpectedTokens);
215 }
216 } // end anonymous namespace
217