xref: /aosp_15_r20/art/compiler/utils/arm64/assembler_arm64.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_COMPILER_UTILS_ARM64_ASSEMBLER_ARM64_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_COMPILER_UTILS_ARM64_ASSEMBLER_ARM64_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <stdint.h>
21*795d594fSAndroid Build Coastguard Worker #include <memory>
22*795d594fSAndroid Build Coastguard Worker #include <vector>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils_iterator.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
28*795d594fSAndroid Build Coastguard Worker #include "dwarf/register.h"
29*795d594fSAndroid Build Coastguard Worker #include "offsets.h"
30*795d594fSAndroid Build Coastguard Worker #include "utils/arm64/managed_register_arm64.h"
31*795d594fSAndroid Build Coastguard Worker #include "utils/assembler.h"
32*795d594fSAndroid Build Coastguard Worker 
33*795d594fSAndroid Build Coastguard Worker // TODO(VIXL): Make VIXL compile cleanly with -Wshadow, -Wdeprecated-declarations.
34*795d594fSAndroid Build Coastguard Worker #pragma GCC diagnostic push
35*795d594fSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wshadow"
36*795d594fSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
37*795d594fSAndroid Build Coastguard Worker #include "aarch64/disasm-aarch64.h"
38*795d594fSAndroid Build Coastguard Worker #include "aarch64/macro-assembler-aarch64.h"
39*795d594fSAndroid Build Coastguard Worker #pragma GCC diagnostic pop
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker class Arm64InstructionSetFeatures;
44*795d594fSAndroid Build Coastguard Worker 
45*795d594fSAndroid Build Coastguard Worker namespace arm64 {
46*795d594fSAndroid Build Coastguard Worker 
DWARFReg(vixl::aarch64::CPURegister reg)47*795d594fSAndroid Build Coastguard Worker static inline dwarf::Reg DWARFReg(vixl::aarch64::CPURegister reg) {
48*795d594fSAndroid Build Coastguard Worker   if (reg.IsFPRegister()) {
49*795d594fSAndroid Build Coastguard Worker     return dwarf::Reg::Arm64Fp(reg.GetCode());
50*795d594fSAndroid Build Coastguard Worker   } else {
51*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(reg.GetCode(), 31u);  // X0 - X30.
52*795d594fSAndroid Build Coastguard Worker     return dwarf::Reg::Arm64Core(reg.GetCode());
53*795d594fSAndroid Build Coastguard Worker   }
54*795d594fSAndroid Build Coastguard Worker }
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker #define MEM_OP(...)      vixl::aarch64::MemOperand(__VA_ARGS__)
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker enum LoadOperandType {
59*795d594fSAndroid Build Coastguard Worker   kLoadSignedByte,
60*795d594fSAndroid Build Coastguard Worker   kLoadUnsignedByte,
61*795d594fSAndroid Build Coastguard Worker   kLoadSignedHalfword,
62*795d594fSAndroid Build Coastguard Worker   kLoadUnsignedHalfword,
63*795d594fSAndroid Build Coastguard Worker   kLoadWord,
64*795d594fSAndroid Build Coastguard Worker   kLoadCoreWord,
65*795d594fSAndroid Build Coastguard Worker   kLoadSWord,
66*795d594fSAndroid Build Coastguard Worker   kLoadDWord
67*795d594fSAndroid Build Coastguard Worker };
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker enum StoreOperandType {
70*795d594fSAndroid Build Coastguard Worker   kStoreByte,
71*795d594fSAndroid Build Coastguard Worker   kStoreHalfword,
72*795d594fSAndroid Build Coastguard Worker   kStoreWord,
73*795d594fSAndroid Build Coastguard Worker   kStoreCoreWord,
74*795d594fSAndroid Build Coastguard Worker   kStoreSWord,
75*795d594fSAndroid Build Coastguard Worker   kStoreDWord
76*795d594fSAndroid Build Coastguard Worker };
77*795d594fSAndroid Build Coastguard Worker 
78*795d594fSAndroid Build Coastguard Worker class Arm64Assembler final : public Assembler {
79*795d594fSAndroid Build Coastguard Worker  public:
80*795d594fSAndroid Build Coastguard Worker   explicit Arm64Assembler(
81*795d594fSAndroid Build Coastguard Worker       ArenaAllocator* allocator, const Arm64InstructionSetFeatures* features = nullptr);
82*795d594fSAndroid Build Coastguard Worker 
~Arm64Assembler()83*795d594fSAndroid Build Coastguard Worker   virtual ~Arm64Assembler() {}
84*795d594fSAndroid Build Coastguard Worker 
GetVIXLAssembler()85*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::MacroAssembler* GetVIXLAssembler() { return &vixl_masm_; }
86*795d594fSAndroid Build Coastguard Worker 
87*795d594fSAndroid Build Coastguard Worker   // Finalize the code.
88*795d594fSAndroid Build Coastguard Worker   void FinalizeCode() override;
89*795d594fSAndroid Build Coastguard Worker 
90*795d594fSAndroid Build Coastguard Worker   // Size of generated code.
91*795d594fSAndroid Build Coastguard Worker   size_t CodeSize() const override;
92*795d594fSAndroid Build Coastguard Worker   const uint8_t* CodeBufferBaseAddress() const override;
93*795d594fSAndroid Build Coastguard Worker 
94*795d594fSAndroid Build Coastguard Worker   // Copy instructions out of assembly buffer into the given region of memory.
95*795d594fSAndroid Build Coastguard Worker   void CopyInstructions(const MemoryRegion& region) override;
96*795d594fSAndroid Build Coastguard Worker 
97*795d594fSAndroid Build Coastguard Worker   void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs);
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker   void SpillRegisters(vixl::aarch64::CPURegList registers, int offset);
100*795d594fSAndroid Build Coastguard Worker   void UnspillRegisters(vixl::aarch64::CPURegList registers, int offset);
101*795d594fSAndroid Build Coastguard Worker 
102*795d594fSAndroid Build Coastguard Worker   // A helper to save/restore a list of ZRegisters to a specified stack offset location.
103*795d594fSAndroid Build Coastguard Worker   template <bool is_save>
SaveRestoreZRegisterList(uint32_t vreg_bit_vector,int64_t stack_offset)104*795d594fSAndroid Build Coastguard Worker   void SaveRestoreZRegisterList(uint32_t vreg_bit_vector, int64_t stack_offset) {
105*795d594fSAndroid Build Coastguard Worker     if (vreg_bit_vector == 0) {
106*795d594fSAndroid Build Coastguard Worker       return;
107*795d594fSAndroid Build Coastguard Worker     }
108*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::UseScratchRegisterScope temps(GetVIXLAssembler());
109*795d594fSAndroid Build Coastguard Worker     vixl::aarch64::Register temp = temps.AcquireX();
110*795d594fSAndroid Build Coastguard Worker     vixl_masm_.Add(temp, vixl::aarch64::sp, stack_offset);
111*795d594fSAndroid Build Coastguard Worker     size_t slot_no = 0;
112*795d594fSAndroid Build Coastguard Worker     for (uint32_t i : LowToHighBits(vreg_bit_vector)) {
113*795d594fSAndroid Build Coastguard Worker       if (is_save) {
114*795d594fSAndroid Build Coastguard Worker         vixl_masm_.Str(vixl::aarch64::ZRegister(i),
115*795d594fSAndroid Build Coastguard Worker                        vixl::aarch64::SVEMemOperand(temp, slot_no, vixl::aarch64::SVE_MUL_VL));
116*795d594fSAndroid Build Coastguard Worker       } else {
117*795d594fSAndroid Build Coastguard Worker         vixl_masm_.Ldr(vixl::aarch64::ZRegister(i),
118*795d594fSAndroid Build Coastguard Worker                        vixl::aarch64::SVEMemOperand(temp, slot_no, vixl::aarch64::SVE_MUL_VL));
119*795d594fSAndroid Build Coastguard Worker       }
120*795d594fSAndroid Build Coastguard Worker       slot_no++;
121*795d594fSAndroid Build Coastguard Worker     }
122*795d594fSAndroid Build Coastguard Worker   }
123*795d594fSAndroid Build Coastguard Worker 
124*795d594fSAndroid Build Coastguard Worker   // Jump to address (not setting link register)
125*795d594fSAndroid Build Coastguard Worker   void JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch);
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker   //
128*795d594fSAndroid Build Coastguard Worker   // Heap poisoning.
129*795d594fSAndroid Build Coastguard Worker   //
130*795d594fSAndroid Build Coastguard Worker 
131*795d594fSAndroid Build Coastguard Worker   // Poison a heap reference contained in `reg`.
132*795d594fSAndroid Build Coastguard Worker   void PoisonHeapReference(vixl::aarch64::Register reg);
133*795d594fSAndroid Build Coastguard Worker   // Unpoison a heap reference contained in `reg`.
134*795d594fSAndroid Build Coastguard Worker   void UnpoisonHeapReference(vixl::aarch64::Register reg);
135*795d594fSAndroid Build Coastguard Worker   // Poison a heap reference contained in `reg` if heap poisoning is enabled.
136*795d594fSAndroid Build Coastguard Worker   void MaybePoisonHeapReference(vixl::aarch64::Register reg);
137*795d594fSAndroid Build Coastguard Worker   // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
138*795d594fSAndroid Build Coastguard Worker   void MaybeUnpoisonHeapReference(vixl::aarch64::Register reg);
139*795d594fSAndroid Build Coastguard Worker 
140*795d594fSAndroid Build Coastguard Worker   // Emit code checking the status of the Marking Register, and aborting
141*795d594fSAndroid Build Coastguard Worker   // the program if MR does not match the value stored in the art::Thread
142*795d594fSAndroid Build Coastguard Worker   // object.
143*795d594fSAndroid Build Coastguard Worker   //
144*795d594fSAndroid Build Coastguard Worker   // Argument `temp` is used as a temporary register to generate code.
145*795d594fSAndroid Build Coastguard Worker   // Argument `code` is used to identify the different occurrences of
146*795d594fSAndroid Build Coastguard Worker   // MaybeGenerateMarkingRegisterCheck and is passed to the BRK instruction.
147*795d594fSAndroid Build Coastguard Worker   void GenerateMarkingRegisterCheck(vixl::aarch64::Register temp, int code = 0);
148*795d594fSAndroid Build Coastguard Worker 
Bind(Label * label)149*795d594fSAndroid Build Coastguard Worker   void Bind([[maybe_unused]] Label* label) override {
150*795d594fSAndroid Build Coastguard Worker     UNIMPLEMENTED(FATAL) << "Do not use Bind(Label*) for ARM64";
151*795d594fSAndroid Build Coastguard Worker   }
Jump(Label * label)152*795d594fSAndroid Build Coastguard Worker   void Jump([[maybe_unused]] Label* label) override {
153*795d594fSAndroid Build Coastguard Worker     UNIMPLEMENTED(FATAL) << "Do not use Jump(Label*) for ARM64";
154*795d594fSAndroid Build Coastguard Worker   }
155*795d594fSAndroid Build Coastguard Worker 
Bind(vixl::aarch64::Label * label)156*795d594fSAndroid Build Coastguard Worker   void Bind(vixl::aarch64::Label* label) {
157*795d594fSAndroid Build Coastguard Worker     vixl_masm_.Bind(label);
158*795d594fSAndroid Build Coastguard Worker   }
Jump(vixl::aarch64::Label * label)159*795d594fSAndroid Build Coastguard Worker   void Jump(vixl::aarch64::Label* label) {
160*795d594fSAndroid Build Coastguard Worker     vixl_masm_.B(label);
161*795d594fSAndroid Build Coastguard Worker   }
162*795d594fSAndroid Build Coastguard Worker 
reg_x(int code)163*795d594fSAndroid Build Coastguard Worker   static vixl::aarch64::Register reg_x(int code) {
164*795d594fSAndroid Build Coastguard Worker     CHECK(code < kNumberOfXRegisters) << code;
165*795d594fSAndroid Build Coastguard Worker     if (code == SP) {
166*795d594fSAndroid Build Coastguard Worker       return vixl::aarch64::sp;
167*795d594fSAndroid Build Coastguard Worker     } else if (code == XZR) {
168*795d594fSAndroid Build Coastguard Worker       return vixl::aarch64::xzr;
169*795d594fSAndroid Build Coastguard Worker     }
170*795d594fSAndroid Build Coastguard Worker     return vixl::aarch64::XRegister(code);
171*795d594fSAndroid Build Coastguard Worker   }
172*795d594fSAndroid Build Coastguard Worker 
reg_w(int code)173*795d594fSAndroid Build Coastguard Worker   static vixl::aarch64::Register reg_w(int code) {
174*795d594fSAndroid Build Coastguard Worker     CHECK(code < kNumberOfWRegisters) << code;
175*795d594fSAndroid Build Coastguard Worker     if (code == WSP) {
176*795d594fSAndroid Build Coastguard Worker       return vixl::aarch64::wsp;
177*795d594fSAndroid Build Coastguard Worker     } else if (code == WZR) {
178*795d594fSAndroid Build Coastguard Worker       return vixl::aarch64::wzr;
179*795d594fSAndroid Build Coastguard Worker     }
180*795d594fSAndroid Build Coastguard Worker     return vixl::aarch64::WRegister(code);
181*795d594fSAndroid Build Coastguard Worker   }
182*795d594fSAndroid Build Coastguard Worker 
reg_d(int code)183*795d594fSAndroid Build Coastguard Worker   static vixl::aarch64::VRegister reg_d(int code) {
184*795d594fSAndroid Build Coastguard Worker     return vixl::aarch64::DRegister(code);
185*795d594fSAndroid Build Coastguard Worker   }
186*795d594fSAndroid Build Coastguard Worker 
reg_s(int code)187*795d594fSAndroid Build Coastguard Worker   static vixl::aarch64::VRegister reg_s(int code) {
188*795d594fSAndroid Build Coastguard Worker     return vixl::aarch64::SRegister(code);
189*795d594fSAndroid Build Coastguard Worker   }
190*795d594fSAndroid Build Coastguard Worker 
191*795d594fSAndroid Build Coastguard Worker  private:
192*795d594fSAndroid Build Coastguard Worker   // VIXL assembler.
193*795d594fSAndroid Build Coastguard Worker   vixl::aarch64::MacroAssembler vixl_masm_;
194*795d594fSAndroid Build Coastguard Worker 
195*795d594fSAndroid Build Coastguard Worker   // Used for testing.
196*795d594fSAndroid Build Coastguard Worker   friend class Arm64ManagedRegister_VixlRegisters_Test;
197*795d594fSAndroid Build Coastguard Worker };
198*795d594fSAndroid Build Coastguard Worker 
199*795d594fSAndroid Build Coastguard Worker }  // namespace arm64
200*795d594fSAndroid Build Coastguard Worker }  // namespace art
201*795d594fSAndroid Build Coastguard Worker 
202*795d594fSAndroid Build Coastguard Worker #endif  // ART_COMPILER_UTILS_ARM64_ASSEMBLER_ARM64_H_
203