• 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(TARGET_AARCH64);
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(TARGET_X64) == 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(TARGET_AARCH64) == 0) {
77             LLVMInitializeAArch64TargetInfo();
78             LLVMInitializeAArch64TargetMC();
79             LLVMInitializeAArch64Disassembler();
80             LLVMInitializeAArch64AsmPrinter();
81             LLVMInitializeAArch64AsmParser();
82             LLVMInitializeAArch64Target();
83         } else {
84             LOG_ECMA(FATAL) << "this branch is unreachable";
85             UNREACHABLE();
86         }
87     }
88 
DisassembleChunk(const char * triple,Assembler * assemlber,std::ostream & os)89     void DisassembleChunk(const char *triple, Assembler *assemlber, std::ostream &os)
90     {
91         LLVMDisasmContextRef dcr = LLVMCreateDisasm(triple, nullptr, 0, nullptr, SymbolLookupCallback);
92         uint8_t *byteSp = assemlber->GetBegin();
93         size_t numBytes = assemlber->GetCurrentPosition();
94         unsigned pc = 0;
95         const char outStringSize = 100;
96         char outString[outStringSize];
97         while (numBytes > 0) {
98             size_t InstSize = LLVMDisasmInstruction(dcr, byteSp, numBytes, pc, outString, outStringSize);
99             if (InstSize == 0) {
100                 // 8 : 8 means width of the pc offset and instruction code
101                 os << std::setw(8) << std::setfill('0') << std::hex << pc << ":" << std::setw(8)
102                    << *reinterpret_cast<uint32_t *>(byteSp) << "maybe constant" << std::endl;
103                 pc += 4; // 4 pc length
104                 byteSp += 4; // 4 sp offset
105                 numBytes -= 4; // 4 num bytes
106             }
107             // 8 : 8 means width of the pc offset and instruction code
108             os << std::setw(8) << std::setfill('0') << std::hex << pc << ":" << std::setw(8)
109                << *reinterpret_cast<uint32_t *>(byteSp) << " " << outString << std::endl;
110             pc += InstSize;
111             byteSp += InstSize;
112             numBytes -= InstSize;
113         }
114         LLVMDisasmDispose(dcr);
115     }
116     EcmaVM *instance {nullptr};
117     JSThread *thread {nullptr};
118     EcmaHandleScope *scope {nullptr};
119     Chunk *chunk_ {nullptr};
120 };
121 
122 #define __ masm.
HWTEST_F_L0(AssemblerAarch64Test,Mov)123 HWTEST_F_L0(AssemblerAarch64Test, Mov)
124 {
125     std::string expectResult("00000000:d28acf01 \tmov\tx1, #22136\n"
126                              "00000004:f2a24681 \tmovk\tx1, #4660, lsl #16\n"
127                              "00000008:f2ffffe1 \tmovk\tx1, #65535, lsl #48\n"
128                              "0000000c:d2801de2 \tmov\tx2, #239\n"
129                              "00000010:f2b579a2 \tmovk\tx2, #43981, lsl #16\n"
130                              "00000014:f2cacf02 \tmovk\tx2, #22136, lsl #32\n"
131                              "00000018:f2e24682 \tmovk\tx2, #4660, lsl #48\n"
132                              "0000001c:b2683be3 \tmov\tx3, #549739036672\n"
133                              "00000020:f2824683 \tmovk\tx3, #4660\n"
134                              "00000024:32083fe4 \tmov\tw4, #-16776961\n");
135     AssemblerAarch64 masm(chunk_);
136     __ Mov(Register(X1),  Immediate(0xffff000012345678));
137     __ Mov(Register(X2),  Immediate(0x12345678abcd00ef));
138     __ Mov(Register(X3),  Immediate(0x7fff001234));
139     __ Mov(Register(X4).W(),  Immediate(0xff0000ff));
140     std::ostringstream oss;
141     DisassembleChunk(TARGET_AARCH64, &masm, oss);
142     ASSERT_EQ(oss.str(), expectResult);
143 }
144 
HWTEST_F_L0(AssemblerAarch64Test,MovReg)145 HWTEST_F_L0(AssemblerAarch64Test, MovReg)
146 {
147     std::string expectResult("00000000:aa0203e1 \tmov\tx1, x2\n"
148                              "00000004:910003e2 \tmov\tx2, sp\n"
149                              "00000008:2a0203e1 \tmov\tw1, w2\n");
150     AssemblerAarch64 masm(chunk_);
151     __ Mov(Register(X1),  Register(X2));
152     __ Mov(Register(X2),  Register(SP));
153     __ Mov(Register(X1, W),  Register(X2, W));
154     std::ostringstream oss;
155     DisassembleChunk(TARGET_AARCH64, &masm, oss);
156     ASSERT_EQ(oss.str(), expectResult);
157 }
158 
HWTEST_F_L0(AssemblerAarch64Test,LdpStp)159 HWTEST_F_L0(AssemblerAarch64Test, LdpStp)
160 {
161     std::string expectResult("00000000:a8808be1 \tstp\tx1, x2, [sp], #8\n"
162                              "00000004:a9c08be1 \tldp\tx1, x2, [sp, #8]!\n"
163                              "00000008:a94093e3 \tldp\tx3, x4, [sp, #8]\n"
164                              "0000000c:294113e3 \tldp\tw3, w4, [sp, #8]\n");
165 
166     AssemblerAarch64 masm(chunk_);
167     __ Stp(Register(X1),  Register(X2), MemoryOperand(Register(SP), 8, POSTINDEX));
168     __ Ldp(Register(X1),  Register(X2), MemoryOperand(Register(SP), 8, PREINDEX));
169     __ Ldp(Register(X3),  Register(X4), MemoryOperand(Register(SP), 8, OFFSET));
170     __ Ldp(Register(X3).W(),  Register(X4).W(), MemoryOperand(Register(SP), 8, OFFSET));
171     std::ostringstream oss;
172     DisassembleChunk(TARGET_AARCH64, &masm, oss);
173     ASSERT_EQ(oss.str(), expectResult);
174 }
175 
HWTEST_F_L0(AssemblerAarch64Test,LdrStr)176 HWTEST_F_L0(AssemblerAarch64Test, LdrStr)
177 {
178     std::string expectResult("00000000:f80087e1 \tstr\tx1, [sp], #8\n"
179                              "00000004:f81f87e1 \tstr\tx1, [sp], #-8\n"
180                              "00000008:f8408fe1 \tldr\tx1, [sp, #8]!\n"
181                              "0000000c:f94007e3 \tldr\tx3, [sp, #8]\n"
182                              "00000010:b9400be3 \tldr\tw3, [sp, #8]\n"
183                              "00000014:38408fe1 \tldrb\tw1, [sp, #8]!\n"
184                              "00000018:394023e1 \tldrb\tw1, [sp, #8]\n"
185                              "0000001c:78408fe1 \tldrh\tw1, [sp, #8]!\n"
186                              "00000020:794013e1 \tldrh\tw1, [sp, #8]\n"
187                              "00000024:f85f83e1 \tldur\tx1, [sp, #-8]\n"
188                              "00000028:f81f83e3 \tstur\tx3, [sp, #-8]\n");
189 
190     AssemblerAarch64 masm(chunk_);
191     __ Str(Register(X1), MemoryOperand(Register(SP), 8, POSTINDEX));
192     __ Str(Register(X1), MemoryOperand(Register(SP), -8, POSTINDEX));
193     __ Ldr(Register(X1), MemoryOperand(Register(SP), 8, PREINDEX));
194     __ Ldr(Register(X3), MemoryOperand(Register(SP), 8, OFFSET));
195     __ Ldr(Register(X3).W(), MemoryOperand(Register(SP), 8, OFFSET));
196     __ Ldrb(Register(X1).W(), MemoryOperand(Register(SP), 8, PREINDEX));
197     __ Ldrb(Register(X1).W(), MemoryOperand(Register(SP), 8, OFFSET));
198     __ Ldrh(Register(X1).W(), MemoryOperand(Register(SP), 8, PREINDEX));
199     __ Ldrh(Register(X1).W(), MemoryOperand(Register(SP), 8, OFFSET));
200     __ Ldur(Register(X1), MemoryOperand(Register(SP), -8, OFFSET));
201     __ Stur(Register(X3), MemoryOperand(Register(SP), -8, OFFSET));
202     std::ostringstream oss;
203     DisassembleChunk(TARGET_AARCH64, &masm, oss);
204     ASSERT_EQ(oss.str(), expectResult);
205 }
206 
HWTEST_F_L0(AssemblerAarch64Test,AddSub)207 HWTEST_F_L0(AssemblerAarch64Test, AddSub)
208 {
209     std::string expectResult("00000000:910023ff \tadd\tsp, sp, #8\n"
210                              "00000004:d10023ff \tsub\tsp, sp, #8\n"
211                              "00000008:8b020021 \tadd\tx1, x1, x2\n"
212                              "0000000c:8b030c41 \tadd\tx1, x2, x3, lsl #3\n"
213                              "00000010:8b234c41 \tadd\tx1, x2, w3, uxtw #3\n"
214                              "00000014:8b224fff \tadd\tsp, sp, w2, uxtw #3\n");
215     AssemblerAarch64 masm(chunk_);
216     __ Add(Register(SP), Register(SP), Immediate(8));
217     __ Add(Register(SP), Register(SP), Immediate(-8));
218     __ Add(Register(X1), Register(X1), Operand(Register(X2)));
219     __ Add(Register(X1), Register(X2), Operand(Register(X3), LSL, 3));
220     __ Add(Register(X1), Register(X2), Operand(Register(X3), UXTW, 3));
221     __ Add(Register(SP), Register(SP), Operand(Register(X2), UXTW, 3));
222 
223     std::ostringstream oss;
224     DisassembleChunk(TARGET_AARCH64, &masm, oss);
225     ASSERT_EQ(oss.str(), expectResult);
226 }
227 
HWTEST_F_L0(AssemblerAarch64Test,CMP)228 HWTEST_F_L0(AssemblerAarch64Test, CMP)
229 {
230     std::string expectResult("00000000:eb02003f \tcmp\tx1, x2\n"
231                              "00000004:f100203f \tcmp\tx1, #8\n");
232     AssemblerAarch64 masm(chunk_);
233     __ Cmp(Register(X1), Register(X2));
234     __ Cmp(Register(X1), Immediate(8));
235 
236     std::ostringstream oss;
237     DisassembleChunk(TARGET_AARCH64, &masm, oss);
238     ASSERT_EQ(oss.str(), expectResult);
239 }
240 
HWTEST_F_L0(AssemblerAarch64Test,Branch)241 HWTEST_F_L0(AssemblerAarch64Test, Branch)
242 {
243     std::string expectResult("00000000:eb02003f \tcmp\tx1, x2\n"
244                              "00000004:54000080 \tb.eq\t0x14\n"
245                              "00000008:f100203f \tcmp\tx1, #8\n"
246                              "0000000c:5400004c \tb.gt\t0x14\n"
247                              "00000010:14000002 \tb\t0x18\n"
248                              "00000014:d2800140 \tmov\tx0, #10\n"
249                              "00000018:b27f03e0 \torr\tx0, xzr, #0x2\n");
250     AssemblerAarch64 masm(chunk_);
251     Label label1;
252     Label label2;
253     __ Cmp(Register(X1), Register(X2));
254     __ B(Condition::EQ, &label1);
255     __ Cmp(Register(X1), Immediate(8));
256     __ B(Condition::GT, &label1);
257     __ B(&label2);
258     __ Bind(&label1);
259     {
260         __ Mov(Register(X0), Immediate(0xa));
261     }
262     __ Bind(&label2);
263     {
264         __ Mov(Register(X0), Immediate(0x2));
265     }
266 
267     std::ostringstream oss;
268     DisassembleChunk(TARGET_AARCH64, &masm, oss);
269     ASSERT_EQ(oss.str(), expectResult);
270 }
271 
HWTEST_F_L0(AssemblerAarch64Test,Loop)272 HWTEST_F_L0(AssemblerAarch64Test, Loop)
273 {
274     std::string expectResult("00000000:7100005f \tcmp\tw2, #0\n"
275                              "00000004:540000e0 \tb.eq\t0x20\n"
276                              "00000008:51000442 \tsub\tw2, w2, #1\n"
277                              "0000000c:8b224c84 \tadd\tx4, x4, w2, uxtw #3\n"
278                              "00000010:f85f8485 \tldr\tx5, [x4], #-8\n"
279                              "00000014:f81f8fe5 \tstr\tx5, [sp, #-8]!\n"
280                              "00000018:51000442 \tsub\tw2, w2, #1\n"
281                              "0000001c:54ffffa5 \tb.pl\t0x10\n"
282                              "00000020:d2800140 \tmov\tx0, #10\n");
283     AssemblerAarch64 masm(chunk_);
284     Label label1;
285     Label labelLoop;
286     Register count(X2, W);
287     Register base(X4);
288     Register temp(X5);
289     __ Cmp(count, Immediate(0));
290     __ B(Condition::EQ, &label1);
291     __ Add(count, count, Immediate(-1));
292     __ Add(base, base, Operand(count, UXTW, 3));
293     __ Bind(&labelLoop);
294     {
295         __ Ldr(temp, MemoryOperand(base, -8, POSTINDEX));
296         __ Str(temp, MemoryOperand(Register(SP), -8, PREINDEX));
297         __ Add(count, count, Immediate(-1));
298         __ B(Condition::PL, &labelLoop);
299     }
300     __ Bind(&label1);
301     {
302         __ Mov(Register(X0), Immediate(0xa));
303     }
304     std::ostringstream oss;
305     DisassembleChunk(TARGET_AARCH64, &masm, oss);
306     ASSERT_EQ(oss.str(), expectResult);
307 }
308 
HWTEST_F_L0(AssemblerAarch64Test,TbzAndCbz)309 HWTEST_F_L0(AssemblerAarch64Test, TbzAndCbz)
310 {
311     std::string expectResult("00000000:36780001 \ttbz\tw1, #15, 0x0\n"
312                              "00000004:b60000c2 \ttbz\tx2, #32, 0x1c\n"
313                              "00000008:372800c2 \ttbnz\tw2, #5, 0x20\n"
314                              "0000000c:34000063 \tcbz\tw3, 0x18\n"
315                              "00000010:b5000064 \tcbnz\tx4, 0x1c\n"
316                              "00000014:b4000065 \tcbz\tx5, 0x20\n"
317                              "00000018:b24003e0 \torr\tx0, xzr, #0x1\n"
318                              "0000001c:b27f03e0 \torr\tx0, xzr, #0x2\n"
319                              "00000020:b24007e0 \torr\tx0, xzr, #0x3\n");
320     AssemblerAarch64 masm(chunk_);
321     Label label1;
322     Label label2;
323     Label label3;
324     __ Tbz(Register(X1), 15, &label1);
325     __ Tbz(Register(X2), 32,  &label2);
326     __ Tbnz(Register(X2), 5,  &label3);
327     __ Cbz(Register(X3).W(), &label1);
328     __ Cbnz(Register(X4), &label2);
329     __ Cbz(Register(X5), &label3);
330     __ Bind(&label1);
331     {
332         __ Mov(Register(X0), Immediate(0x1));
333     }
334     __ Bind(&label2);
335     {
336         __ Mov(Register(X0), Immediate(0x2));
337     }
338     __ Bind(&label3);
339     {
340         __ Mov(Register(X0), Immediate(0x3));
341     }
342     std::ostringstream oss;
343     DisassembleChunk(TARGET_AARCH64, &masm, oss);
344     ASSERT_EQ(oss.str(), expectResult);
345 }
346 
HWTEST_F_L0(AssemblerAarch64Test,Call)347 HWTEST_F_L0(AssemblerAarch64Test, Call)
348 {
349     std::string expectResult("00000000:b24003e0 \torr\tx0, xzr, #0x1\n"
350                              "00000004:b27f03e1 \torr\tx1, xzr, #0x2\n"
351                              "00000008:b24007e2 \torr\tx2, xzr, #0x3\n"
352                              "0000000c:97fffffd \tbl\t0x0\n"
353                              "00000010:d63f0040 \tblr\tx2\n");
354     AssemblerAarch64 masm(chunk_);
355     Label label1;
356     __ Bind(&label1);
357     {
358         __ Mov(Register(X0), Immediate(0x1));
359         __ Mov(Register(X1), Immediate(0x2));
360         __ Mov(Register(X2), Immediate(0x3));
361         __ Bl(&label1);
362         __ Blr(Register(X2));
363     }
364     std::ostringstream oss;
365     DisassembleChunk(TARGET_AARCH64, &masm, oss);
366     ASSERT_EQ(oss.str(), expectResult);
367 }
368 
HWTEST_F_L0(AssemblerAarch64Test,RetAndBrk)369 HWTEST_F_L0(AssemblerAarch64Test, RetAndBrk)
370 {
371     std::string expectResult("00000000:d65f03c0 \tret\n"
372                              "00000004:d65f0280 \tret\tx20\n"
373                              "00000008:d4200000 \tbrk\t#0\n");
374     AssemblerAarch64 masm(chunk_);
375     __ Ret();
376     __ Ret(Register(X20));
377     __ Brk(Immediate(0));
378 
379     std::ostringstream oss;
380     DisassembleChunk(TARGET_AARCH64, &masm, oss);
381     ASSERT_EQ(oss.str(), expectResult);
382 }
383 #undef __
384 }
385