diff --git a/llvm/include/llvm/MC/MCFragment.h b/llvm/include/llvm/MC/MCFragment.h --- a/llvm/include/llvm/MC/MCFragment.h +++ b/llvm/include/llvm/MC/MCFragment.h @@ -69,6 +69,10 @@ /// Whether fragment is being laid out. bool IsBeingLaidOut; + /// SubsectionNumber - the subsection this fragment belongs to. This is 0 if + // the fragment is not in any subsection + unsigned SubsectionNumber = 0; + protected: bool HasInstructions; @@ -102,6 +106,9 @@ bool hasInstructions() const { return HasInstructions; } void dump() const; + + void setSubsectionNumber(unsigned Value) { SubsectionNumber = Value; } + unsigned getSubsectionNumber() const { return SubsectionNumber; } }; class MCDummyFragment : public MCFragment { diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -579,12 +579,7 @@ if (!Asm->getWriter().isSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet)) return; - MCFragment *FA = SA.getFragment(); - MCFragment *FB = SB.getFragment(); - if (FA == FB && !SA.isVariable() && !SA.isUnset() && !SB.isVariable() && - !SB.isUnset()) { - Addend += (SA.getOffset() - SB.getOffset()); - + auto FinalizeFolding = [&]() { // Pointers to Thumb symbols need to have their low-bit set to allow // for interworking. if (Asm->isThumbFunc(&SA)) @@ -598,11 +593,18 @@ // Clear the symbol expr pointers to indicate we have folded these // operands. A = B = nullptr; - return; - } + }; - if (!Layout) + const MCFragment *FA = SA.getFragment(); + const MCFragment *FB = SB.getFragment(); + // If both symbols are in the same fragment, return the difference of their + // offsets + if (FA == FB && !SA.isVariable() && !SA.isUnset() && !SB.isVariable() && + !SB.isUnset()) { + Addend += (SA.getOffset() - SB.getOffset()); + FinalizeFolding(); return; + } const MCSection &SecA = *FA->getParent(); const MCSection &SecB = *FB->getParent(); @@ -610,30 +612,45 @@ if ((&SecA != &SecB) && !Addrs) return; - // One of the symbol involved is part of a fragment being laid out. Quit now - // to avoid a self loop. - if (!Layout->canGetFragmentOffset(FA) || !Layout->canGetFragmentOffset(FB)) - return; + // When layout is not finalized, our ability to resolve differences between + // symbols is limited to specific cases where the fragments between two + // symbols (including the fragments the symbols are defined in) are fixed-size + // fragments so the difference can be calculated. For example, this is + // important when the Subtarget is changed and a new MCDataFragment is created + // in the case of foo: instr; .arch_extension ext; instr .if . - foo + if (!Layout) { + if (SA.isVariable() || SA.isUnset() || SB.isVariable() || SB.isUnset() || + FA->getKind() != MCFragment::FT_Data || + FB->getKind() != MCFragment::FT_Data || + FA->getSubsectionNumber() != FB->getSubsectionNumber()) + return; + int64_t Offset = 0; + for (auto FI = FB->getIterator(), FE = SecA.end(); FI != FE; ++FI) { + if (&*FI == FA) { + Addend += Offset + (SA.getOffset() - SB.getOffset()); + FinalizeFolding(); + return; + } - // Eagerly evaluate. - Addend += Layout->getSymbolOffset(A->getSymbol()) - - Layout->getSymbolOffset(B->getSymbol()); - if (Addrs && (&SecA != &SecB)) - Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB)); - - // Pointers to Thumb symbols need to have their low-bit set to allow - // for interworking. - if (Asm->isThumbFunc(&SA)) - Addend |= 1; - - // If symbol is labeled as micromips, we set low-bit to ensure - // correct offset in .gcc_except_table - if (Asm->getBackend().isMicroMips(&SA)) - Addend |= 1; - - // Clear the symbol expr pointers to indicate we have folded these - // operands. - A = B = nullptr; + if (FI->getKind() == MCFragment::FT_Data) + Offset += (cast(FI))->getContents().size(); + else + return; + } + } else { + // One of the symbol involved is part of a fragment being laid out. Quit now + // to avoid a self loop. + if (!Layout->canGetFragmentOffset(FA) || !Layout->canGetFragmentOffset(FB)) + return; + + // Eagerly evaluate when layout is finazlied + Addend += Layout->getSymbolOffset(A->getSymbol()) - + Layout->getSymbolOffset(B->getSymbol()); + if (Addrs && (&SecA != &SecB)) + Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB)); + + FinalizeFolding(); + } } static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A, diff --git a/llvm/test/MC/ARM/directive_if_offset.s b/llvm/test/MC/ARM/directive_if_offset.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ARM/directive_if_offset.s @@ -0,0 +1,14 @@ +@ RUN: llvm-mc -triple armv7a-linux-gnueabihf %s -filetype=obj -o /dev/null 2>&1 | FileCheck --allow-empty %s +@ RUN: llvm-mc -triple armv7a-linux-gnueabihf %s -filetype=obj -o %t | llvm-objdump -d %t | FileCheck --check-prefix=CHECK-ASM %s + +nop +// Create a new MCDataFragment due to Subtarget change +.arch_extension sec +9997:nop +.if . - 9997b == 0 +// CHECK-NOT: error: expected absolute expression +orr r1, r1, #1 +.else +orr r1, r1, #2 +.endif +// CHECK-ASM: orr r1, r1, #2 diff --git a/llvm/test/MC/ARM/directive_if_offset_error.s b/llvm/test/MC/ARM/directive_if_offset_error.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ARM/directive_if_offset_error.s @@ -0,0 +1,23 @@ +@ RUN: not llvm-mc -filetype=obj -triple arm-linux-gnueabihf %s -o /dev/null 2>&1 | FileCheck %s + +9997: nop + .align 4 + nop +.if . - 9997b == 4 +// CHECK: error: expected absolute expression +.endif + +9997: nop + .space 4 + nop +.if . - 9997b == 4 +// CHECK: error: expected absolute expression +.endif + +9997: + ldr r0,=0x12345678 + .ltorg + nop +.if . - 9997b == 4 +// CHECK: error: expected absolute expression +.endif diff --git a/llvm/test/MC/ARM/thumb2_directive_if_offset_error.s b/llvm/test/MC/ARM/thumb2_directive_if_offset_error.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ARM/thumb2_directive_if_offset_error.s @@ -0,0 +1,8 @@ +@ RUN: not llvm-mc -filetype=obj -triple thumbv7a-linux-gnueabihf %s -o /dev/null 2>&1 | FileCheck %s + +9997: nop + b external + nop +.if . - 9997b == 4 +// CHECK: error: expected absolute expression +.endif diff --git a/llvm/test/MC/ELF/subsection.s b/llvm/test/MC/ELF/subsection.s --- a/llvm/test/MC/ELF/subsection.s +++ b/llvm/test/MC/ELF/subsection.s @@ -12,7 +12,7 @@ // CHECK-NOT: Contents of section .rela.text: // CHECK: Contents of section .data: -// CHECK-NEXT: 0000 01030402 74657374 +// CHECK-NEXT: 0000 01010402 74657374 .data l0: .byte 1 diff --git a/llvm/test/MC/MachO/reloc-diff.s b/llvm/test/MC/MachO/reloc-diff.s --- a/llvm/test/MC/MachO/reloc-diff.s +++ b/llvm/test/MC/MachO/reloc-diff.s @@ -22,9 +22,5 @@ // CHECK-NEXT: 0x0 0 2 n/a GENERIC_RELOC_PAIR 1 0x0 // CHECK-NEXT: 0x8 0 2 n/a GENERIC_RELOC_LOCAL_SECTDIFF 1 0x0 // CHECK-NEXT: 0x0 0 2 n/a GENERIC_RELOC_PAIR 1 0x0 -// CHECK-NEXT: 0x4 0 2 n/a GENERIC_RELOC_LOCAL_SECTDIFF 1 0x0 -// CHECK-NEXT: 0x0 0 2 n/a GENERIC_RELOC_PAIR 1 0x0 -// CHECK-NEXT: 0x0 0 2 n/a GENERIC_RELOC_SECTDIFF 1 0x0 -// CHECK-NEXT: 0x0 0 2 n/a GENERIC_RELOC_PAIR 1 0x0 // CHECK-NEXT: } // CHECK-NEXT: ]