Skip to content

Commit fbc9d68

Browse files
mcfimeta-codesync[bot]
authored andcommitted
Apply HHVM-specific modifications for vixl 8.0.0
Summary: Apply HHVM-specific modifications on top of the upstream vixl 8.0.0 baseline. This is the third diff in a stack that upgrades vixl from the old a64 version to the new aarch64 version (8.0.0). Changes include: hphp/vixl (HHVM-specific adaptations of upstream vixl): - Add BUCK build file and CMakeLists.txt for HHVM build integration - Add hphp-compat.h compatibility header (using namespace aarch64 bridge only; all deprecated aliases like FPRegister removed) - Modify vixl source files to integrate with HHVM's memory management, code generation, and debugging infrastructure - Adapt test files for HHVM's test framework - Use vixl's udf(1) for trap instruction (replacing dc32(1) workaround) - Make EmissionCheckScope (and subclasses SingleEmissionCheckScope, MacroEmissionCheckScope, ExactAssemblyScope) a no-op under HPHP_VIXL to eliminate per-instruction overhead from scope guard construction/destruction and redundant assertCanEmit() buffer checks. This removes ~8 member stores + 1 redundant bounds check + 2-3 branches per instruction emission that were absent in the old vixl version. hphp/runtime (HHVM JIT backend updates): - Update ARM backend to use new vixl aarch64 namespace and API (vixl::aarch64 instead of vixl) - Update register definitions and physical register mappings (FPRegister -> VRegister) - Update instruction encoding/decoding for new vixl API - Update disassembler integration - Update relocation and smashable instruction handling hphp/tools (tc-print): - Update offline-arm-code.cpp to use new vixl aarch64 headers and API (hphp-compat.h, GetLiteralAddress<T>(), GetImmPCOffsetTarget()) hphp/util: - Update data-block.h for compatibility with new vixl API Reviewed By: ricklavoie, ottoni Differential Revision: D94756745 fbshipit-source-id: 15fbb081ddb7ba2a281e04b5c0de4e55d07e606d
1 parent 3baf7a1 commit fbc9d68

66 files changed

Lines changed: 1145 additions & 425 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

hphp/runtime/test/relocation-test.cpp

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include "hphp/runtime/vm/jit/relocation.h"
1919
#include "hphp/util/arch.h"
2020
#include "hphp/util/data-block.h"
21-
#include "hphp/vixl/a64/macro-assembler-a64.h"
21+
#include "hphp/vixl/hphp-compat.h"
2222

2323
#include <gtest/gtest.h>
2424

@@ -89,30 +89,30 @@ TEST(Relocation, RelocateBccImm2MovzMovkBccReg) {
8989
// 3. Call relocate()
9090
RelocationInfo rel;
9191
AreaIndex ai = AreaIndex::Main;
92-
auto instr = Instruction::Cast(end);
92+
const Instruction* instr = Instruction::Cast(end);
9393
relocate(rel, main, start, end, main, meta, nullptr, ai);
9494

9595
// 4. Expect !b.cc, movz/movk X and br X where with imm in X
9696
auto bcc = instr;
9797
EXPECT_TRUE(bcc->IsCondBranchImm());
9898
EXPECT_EQ(bcc->ConditionBranch(), InvertCondition(cond));
9999

100-
auto movz = bcc->NextInstruction();
100+
auto movz = bcc->GetNextInstruction();
101101
EXPECT_TRUE(movz->IsMovz());
102102
const auto rd = movz->Rd();
103-
uint64_t target = movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
104-
instr = movz->NextInstruction();
103+
uint64_t target = (uint64_t)movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
104+
instr = movz->GetNextInstruction();
105105
while (instr->IsMovk()) {
106106
EXPECT_EQ(instr->Rd(), rd);
107-
target |= instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
108-
instr = instr->NextInstruction();
107+
target |= (uint64_t)instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
108+
instr = instr->GetNextInstruction();
109109
}
110110
EXPECT_EQ(Instruction::Cast(target), bccOrig->ImmPCOffsetTarget());
111111

112112
auto br = instr;
113113
EXPECT_TRUE(br->IsUncondBranchReg());
114114
EXPECT_EQ(br->Rn(), rd);
115-
EXPECT_EQ(bcc->ImmPCOffsetTarget(), br->NextInstruction());
115+
EXPECT_EQ(bcc->ImmPCOffsetTarget(), br->GetNextInstruction());
116116
}
117117

