diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp --- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -361,9 +361,30 @@ return false; } } - bool isS16ImmX4() const { return Kind == Expression || - (Kind == Immediate && isInt<16>(getImm()) && - (getImm() & 3) == 0); } + + bool isS16ImmX4() const { + switch (Kind) { + case Expression: + return true; + case Immediate: + case ContextImmediate: + return isInt<16>(getImmS16Context()) && (getImmS16Context() & 3) == 0; + default: + return false; + } + } + + bool isS16ImmX16() const { + switch (Kind) { + case Expression: + return true; + case Immediate: + case ContextImmediate: + return isInt<16>(getImmS16Context()) && (getImmS16Context() & 15) == 0; + default: + return false; + } + } bool isHashImmX8() const { // The Hash Imm form is used for instructions that check or store a hash. @@ -373,9 +394,6 @@ (getImm() & 7) == 0); } - bool isS16ImmX16() const { return Kind == Expression || - (Kind == Immediate && isInt<16>(getImm()) && - (getImm() & 15) == 0); } bool isS34ImmX16() const { return Kind == Expression || (Kind == Immediate && isInt<34>(getImm()) && (getImm() & 15) == 0); diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -44,6 +44,7 @@ case PPC::fixup_ppc_half16: return Value & 0xffff; case PPC::fixup_ppc_half16ds: + case PPC::fixup_ppc_half16dq: return Value & 0xfffc; case PPC::fixup_ppc_pcrel34: case PPC::fixup_ppc_imm34: @@ -60,6 +61,7 @@ case FK_Data_2: case PPC::fixup_ppc_half16: case PPC::fixup_ppc_half16ds: + case PPC::fixup_ppc_half16dq: return 2; case FK_Data_4: case PPC::fixup_ppc_brcond14: diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp @@ -125,6 +125,7 @@ } break; case PPC::fixup_ppc_half16ds: + case PPC::fixup_ppc_half16dq: Target.print(errs()); errs() << '\n'; report_fatal_error("Invalid PC-relative half16ds relocation"); @@ -349,6 +350,7 @@ } break; case PPC::fixup_ppc_half16ds: + case PPC::fixup_ppc_half16dq: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h @@ -51,6 +51,10 @@ /// register number. fixup_ppc_nofixup, + /// A 16-bit fixup corresponding to lo16(_foo) with implied 3 zero bits for + /// instrs like 'lxv'. Produces the same relocation as fixup_ppc_half16ds. + fixup_ppc_half16dq, + // Marker LastTargetFixupKind, NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -198,8 +198,8 @@ } // Otherwise add a fixup for the displacement field. - Fixups.push_back(MCFixup::create(IsLittleEndian? 0 : 2, MO.getExpr(), - (MCFixupKind)PPC::fixup_ppc_half16ds)); + Fixups.push_back(MCFixup::create(IsLittleEndian ? 0 : 2, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_half16dq)); return RegBits; } diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp @@ -110,9 +110,19 @@ if (Value.isAbsolute()) { int64_t Result = evaluateAsInt64(Value.getConstant()); - if ((Fixup == nullptr || (unsigned)Fixup->getKind() != PPC::fixup_ppc_half16) && - (Result >= 0x8000)) + bool IsHalf16 = + Fixup && (unsigned)Fixup->getKind() == PPC::fixup_ppc_half16; + bool IsHalf16DS = + Fixup && (unsigned)Fixup->getKind() == PPC::fixup_ppc_half16ds; + bool IsHalf16DQ = + Fixup && (unsigned)Fixup->getKind() == PPC::fixup_ppc_half16dq; + bool IsHalf = IsHalf16 || IsHalf16DS || IsHalf16DQ; + + if (!IsHalf && Result >= 0x8000) return false; + if ((IsHalf16DS && (Result & 0x3)) || (IsHalf16DQ && (Result & 0xf))) + return false; + Res = MCValue::get(Result); } else { if (!Layout) diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -1016,7 +1016,7 @@ } def PPCDispRIXOperand : AsmOperandClass { let Name = "DispRIX"; let PredicateMethod = "isS16ImmX4"; - let RenderMethod = "addImmOperands"; + let RenderMethod = "addS16ImmOperands"; } def dispRIX : Operand { let ParserMatchClass = PPCDispRIXOperand; @@ -1030,7 +1030,7 @@ } def PPCDispRIX16Operand : AsmOperandClass { let Name = "DispRIX16"; let PredicateMethod = "isS16ImmX16"; - let RenderMethod = "addImmOperands"; + let RenderMethod = "addS16ImmOperands"; } def dispRIX16 : Operand { let ParserMatchClass = PPCDispRIX16Operand; diff --git a/llvm/test/MC/PowerPC/ppc64-abs-reloc.s b/llvm/test/MC/PowerPC/ppc64-abs-reloc.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/PowerPC/ppc64-abs-reloc.s @@ -0,0 +1,31 @@ +# RUN: llvm-mc -triple powerpc64le-unknown-linux-gnu %s -filetype=obj -o - | \ +# RUN: llvm-objdump -D -r - | FileCheck %s + .text + .abiversion 2 + .file "b.c" + .globl test # -- Begin function test + .p2align 4 + .type test,@function +test: # @test +.Lfunc_begin0: + .cfi_startproc +# %bb.0: # %entry + add 5, 3, 4 + extsw 3, 5 + .space 32776 +lab2: + lxv 5, (lab2-test)@l(4) + ld 5, (lab2-test)@l(4) + lwz 5, (lab2-test)@l(4) + lxv 5, 8389632@l(4) + ld 5, 8389632@l(4) + lwz 5, 8389632@l(4) + blr + .cfi_endproc + +# CHECK: lxv 5, -32752(4) +# CHECK: ld 5, -32752(4) +# CHECK: lwz 5, -32752(4) +# CHECK: lxv 5, 1024(4) +# CHECK: ld 5, 1024(4) +# CHECK: lwz 5, 1024(4)