• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/assembler/aarch64/assembler_aarch64.h"
17 
18 #include <ostream>
19 #include <sstream>
20 
21 #include "ecmascript/ecma_vm.h"
22 #include "ecmascript/mem/dyn_chunk.h"
23 #include "ecmascript/tests/test_helper.h"
24 
25 #include "llvm-c/Analysis.h"
26 #include "llvm-c/Core.h"
27 #include "llvm-c/Disassembler.h"
28 #include "llvm-c/ExecutionEngine.h"
29 #include "llvm-c/Target.h"
30 
31 namespace panda::test {
32 using namespace panda::ecmascript;
33 using namespace panda::ecmascript::aarch64;
34 class AssemblerAarch64Test : public testing::Test {
35 public:
SetUpTestCase()36     static void SetUpTestCase()
37     {
38         GTEST_LOG_(INFO) << "SetUpTestCase";
39     }
40 
TearDownTestCase()41     static void TearDownTestCase()
42     {
43         GTEST_LOG_(INFO) << "TearDownCase";
44     }
45 
SetUp()46     void SetUp() override
47     {
48         InitializeLLVM("aarch64-unknown-linux-gnu");
49         TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
50         chunk_ = thread->GetEcmaVM()->GetChunk();
51     }
52 
TearDown()53     void TearDown() override
54     {
55         TestHelper::DestroyEcmaVMWithScope(instance, scope);
56     }
57 
SymbolLookupCallback(void * disInfo,uint64_t referenceValue,uint64_t * referenceType,uint64_t referencePC,const char ** referenceName)58     static const char *SymbolLookupCallback([[maybe_unused]] void *disInfo, [[maybe_unused]] uint64_t referenceValue,
59                                             uint64_t *referenceType, [[maybe_unused]]uint64_t referencePC,
60                                             [[maybe_unused]] const char **referenceName)
61     {
62         *referenceType = LLVMDisassembler_ReferenceType_InOut_None;
63         return nullptr;
64     }
65 
InitializeLLVM(std::string triple)66     void InitializeLLVM(std::string triple)
67     {
68         if (triple.compare("x86_64-unknown-linux-gnu") == 0) {
69             LLVMInitializeX86TargetInfo();
70             LLVMInitializeX86TargetMC();
71             LLVMInitializeX86Disassembler();
72             /* this method must be called, ohterwise "Target does not support MC emission" */
73             LLVMInitializeX86AsmPrinter();
74             LLVMInitializeX86AsmParser();
75             LLVMInitializeX86Target();
76         } else if (triple.compare("aarch64-unknown-linux-gnu") == 0) {
77             LLVMInitializeAArch64TargetInfo();
78             LLVMInitializeAArch64TargetMC();
79             LLVMInitializeAArch64Disassembler();
80             LLVMInitializeAArch64AsmPrinter();
81             LLVMInitializeAArch64AsmParser();
82             LLVMInitializeAArch64Target();
83         } else if (triple.compare("arm-unknown-linux-gnu") == 0) {
84             LLVMInitializeARMTargetInfo();
85             LLVMInitializeARMTargetMC();
86             LLVMInitializeARMDisassembler();
87             LLVMInitializeARMAsmPrinter();
88             LLVMInitializeARMAsmParser();
89             LLVMInitializeARMTarget();
90         } else {
91             UNREACHABLE();
92         }
93     }
94 
DisassembleChunk(const char * triple,Assembler * assemlber,std::ostream & os)95     void DisassembleChunk(const char *triple, Assembler *assemlber, std::ostream &os)
96     {
97         LLVMDisasmContextRef dcr = LLVMCreateDisasm(triple, nullptr, 0, nullptr, SymbolLookupCallback);
98         uint8_t *byteSp = assemlber->GetBegin();
99         size_t numBytes = assemlber->GetCurrentPosition();
100         unsigned pc = 0;
101         const char outStringSize = 100;
102         char outString[outStringSize];
103         while (numBytes > 0) {
104             size_t InstSize = LLVMDisasmInstruction(dcr, byteSp, numBytes, pc, outString, outStringSize);
105             if (InstSize == 0) {
106                 // 8 : 8 means width of the pc offset and instruction code
107                 os << std::setw(8) << std::setfill('0') << std::hex << pc << ":" << std::setw(8)
108                    << *reinterpret_cast<uint32_t *>(byteSp) << "maybe constant" << std::endl;
109                 pc += 4; // 4 pc length
110                 byteSp += 4; // 4 sp offset
111                 numBytes -= 4; // 4 num bytes
112             }
113             // 8 : 8 means width of the pc offset and instruction code
114             os << std::setw(8) << std::setfill('0') << std::hex << pc << ":" << std::setw(8)
115                << *reinterpret_cast<uint32_t *>(byteSp) << " " << outString << std::endl;
116             pc += InstSize;
117             byteSp += InstSize;
118             numBytes -= InstSize;
119         }
120         LLVMDisasmDispose(dcr);
121     }
122     EcmaVM *instance {nullptr};
123     JSThread *thread {nullptr};
124     EcmaHandleScope *scope {nullptr};
125     Chunk *chunk_ {nullptr};
126 };
127 
128 #define __ masm.
HWTEST_F_L0(AssemblerAarch64Test,Mov)129 HWTEST_F_L0(AssemblerAarch64Test, Mov)
130 {
131     std::string expectResult("00000000:d28acf01 \tmov\tx1, #22136\n"
132                              "00000004:f2a24681 \tmovk\tx1, #4660, lsl #16\n"
133                              "00000008:f2ffffe1 \tmovk\tx1, #65535, lsl #48\n"
134                              "0000000c:d2801de2 \tmov\tx2, #239\n"
135                              "00000010:f2b579a2 \tmovk\tx2, #43981, lsl #16\n"
136                              "00000014:f2cacf02 \tmovk\tx2, #22136, lsl #32\n"
137                              "00000018:f2e24682 \tmovk\tx2, #4660, lsl #48\n"
138                              "0000001c:b2683be3 \tmov\tx3, #549739036672\n"
139                              "00000020:f2824683 \tmovk\tx3, #4660\n"
140                              "00000024:32083fe4 \tmov\tw4, #-16776961\n");
141     AssemblerAarch64 masm(chunk_);
142     __ Mov(Register(X1),  Immediate(0xffff000012345678));
143     __ Mov(Register(X2),  Immediate(0x12345678abcd00ef));
144     __ Mov(Register(X3),  Immediate(0x7fff001234));
145     __ Mov(Register(X4).W(),  Immediate(0xff0000ff));
146     std::ostringstream oss;
147     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
148     ASSERT_EQ(oss.str(), expectResult);
149 }
150 
HWTEST_F_L0(AssemblerAarch64Test,MovReg)151 HWTEST_F_L0(AssemblerAarch64Test, MovReg)
152 {
153     std::string expectResult("00000000:aa0203e1 \tmov\tx1, x2\n"
154                              "00000004:910003e2 \tmov\tx2, sp\n"
155                              "00000008:2a0203e1 \tmov\tw1, w2\n");
156     AssemblerAarch64 masm(chunk_);
157     __ Mov(Register(X1),  Register(X2));
158     __ Mov(Register(X2),  Register(SP));
159     __ Mov(Register(X1, W),  Register(X2, W));
160     std::ostringstream oss;
161     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
162     ASSERT_EQ(oss.str(), expectResult);
163 }
164 
HWTEST_F_L0(AssemblerAarch64Test,LdpStp)165 HWTEST_F_L0(AssemblerAarch64Test, LdpStp)
166 {
167     std::string expectResult("00000000:a8808be1 \tstp\tx1, x2, [sp], #8\n"
168                              "00000004:a9c08be1 \tldp\tx1, x2, [sp, #8]!\n"
169                              "00000008:a94093e3 \tldp\tx3, x4, [sp, #8]\n"
170                              "0000000c:294113e3 \tldp\tw3, w4, [sp, #8]\n");
171 
172     AssemblerAarch64 masm(chunk_);
173     __ Stp(Register(X1),  Register(X2), MemoryOperand(Register(SP), 8, POSTINDEX));
174     __ Ldp(Register(X1),  Register(X2), MemoryOperand(Register(SP), 8, PREINDEX));
175     __ Ldp(Register(X3),  Register(X4), MemoryOperand(Register(SP), 8, OFFSET));
176     __ Ldp(Register(X3).W(),  Register(X4).W(), MemoryOperand(Register(SP), 8, OFFSET));
177     std::ostringstream oss;
178     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
179     ASSERT_EQ(oss.str(), expectResult);
180 }
181 
HWTEST_F_L0(AssemblerAarch64Test,LdrStr)182 HWTEST_F_L0(AssemblerAarch64Test, LdrStr)
183 {
184     std::string expectResult("00000000:f80087e1 \tstr\tx1, [sp], #8\n"
185                              "00000004:f81f87e1 \tstr\tx1, [sp], #-8\n"
186                              "00000008:f8408fe1 \tldr\tx1, [sp, #8]!\n"
187                              "0000000c:f94007e3 \tldr\tx3, [sp, #8]\n"
188                              "00000010:b9400be3 \tldr\tw3, [sp, #8]\n"
189                              "00000014:38408fe1 \tldrb\tw1, [sp, #8]!\n"
190                              "00000018:394023e1 \tldrb\tw1, [sp, #8]\n"
191                              "0000001c:78408fe1 \tldrh\tw1, [sp, #8]!\n"
192                              "00000020:794013e1 \tldrh\tw1, [sp, #8]\n"
193                              "00000024:f85f83e1 \tldur\tx1, [sp, #-8]\n"
194                              "00000028:f81f83e3 \tstur\tx3, [sp, #-8]\n");
195 
196     AssemblerAarch64 masm(chunk_);
197     __ Str(Register(X1), MemoryOperand(Register(SP), 8, POSTINDEX));
198     __ Str(Register(X1), MemoryOperand(Register(SP), -8, POSTINDEX));
199     __ Ldr(Register(X1), MemoryOperand(Register(SP), 8, PREINDEX));
200     __ Ldr(Register(X3), MemoryOperand(Register(SP), 8, OFFSET));
201     __ Ldr(Register(X3).W(), MemoryOperand(Register(SP), 8, OFFSET));
202     __ Ldrb(Register(X1).W(), MemoryOperand(Register(SP), 8, PREINDEX));
203     __ Ldrb(Register(X1).W(), MemoryOperand(Register(SP), 8, OFFSET));
204     __ Ldrh(Register(X1).W(), MemoryOperand(Register(SP), 8, PREINDEX));
205     __ Ldrh(Register(X1).W(), MemoryOperand(Register(SP), 8, OFFSET));
206     __ Ldur(Register(X1), MemoryOperand(Register(SP), -8, OFFSET));
207     __ Stur(Register(X3), MemoryOperand(Register(SP), -8, OFFSET));
208     std::ostringstream oss;
209     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
210     ASSERT_EQ(oss.str(), expectResult);
211 }
212 
HWTEST_F_L0(AssemblerAarch64Test,AddSub)213 HWTEST_F_L0(AssemblerAarch64Test, AddSub)
214 {
215     std::string expectResult("00000000:910023ff \tadd\tsp, sp, #8\n"
216                              "00000004:d10023ff \tsub\tsp, sp, #8\n"
217                              "00000008:8b020021 \tadd\tx1, x1, x2\n"
218                              "0000000c:8b030c41 \tadd\tx1, x2, x3, lsl #3\n"
219                              "00000010:8b234c41 \tadd\tx1, x2, w3, uxtw #3\n"
220                              "00000014:8b224fff \tadd\tsp, sp, w2, uxtw #3\n");
221     AssemblerAarch64 masm(chunk_);
222     __ Add(Register(SP), Register(SP), Immediate(8));
223     __ Add(Register(SP), Register(SP), Immediate(-8));
224     __ Add(Register(X1), Register(X1), Operand(Register(X2)));
225     __ Add(Register(X1), Register(X2), Operand(Register(X3), LSL, 3));
226     __ Add(Register(X1), Register(X2), Operand(Register(X3), UXTW, 3));
227     __ Add(Register(SP), Register(SP), Operand(Register(X2), UXTW, 3));
228 
229     std::ostringstream oss;
230     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
231     ASSERT_EQ(oss.str(), expectResult);
232 }
233 
HWTEST_F_L0(AssemblerAarch64Test,CMP)234 HWTEST_F_L0(AssemblerAarch64Test, CMP)
235 {
236     std::string expectResult("00000000:eb02003f \tcmp\tx1, x2\n"
237                              "00000004:f100203f \tcmp\tx1, #8\n");
238     AssemblerAarch64 masm(chunk_);
239     __ Cmp(Register(X1), Register(X2));
240     __ Cmp(Register(X1), Immediate(8));
241 
242     std::ostringstream oss;
243     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
244     ASSERT_EQ(oss.str(), expectResult);
245 }
246 
HWTEST_F_L0(AssemblerAarch64Test,Branch)247 HWTEST_F_L0(AssemblerAarch64Test, Branch)
248 {
249     std::string expectResult("00000000:eb02003f \tcmp\tx1, x2\n"
250                              "00000004:54000080 \tb.eq\t0x14\n"
251                              "00000008:f100203f \tcmp\tx1, #8\n"
252                              "0000000c:5400004c \tb.gt\t0x14\n"
253                              "00000010:14000002 \tb\t0x18\n"
254                              "00000014:d2800140 \tmov\tx0, #10\n"
255                              "00000018:b27f03e0 \torr\tx0, xzr, #0x2\n");
256     AssemblerAarch64 masm(chunk_);
257     Label label1;
258     Label label2;
259     __ Cmp(Register(X1), Register(X2));
260     __ B(Condition::EQ, &label1);
261     __ Cmp(Register(X1), Immediate(8));
262     __ B(Condition::GT, &label1);
263     __ B(&label2);
264     __ Bind(&label1);
265     {
266         __ Mov(Register(X0), Immediate(0xa));
267     }
268     __ Bind(&label2);
269     {
270         __ Mov(Register(X0), Immediate(0x2));
271     }
272 
273     std::ostringstream oss;
274     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
275     ASSERT_EQ(oss.str(), expectResult);
276 }
277 
HWTEST_F_L0(AssemblerAarch64Test,Loop)278 HWTEST_F_L0(AssemblerAarch64Test, Loop)
279 {
280     std::string expectResult("00000000:7100005f \tcmp\tw2, #0\n"
281                              "00000004:540000e0 \tb.eq\t0x20\n"
282                              "00000008:51000442 \tsub\tw2, w2, #1\n"
283                              "0000000c:8b224c84 \tadd\tx4, x4, w2, uxtw #3\n"
284                              "00000010:f85f8485 \tldr\tx5, [x4], #-8\n"
285                              "00000014:f81f8fe5 \tstr\tx5, [sp, #-8]!\n"
286                              "00000018:51000442 \tsub\tw2, w2, #1\n"
287                              "0000001c:54ffffa5 \tb.pl\t0x10\n"
288                              "00000020:d2800140 \tmov\tx0, #10\n");
289     AssemblerAarch64 masm(chunk_);
290     Label label1;
291     Label labelLoop;
292     Register count(X2, W);
293     Register base(X4);
294     Register temp(X5);
295     __ Cmp(count, Immediate(0));
296     __ B(Condition::EQ, &label1);
297     __ Add(count, count, Immediate(-1));
298     __ Add(base, base, Operand(count, UXTW, 3));
299     __ Bind(&labelLoop);
300     {
301         __ Ldr(temp, MemoryOperand(base, -8, POSTINDEX));
302         __ Str(temp, MemoryOperand(Register(SP), -8, PREINDEX));
303         __ Add(count, count, Immediate(-1));
304         __ B(Condition::PL, &labelLoop);
305     }
306     __ Bind(&label1);
307     {
308         __ Mov(Register(X0), Immediate(0xa));
309     }
310     std::ostringstream oss;
311     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
312     ASSERT_EQ(oss.str(), expectResult);
313 }
314 
HWTEST_F_L0(AssemblerAarch64Test,TbzAndCbz)315 HWTEST_F_L0(AssemblerAarch64Test, TbzAndCbz)
316 {
317     std::string expectResult("00000000:36780001 \ttbz\tw1, #15, 0x0\n"
318                              "00000004:b60000c2 \ttbz\tx2, #32, 0x1c\n"
319                              "00000008:372800c2 \ttbnz\tw2, #5, 0x20\n"
320                              "0000000c:34000063 \tcbz\tw3, 0x18\n"
321                              "00000010:b5000064 \tcbnz\tx4, 0x1c\n"
322                              "00000014:b4000065 \tcbz\tx5, 0x20\n"
323                              "00000018:b24003e0 \torr\tx0, xzr, #0x1\n"
324                              "0000001c:b27f03e0 \torr\tx0, xzr, #0x2\n"
325                              "00000020:b24007e0 \torr\tx0, xzr, #0x3\n");
326     AssemblerAarch64 masm(chunk_);
327     Label label1;
328     Label label2;
329     Label label3;
330     __ Tbz(Register(X1), 15, &label1);
331     __ Tbz(Register(X2), 32,  &label2);
332     __ Tbnz(Register(X2), 5,  &label3);
333     __ Cbz(Register(X3).W(), &label1);
334     __ Cbnz(Register(X4), &label2);
335     __ Cbz(Register(X5), &label3);
336     __ Bind(&label1);
337     {
338         __ Mov(Register(X0), Immediate(0x1));
339     }
340     __ Bind(&label2);
341     {
342         __ Mov(Register(X0), Immediate(0x2));
343     }
344     __ Bind(&label3);
345     {
346         __ Mov(Register(X0), Immediate(0x3));
347     }
348     std::ostringstream oss;
349     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
350     ASSERT_EQ(oss.str(), expectResult);
351 }
352 
HWTEST_F_L0(AssemblerAarch64Test,Call)353 HWTEST_F_L0(AssemblerAarch64Test, Call)
354 {
355     std::string expectResult("00000000:b24003e0 \torr\tx0, xzr, #0x1\n"
356                              "00000004:b27f03e1 \torr\tx1, xzr, #0x2\n"
357                              "00000008:b24007e2 \torr\tx2, xzr, #0x3\n"
358                              "0000000c:97fffffd \tbl\t0x0\n"
359                              "00000010:d63f0040 \tblr\tx2\n");
360     AssemblerAarch64 masm(chunk_);
361     Label label1;
362     __ Bind(&label1);
363     {
364         __ Mov(Register(X0), Immediate(0x1));
365         __ Mov(Register(X1), Immediate(0x2));
366         __ Mov(Register(X2), Immediate(0x3));
367         __ Bl(&label1);
368         __ Blr(Register(X2));
369     }
370     std::ostringstream oss;
371     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
372     ASSERT_EQ(oss.str(), expectResult);
373 }
374 
HWTEST_F_L0(AssemblerAarch64Test,RetAndBrk)375 HWTEST_F_L0(AssemblerAarch64Test, RetAndBrk)
376 {
377     std::string expectResult("00000000:d65f03c0 \tret\n"
378                              "00000004:d65f0280 \tret\tx20\n"
379                              "00000008:d4200000 \tbrk\t#0\n");
380     AssemblerAarch64 masm(chunk_);
381     __ Ret();
382     __ Ret(Register(X20));
383     __ Brk(Immediate(0));
384 
385     std::ostringstream oss;
386     DisassembleChunk("aarch64-unknown-linux-gnu", &masm, oss);
387     ASSERT_EQ(oss.str(), expectResult);
388 }
389 #undef __
390 }