diff options
Diffstat (limited to 'llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp')
-rw-r--r-- | llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp | 124 |
1 files changed, 122 insertions, 2 deletions
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp index 676efc500455..fb65e7320f2b 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -48,7 +48,9 @@ getDirectBrEncoding(const MCInst &MI, unsigned OpNo, // Add a fixup for the branch target. Fixups.push_back(MCFixup::create(0, MO.getExpr(), - (MCFixupKind)PPC::fixup_ppc_br24)); + ((MI.getOpcode() == PPC::BL8_NOTOC) + ? (MCFixupKind)PPC::fixup_ppc_br24_notoc + : (MCFixupKind)PPC::fixup_ppc_br24))); return 0; } @@ -102,6 +104,20 @@ unsigned PPCMCCodeEmitter::getImm16Encoding(const MCInst &MI, unsigned OpNo, return 0; } +uint64_t +PPCMCCodeEmitter::getImm34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg() || MO.isImm()) + return getMachineOpValue(MI, MO, Fixups, STI); + + // Add a fixup for the immediate field. + Fixups.push_back(MCFixup::create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_pcrel34)); + return 0; +} + unsigned PPCMCCodeEmitter::getMemRIEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { @@ -159,6 +175,104 @@ unsigned PPCMCCodeEmitter::getMemRIX16Encoding(const MCInst &MI, unsigned OpNo, return RegBits; } +uint64_t +PPCMCCodeEmitter::getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode the PCRelative version of memri34: imm34(r0). + // In the PC relative version the register for the address must be zero. + // The 34 bit immediate can fall into one of three cases: + // 1) It is a relocation to be filled in by the linker represented as: + // (MCExpr::SymbolRef) + // 2) It is a relocation + SignedOffset represented as: + // (MCExpr::Binary(MCExpr::SymbolRef + MCExpr::Constant)) + // 3) It is a known value at compile time. + + // Make sure that the register is a zero as expected. + assert(MI.getOperand(OpNo + 1).isImm() && "Expecting an immediate."); + uint64_t RegBits = + getMachineOpValue(MI, MI.getOperand(OpNo + 1), Fixups, STI) << 34; + assert(RegBits == 0 && "Operand must be 0."); + + // If this is not a MCExpr then we are in case 3) and we are dealing with + // a value known at compile time, not a relocation. + const MCOperand &MO = MI.getOperand(OpNo); + if (!MO.isExpr()) + return ((getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL) | RegBits; + + // At this point in the function it is known that MO is of type MCExpr. + // Therefore we are dealing with either case 1) a symbol ref or + // case 2) a symbol ref plus a constant. + const MCExpr *Expr = MO.getExpr(); + switch (Expr->getKind()) { + default: + llvm_unreachable("Unsupported MCExpr for getMemRI34PCRelEncoding."); + case MCExpr::SymbolRef: { + // Relocation alone. + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr); + (void)SRE; + // Currently these are the only valid PCRelative Relocations. + assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) && + "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL"); + // Generate the fixup for the relocation. + Fixups.push_back( + MCFixup::create(0, Expr, + static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34))); + // Put zero in the location of the immediate. The linker will fill in the + // correct value based on the relocation. + return 0; + } + case MCExpr::Binary: { + // Relocation plus some offset. + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr); + assert(BE->getOpcode() == MCBinaryExpr::Add && + "Binary expression opcode must be an add."); + + const MCExpr *LHS = BE->getLHS(); + const MCExpr *RHS = BE->getRHS(); + + // Need to check in both directions. Reloc+Offset and Offset+Reloc. + if (LHS->getKind() != MCExpr::SymbolRef) + std::swap(LHS, RHS); + + if (LHS->getKind() != MCExpr::SymbolRef || + RHS->getKind() != MCExpr::Constant) + llvm_unreachable("Expecting to have one constant and one relocation."); + + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(LHS); + (void)SRE; + assert(isInt<34>(cast<MCConstantExpr>(RHS)->getValue()) && + "Value must fit in 34 bits."); + + // Currently these are the only valid PCRelative Relocations. + assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) && + "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL"); + // Generate the fixup for the relocation. + Fixups.push_back( + MCFixup::create(0, Expr, + static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34))); + // Put zero in the location of the immediate. The linker will fill in the + // correct value based on the relocation. + return 0; + } + } +} + +uint64_t +PPCMCCodeEmitter::getMemRI34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode (imm, reg) as a memri34, which has the low 34-bits as the + // displacement and the next 5 bits as the register #. + assert(MI.getOperand(OpNo + 1).isReg() && "Expecting a register."); + uint64_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo + 1), Fixups, STI) + << 34; + const MCOperand &MO = MI.getOperand(OpNo); + return ((getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL) | RegBits; +} + unsigned PPCMCCodeEmitter::getSPE8DisEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) @@ -257,7 +371,7 @@ static unsigned getOpIdxForMO(const MCInst &MI, const MCOperand &MO) { return ~0U; // Silence any warnings about no return. } -unsigned PPCMCCodeEmitter:: +uint64_t PPCMCCodeEmitter:: getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { @@ -316,5 +430,11 @@ unsigned PPCMCCodeEmitter::getInstSizeInBytes(const MCInst &MI) const { return Desc.getSize(); } +bool PPCMCCodeEmitter::isPrefixedInstruction(const MCInst &MI) const { + unsigned Opcode = MI.getOpcode(); + const PPCInstrInfo *InstrInfo = static_cast<const PPCInstrInfo*>(&MCII); + return InstrInfo->isPrefixed(Opcode); +} + #define ENABLE_INSTR_PREDICATE_VERIFIER #include "PPCGenMCCodeEmitter.inc" |