Index: lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -218,20 +218,16 @@ case AArch64::fixup_aarch64_movw: { AArch64MCExpr::VariantKind RefKind = static_cast(Target.getRefKind()); - if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_ABS) { - if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_SABS) { + if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_ABS && + AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_SABS) { // VK_GOTTPREL, VK_TPREL, VK_DTPREL are movw fixups, but they can't // ever be resolved in the assembler. Ctx.reportError(Fixup.getLoc(), "relocation for a thread-local variable points to an " "absolute symbol"); return Value; - } - Ctx.reportError(Fixup.getLoc(), - "resolvable R_AARCH64_MOVW_SABS_G* fixups are not " - "yet implemented"); - return Value; } + if (!IsResolved) { // FIXME: Figure out when this can actually happen, and verify our // behavior. @@ -239,25 +235,56 @@ "implemented"); return Value; } - switch (AArch64MCExpr::getAddressFrag(RefKind)) { - case AArch64MCExpr::VK_G0: - break; - case AArch64MCExpr::VK_G1: - Value = Value >> 16; - break; - case AArch64MCExpr::VK_G2: - Value = Value >> 32; - break; - case AArch64MCExpr::VK_G3: - Value = Value >> 48; - break; - default: - llvm_unreachable("Variant kind doesn't correspond to fixup"); + + if (RefKind & AArch64MCExpr::VK_SABS) { + switch (AArch64MCExpr::getAddressFrag(RefKind)) { + case AArch64MCExpr::VK_G0: + break; + case AArch64MCExpr::VK_G1: + SignedValue = SignedValue >> 16; + break; + case AArch64MCExpr::VK_G2: + SignedValue = SignedValue >> 32; + break; + case AArch64MCExpr::VK_G3: + SignedValue = SignedValue >> 48; + break; + default: + llvm_unreachable("Variant kind doesn't correspond to fixup"); + } + + } else { + switch (AArch64MCExpr::getAddressFrag(RefKind)) { + case AArch64MCExpr::VK_G0: + break; + case AArch64MCExpr::VK_G1: + Value = Value >> 16; + break; + case AArch64MCExpr::VK_G2: + Value = Value >> 32; + break; + case AArch64MCExpr::VK_G3: + Value = Value >> 48; + break; + default: + llvm_unreachable("Variant kind doesn't correspond to fixup"); + } } + if (RefKind & AArch64MCExpr::VK_NC) Value &= 0xFFFF; + else if (RefKind & AArch64MCExpr::VK_SABS) { + if (SignedValue > 0xFFFF || SignedValue < -0xFFFF) + Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + + // Invert the negative immediate because it will feed into a MOVN. + if (SignedValue < 0) + SignedValue = ~SignedValue; + Value = static_cast(SignedValue); + } else if (Value > 0xFFFF) Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); + return Value; } case AArch64::fixup_aarch64_pcrel_branch14: @@ -336,6 +363,7 @@ return; // Doesn't change encoding. MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); MCContext &Ctx = Asm.getContext(); + int64_t SignedValue = static_cast(Value); // Apply any target-specific value adjustments. Value = adjustFixupValue(Fixup, Target, Value, Ctx, TheTriple, IsResolved); @@ -364,6 +392,14 @@ Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff); } } + + AArch64MCExpr::VariantKind RefKind = + static_cast(Target.getRefKind()); + if (RefKind & AArch64MCExpr::VK_SABS && SignedValue < 0) { + // Generate a MOVN instead of MOVZ if the immediate is negative. + // For MOVZ, bit 30 is 1 and for MOVN it is 0. + Data[Offset + 3] &= ~(1 << 6); + } } bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst, Index: test/MC/AArch64/fixup-absolute-signed.s =================================================================== --- /dev/null +++ test/MC/AArch64/fixup-absolute-signed.s @@ -0,0 +1,44 @@ +// RUN: llvm-mc -triple aarch64--none-eabi -filetype obj < %s -o - | llvm-objdump -d - | FileCheck %s + +onepart_before = 12345 +twopart_before = -12345678 +threepart_before = -1234567890 + +// CHECK: movn x0, #0, lsl #32 +// CHECK: movn x0, #0, lsl #32 +movz x0, #:abs_g2_s:threepart_before +movz x0, #:abs_g2_s:threepart_after + +// CHECK: movk x0, #65535, lsl #32 +// CHECK: movk x0, #65535, lsl #32 +movk x0, #:abs_g2_nc:threepart_before +movk x0, #:abs_g2_nc:threepart_after + +// CHECK: mov x0, #-12320769 +// CHECK: mov x0, #-12320769 +movz x0, #:abs_g1_s:twopart_before +movz x0, #:abs_g1_s:twopart_after + +// CHECK: movk x0, #46697, lsl #16 +// CHECK: movk x0, #46697, lsl #16 +movk x0, #:abs_g1_nc:threepart_before +movk x0, #:abs_g1_nc:threepart_after + +// CHECK: mov x0, #12345 +// CHECK: mov x0, #12345 +movz x0, #:abs_g0_s:onepart_before +movz x0, #:abs_g0_s:onepart_after + +// CHECK: movk x0, #64814 +// CHECK: movk x0, #64814 +movk x0, #:abs_g0_nc:threepart_before +movk x0, #:abs_g0_nc:threepart_after + +// CHECK: mov x0, #-12346 +// CHECK: mov x0, #-12346 +movn x0, #:abs_g0_s:onepart_before +movn x0, #:abs_g0_s:onepart_after + +onepart_after = 12345 +twopart_after = -12345678 +threepart_after = -1234567890 Index: test/MC/AArch64/fixup-out-of-range.s =================================================================== --- test/MC/AArch64/fixup-out-of-range.s +++ test/MC/AArch64/fixup-out-of-range.s @@ -61,9 +61,12 @@ // CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range movz x0, #:abs_g1:value2 -// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: resolvable R_AARCH64_MOVW_SABS_G* fixups are not yet implemented +// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range movz x0, #:abs_g0_s:value1 +// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range + movz x0, #:abs_g1_s:value2 + // CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: relocation for a thread-local variable points to an absolute symbol movz x0, #:tprel_g0:value1