Index: llvm/trunk/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ llvm/trunk/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) { - // 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; - } + 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(), - "resolvable R_AARCH64_MOVW_SABS_G* fixups are not " - "yet implemented"); + "relocation for a thread-local variable points to an " + "absolute symbol"); return Value; } + if (!IsResolved) { // FIXME: Figure out when this can actually happen, and verify our // behavior. @@ -239,25 +235,57 @@ "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 (AArch64MCExpr::getSymbolLoc(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) + + if (RefKind & AArch64MCExpr::VK_NC) { Value &= 0xFFFF; - else if (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 +364,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 +393,19 @@ Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff); } } + + // FIXME: getFixupKindInfo() and getFixupKindNumBytes() could be fixed to + // handle this more cleanly. This may affect the output of -show-mc-encoding. + AArch64MCExpr::VariantKind RefKind = + static_cast(Target.getRefKind()); + if (RefKind & AArch64MCExpr::VK_SABS) { + // If the immediate is negative, generate MOVN else MOVZ. + // (Bit 30 = 0) ==> MOVN, (Bit 30 = 1) ==> MOVZ. + if (SignedValue < 0) + Data[Offset + 3] &= ~(1 << 6); + else + Data[Offset + 3] |= (1 << 6); + } } bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst, Index: llvm/trunk/test/MC/AArch64/fixup-absolute-signed.s =================================================================== --- llvm/trunk/test/MC/AArch64/fixup-absolute-signed.s +++ llvm/trunk/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, #12345 +// CHECK: mov x0, #12345 +movn x0, #:abs_g0_s:onepart_before +movn x0, #:abs_g0_s:onepart_after + +onepart_after = 12345 +twopart_after = -12345678 +threepart_after = -1234567890 Index: llvm/trunk/test/MC/AArch64/fixup-out-of-range.s =================================================================== --- llvm/trunk/test/MC/AArch64/fixup-out-of-range.s +++ llvm/trunk/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