1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "dex/quick/quick_compiler.h"
18 #include "dex/pass_manager.h"
19 #include "dex/verification_results.h"
20 #include "dex/quick/dex_file_to_method_inliner_map.h"
21 #include "runtime/dex_file.h"
22 #include "driver/compiler_options.h"
23 #include "driver/compiler_driver.h"
24 #include "codegen_x86.h"
25 #include "gtest/gtest.h"
26 #include "utils/assembler_test_base.h"
27 
28 namespace art {
29 
30 class QuickAssembleX86TestBase : public testing::Test {
31  protected:
Prepare(InstructionSet target)32   X86Mir2Lir* Prepare(InstructionSet target) {
33     isa_ = target;
34     pool_.reset(new ArenaPool());
35     compiler_options_.reset(new CompilerOptions(
36         CompilerOptions::kDefaultCompilerFilter,
37         CompilerOptions::kDefaultHugeMethodThreshold,
38         CompilerOptions::kDefaultLargeMethodThreshold,
39         CompilerOptions::kDefaultSmallMethodThreshold,
40         CompilerOptions::kDefaultTinyMethodThreshold,
41         CompilerOptions::kDefaultNumDexMethodsThreshold,
42         CompilerOptions::kDefaultInlineDepthLimit,
43         CompilerOptions::kDefaultInlineMaxCodeUnits,
44         false,
45         CompilerOptions::kDefaultTopKProfileThreshold,
46         false,
47         CompilerOptions::kDefaultGenerateDebugInfo,
48         false,
49         false,
50         false,
51         false,
52         nullptr,
53         new PassManagerOptions(),
54         nullptr,
55         false));
56     verification_results_.reset(new VerificationResults(compiler_options_.get()));
57     method_inliner_map_.reset(new DexFileToMethodInlinerMap());
58     compiler_driver_.reset(new CompilerDriver(
59         compiler_options_.get(),
60         verification_results_.get(),
61         method_inliner_map_.get(),
62         Compiler::kQuick,
63         isa_,
64         nullptr,
65         false,
66         nullptr,
67         nullptr,
68         nullptr,
69         0,
70         false,
71         false,
72         "",
73         0,
74         -1,
75         ""));
76     cu_.reset(new CompilationUnit(pool_.get(), isa_, compiler_driver_.get(), nullptr));
77     DexFile::CodeItem* code_item = static_cast<DexFile::CodeItem*>(
78         cu_->arena.Alloc(sizeof(DexFile::CodeItem), kArenaAllocMisc));
79     memset(code_item, 0, sizeof(DexFile::CodeItem));
80     cu_->mir_graph.reset(new MIRGraph(cu_.get(), &cu_->arena));
81     cu_->mir_graph->current_code_item_ = code_item;
82     cu_->cg.reset(QuickCompiler::GetCodeGenerator(cu_.get(), nullptr));
83 
84     test_helper_.reset(new AssemblerTestInfrastructure(
85         isa_ == kX86 ? "x86" : "x86_64",
86         "as",
87         isa_ == kX86 ? " --32" : "",
88         "objdump",
89         " -h",
90         "objdump",
91         isa_ == kX86 ?
92             " -D -bbinary -mi386 --no-show-raw-insn" :
93             " -D -bbinary -mi386:x86-64 -Mx86-64,addr64,data32 --no-show-raw-insn",
94         nullptr));
95 
96     X86Mir2Lir* m2l = static_cast<X86Mir2Lir*>(cu_->cg.get());
97     m2l->CompilerInitializeRegAlloc();
98     return m2l;
99   }
100 
Release()101   void Release() {
102     cu_.reset();
103     compiler_driver_.reset();
104     method_inliner_map_.reset();
105     verification_results_.reset();
106     compiler_options_.reset();
107     pool_.reset();
108 
109     test_helper_.reset();
110   }
111 
TearDown()112   void TearDown() OVERRIDE {
113     Release();
114   }
115 
CheckTools(InstructionSet target)116   bool CheckTools(InstructionSet target) {
117     Prepare(target);
118     bool result = test_helper_->CheckTools();
119     Release();
120     return result;
121   }
122 
123   std::unique_ptr<CompilationUnit> cu_;
124   std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
125 
126  private:
127   InstructionSet isa_;
128   std::unique_ptr<ArenaPool> pool_;
129   std::unique_ptr<CompilerOptions> compiler_options_;
130   std::unique_ptr<VerificationResults> verification_results_;
131   std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_;
132   std::unique_ptr<CompilerDriver> compiler_driver_;
133 };
134 
135 class QuickAssembleX86LowLevelTest : public QuickAssembleX86TestBase {
136  protected:
Test(InstructionSet target,std::string test_name,std::string gcc_asm,int opcode,int op0=0,int op1=0,int op2=0,int op3=0,int op4=0)137   void Test(InstructionSet target, std::string test_name, std::string gcc_asm,
138             int opcode, int op0 = 0, int op1 = 0, int op2 = 0, int op3 = 0, int op4 = 0) {
139     X86Mir2Lir* m2l = Prepare(target);
140 
141     LIR lir;
142     memset(&lir, 0, sizeof(LIR));
143     lir.opcode = opcode;
144     lir.operands[0] = op0;
145     lir.operands[1] = op1;
146     lir.operands[2] = op2;
147     lir.operands[3] = op3;
148     lir.operands[4] = op4;
149     lir.flags.size = m2l->GetInsnSize(&lir);
150 
151     AssemblerStatus status = m2l->AssembleInstructions(&lir, 0);
152     // We don't expect a retry.
153     ASSERT_EQ(status, AssemblerStatus::kSuccess);
154 
155     // Need a "base" std::vector.
156     std::vector<uint8_t> buffer(m2l->code_buffer_.begin(), m2l->code_buffer_.end());
157     test_helper_->Driver(buffer, gcc_asm, test_name);
158 
159     Release();
160   }
161 };
162 
TEST_F(QuickAssembleX86LowLevelTest,Addpd)163 TEST_F(QuickAssembleX86LowLevelTest, Addpd) {
164   Test(kX86, "Addpd", "addpd %xmm1, %xmm0\n", kX86AddpdRR,
165        RegStorage::Solo128(0).GetReg(), RegStorage::Solo128(1).GetReg());
166   Test(kX86_64, "Addpd", "addpd %xmm1, %xmm0\n", kX86AddpdRR,
167        RegStorage::Solo128(0).GetReg(), RegStorage::Solo128(1).GetReg());
168 }
169 
TEST_F(QuickAssembleX86LowLevelTest,Subpd)170 TEST_F(QuickAssembleX86LowLevelTest, Subpd) {
171   Test(kX86, "Subpd", "subpd %xmm1, %xmm0\n", kX86SubpdRR,
172        RegStorage::Solo128(0).GetReg(), RegStorage::Solo128(1).GetReg());
173   Test(kX86_64, "Subpd", "subpd %xmm1, %xmm0\n", kX86SubpdRR,
174        RegStorage::Solo128(0).GetReg(), RegStorage::Solo128(1).GetReg());
175 }
176 
TEST_F(QuickAssembleX86LowLevelTest,Mulpd)177 TEST_F(QuickAssembleX86LowLevelTest, Mulpd) {
178   Test(kX86, "Mulpd", "mulpd %xmm1, %xmm0\n", kX86MulpdRR,
179        RegStorage::Solo128(0).GetReg(), RegStorage::Solo128(1).GetReg());
180   Test(kX86_64, "Mulpd", "mulpd %xmm1, %xmm0\n", kX86MulpdRR,
181        RegStorage::Solo128(0).GetReg(), RegStorage::Solo128(1).GetReg());
182 }
183 
TEST_F(QuickAssembleX86LowLevelTest,Pextrw)184 TEST_F(QuickAssembleX86LowLevelTest, Pextrw) {
185   Test(kX86, "Pextrw", "pextrw $7, %xmm3, 8(%eax)\n", kX86PextrwMRI,
186        RegStorage::Solo32(r0).GetReg(), 8, RegStorage::Solo128(3).GetReg(), 7);
187   Test(kX86_64, "Pextrw", "pextrw $7, %xmm8, 8(%r10)\n", kX86PextrwMRI,
188        RegStorage::Solo64(r10q).GetReg(), 8, RegStorage::Solo128(8).GetReg(), 7);
189 }
190 
191 class QuickAssembleX86MacroTest : public QuickAssembleX86TestBase {
192  protected:
193   typedef void (X86Mir2Lir::*AsmFn)(MIR*);
194 
TestVectorFn(InstructionSet target,Instruction::Code opcode,AsmFn f,std::string inst_string)195   void TestVectorFn(InstructionSet target,
196                     Instruction::Code opcode,
197                     AsmFn f,
198                     std::string inst_string) {
199     X86Mir2Lir *m2l = Prepare(target);
200 
201     // Create a vector MIR.
202     MIR* mir = cu_->mir_graph->NewMIR();
203     mir->dalvikInsn.opcode = opcode;
204     mir->dalvikInsn.vA = 0;  // Destination and source.
205     mir->dalvikInsn.vB = 1;  // Source.
206     int vector_size = 128;
207     int vector_type = kDouble;
208     mir->dalvikInsn.vC = (vector_type << 16) | vector_size;  // Type size.
209     (m2l->*f)(mir);
210     m2l->AssembleLIR();
211 
212     std::string gcc_asm = inst_string + " %xmm1, %xmm0\n";
213     // Need a "base" std::vector.
214     std::vector<uint8_t> buffer(m2l->code_buffer_.begin(), m2l->code_buffer_.end());
215     test_helper_->Driver(buffer, gcc_asm, inst_string);
216 
217     Release();
218   }
219 
220   // Tests are member functions as many of the assembler functions are protected or private,
221   // and it would be inelegant to define ART_FRIEND_TEST for all the tests.
222 
TestAddpd()223   void TestAddpd() {
224     TestVectorFn(kX86,
225                  static_cast<Instruction::Code>(kMirOpPackedAddition),
226                  &X86Mir2Lir::GenAddVector,
227                  "addpd");
228     TestVectorFn(kX86_64,
229                  static_cast<Instruction::Code>(kMirOpPackedAddition),
230                  &X86Mir2Lir::GenAddVector,
231                  "addpd");
232   }
233 
TestSubpd()234   void TestSubpd() {
235     TestVectorFn(kX86,
236                  static_cast<Instruction::Code>(kMirOpPackedSubtract),
237                  &X86Mir2Lir::GenSubtractVector,
238                  "subpd");
239     TestVectorFn(kX86_64,
240                  static_cast<Instruction::Code>(kMirOpPackedSubtract),
241                  &X86Mir2Lir::GenSubtractVector,
242                  "subpd");
243   }
244 
TestMulpd()245   void TestMulpd() {
246     TestVectorFn(kX86,
247                  static_cast<Instruction::Code>(kMirOpPackedMultiply),
248                  &X86Mir2Lir::GenMultiplyVector,
249                  "mulpd");
250     TestVectorFn(kX86_64,
251                  static_cast<Instruction::Code>(kMirOpPackedMultiply),
252                  &X86Mir2Lir::GenMultiplyVector,
253                  "mulpd");
254   }
255 };
256 
TEST_F(QuickAssembleX86MacroTest,CheckTools)257 TEST_F(QuickAssembleX86MacroTest, CheckTools) {
258   ASSERT_TRUE(CheckTools(kX86)) << "x86 tools not found.";
259   ASSERT_TRUE(CheckTools(kX86_64)) << "x86_64 tools not found.";
260 }
261 
262 #define DECLARE_TEST(name)             \
263   TEST_F(QuickAssembleX86MacroTest, name) { \
264     Test ## name();                    \
265   }
266 
267 DECLARE_TEST(Addpd)
268 DECLARE_TEST(Subpd)
269 DECLARE_TEST(Mulpd)
270 
271 }  // namespace art
272