diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def @@ -97,6 +97,7 @@ #undef R_PPC64_DTPREL16_HIGH #undef R_PPC64_DTPREL16_HIGHA #undef R_PPC64_REL24_NOTOC +#undef R_PPC64_PCREL_OPT #undef R_PPC64_PCREL34 #undef R_PPC64_GOT_PCREL34 #undef R_PPC64_IRELATIVE @@ -194,6 +195,7 @@ ELF_RELOC(R_PPC64_DTPREL16_HIGH, 114) ELF_RELOC(R_PPC64_DTPREL16_HIGHA, 115) ELF_RELOC(R_PPC64_REL24_NOTOC, 116) +ELF_RELOC(R_PPC64_PCREL_OPT, 123) ELF_RELOC(R_PPC64_PCREL34, 132) ELF_RELOC(R_PPC64_GOT_PCREL34, 133) ELF_RELOC(R_PPC64_IRELATIVE, 248) diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -302,6 +302,7 @@ VK_PPC_TLSLD, // symbol@tlsld VK_PPC_LOCAL, // symbol@local VK_PPC_NOTOC, // symbol@notoc + VK_PPC_PCREL_OPT, // .reloc expr, R_PPC64_PCREL_OPT, expr VK_COFF_IMGREL32, // symbol@imgrel (image-relative) 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 @@ -322,6 +322,7 @@ case VK_PPC_TLSLD: return "tlsld"; case VK_PPC_LOCAL: return "local"; case VK_PPC_NOTOC: return "notoc"; + case VK_PPC_PCREL_OPT: return "<>"; case VK_COFF_IMGREL32: return "IMGREL"; case VK_Hexagon_LO16: return "LO16"; case VK_Hexagon_HI16: return "HI16"; 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 @@ -126,6 +126,7 @@ bool ParseDarwinDirectiveMachine(SMLoc L); bool ParseDirectiveAbiVersion(SMLoc L); bool ParseDirectiveLocalEntry(SMLoc L); + bool ParseDirectiveReloc(SMLoc L); bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -1660,6 +1661,8 @@ ParseDirectiveAbiVersion(DirectiveID.getLoc()); else if (IDVal == ".localentry") ParseDirectiveLocalEntry(DirectiveID.getLoc()); + else if (IDVal == ".reloc") + ParseDirectiveReloc(DirectiveID.getLoc()); else return true; return false; @@ -1804,7 +1807,110 @@ return false; } +/// ParseDirectiveReloc +/// Very similar to the one in AsmParser::parseDirectiveReloc except that we +/// want to be able to parse MCExpr::Binary too. +/// Format: .reloc expression , identifier [ , expression ] +/// For example: +/// pld 3, vec@got@pcrel(0), 1 +/// .Lpcrel1: +/// .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8) +/// lwa 3, 4(3) +/// The .reloc directive instructs the assembler to emit a relocation of type +/// R_PPC64_RCREL_OPT, referencing offset `.Lpcrel1-8` (the pc-relative load +/// from the got) with addend `.-(.Lpcrel1-8)` (the offset from got access +/// instruction to the associated load/store instruction). +/// The relocation specifies that the instructions at r_offset (pld) and +/// r_offset + r_addend (lwa) may be optimized by the linker (ie the compiler +/// guarantees that register lifetimes are such that the optimization is safe). +/// The parent class cannot handle binary expressions such as .Lpcrel1-8 where +/// we subtract some offset from the position of the label. This addition is +/// is meant to allow that. +bool PPCAsmParser::ParseDirectiveReloc(SMLoc DirectiveLoc) { + const MCExpr *Offset; + const MCExpr *Expr = nullptr; + int64_t OffsetVal; + SMLoc OffsetLoc = getLexer().getTok().getLoc(); + + // Get the MCExpr that represents the first expression that immediately + // follows the .reloc. + // Note that parseExpression() returns false on success. + // So, if we fail to parse the first expression just bail. + if (getParser().parseExpression(Offset)) + return true; + + // If the expression is a negative value bail out. An absolute value needs to + // positive. + if (Offset->evaluateAsAbsolute(OffsetVal, getStreamer().getAssemblerPtr()) && + check(OffsetVal < 0, OffsetLoc, "expression is negative")) + return true; + + // The expression must be either a constant, a symbol or a binary expression. + // If it is not: exit. + if (check(Offset->getKind() != llvm::MCExpr::Constant && + Offset->getKind() != llvm::MCExpr::SymbolRef && + Offset->getKind() != llvm::MCExpr::Binary, + OffsetLoc, + "expected non-negative constant, label or a binary expression")) + return true; + + // Check that the binary expression is either symbol+offset or symbol-offset. + if (Offset->getKind() == llvm::MCExpr::Binary) { + const MCBinaryExpr *BinExpr = cast(Offset); + if (check(BinExpr->getLHS()->getKind() != MCExpr::SymbolRef || + BinExpr->getRHS()->getKind() != MCExpr::Constant, + OffsetLoc, + "Binary expression should be symbol+/-offset.")) + return true; + if (check(BinExpr->getOpcode() != MCBinaryExpr::Add && + BinExpr->getOpcode() != MCBinaryExpr::Sub, + OffsetLoc, + "Binary expression operation should be + or -.")) + return true; + } + + // Parse the next token. It needs to be the comma between the first expression + // and the identifier. + if (parseToken(AsmToken::Comma, "expected comma")) + return true; + + // The identifier needs to be the relocaiton name. + if (check(getTok().isNot(AsmToken::Identifier), "expected relocation name")) + return true; + + // Get the location and name of the identifier (the relocation name). + SMLoc NameLoc = getLexer().getTok().getLoc(); + StringRef Name = getLexer().getTok().getIdentifier(); + // Go to the next token. + getParser().Lex(); + + // Check for the second comma to see if the second expression is there after + // the identifier. If the next token is not a comma the Expr varaible is left + // as a null pointer. This is fine because emitRelocDirective can handle that. + if (getLexer().is(AsmToken::Comma)) { + getParser().Lex(); + SMLoc ExprLoc = getLexer().getLoc(); + if (getParser().parseExpression(Expr)) + return true; + + MCValue Value; + if (!Expr->evaluateAsRelocatable(Value, nullptr, nullptr)) + return Error(ExprLoc, "expression must be relocatable"); + } + + // Make sure that we have now reached the end of the .reloc directive. + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in .reloc directive")) + return true; + // Now that all of the pieces are (Offset, Name, Expr) have been parsed we + // move to emit the .reloc directive. + if (getStreamer().emitRelocDirective(*Offset, Name, Expr, DirectiveLoc, + getSTI())) + return Error(NameLoc, "unknown relocation name"); + + return false; +} /// Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCAsmParser() { 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 @@ -33,6 +33,7 @@ case FK_Data_4: case FK_Data_8: case PPC::fixup_ppc_nofixup: + case PPC::fixup_ppc_linker_opt: return Value; case PPC::fixup_ppc_brcond14: case PPC::fixup_ppc_brcond14abs: @@ -71,6 +72,7 @@ case FK_Data_8: return 8; case PPC::fixup_ppc_nofixup: + case PPC::fixup_ppc_linker_opt: return 0; } } @@ -99,7 +101,8 @@ { "fixup_ppc_brcond14abs", 16, 14, 0 }, { "fixup_ppc_half16", 0, 16, 0 }, { "fixup_ppc_half16ds", 0, 14, 0 }, - { "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_linker_opt", 0, 0, 0 }, { "fixup_ppc_nofixup", 0, 0, 0 } }; const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = { @@ -112,6 +115,7 @@ { "fixup_ppc_half16", 0, 16, 0 }, { "fixup_ppc_half16ds", 2, 14, 0 }, { "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_linker_opt", 0, 0, 0 }, { "fixup_ppc_nofixup", 0, 0, 0 } }; @@ -158,6 +162,8 @@ switch ((unsigned)Kind) { default: return Kind >= FirstLiteralRelocationKind; + case PPC::fixup_ppc_linker_opt: + return true; case PPC::fixup_ppc_br24: case PPC::fixup_ppc_br24abs: case PPC::fixup_ppc_br24_notoc: 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 @@ -386,6 +386,9 @@ break; } break; + case PPC::fixup_ppc_linker_opt: + Type = ELF::R_PPC64_PCREL_OPT; + break; case PPC::fixup_ppc_nofixup: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h @@ -41,6 +41,11 @@ // EmitLabel updates LastLabel and LastLabelLoc when a new label is emitted. void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; + // Emit a .reloc label. + bool emitRelocDirective(const MCExpr &Offset, StringRef Name, + const MCExpr *Expr, SMLoc Loc, + const MCSubtargetInfo &STI) override; + private: void emitPrefixedInstruction(const MCInst &Inst, const MCSubtargetInfo &STI); }; diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp @@ -18,8 +18,8 @@ // //===----------------------------------------------------------------------===// - #include "PPCELFStreamer.h" +#include "PPCFixupKinds.h" #include "PPCInstrInfo.h" #include "PPCMCCodeEmitter.h" #include "llvm/BinaryFormat/ELF.h" @@ -103,6 +103,138 @@ MCELFStreamer::emitLabel(Symbol); } +// Given an MCBinary expression of the form Symbol +/- Constant find the data +// fragment and the offset into that data fragment that the expression +// represents. +// Function returns true on success and false otherwise. +static bool getOffsetFromBinaryExpr(const MCBinaryExpr &BinExpr, + uint64_t &Offset, MCDataFragment *&DF) { + const MCExpr *LHS = BinExpr.getLHS(); + const MCExpr *RHS = BinExpr.getRHS(); + // We only support Symbol +/- Constant. + if (LHS->getKind() != MCExpr::SymbolRef || RHS->getKind() != MCExpr::Constant) + return false; + + const MCSymbolRefExpr *Symbol = cast(LHS); + const MCConstantExpr *ConstVal = cast(RHS); + + // Get the Data Fragment. + // If there is no data fragment for this symbol just return false. + MCFragment *Fragment = Symbol->getSymbol().getFragment(); + if (!Fragment || Fragment->getKind() != MCFragment::FT_Data) + return false; + + // Get the offset of the symbol within the fragment. + Offset = Symbol->getSymbol().getOffset(); + switch (BinExpr.getOpcode()) { + default: + // Other opcodes are not supported. + return false; + case MCBinaryExpr::Add: + Offset += ConstVal->getValue(); + break; + case MCBinaryExpr::Sub: + Offset -= ConstVal->getValue(); + break; + } + + DF = cast(Fragment); + return true; +} + +// Emit the .reloc directive. This is a PPC extension of what is being done in +// the generic ELF streamer. +bool PPCELFStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name, + const MCExpr *Expr, SMLoc Loc, + const MCSubtargetInfo &STI) { + // Get the MCFixupKind that corresponds to Name. + Optional MaybeKind = + getAssembler().getBackend().getFixupKind(Name); + if (!MaybeKind.hasValue()) + return true; + + MCFixupKind Kind = *MaybeKind; + + // If there is no MCExpr use the current position as the default. + // This is also what the base class assumes when the Expr after the relocation + // name is omitted. + if (Expr == nullptr) + Expr = MCSymbolRefExpr::create(getContext().createTempSymbol(), + getContext()); + + // Handle the Binary and Symbol cases separately. Anything else just drops + // through for default handling in the base class. + switch (Offset.getKind()) { + // For .reloc directives: + // .reloc Offset, REF_NAME, Expr + // Handle the situation where Offset is of the form Symbol+/-Constant. + // For example: + // pld 3, vec@got@pcrel(0), 1 + // .Lpcrel1: + // .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8) + // lwa 3, 4(3) + // This section deals with the .Lpcrel1-8. + case MCExpr::Binary: { + const MCBinaryExpr &BinExpr = cast(Offset); + uint64_t ComputedOffset; + MCDataFragment *DF = nullptr; + // Get the data fragment and offset into data fragment. + bool HaveOffset = getOffsetFromBinaryExpr(BinExpr, ComputedOffset, DF); + (void)HaveOffset; + assert(HaveOffset && "Unable to get the offset of the binary expression."); + assert(DF && "Expected a valid data fragment."); + + DF->getFixups().push_back(MCFixup::create(ComputedOffset, Expr, Kind, Loc)); + return false; + } + // For .reloc directives: + // .reloc Offset, REF_NAME, Expr + // Handle the situation where Offset is of the form Symbol. + // And Symbol is a variable symbol of the form: + // Symbol=.+/-Constant + // For example: + // pld 3, vec@got@pcrel(0), 1 + // .Lpcrel101=.-8 + // .reloc .Lpcrel101,R_PPC64_PCREL_OPT,.-.Lpcrel101 + // lwa 3, 4(3) + // This section deals with the variable label .Lpcrel101=.-8 + case MCExpr::SymbolRef: { + const MCSymbolRefExpr &SRE = cast(Offset); + const MCSymbol &Symbol = SRE.getSymbol(); + // The base class can handle symbols that are undefined. + if (!Symbol.isDefined()) + break; + + // Symbols that are not variable are already handled the way we want in the + // base class. So, let the base class do it. + if (!Symbol.isVariable()) + break; + + // Only the binary expression case is handled by the following code so fail + // early if we are in any other situation. + const MCExpr *SymbolExpr = Symbol.getVariableValue(); + assert(SymbolExpr->getKind() == MCExpr::Binary && + "Unsupported symbol expression for a variable symbol."); + + const MCBinaryExpr &BinExpr = cast(*SymbolExpr); + uint64_t ComputedOffset; + MCDataFragment *DF = nullptr; + // Get the offset and data fragment for the symbol's expression. + bool HaveOffset = getOffsetFromBinaryExpr(BinExpr, ComputedOffset, DF); + (void)HaveOffset; + assert(HaveOffset && "Unable to get the offset of the binary expression."); + assert(DF && "Expected a valid data fragment."); + DF->getFixups().push_back(MCFixup::create(ComputedOffset, Expr, Kind, Loc)); + return false; + } + default: + // Fall through to the base class. + break; + } + // If the directive cannot be handled here pass it on to the base class. + return MCELFStreamer::emitRelocDirective(Offset, Name, Expr, Loc, STI); +} + MCELFStreamer *llvm::createPPCELFStreamer( MCContext &Context, std::unique_ptr MAB, std::unique_ptr OW, 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 @@ -43,6 +43,11 @@ // A 34-bit fixup corresponding to PC-relative paddi. fixup_ppc_pcrel34, + /// Not a true fixup, but ties a pc-relative got access to an associated + /// memory operation to indicate to the linker that the sequence is safe to + /// optimize. + fixup_ppc_linker_opt, + /// Not a true fixup, but ties a symbol to a call to __tls_get_addr for the /// TLS general and local dynamic models, or inserts the thread-pointer /// register number. diff --git a/llvm/test/MC/PowerPC/pcrel-reloc-with-expr.s b/llvm/test/MC/PowerPC/pcrel-reloc-with-expr.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/PowerPC/pcrel-reloc-with-expr.s @@ -0,0 +1,401 @@ +# RUN: llvm-mc -triple=powerpc64le-unknown-unknown -filetype=obj %s | \ +# RUN: llvm-objdump -dr --mcpu=pwr10 - | FileCheck %s +# RUN: llvm-mc -triple=powerpc64-unknown-unknown -filetype=obj %s | \ +# RUN: llvm-objdump -dr --mcpu=pwr10 - | FileCheck %s + + +## +# This section of tests contains the MCBinaryExpr as the first parameter of the +# .reloc relocation. +## + .text + .abiversion 2 + .globl Minimal + .p2align 4 + .type Minimal,@function +Minimal: +.LMinimal$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel1: + .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8) + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK-LABEL: Minimal +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x8 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + .globl SingleInsnBetween + .p2align 4 + .type SingleInsnBetween,@function +SingleInsnBetween: +.LSingleInsnBetween$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel2: + addi 3, 3, 42 + .reloc .Lpcrel2-8,R_PPC64_PCREL_OPT,.-(.Lpcrel2-8) + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK_LABEL: SingleInsnBetween +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0xc +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + + .globl MultiInsnBetween # -- Begin function + .p2align 4 + .type MultiInsnBetween,@function +MultiInsnBetween: +.LMultiInsnBetween$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel3: + addi 3, 3, 42 + addi 3, 3, 42 + addi 3, 3, 42 + addi 3, 3, 42 + addi 3, 3, 42 + .reloc .Lpcrel3-8,R_PPC64_PCREL_OPT,.-(.Lpcrel3-8) + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK_LABEL: MultiInsnBetween +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x1c +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + .globl PrefixInsnBetween + .p2align 6 + .type PrefixInsnBetween,@function + .space 48 # Add a space to force an alignment of a paddi. +PrefixInsnBetween: +.LPrefixInsnBetween$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel4: + addi 3, 3, 42 + paddi 3, 3, 42, 0 + addi 3, 3, 42 + paddi 3, 3, 42, 0 + addi 3, 3, 42 + .reloc .Lpcrel4-8,R_PPC64_PCREL_OPT,.-(.Lpcrel4-8) + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK_LABEL: PrefixInsnBetween +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x28 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: nop +# CHECK-NEXT: paddi 3, 3, 42, 0 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: paddi 3, 3, 42, 0 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + + .globl SpaceBetween # -- Begin function + .p2align 4 + .type SpaceBetween,@function +SpaceBetween: +.LSpaceBetween$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel5: + addi 3, 3, 42 + paddi 3, 3, 42, 0 + addi 3, 3, 42 + .space 40, 0 + paddi 3, 3, 42, 0 + addi 3, 3, 42 + .reloc .Lpcrel5-8,R_PPC64_PCREL_OPT,.-(.Lpcrel5-8) + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK_LABEL: SpaceBetween +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x50 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: nop +# CHECK-NEXT: paddi 3, 3, 42, 0 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK: paddi 3, 3, 42, 0 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + + .globl Plus + .p2align 4 + .type Plus,@function +Plus: +.LPlus$local: +.Lpcrel6: + addi 3, 3, 42 + addi 3, 3, 42 + pld 3, vec@got@pcrel(0), 1 + .reloc .Lpcrel6+8,R_PPC64_PCREL_OPT,.-(.Lpcrel6+8) + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK-LABEL: Plus +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x8 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + +## +# This section of tests contains the variable MCSymbol as part of the +# MCSymbolRefExpr for the first parameter of the .reloc relocation. +## + .globl VarLabelMinimal # -- Begin function + .p2align 4 + .type VarLabelMinimal,@function +VarLabelMinimal: +.LVarLabelMinimal$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel101=.-8 + .reloc .Lpcrel101,R_PPC64_PCREL_OPT,.-.Lpcrel101 + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK-LABEL: VarLabelMinimal +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x8 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + + .globl VarLabelSingleInsnBetween + .p2align 4 + .type VarLabelSingleInsnBetween,@function +VarLabelSingleInsnBetween: +.LVarLabelSingleInsnBetween$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel102=.-8 + addi 3, 3, 42 + .reloc .Lpcrel102,R_PPC64_PCREL_OPT,.-.Lpcrel102 + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK_LABEL: VarLabelSingleInsnBetween +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0xc +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + .globl VarLabelMultiInsnBetween # -- Begin function + .p2align 4 + .type VarLabelMultiInsnBetween,@function +VarLabelMultiInsnBetween: +.LVarLabelMultiInsnBetween$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel103=.-8 + addi 3, 3, 42 + addi 3, 3, 42 + addi 3, 3, 42 + addi 3, 3, 42 + addi 3, 3, 42 + .reloc .Lpcrel103,R_PPC64_PCREL_OPT,.-.Lpcrel103 + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK_LABEL: VarLabelMultiInsnBetween +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x1c +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + + .globl VarLabelPrefixInsnBetween # -- Begin function + .p2align 4 + .type VarLabelPrefixInsnBetween,@function +VarLabelPrefixInsnBetween: +.LVarLabelPrefixInsnBetween$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel104=.-8 + addi 3, 3, 42 + paddi 3, 3, 42, 0 + addi 3, 3, 42 + paddi 3, 3, 42, 0 + addi 3, 3, 42 + .reloc .Lpcrel104,R_PPC64_PCREL_OPT,.-.Lpcrel104 + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK_LABEL: VarLabelPrefixInsnBetween +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x24 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: paddi 3, 3, 42, 0 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: paddi 3, 3, 42, 0 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + + .globl VarLabelSpaceBetween # -- Begin function + .p2align 4 + .type VarLabelSpaceBetween,@function +VarLabelSpaceBetween: +.LVarLabelSpaceBetween$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel105=.-8 + addi 3, 3, 42 + paddi 3, 3, 42, 0 + addi 3, 3, 42 + .space 40, 0 + paddi 3, 3, 42, 0 + addi 3, 3, 42 + .reloc .Lpcrel105,R_PPC64_PCREL_OPT,.-.Lpcrel105 + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK_LABEL: VarLabelSpaceBetween +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x4c +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: paddi 3, 3, 42, 0 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK: paddi 3, 3, 42, 0 +# CHECK-NEXT: addi 3, 3, 42 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + + .globl VarLabelPlus + .p2align 4 + .type VarLabelPlus,@function +VarLabelPlus: +.LVarLabelPlus$local: +.Lpcrel106: + addi 3, 3, 42 + addi 3, 3, 42 + pld 3, vec@got@pcrel(0), 1 + .reloc .Lpcrel106+8,R_PPC64_PCREL_OPT,.-(.Lpcrel106+8) + lwa 3, 4(3) + blr + .long 0 + .quad 0 +# CHECK-LABEL: VarLabelPlus +# CHECK: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x8 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + +# Check the situation where the PLD requires an alignment nop. + .globl AlignPLD + .p2align 6 + .type AlignPLD,@function + .space 60 # Force the pld to require an alignment nop. +AlignPLD: +.LAlignPLD$local: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel201: + .reloc .Lpcrel201-8,R_PPC64_PCREL_OPT,.-(.Lpcrel201-8) + lwa 3, 4(3) + blr +# CHECK-LABEL: AlignPLD +# CHECK: nop +# CHECK-NEXT: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x8 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + +# The label and the pld are on the same line and so the nop is inserted before +# the label and the relocation should work. + .globl AlignPLDSameLine + .p2align 6 + .type AlignPLDSameLine,@function + .space 60 # Force the pld to require an alignment nop. +AlignPLDSameLine: +.LAlignPLDSameLine$local: +.Lpcrel202: pld 3, vec@got@pcrel(0), 1 + .reloc .Lpcrel202,R_PPC64_PCREL_OPT,.-.Lpcrel202 + lwa 3, 4(3) + blr +# CHECK-LABEL: AlignPLDSameLine +# CHECK: nop +# CHECK-NEXT: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x8 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + .globl AlignPLDLabelBefore + .p2align 6 + .type AlignPLDLabelBefore,@function + .space 60 # Force the pld to require an alignment nop. +AlignPLDLabelBefore: +.LAlignPLDLabelBefore$local: +.Label: + pld 3, vec@got@pcrel(0), 1 +.Lpcrel203: + .reloc .Lpcrel203-8,R_PPC64_PCREL_OPT,.-(.Lpcrel203-8) + lwa 3, 4(3) + blr +# CHECK-LABEL: AlignPLDLabelBefore +# CHECK: nop +# CHECK-NEXT: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x8 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr + + .globl AlignPLDLabelSameLine + .p2align 6 + .type AlignPLDLabelSameLine,@function + .space 60 # Force the pld to require an alignment nop. +AlignPLDLabelSameLine: +.Label2: pld 3, vec@got@pcrel(0), 1 +.Lpcrel204: + .reloc .Lpcrel204-8,R_PPC64_PCREL_OPT,.-(.Lpcrel204-8) + lwa 3, 4(3) + blr +# CHECK-LABEL: AlignPLDLabelSameLine +# CHECK: nop +# CHECK-NEXT: pld 3, 0(0), 1 +# CHECK-NEXT: R_PPC64_GOT_PCREL34 vec +# CHECK-NEXT: R_PPC64_PCREL_OPT *ABS*+0x8 +# CHECK-NEXT: lwa 3, 4(3) +# CHECK-NEXT: blr