118118
/*
@@ -153,7 +153,7 @@ TEST(Relocation, RelocateCbz2MovzMovkCbnzReg) {
153153
// 3. Call relocate()
154154
RelocationInfo rel;
155155
AreaIndex ai = AreaIndex::Main;
156-
auto instr = Instruction::Cast(end);
156+
const Instruction* instr = Instruction::Cast(end);
157157
relocate(rel, main, start, end, main, meta, nullptr, ai);
158158

159159
// 4. Expect cbnz, movz/movk X and br X where with imm in X
@@ -162,22 +162,22 @@ TEST(Relocation, RelocateCbz2MovzMovkCbnzReg) {
162162
const auto rt = cbnz->Rt();
163163
EXPECT_EQ(cbzOrig->Rt(), rt);
164164

165-
auto movz = cbnz->NextInstruction();
165+
auto movz = cbnz->GetNextInstruction();
166166
EXPECT_TRUE(movz->IsMovz());
167167
const auto rd = movz->Rd();
168-
uint64_t target = movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
169-
instr = movz->NextInstruction();
168+
uint64_t target = (uint64_t)movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
169+
instr = movz->GetNextInstruction();
170170
while (instr->IsMovk()) {
171171
EXPECT_EQ(instr->Rd(), rd);
172-
target |= instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
173-
instr = instr->NextInstruction();
172+
target |= (uint64_t)instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
173+
instr = instr->GetNextInstruction();
174174
}
175175
EXPECT_EQ(Instruction::Cast(target), cbzOrig->ImmPCOffsetTarget());
176176

177177
auto br = instr;
178178
EXPECT_TRUE(br->IsUncondBranchReg());
179179
EXPECT_EQ(br->Rn(), rd);
180-
EXPECT_EQ(cbnz->ImmPCOffsetTarget(), br->NextInstruction());
180+
EXPECT_EQ(cbnz->ImmPCOffsetTarget(), br->GetNextInstruction());
181181
}
182182

183183
/*
@@ -218,7 +218,7 @@ TEST(Relocation, RelocateTbz2MovzMovkTbnzReg) {
218218
// 3. Call relocate()
219219
RelocationInfo rel;
220220
AreaIndex ai = AreaIndex::Main;
221-
auto instr = Instruction::Cast(end);
221+
const Instruction* instr = Instruction::Cast(end);
222222
relocate(rel, main, start, end, main, meta, nullptr, ai);
223223

224224
// 4. Expect tbnz, movz/movk X and br X where with imm in X
@@ -229,22 +229,22 @@ TEST(Relocation, RelocateTbz2MovzMovkTbnzReg) {
229229
const auto bit_pos = tbnz->ImmTestBranchBit40();
230230
EXPECT_EQ(bit_pos, 3);
231231

232-
auto movz = tbnz->NextInstruction();
232+
auto movz = tbnz->GetNextInstruction();
233233
EXPECT_TRUE(movz->IsMovz());
234234
const auto rd = movz->Rd();
235-
uint64_t target = movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
236-
instr = movz->NextInstruction();
235+
uint64_t target = (uint64_t)movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
236+
instr = movz->GetNextInstruction();
237237
while (instr->IsMovk()) {
238238
EXPECT_EQ(instr->Rd(), rd);
239-
target |= instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
240-
instr = instr->NextInstruction();
239+
target |= (uint64_t)instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
240+
instr = instr->GetNextInstruction();
241241
}
242242
EXPECT_EQ(Instruction::Cast(target), tbzOrig->ImmPCOffsetTarget());
243243

244244
auto br = instr;
245245
EXPECT_TRUE(br->IsUncondBranchReg());
246246
EXPECT_EQ(br->Rn(), rd);
247-
EXPECT_EQ(tbnz->ImmPCOffsetTarget(), br->NextInstruction());
247+
EXPECT_EQ(tbnz->ImmPCOffsetTarget(), br->GetNextInstruction());
248248
}
249249

250250
/*
@@ -275,7 +275,7 @@ TEST(Relocation, RelocateMovzMovkLdr2LdrLiteral) {
275275
// with this test.
276276
a.dc64(0xdeadbeef);
277277
meta.addressImmediates.insert(main.frontier());
278-
a.Mov(x17, start + 4);
278+
a.Mov(x17, reinterpret_cast<uint64_t>(start + 4));
279279

280280
a.Ldr(x0, MemOperand(x17, 0));
281281

@@ -284,13 +284,13 @@ TEST(Relocation, RelocateMovzMovkLdr2LdrLiteral) {
284284
// 3. Call relocate()
285285
RelocationInfo rel;
286286
AreaIndex ai = AreaIndex::Main;
287-
auto instr = Instruction::Cast(end + 8);
287+
const Instruction* instr = Instruction::Cast(end + 8);
288288
relocate(rel, main, start, end, main, meta, nullptr, ai);
289289

290290
// 4. Expect a Ldr Literal to $x0 from addr
291291
EXPECT_TRUE(instr->IsLoadLiteral());
292292
EXPECT_EQ(instr->Rd(), 0);
293-
EXPECT_EQ(reinterpret_cast<TCA>(instr->LiteralAddress()), end);
293+
EXPECT_EQ(reinterpret_cast<TCA>(instr->GetLiteralAddress<uint8_t*>()), end);
294294
}
295295

296296
/*
@@ -317,26 +317,26 @@ TEST(Relocation, RelocateAdjustedMovzMovk) {
317317
main.setFrontier(start + (2 << 20) + 16);
318318
MacroAssembler a { main };
319319
meta.addressImmediates.insert(main.frontier());
320-
a.Mov(x17, start + 8);
320+
a.Mov(x17, reinterpret_cast<uint64_t>(start + 8));
321321

322322
auto end = main.frontier();
323323

324324
// 3. Call relocate()
325325
RelocationInfo rel;
326326
AreaIndex ai = AreaIndex::Main;
327-
auto instr = Instruction::Cast(end);
327+
const Instruction* instr = Instruction::Cast(end);
328328
relocate(rel, main, start, end, main, meta, nullptr, ai);
329329

330330
// 4. Expect movz/movk of new target
331331
auto movz = instr + (2 << 20) + 16;
332332
EXPECT_TRUE(movz->IsMovz());
333333
EXPECT_EQ(movz->Rd(), 17);
334-
uint64_t target = movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
335-
instr = movz->NextInstruction();
334+
uint64_t target = (uint64_t)movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
335+
instr = movz->GetNextInstruction();
336336
while (instr->IsMovk()) {
337337
EXPECT_EQ(instr->Rd(), 17);
338-
target |= instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
339-
instr = instr->NextInstruction();
338+
target |= (uint64_t)instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
339+
instr = instr->GetNextInstruction();
340340
}
341341
EXPECT_EQ(Instruction::Cast(target), Instruction::Cast(end + 8));
342342
}
@@ -367,27 +367,27 @@ TEST(Relocation, RelocateInternalAdjustedMovzMovk) {
367367

368368
MacroAssembler a { main };
369369
meta.addressImmediates.insert(main.frontier());
370-
a.Mov(x17, start + (2 << 20) + 16);
370+
a.Mov(x17, reinterpret_cast<uint64_t>(start + (2 << 20) + 16));
371371
main.setFrontier(start + (4 << 20) + 32);
372372

373373
auto end = main.frontier();
374374

375375
// 3. Call relocate()
376376
RelocationInfo rel;
377377
AreaIndex ai = AreaIndex::Main;
378-
auto instr = Instruction::Cast(end);
378+
const Instruction* instr = Instruction::Cast(end);
379379
relocate(rel, main, start, end, main, meta, nullptr, ai);
380380

381381
// 4. Expect movz/movk of new target
382382
auto movz = instr;
383383
EXPECT_TRUE(movz->IsMovz());
384384
EXPECT_EQ(movz->Rd(), 17);
385-
uint64_t target = movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
386-
instr = movz->NextInstruction();
385+
uint64_t target = (uint64_t)movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
386+
instr = movz->GetNextInstruction();
387387
while (instr->IsMovk()) {
388388
EXPECT_EQ(instr->Rd(), 17);
389-
target |= instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
390-
instr = instr->NextInstruction();
389+
target |= (uint64_t)instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
390+
instr = instr->GetNextInstruction();
391391
}
392392
EXPECT_EQ(Instruction::Cast(target), Instruction::Cast(end + (2 << 20) + 16));
393393
}
@@ -416,7 +416,7 @@ TEST(Relocation, AdjustMovzMovk) {
416416

417417
MacroAssembler a { main };
418418
meta.addressImmediates.insert(main.frontier());
419-
a.Mov(x17, orig + (2 << 20) + 16);
419+
a.Mov(x17, reinterpret_cast<uint64_t>(orig + (2 << 20) + 16));
420420
main.setFrontier(orig + (2 << 20) + 16);
421421

422422
auto start = main.frontier();
@@ -433,12 +433,12 @@ TEST(Relocation, AdjustMovzMovk) {
433433
auto movz = Instruction::Cast(orig);
434434
EXPECT_TRUE(movz->IsMovz());
435435
EXPECT_EQ(movz->Rd(), 17);
436-
uint64_t target = movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
437-
auto instr = movz->NextInstruction();
436+
uint64_t target = (uint64_t)movz->ImmMoveWide() << (16 * movz->ShiftMoveWide());
437+
auto instr = movz->GetNextInstruction();
438438
while (instr->IsMovk()) {
439439
EXPECT_EQ(instr->Rd(), 17);
440-
target |= instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
441-
instr = instr->NextInstruction();
440+
target |= (uint64_t)instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
441+
instr = instr->GetNextInstruction();
442442
}
443443
EXPECT_EQ(Instruction::Cast(target), Instruction::Cast(end));
444444
}

hphp/runtime/vm/jit/abi-arm.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,11 @@ PhysReg rret_simd(size_t i) {
190190

191191
PhysReg rarg(size_t i) {
192192
assertx(i < num_arg_regs());
193-
return vixl::Register::XRegFromCode(i);
193+
return vixl::XRegister(i);
194194
}
195195
PhysReg rarg_simd(size_t i) {
196196
assertx(i < num_arg_regs_simd());
197-
return vixl::FPRegister::DRegFromCode(i);
197+
return vixl::DRegister(i);
198198
}
199199
PhysReg rarg_ind_ret(size_t i) {
200200
assertx(i < num_arg_regs_ind_ret());

hphp/runtime/vm/jit/abi-arm.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818

1919
#include "hphp/runtime/vm/jit/abi-regs.h"
2020
#include "hphp/runtime/vm/jit/phys-reg.h"
21+
#include "hphp/runtime/vm/jit/types.h"
2122

2223
#include "hphp/util/asm-x64.h"
23-
#include "hphp/vixl/a64/assembler-a64.h"
24-
#include "hphp/vixl/a64/constants-a64.h"
24+
#include "hphp/vixl/hphp-compat.h"
2525

2626
namespace HPHP::jit {
2727

@@ -90,15 +90,17 @@ inline vixl::Register x2a(PhysReg x64reg) {
9090
return vixl::Register(vixl::CPURegister(x64reg));
9191
}
9292

93-
inline vixl::FPRegister x2f(PhysReg x64reg) {
93+
inline vixl::VRegister x2f(PhysReg x64reg) {
9494
always_assert(x64reg.isSIMD());
95-
return vixl::FPRegister(vixl::CPURegister(x64reg));
95+
return vixl::VRegister(vixl::CPURegister(x64reg));
9696
}
9797

9898
inline vixl::VRegister x2v(PhysReg x64reg) {
9999
always_assert(x64reg.isSIMD());
100100
auto const r = vixl::CPURegister(x64reg);
101-
return vixl::VRegister(r.code(), 128);
101+
// Use .16b (16 lanes of bytes) format for 128-bit vector operations.
102+
// The new VIXL requires an explicit lane count for ld1/st1 encoding.
103+
return vixl::VRegister(r.code(), 128, 16);
102104
}
103105

104106
/*

hphp/runtime/vm/jit/align-arm.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "hphp/runtime/vm/jit/smashable-instr-arm.h"
2121

2222
#include "hphp/util/data-block.h"
23-
#include "hphp/vixl/a64/macro-assembler-a64.h"
23+
#include "hphp/vixl/hphp-compat.h"
2424

2525
#include <folly/Bits.h>
2626

hphp/runtime/vm/jit/phys-reg.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
#include "hphp/util/arch.h"
2424
#include "hphp/util/asm-x64.h"
25-
#include "hphp/vixl/a64/macro-assembler-a64.h"
25+
#include "hphp/vixl/hphp-compat.h"
2626

2727
namespace HPHP::jit {
2828

@@ -48,7 +48,7 @@ std::string show(PhysReg r) {
4848

4949
return folly::to<std::string>(
5050
r.isGP() ? (vixl::Register(r).size() == vixl::kXRegSize ? 'x' : 'w')
51-
: (vixl::FPRegister(r).size() == vixl::kSRegSize ? 's' : 'd'),
51+
: (vixl::VRegister(r).size() == vixl::kSRegSize ? 's' : 'd'),
5252
((vixl::CPURegister)r).code()
5353
);
5454
}

hphp/runtime/vm/jit/phys-reg.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
#include "hphp/util/asm-x64.h"
2020
#include "hphp/util/bitops.h"
21-
#include "hphp/vixl/a64/assembler-a64.h"
21+
#include "hphp/vixl/hphp-compat.h"
2222

2323
#include <type_traits>
2424

@@ -39,17 +39,26 @@ struct Vout;
3939
struct PhysReg {
4040
private:
4141
static constexpr auto kGPOffset = 0;
42-
static constexpr auto kNumGP = 48;
4342

44-
static constexpr auto kSIMDOffset = kNumGP;
43+
#ifdef __aarch64__
44+
// Arm64 VIXL uses number 63 to represent SP internally, so
45+
// kNumGP must be >= 64 for Arm64.
46+
static constexpr auto kNumGP = 64;
47+
static constexpr auto kNumSIMD = 48;
48+
#else
49+
// TODO: Eventually, we should move to arm64 kNumGP and kNumSIMD
50+
// for platform parity.
51+
static constexpr auto kNumGP = 48;
4552
static constexpr auto kNumSIMD = 64;
53+
#endif
4654

55+
static constexpr auto kSIMDOffset = kNumGP;
4756
static constexpr auto kSFOffset = kNumGP + kNumSIMD;
4857
static constexpr auto kNumSF = 1;
4958

5059
public:
5160
/*
52-
* 48 GP regs + 64 SIMD regs + 1 SF reg + 15 empty == 128 regs.
61+
* 64 GP regs + 48 SIMD regs + 1 SF reg + 15 empty == 128 regs.
5362
*
5463
* We can toggle these values, but they need sum to 128 so that RegSet can
5564
* fit into two registers.
@@ -70,7 +79,7 @@ struct PhysReg {
7079
explicit constexpr PhysReg(Reg8 r) : n(int(r)) {}
7180

7281
constexpr /* implicit */ PhysReg(vixl::Register r) : n(r.code()) {}
73-
constexpr /* implicit */ PhysReg(vixl::FPRegister r)
82+
constexpr /* implicit */ PhysReg(vixl::VRegister r)
7483
: n(r.code() + kSIMDOffset) {}
7584

7685
/* implicit */ operator Reg64() const {
@@ -95,7 +104,7 @@ struct PhysReg {
95104
vixl::CPURegister::kRegister);
96105
} else if (isSIMD()) {
97106
return vixl::CPURegister(n - kSIMDOffset, vixl::kDRegSize,
98-
vixl::CPURegister::kFPRegister);
107+
vixl::CPURegister::kVRegister);
99108
} else {
100109
assertx(isSF());
101110
return vixl::NoCPUReg;
@@ -111,6 +120,10 @@ struct PhysReg {
111120
}
112121
bool isGP() const {
113122
static_assert(kGPOffset == 0, "kGPOffset is expected to be zero.");
123+
#if defined(__aarch64__)
124+
if (n == vixl::kSPRegInternalCode) return true;
125+
if (n > vixl::kSpRegCode && n < vixl::kSPRegInternalCode) return false;
126+
#endif
114127
return n < kGPOffset+numGP();
115128
}
116129
bool isSIMD() const { return n >= kSIMDOffset && n < kSIMDOffset+numSIMD(); }

0 commit comments

Comments
 (0)