Skip to content

Commit bac905a

Browse files
mcfifacebook-github-bot
authored andcommitted
Use a single ldr to load a large immediate in lieu of multiple movz/movk instructions (facebook#9712)
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 a373fac commit bac905a

File tree

6 files changed

+57
-31
lines changed

6 files changed

+57
-31
lines changed

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

Lines changed: 24 additions & 11 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)
@@ -622,12 +622,11 @@ void Vgen::handleLiterals(Venv& env) {
622622
if (pl.width == 32) {
623623
cb->dword(static_cast<uint32_t>(pl.value));
624624
} else if (pl.width == 64) {
625-
if (pl.smashable) {
626-
// Although the region is actually dead, we mark it as live, so that
627-
// the relocator can remove the padding.
628-
align(*cb, &env.meta, Alignment::QuadWordSmashable, AlignContext::Live);
629-
literalAddress = cb->frontier();
630-
}
625+
// Although the region is actually dead, we mark it as live, so that
626+
// the relocator can remove the padding.
627+
align(*cb, &env.meta, Alignment::QuadWordSmashable,
628+
pl.smashable ? AlignContext::Live : AlignContext::Dead);
629+
literalAddress = cb->frontier();
631630
cb->qword(pl.value);
632631
} else {
633632
not_reached();
@@ -799,11 +798,18 @@ void Vgen::emit(const fallthru& /*i*/) {
799798

800799
#define Y(vasm_opc, simd_w, vr_w, gpr_w, imm) \
801800
void Vgen::emit(const vasm_opc& i) { \
801+
vixl::Label data; \
802802
if (i.d.isSIMD()) { \
803803
emitSimdImmInt(a, static_cast<uint##vr_w##_t>(i.s.simd_w()), i.d); \
804804
} else { \
805805
Vreg##vr_w d = i.d; \
806-
a->Mov(gpr_w(d), imm); \
806+
if constexpr(vr_w > 16) { \
807+
poolLiteral(*env.cb, env.meta, imm, vr_w, false); \
808+
a->bind(&data); \
809+
a->Ldr(gpr_w(d), &data); \
810+
} else { \
811+
a->Mov(gpr_w(d), imm); \
812+
} \
807813
} \
808814
}
809815

@@ -857,9 +863,13 @@ void Vgen::emit(const mcprep& i) {
857863
///////////////////////////////////////////////////////////////////////////////
858864

859865
void Vgen::emit(const call& i) {
866+
vixl::Label data;
860867
if (!i.stackUnaligned) trap_unaligned_stack();
861868
recordAddressImmediate();
862-
a->Mov(rAsm, i.target);
869+
870+
poolLiteral(*env.cb, env.meta, (uint64_t)i.target, 32, false);
871+
a->bind(&data); // This will be remapped during the handleLiterals phase.
872+
a->Ldr(rAsm_w, &data);
863873
a->Blr(rAsm);
864874
if (i.watch) {
865875
*i.watch = a->frontier();
@@ -1135,7 +1145,6 @@ void Vgen::emit(const lea& i) {
11351145

11361146
void Vgen::emit(const leap& i) {
11371147
vixl::Label imm_data;
1138-
vixl::Label after_data;
11391148

11401149
// Cannot use simple a->Mov() since such a sequence cannot be
11411150
// adjusted while live following a relocation.
@@ -1147,8 +1156,12 @@ void Vgen::emit(const leap& i) {
11471156
}
11481157

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

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

hphp/runtime/vm/jit/vasm-gen-inl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ TCA vwrap_impl(CodeBlock& main, CodeBlock& cold, DataBlock& data,
100100
if (!meta) {
101101
dummy_meta.addressImmediates.clear();
102102
dummy_meta.fallthru.reset();
103+
dummy_meta.alignments.clear();
103104
}
104105
assertx(dummy_meta.empty());
105106

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)