Skip to content

Commit b5588ce

Browse files
authored
[LLD][MachO][NFC] Refactor LOH code (#141153)
In `applyAdrpAddLdr()` we make a transformation that is identical to the one in `applyAdrpAdd()`, so lets reuse that code. Also refactor `forEachHint()` to use more `ArrayRef` and move around some lines for consistancy.
1 parent 344f594 commit b5588ce

File tree

1 file changed

+27
-62
lines changed

1 file changed

+27
-62
lines changed

lld/MachO/Arch/ARM64.cpp

Lines changed: 27 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -392,25 +392,26 @@ static void writeImmediateLdr(void *loc, const Ldr &ldr) {
392392
// ->
393393
// adr xM, _foo
394394
// nop
395-
static void applyAdrpAdd(uint8_t *buf, const ConcatInputSection *isec,
395+
static bool applyAdrpAdd(uint8_t *buf, const ConcatInputSection *isec,
396396
uint64_t offset1, uint64_t offset2) {
397397
uint32_t ins1 = read32le(buf + offset1);
398398
uint32_t ins2 = read32le(buf + offset2);
399399
Adrp adrp;
400400
Add add;
401401
if (!parseAdrp(ins1, adrp) || !parseAdd(ins2, add))
402-
return;
402+
return false;
403403
if (adrp.destRegister != add.srcRegister)
404-
return;
404+
return false;
405405

406406
uint64_t addr1 = isec->getVA() + offset1;
407407
uint64_t referent = pageBits(addr1) + adrp.addend + add.addend;
408408
int64_t delta = referent - addr1;
409409
if (!isValidAdrOffset(delta))
410-
return;
410+
return false;
411411

412412
writeAdr(buf + offset1, add.destRegister, delta);
413413
writeNop(buf + offset2);
414+
return true;
414415
}
415416

416417
// Transforms two adrp instructions into a single adrp if their referent
@@ -495,16 +496,12 @@ static void applyAdrpAddLdr(uint8_t *buf, const ConcatInputSection *isec,
495496
uint64_t offset1, uint64_t offset2,
496497
uint64_t offset3) {
497498
uint32_t ins1 = read32le(buf + offset1);
498-
Adrp adrp;
499-
if (!parseAdrp(ins1, adrp))
500-
return;
501499
uint32_t ins2 = read32le(buf + offset2);
502-
Add add;
503-
if (!parseAdd(ins2, add))
504-
return;
505500
uint32_t ins3 = read32le(buf + offset3);
501+
Adrp adrp;
502+
Add add;
506503
Ldr ldr;
507-
if (!parseLdr(ins3, ldr))
504+
if (!parseAdrp(ins1, adrp) || !parseAdd(ins2, add) || !parseLdr(ins3, ldr))
508505
return;
509506
if (adrp.destRegister != add.srcRegister)
510507
return;
@@ -527,18 +524,8 @@ static void applyAdrpAddLdr(uint8_t *buf, const ConcatInputSection *isec,
527524
return;
528525
}
529526

530-
// Load the target address into a register and load from there indirectly.
531-
// adr x1, _foo
532-
// nop
533-
// ldr x2, [x1, #off]
534-
int64_t adrOffset = referent - addr1;
535-
if (isValidAdrOffset(adrOffset)) {
536-
writeAdr(buf + offset1, ldr.baseRegister, adrOffset);
537-
// Note: ld64 moves the offset into the adr instruction for AdrpAddLdr, but
538-
// not for AdrpLdrGotLdr. Its effect is the same either way.
539-
writeNop(buf + offset2);
527+
if (applyAdrpAdd(buf, isec, offset1, offset2))
540528
return;
541-
}
542529

543530
// Move the target's page offset into the ldr's immediate offset.
544531
// adrp x0, _foo@PAGE
@@ -572,67 +559,45 @@ static void applyAdrpLdrGotLdr(uint8_t *buf, const ConcatInputSection *isec,
572559
// adrp x1, _foo@GOTPAGE
573560
// ldr x2, [x1, _foo@GOTPAGEOFF]
574561
// ldr x3, [x2, #off]
575-
576-
uint32_t ins1 = read32le(buf + offset1);
577-
Adrp adrp;
578-
if (!parseAdrp(ins1, adrp))
579-
return;
580562
uint32_t ins3 = read32le(buf + offset3);
581563
Ldr ldr3;
582564
if (!parseLdr(ins3, ldr3))
583565
return;
584-
585-
if (ldr2.baseRegister != adrp.destRegister)
586-
return;
587566
if (ldr3.baseRegister != ldr2.destRegister)
588567
return;
589568
// Loads from the GOT must be pointer sized.
590569
if (ldr2.p2Size != 3 || ldr2.isFloat)
591570
return;
592-
593-
uint64_t addr1 = isec->getVA() + offset1;
594-
uint64_t addr2 = isec->getVA() + offset2;
595-
uint64_t referent = pageBits(addr1) + adrp.addend + ldr2.offset;
596-
// Load the GOT entry's address directly.
597-
// nop
598-
// ldr x2, _foo@GOTPAGE + _foo@GOTPAGEOFF
599-
// ldr x3, [x2, #off]
600-
Ldr literalLdr = ldr2;
601-
literalLdr.offset = referent - addr2;
602-
if (isLiteralLdrEligible(literalLdr)) {
603-
writeNop(buf + offset1);
604-
writeLiteralLdr(buf + offset2, literalLdr);
605-
}
571+
applyAdrpLdr(buf, isec, offset1, offset2);
606572
}
607573
}
608574

609-
static uint64_t readValue(const uint8_t *&ptr, const uint8_t *end) {
610-
unsigned int n = 0;
611-
uint64_t value = decodeULEB128(ptr, &n, end);
612-
ptr += n;
613-
return value;
614-
}
615-
616575
template <typename Callback>
617576
static void forEachHint(ArrayRef<uint8_t> data, Callback callback) {
618577
std::array<uint64_t, 3> args;
619578

620-
for (const uint8_t *p = data.begin(), *end = data.end(); p < end;) {
621-
uint64_t type = readValue(p, end);
579+
auto readNext = [&]() -> uint64_t {
580+
unsigned int n = 0;
581+
uint64_t value = decodeULEB128(data.data(), &n, data.end());
582+
data = data.drop_front(n);
583+
return value;
584+
};
585+
586+
while (!data.empty()) {
587+
uint64_t type = readNext();
622588
if (type == 0)
623589
break;
624590

625-
uint64_t argCount = readValue(p, end);
591+
uint64_t argCount = readNext();
592+
for (unsigned i = 0; i < argCount; ++i) {
593+
uint64_t arg = readNext();
594+
if (i < 3)
595+
args[i] = arg;
596+
}
626597
// All known LOH types as of 2022-09 have 3 or fewer arguments; skip others.
627-
if (argCount > 3) {
628-
for (unsigned i = 0; i < argCount; ++i)
629-
readValue(p, end);
598+
if (argCount > 3)
630599
continue;
631-
}
632-
633-
for (unsigned i = 0; i < argCount; ++i)
634-
args[i] = readValue(p, end);
635-
callback(type, ArrayRef<uint64_t>(args.data(), argCount));
600+
callback(type, ArrayRef(args.data(), argCount));
636601
}
637602
}
638603

0 commit comments

Comments
 (0)