Skip to content

Commit 4943a29

Browse files
mcfifacebook-github-bot
authored andcommitted
Use a single ldr to load a large immediate in lieu of multiple movz/movk instructions
Summary: On Arm64, we may need up to 4 movz/movk instructions to load a 64-bit immediate to a GP register, which may contribute to some non-trivial portion in code size. To reduce the code size, this diff puts an immediate in literal pool and emits a single ldr instruction to load from memory. Differential Revision: D91732849
1 parent 9f0e9f6 commit 4943a29

File tree

5 files changed

+51
-25
lines changed

5 files changed

+51
-25
lines changed

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

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ bool flagRequired(Vflags flags, StatusFlags flag) {
209209
struct Vgen {
210210
explicit Vgen(Venv& env)
211211
: env(env)
212-
, assem(*env.cb)
212+
, assem(*env.cb, &env.meta)
213213
, a(&assem)
214214
, base(a->frontier())
215215
, current(env.current)
@@ -799,11 +799,18 @@ void Vgen::emit(const fallthru& /*i*/) {
799799

800800
#define Y(vasm_opc, simd_w, vr_w, gpr_w, imm) \
801801
void Vgen::emit(const vasm_opc& i) { \
802+
vixl::Label data; \
802803
if (i.d.isSIMD()) { \
803804
emitSimdImmInt(a, static_cast<uint##vr_w##_t>(i.s.simd_w()), i.d); \
804805
} else { \
805806
Vreg##vr_w d = i.d; \
806-
a->Mov(gpr_w(d), imm); \
807+
if constexpr(vr_w > 16) { \
808+
poolLiteral(*env.cb, env.meta, imm, vr_w, false); \
809+
a->bind(&data); \
810+
a->Ldr(gpr_w(d), &data); \
811+
} else { \
812+
a->Mov(gpr_w(d), imm); \
813+
} \
807814
} \
808815
}
809816

@@ -857,9 +864,13 @@ void Vgen::emit(const mcprep& i) {
857864
///////////////////////////////////////////////////////////////////////////////
858865

859866
void Vgen::emit(const call& i) {
867+
vixl::Label data;
860868
if (!i.stackUnaligned) trap_unaligned_stack();
861869
recordAddressImmediate();
862-
a->Mov(rAsm, i.target);
870+
871+
poolLiteral(*env.cb, env.meta, (uint64_t)i.target, 32, false);
872+
a->bind(&data); // This will be remapped during the handleLiterals phase.
873+
a->Ldr(rAsm_w, &data);
863874
a->Blr(rAsm);
864875
if (i.watch) {
865876
*i.watch = a->frontier();
@@ -1135,7 +1146,6 @@ void Vgen::emit(const lea& i) {
11351146

11361147
void Vgen::emit(const leap& i) {
11371148
vixl::Label imm_data;
1138-
vixl::Label after_data;
11391149

11401150
// Cannot use simple a->Mov() since such a sequence cannot be
11411151
// adjusted while live following a relocation.
@@ -1147,8 +1157,12 @@ void Vgen::emit(const leap& i) {
11471157
}
11481158

11491159
void Vgen::emit(const lead& i) {
1160+
vixl::Label imm_data;
1161+
11501162
recordAddressImmediate();
1151-
a->Mov(X(i.d), i.s.get());
1163+
poolLiteral(*env.cb, env.meta, (uint64_t)i.s.get(), 32, false);
1164+
a->bind(&imm_data); // This will be remapped during the handleLiterals phase.
1165+
a->Ldr(W(i.d), &imm_data);
11521166
}
11531167

11541168
#define Y(vasm_opc, arm_opc, src_dst, m) \

hphp/vixl/a64/assembler-a64.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,9 @@ bool MemOperand::IsPostIndex() const {
347347

348348

349349
// Assembler
350-
Assembler::Assembler(HPHP::CodeBlock& cb)
350+
Assembler::Assembler(HPHP::CodeBlock& cb, HPHP::jit::CGMeta* meta)
351351
: cb_(cb)
352+
, meta_(meta)
352353
, next_literal_pool_check_(cb.frontier() + kLiteralPoolCheckInterval)
353354
, literal_pool_monitor_(0) {
354355
// Assert that this is an LP64 system.

hphp/vixl/a64/assembler-a64.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include "hphp/util/data-block.h"
3131
#include "hphp/runtime/vm/jit/types.h"
32+
#include "hphp/runtime/vm/jit/cg-meta.h"
3233

3334
#include "hphp/vixl/globals.h"
3435
#include "hphp/vixl/utils.h"
@@ -614,7 +615,7 @@ class Literal {
614615
// Assembler.
615616
class Assembler {
616617
public:
617-
explicit Assembler(HPHP::CodeBlock& cb);
618+
explicit Assembler(HPHP::CodeBlock& cb, HPHP::jit::CGMeta* meta = nullptr);
618619

619620
// The destructor asserts that one of the following is true:
620621
// * The Assembler object has not been used.
@@ -646,6 +647,8 @@ class Assembler {
646647

647648
HPHP::CodeBlock& code() const { return cb_; }
648649

650+
HPHP::jit::CGMeta* meta() const { return meta_; }
651+
649652
HPHP::jit::TCA base() const { return cb_.base(); }
650653

651654
HPHP::jit::TCA frontier() const {
@@ -1679,7 +1682,7 @@ class Assembler {
16791682
}
16801683

16811684
void CheckLiteralPool(LiteralPoolEmitOption option = JumpRequired);
1682-
void EmitLiteralPool(LiteralPoolEmitOption option = NoJumpRequired);
1685+
void EmitLiteralPool(LiteralPoolEmitOption option = JumpRequired);
16831686
size_t LiteralPoolSize();
16841687

16851688
static bool IsImmLogical(uint64_t value, unsigned width) {
@@ -1860,7 +1863,7 @@ class Assembler {
18601863

18611864
// The buffer into which code and relocation info are generated.
18621865
HPHP::CodeBlock& cb_;
1863-
1866+
HPHP::jit::CGMeta* meta_;
18641867
std::list<Literal*> literals_;
18651868
HPHP::CodeAddress next_literal_pool_check_;
18661869
unsigned literal_pool_monitor_;

hphp/vixl/a64/macro-assembler-a64.cc

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -277,26 +277,35 @@ void MacroAssembler::Mov(const Register& rd, uint64_t imm) {
277277
Register temp = rd.IsSP() ? AppropriateTempFor(rd) : rd;
278278

279279
assert((reg_size % 16) == 0);
280-
bool first_mov_done = false;
281-
for (unsigned i = 0; i < (reg_size / 16); i++) {
282-
uint64_t imm16 = (imm >> (16 * i)) & 0xffffL;
283-
if (imm16 != 0) {
284-
if (!first_mov_done) {
285-
// Move the first non-zero 16-bit chunk into the destination register.
286-
movz(temp, imm16, 16 * i);
287-
first_mov_done = true;
288-
} else {
289-
// Construct a wider constant.
290-
movk(temp, imm16, 16 * i);
280+
281+
if (meta() == nullptr) {
282+
bool first_mov_done = false;
283+
for (unsigned i = 0; i < (reg_size / 16); i++) {
284+
uint64_t imm16 = (imm >> (16 * i)) & 0xffffL;
285+
if (imm16 != 0) {
286+
if (!first_mov_done) {
287+
// Move the first non-zero 16-bit chunk into the destination register.
288+
movz(temp, imm16, 16 * i);
289+
first_mov_done = true;
290+
} else {
291+
// Construct a wider constant.
292+
movk(temp, imm16, 16 * i);
293+
}
291294
}
292295
}
296+
assert(first_mov_done);
297+
__builtin_debugtrap();
298+
} else {
299+
Label data;
300+
meta()->addressImmediates.insert(code().frontier());
301+
poolLiteral(code(), *meta(), imm, 64, false);
302+
bind(&data);
303+
Ldr(rd, &data);
293304
}
294305

295306
if (rd.IsSP()) {
296307
mov(rd, temp);
297308
}
298-
299-
assert(first_mov_done);
300309
}
301310
}
302311

hphp/vixl/a64/macro-assembler-a64.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
#include "hphp/vixl/a64/assembler-a64.h"
3030
#include "hphp/vixl/a64/debugger-a64.h"
3131

32-
3332
#define LS_MACRO_LIST(V) \
3433
V(Ldrb, Register&, rt, LDRB_w) \
3534
V(Strb, Register&, rt, STRB_w) \
@@ -45,8 +44,8 @@ namespace vixl {
4544

4645
class MacroAssembler : public Assembler {
4746
public:
48-
explicit MacroAssembler(HPHP::CodeBlock& cb)
49-
: Assembler(cb),
47+
explicit MacroAssembler(HPHP::CodeBlock& cb, HPHP::jit::CGMeta* meta = nullptr)
48+
: Assembler(cb, meta),
5049
#ifndef NDEBUG
5150
allow_macro_instructions_(true),
5251
#endif

0 commit comments

Comments
 (0)