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 @@ -341,31 +341,11 @@ bool isU10Imm() const { return Kind == Immediate && isUInt<10>(getImm()); } bool isU12Imm() const { return Kind == Immediate && isUInt<12>(getImm()); } - bool isU16Imm() const { - switch (Kind) { - case Expression: - return true; - case Immediate: - case ContextImmediate: - return isUInt<16>(getImmU16Context()); - default: - return false; - } - } - bool isS16Imm() const { - switch (Kind) { - case Expression: - return true; - case Immediate: - case ContextImmediate: - return isInt<16>(getImmS16Context()); - default: - return false; - } - } - bool isS16ImmX4() const { return Kind == Expression || - (Kind == Immediate && isInt<16>(getImm()) && - (getImm() & 3) == 0); } + bool isU16Imm() const { return isExtImm<16>(/*Signed*/ false, 1); } + bool isS16Imm() const { return isExtImm<16>(/*Signed*/ true, 1); } + bool isS16ImmX4() const { return isExtImm<16>(/*Signed*/ true, 4); } + bool isS16ImmX16() const { return isExtImm<16>(/*Signed*/ true, 16); } + bool isS17Imm() const { return isExtImm<17>(/*Signed*/ true, 1); } bool isHashImmX8() const { // The Hash Imm form is used for instructions that check or store a hash. @@ -375,9 +355,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); @@ -388,17 +365,6 @@ return Kind == Expression || (Kind == Immediate && isInt<34>(getImm())); } - bool isS17Imm() const { - switch (Kind) { - case Expression: - return true; - case Immediate: - case ContextImmediate: - return isInt<17>(getImmS16Context()); - default: - return false; - } - } bool isTLSReg() const { return Kind == TLSRegister; } bool isDirectBr() const { if (Kind == Expression) @@ -712,6 +678,25 @@ return CreateExpr(Val, S, E, IsPPC64); } + +private: + template + bool isExtImm(bool Signed, unsigned Multiple) const { + switch (Kind) { + default: + return false; + case Expression: + return true; + case Immediate: + case ContextImmediate: + if (Signed) + return isInt(getImmS16Context()) && + (getImmS16Context() & (Multiple - 1)) == 0; + else + return isUInt(getImmU16Context()) && + (getImmU16Context() & (Multiple - 1)) == 0; + } + } }; } // end anonymous namespace. 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 @@ -197,8 +197,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,18 @@ if (Value.isAbsolute()) { int64_t Result = evaluateAsInt64(Value.getConstant()); - if ((Fixup == nullptr || (unsigned)Fixup->getKind() != PPC::fixup_ppc_half16) && - (Result >= 0x8000)) + bool IsHalf16 = Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16; + bool IsHalf16DS = + Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16ds; + bool IsHalf16DQ = + Fixup && Fixup->getTargetKind() == 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,22 @@ +# RUN: llvm-mc -triple powerpc64le-unknown-linux-gnu %s -filetype=obj -o - | \ +# RUN: llvm-objdump -D -r - | FileCheck %s + .text +test: # @test + 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 + +# 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)