diff --git a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp --- a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp +++ b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp @@ -17,6 +17,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" @@ -65,6 +66,11 @@ unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; + // Helper function for dealing with %lo / %hi in PIC mode. + const VEMCExpr *adjustPICRelocation(VEMCExpr::VariantKind VK, + const MCExpr *Sym); + // Helper function to parse and generate identifier with relocation. + const MCExpr *parseIdentifier(StringRef Identifier); // Custom parse functions for VE specific operands. OperandMatchResultTy parseMEMOperand(OperandVector &Operands); OperandMatchResultTy parseMEMAsOperand(OperandVector &Operands); @@ -946,6 +952,82 @@ return true; } +// Determine if an expression contains a reference to the symbol +// "_GLOBAL_OFFSET_TABLE_". +static bool hasGOTReference(const MCExpr *Expr) { + switch (Expr->getKind()) { + case MCExpr::Target: + if (const VEMCExpr *SE = dyn_cast(Expr)) + return hasGOTReference(SE->getSubExpr()); + break; + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(Expr); + return hasGOTReference(BE->getLHS()) || hasGOTReference(BE->getRHS()); + } + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr &SymRef = *cast(Expr); + return (SymRef.getSymbol().getName() == "_GLOBAL_OFFSET_TABLE_"); + } + + case MCExpr::Unary: + return hasGOTReference(cast(Expr)->getSubExpr()); + } + return false; +} + +const VEMCExpr *VEAsmParser::adjustPICRelocation(VEMCExpr::VariantKind VK, + const MCExpr *Sym) { + // When in PIC mode, "%lo(...)" and "%hi(...)" behave differently. + // If the expression refers contains _GLOBAL_OFFSETE_TABLE, it is + // actually a %pc10 or %pc22 relocation. Otherwise, they are interpreted + // as %got10 or %got22 relocation. + + if (getContext().getObjectFileInfo()->isPositionIndependent()) { + switch (VK) { + default: + break; + case VEMCExpr::VK_VE_LO32: + VK = (hasGOTReference(Sym) ? VEMCExpr::VK_VE_PC_LO32 + : VEMCExpr::VK_VE_GOT_LO32); + break; + case VEMCExpr::VK_VE_HI32: + VK = (hasGOTReference(Sym) ? VEMCExpr::VK_VE_PC_HI32 + : VEMCExpr::VK_VE_GOT_HI32); + break; + } + } + + return VEMCExpr::create(VK, Sym, getContext()); +} + +const MCExpr *VEAsmParser::parseIdentifier(StringRef Identifier) { + StringRef Modifier; + // Search @modifiers like "symbol@hi". + size_t at = Identifier.rfind('@'); + if (at != 0 || at != StringRef::npos) { + std::pair Pair = Identifier.rsplit("@"); + if (!Pair.first.empty() && !Pair.second.empty()) { + Identifier = Pair.first; + Modifier = Pair.second; + } + } + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); + const MCExpr *Res = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + VEMCExpr::VariantKind VK = VEMCExpr::parseVariantKind(Modifier); + if (VK == VEMCExpr::VK_VE_None) { + // Create identifier using default variant kind + VEMCExpr::VariantKind Kind = VEMCExpr::VK_VE_REFLONG; + return VEMCExpr::create(Kind, Res, getContext()); + } + return adjustPICRelocation(VK, Res); +} + OperandMatchResultTy VEAsmParser::parseMEMOperand(OperandVector &Operands) { LLVM_DEBUG(dbgs() << "parseMEMOperand\n"); const AsmToken &Tok = Parser.getTok(); @@ -975,6 +1057,19 @@ return MatchOperand_NoMatch; break; } + + case AsmToken::Identifier: { + StringRef Identifier; + if (!getParser().parseIdentifier(Identifier)) { + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + const MCExpr *EVal = parseIdentifier(Identifier); + + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Offset = VEOperand::CreateImm(EVal, S, E); + } + break; + } + case AsmToken::LParen: // empty disp (= 0) Offset = diff --git a/llvm/lib/Target/VE/Disassembler/VEDisassembler.cpp b/llvm/lib/Target/VE/Disassembler/VEDisassembler.cpp --- a/llvm/lib/Target/VE/Disassembler/VEDisassembler.cpp +++ b/llvm/lib/Target/VE/Disassembler/VEDisassembler.cpp @@ -187,6 +187,8 @@ const void *Decoder); static DecodeStatus DecodeSIMM7(MCInst &Inst, uint64_t insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeSIMM32(MCInst &Inst, uint64_t insn, uint64_t Address, + const void *Decoder); static DecodeStatus DecodeCCOperand(MCInst &Inst, uint64_t insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeRDOperand(MCInst &Inst, uint64_t insn, @@ -468,6 +470,13 @@ return MCDisassembler::Success; } +static DecodeStatus DecodeSIMM32(MCInst &MI, uint64_t insn, uint64_t Address, + const void *Decoder) { + uint64_t tgt = SignExtend64<32>(insn); + MI.addOperand(MCOperand::createImm(tgt)); + return MCDisassembler::Success; +} + static bool isIntegerBCKind(MCInst &MI) { #define BCm_kind(NAME) \ diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEAsmBackend.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEAsmBackend.cpp --- a/llvm/lib/Target/VE/MCTargetDesc/VEAsmBackend.cpp +++ b/llvm/lib/Target/VE/MCTargetDesc/VEAsmBackend.cpp @@ -24,6 +24,68 @@ switch (Kind) { default: llvm_unreachable("Unknown fixup kind!"); + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + case FK_Data_8: + case FK_PCRel_1: + case FK_PCRel_2: + case FK_PCRel_4: + case FK_PCRel_8: + return Value; + case VE::fixup_ve_hi32: + case VE::fixup_ve_pc_hi32: + case VE::fixup_ve_got_hi32: + case VE::fixup_ve_gotoff_hi32: + case VE::fixup_ve_plt_hi32: + case VE::fixup_ve_tls_gd_hi32: + case VE::fixup_ve_tpoff_hi32: + return (Value >> 32) & 0xffffffff; + case VE::fixup_ve_reflong: + case VE::fixup_ve_lo32: + case VE::fixup_ve_pc_lo32: + case VE::fixup_ve_got_lo32: + case VE::fixup_ve_gotoff_lo32: + case VE::fixup_ve_plt_lo32: + case VE::fixup_ve_tls_gd_lo32: + case VE::fixup_ve_tpoff_lo32: + return Value & 0xffffffff; + } +} + +/// getFixupKindNumBytes - The number of bytes the fixup may change. +static unsigned getFixupKindNumBytes(unsigned Kind) { + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + case FK_Data_1: + case FK_PCRel_1: + return 1; + case FK_Data_2: + case FK_PCRel_2: + return 2; + return 4; + case FK_Data_4: + case FK_PCRel_4: + case VE::fixup_ve_reflong: + case VE::fixup_ve_hi32: + case VE::fixup_ve_lo32: + case VE::fixup_ve_pc_hi32: + case VE::fixup_ve_pc_lo32: + case VE::fixup_ve_got_hi32: + case VE::fixup_ve_got_lo32: + case VE::fixup_ve_gotoff_hi32: + case VE::fixup_ve_gotoff_lo32: + case VE::fixup_ve_plt_hi32: + case VE::fixup_ve_plt_lo32: + case VE::fixup_ve_tls_gd_hi32: + case VE::fixup_ve_tls_gd_lo32: + case VE::fixup_ve_tpoff_hi32: + case VE::fixup_ve_tpoff_lo32: + return 4; + case FK_Data_8: + case FK_PCRel_8: + return 8; } } @@ -38,17 +100,44 @@ unsigned getNumFixupKinds() const override { return VE::NumTargetFixupKinds; } const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { + const static MCFixupKindInfo InfosLE[VE::NumTargetFixupKinds] = { + // name, offset, bits, flags + {"fixup_ve_reflong", 0, 32, 0}, + {"fixup_ve_hi32", 0, 32, 0}, + {"fixup_ve_lo32", 0, 32, 0}, + {"fixup_ve_pc_hi32", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_ve_pc_lo32", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_ve_got_hi32", 0, 32, 0}, + {"fixup_ve_got_lo32", 0, 32, 0}, + {"fixup_ve_gotoff_hi32", 0, 32, 0}, + {"fixup_ve_gotoff_lo32", 0, 32, 0}, + {"fixup_ve_plt_hi32", 0, 32, 0}, + {"fixup_ve_plt_lo32", 0, 32, 0}, + {"fixup_ve_tls_gd_hi32", 0, 32, 0}, + {"fixup_ve_tls_gd_lo32", 0, 32, 0}, + {"fixup_ve_tpoff_hi32", 0, 32, 0}, + {"fixup_ve_tpoff_lo32", 0, 32, 0}, + }; + if (Kind < FirstTargetFixupKind) return MCAsmBackend::getFixupKindInfo(Kind); - // FIXME. - llvm_unreachable("getFixupKindInfo() unimplemented"); + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return InfosLE[Kind - FirstTargetFixupKind]; } bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target) override { - // FIXME. - return false; + switch ((VE::Fixups)Fixup.getKind()) { + default: + return false; + case VE::fixup_ve_tls_gd_hi32: + case VE::fixup_ve_tls_gd_lo32: + case VE::fixup_ve_tpoff_hi32: + case VE::fixup_ve_tpoff_lo32: + return true; + } } bool mayNeedRelaxation(const MCInst &Inst, @@ -99,8 +188,21 @@ if (!Value) return; // Doesn't change encoding. - // FIXME. - llvm_unreachable("applyFixup() unimplemented"); + MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); + + // Shift the value into position. + Value <<= Info.TargetOffset; + + unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); + unsigned Offset = Fixup.getOffset(); + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); + // For each byte of the fragment that the fixup touches, mask in the bits + // from the fixup value. The Value has been "split up" into the + // appropriate bitfields above. + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = Endian == support::little ? i : (NumBytes - 1) - i; + Data[Offset + Idx] |= static_cast((Value >> (i * 8)) & 0xff); + } } std::unique_ptr @@ -109,7 +211,6 @@ return createVEELFObjectWriter(OSABI); } }; - } // end anonymous namespace MCAsmBackend *llvm::createVEAsmBackend(const Target &T, diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp --- a/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp +++ b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "VEFixupKinds.h" +#include "VEMCExpr.h" #include "VEMCTargetDesc.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCExpr.h" @@ -37,14 +38,95 @@ unsigned VEELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { - // FIXME: implements. + if (const VEMCExpr *SExpr = dyn_cast(Fixup.getValue())) { + if (SExpr->getKind() == VEMCExpr::VK_VE_PC_LO32) + return ELF::R_VE_PC_LO32; + } + + if (IsPCRel) { + switch (Fixup.getTargetKind()) { + default: + llvm_unreachable("Unimplemented fixup -> relocation"); + case FK_PCRel_1: + llvm_unreachable("Unimplemented fixup fk_data_1 -> relocation"); + case FK_PCRel_2: + llvm_unreachable("Unimplemented fixup fk_data_2 -> relocation"); + // FIXME: relative kind? + case FK_PCRel_4: + return ELF::R_VE_REFLONG; + case FK_PCRel_8: + return ELF::R_VE_REFQUAD; + case VE::fixup_ve_pc_hi32: + return ELF::R_VE_PC_HI32; + case VE::fixup_ve_pc_lo32: + return ELF::R_VE_PC_LO32; + } + } + + switch (Fixup.getTargetKind()) { + default: + llvm_unreachable("Unimplemented fixup -> relocation"); + case FK_Data_1: + llvm_unreachable("Unimplemented fixup fk_data_1 -> relocation"); + case FK_Data_2: + llvm_unreachable("Unimplemented fixup fk_data_2 -> relocation"); + case FK_Data_4: + return ELF::R_VE_REFLONG; + case FK_Data_8: + return ELF::R_VE_REFQUAD; + case VE::fixup_ve_reflong: + return ELF::R_VE_REFLONG; + case VE::fixup_ve_hi32: + return ELF::R_VE_HI32; + case VE::fixup_ve_lo32: + return ELF::R_VE_LO32; + case VE::fixup_ve_pc_hi32: + llvm_unreachable("Unimplemented fixup pc_hi32 -> relocation"); + case VE::fixup_ve_pc_lo32: + llvm_unreachable("Unimplemented fixup pc_lo32 -> relocation"); + case VE::fixup_ve_got_hi32: + return ELF::R_VE_GOT_HI32; + case VE::fixup_ve_got_lo32: + return ELF::R_VE_GOT_LO32; + case VE::fixup_ve_gotoff_hi32: + return ELF::R_VE_GOTOFF_HI32; + case VE::fixup_ve_gotoff_lo32: + return ELF::R_VE_GOTOFF_LO32; + case VE::fixup_ve_plt_hi32: + return ELF::R_VE_PLT_HI32; + case VE::fixup_ve_plt_lo32: + return ELF::R_VE_PLT_LO32; + case VE::fixup_ve_tls_gd_hi32: + return ELF::R_VE_TLS_GD_HI32; + case VE::fixup_ve_tls_gd_lo32: + return ELF::R_VE_TLS_GD_LO32; + case VE::fixup_ve_tpoff_hi32: + return ELF::R_VE_TPOFF_HI32; + case VE::fixup_ve_tpoff_lo32: + return ELF::R_VE_TPOFF_LO32; + } + return ELF::R_VE_NONE; } bool VEELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym, unsigned Type) const { - // FIXME: implements. - return false; + switch (Type) { + default: + return false; + + // All relocations that use a GOT need a symbol, not an offset, as + // the offset of the symbol within the section is irrelevant to + // where the GOT entry is. Don't need to list all the TLS entries, + // as they're all marked as requiring a symbol anyways. + case ELF::R_VE_GOT_HI32: + case ELF::R_VE_GOT_LO32: + case ELF::R_VE_GOTOFF_HI32: + case ELF::R_VE_GOTOFF_LO32: + case ELF::R_VE_TLS_GD_HI32: + case ELF::R_VE_TLS_GD_LO32: + return true; + } } std::unique_ptr diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h b/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h --- a/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h +++ b/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h @@ -14,8 +14,11 @@ namespace llvm { namespace VE { enum Fixups { + /// fixup_ve_reflong - 32-bit fixup corresponding to foo + fixup_ve_reflong = FirstTargetFixupKind, + /// fixup_ve_hi32 - 32-bit fixup corresponding to foo@hi - fixup_ve_hi32 = FirstTargetFixupKind, + fixup_ve_hi32, /// fixup_ve_lo32 - 32-bit fixup corresponding to foo@lo fixup_ve_lo32, diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCCodeEmitter.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEMCCodeEmitter.cpp --- a/llvm/lib/Target/VE/MCTargetDesc/VEMCCodeEmitter.cpp +++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCCodeEmitter.cpp @@ -65,6 +65,9 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint64_t getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; uint64_t getCCOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -119,6 +122,19 @@ return 0; } +uint64_t +VEMCCodeEmitter::getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg() || MO.isImm()) + return getMachineOpValue(MI, MO, Fixups, STI); + + Fixups.push_back( + MCFixup::create(0, MO.getExpr(), (MCFixupKind)VE::fixup_ve_pc_lo32)); + return 0; +} + uint64_t VEMCCodeEmitter::getCCOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h --- a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h +++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h @@ -24,6 +24,7 @@ public: enum VariantKind { VK_VE_None, + VK_VE_REFLONG, VK_VE_HI32, VK_VE_LO32, VK_VE_PC_HI32, diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp --- a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp +++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp @@ -42,6 +42,7 @@ bool VEMCExpr::printVariantKind(raw_ostream &OS, VariantKind Kind) { switch (Kind) { case VK_VE_None: + case VK_VE_REFLONG: return false; case VK_VE_HI32: @@ -58,7 +59,8 @@ case VK_VE_TLS_GD_LO32: case VK_VE_TPOFF_HI32: case VK_VE_TPOFF_LO32: - return false; // OS << "@("; break; + // Use suffix for these variant kinds + return false; } return true; } @@ -66,6 +68,7 @@ void VEMCExpr::printVariantKindSuffix(raw_ostream &OS, VariantKind Kind) { switch (Kind) { case VK_VE_None: + case VK_VE_REFLONG: break; case VK_VE_HI32: OS << "@hi"; @@ -94,15 +97,15 @@ case VK_VE_PLT_HI32: OS << "@plt_hi"; break; + case VK_VE_PLT_LO32: + OS << "@plt_lo"; + break; case VK_VE_TLS_GD_HI32: OS << "@tls_gd_hi"; break; case VK_VE_TLS_GD_LO32: OS << "@tls_gd_lo"; break; - case VK_VE_PLT_LO32: - OS << "@plt_lo"; - break; case VK_VE_TPOFF_HI32: OS << "@tpoff_hi"; break; @@ -135,6 +138,8 @@ switch (Kind) { default: llvm_unreachable("Unhandled VEMCExpr::VariantKind"); + case VK_VE_REFLONG: + return VE::fixup_ve_reflong; case VK_VE_HI32: return VE::fixup_ve_hi32; case VK_VE_LO32: @@ -159,6 +164,10 @@ return VE::fixup_ve_tls_gd_hi32; case VK_VE_TLS_GD_LO32: return VE::fixup_ve_tls_gd_lo32; + case VK_VE_TPOFF_HI32: + return VE::fixup_ve_tpoff_hi32; + case VK_VE_TPOFF_LO32: + return VE::fixup_ve_tpoff_lo32; } } @@ -201,5 +210,14 @@ } void VEMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { + switch (getKind()) { + default: + return; + case VK_VE_TLS_GD_HI32: + case VK_VE_TLS_GD_LO32: + case VK_VE_TPOFF_HI32: + case VK_VE_TPOFF_LO32: + break; + } fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm); } diff --git a/llvm/lib/Target/VE/VEInstrInfo.td b/llvm/lib/Target/VE/VEInstrInfo.td --- a/llvm/lib/Target/VE/VEInstrInfo.td +++ b/llvm/lib/Target/VE/VEInstrInfo.td @@ -381,9 +381,8 @@ // Branch targets have OtherVT type. def brtarget32 : Operand { -} - -def calltarget : Operand { + let EncoderMethod = "getBranchTargetOpValue"; + let DecoderMethod = "DecodeSIMM32"; } // Operand for printing out a condition code. diff --git a/llvm/test/CodeGen/VE/symbol_relocation.ll b/llvm/test/CodeGen/VE/symbol_relocation.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/symbol_relocation.ll @@ -0,0 +1,30 @@ +; RUN: llc -filetype=obj -mtriple=ve -o - %s | llvm-objdump - -d -r \ +; RUN: | FileCheck %s +; RUN: llc -filetype=obj -mtriple=ve -relocation-model=pic -o - %s \ +; RUN: | llvm-objdump - -d -r | FileCheck %s -check-prefix=PIC + +; CHECK: lea %s0, 0 +; CHECK-NEXT: R_VE_LO32 foo +; CHECK-NEXT: and %s0, %s0, (32)0 +; CHECK-NEXT: lea.sl %s12, (, %s0) +; CHECK-NEXT: R_VE_HI32 foo +; PIC: lea %s15, (-24) +; PIC-NEXT: R_VE_PC_LO32 _GLOBAL_OFFSET_TABLE_ +; PIC-NEXT: and %s15, %s15, (32)0 +; PIC-NEXT: sic %s16 +; PIC-NEXT: lea.sl %s15, (%s16, %s15) +; PIC-NEXT: R_VE_PC_HI32 _GLOBAL_OFFSET_TABLE_ +; PIC-NEXT: lea %s12, (-24) +; PIC-NEXT: R_VE_PLT_LO32 foo +; PIC-NEXT: and %s12, %s12, (32)0 +; PIC-NEXT: sic %s16 +; PIC-NEXT: lea.sl %s12, (%s16, %s12) +; PIC-NEXT: R_VE_PLT_HI32 foo + +define i32 @main() { +entry: + %call = call i32 @foo() + ret i32 %call +} + +declare i32 @foo() diff --git a/llvm/test/CodeGen/VE/symbol_relocation_tls.ll b/llvm/test/CodeGen/VE/symbol_relocation_tls.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/symbol_relocation_tls.ll @@ -0,0 +1,178 @@ +; FIXME: Even under non-pic mode, llvm for ve needs to generate pic code since +; nld doesn't work with non-pic code. Thefore, we test only pic codes +; for both cases here. +; llc -filetype=obj -mtriple=ve -o - %s | llvm-objdump - -d -r \ +; | FileCheck %s -check-prefix=LOCAL +; RUN: llc -filetype=obj -mtriple=ve -o - %s | llvm-objdump - -d -r \ +; RUN: | FileCheck %s -check-prefix=GENDYN +; RUN: llc -filetype=obj -mtriple=ve -relocation-model=pic -o - %s \ +; RUN: | llvm-objdump - -d -r | FileCheck %s -check-prefix=GENDYNPIC + +@x = external thread_local global i32, align 4 +@y = internal thread_local global i32 0, align 4 + +; Function Attrs: norecurse nounwind readnone +define nonnull i32* @get_global() { +; GENDYN: lea %s0, (-24) +; GENDYN-NEXT: R_VE_TLS_GD_LO32 x +; GENDYN-NEXT: and %s0, %s0, (32)0 +; GENDYN-NEXT: sic %s10 +; GENDYN-NEXT: lea.sl %s0, (%s10, %s0) +; GENDYN-NEXT: R_VE_TLS_GD_HI32 x +; GENDYN-NEXT: lea %s12, (8) +; GENDYN-NEXT: R_VE_PLT_LO32 __tls_get_addr +; GENDYN-NEXT: and %s12, %s12, (32)0 +; GENDYN-NEXT: lea.sl %s12, (%s10, %s12) +; GENDYN-NEXT: R_VE_PLT_HI32 __tls_get_addr +; GENDYN-NEXT: bsic %s10, (, %s12) +; GENDYN-NEXT: or %s11, 0, %s9 +; +; GENDYNPIC: lea %s15, (-24) +; GENDYNPIC-NEXT: R_VE_PC_LO32 _GLOBAL_OFFSET_TABLE_ +; GENDYNPIC-NEXT: and %s15, %s15, (32)0 +; GENDYNPIC-NEXT: sic %s16 +; GENDYNPIC-NEXT: lea.sl %s15, (%s16, %s15) +; GENDYNPIC-NEXT: R_VE_PC_HI32 _GLOBAL_OFFSET_TABLE_ +; GENDYNPIC-NEXT: lea %s0, (-24) +; GENDYNPIC-NEXT: R_VE_TLS_GD_LO32 x +; GENDYNPIC-NEXT: and %s0, %s0, (32)0 +; GENDYNPIC-NEXT: sic %s10 +; GENDYNPIC-NEXT: lea.sl %s0, (%s10, %s0) +; GENDYNPIC-NEXT: R_VE_TLS_GD_HI32 x +; GENDYNPIC-NEXT: lea %s12, (8) +; GENDYNPIC-NEXT: R_VE_PLT_LO32 __tls_get_addr +; GENDYNPIC-NEXT: and %s12, %s12, (32)0 +; GENDYNPIC-NEXT: lea.sl %s12, (%s10, %s12) +; GENDYNPIC-NEXT: R_VE_PLT_HI32 __tls_get_addr +; GENDYNPIC-NEXT: bsic %s10, (, %s12) +; GENDYNPIC-NEXT: or %s11, 0, %s9 +entry: + ret i32* @x +} + +; Function Attrs: norecurse nounwind readnone +define nonnull i32* @get_local() { +; GENDYN: lea %s0, (-24) +; GENDYN-NEXT: R_VE_TLS_GD_LO32 y +; GENDYN-NEXT: and %s0, %s0, (32)0 +; GENDYN-NEXT: sic %s10 +; GENDYN-NEXT: lea.sl %s0, (%s10, %s0) +; GENDYN-NEXT: R_VE_TLS_GD_HI32 y +; GENDYN-NEXT: lea %s12, (8) +; GENDYN-NEXT: R_VE_PLT_LO32 __tls_get_addr +; GENDYN-NEXT: and %s12, %s12, (32)0 +; GENDYN-NEXT: lea.sl %s12, (%s10, %s12) +; GENDYN-NEXT: R_VE_PLT_HI32 __tls_get_addr +; GENDYN-NEXT: bsic %s10, (, %s12) +; GENDYN-NEXT: or %s11, 0, %s9 +; +; GENDYNPIC: lea %s15, (-24) +; GENDYNPIC-NEXT: R_VE_PC_LO32 _GLOBAL_OFFSET_TABLE_ +; GENDYNPIC-NEXT: and %s15, %s15, (32)0 +; GENDYNPIC-NEXT: sic %s16 +; GENDYNPIC-NEXT: lea.sl %s15, (%s16, %s15) +; GENDYNPIC-NEXT: R_VE_PC_HI32 _GLOBAL_OFFSET_TABLE_ +; GENDYNPIC-NEXT: lea %s0, (-24) +; GENDYNPIC-NEXT: R_VE_TLS_GD_LO32 y +; GENDYNPIC-NEXT: and %s0, %s0, (32)0 +; GENDYNPIC-NEXT: sic %s10 +; GENDYNPIC-NEXT: lea.sl %s0, (%s10, %s0) +; GENDYNPIC-NEXT: R_VE_TLS_GD_HI32 y +; GENDYNPIC-NEXT: lea %s12, (8) +; GENDYNPIC-NEXT: R_VE_PLT_LO32 __tls_get_addr +; GENDYNPIC-NEXT: and %s12, %s12, (32)0 +; GENDYNPIC-NEXT: lea.sl %s12, (%s10, %s12) +; GENDYNPIC-NEXT: R_VE_PLT_HI32 __tls_get_addr +; GENDYNPIC-NEXT: bsic %s10, (, %s12) +; GENDYNPIC-NEXT: or %s11, 0, %s9 +entry: + ret i32* @y +} + +; Function Attrs: norecurse nounwind +define void @set_global(i32 %v) { +; GENDYN: lea %s0, (-24) +; GENDYN-NEXT: R_VE_TLS_GD_LO32 x +; GENDYN-NEXT: and %s0, %s0, (32)0 +; GENDYN-NEXT: sic %s10 +; GENDYN-NEXT: lea.sl %s0, (%s10, %s0) +; GENDYN-NEXT: R_VE_TLS_GD_HI32 x +; GENDYN-NEXT: lea %s12, (8) +; GENDYN-NEXT: R_VE_PLT_LO32 __tls_get_addr +; GENDYN-NEXT: and %s12, %s12, (32)0 +; GENDYN-NEXT: lea.sl %s12, (%s10, %s12) +; GENDYN-NEXT: R_VE_PLT_HI32 __tls_get_addr +; GENDYN-NEXT: bsic %s10, (, %s12) +; GENDYN-NEXT: stl %s18, (, %s0) +; GENDYN-NEXT: ld %s18, 48(, %s9) +; GENDYN-NEXT: or %s11, 0, %s9 +; +; GENDYNPIC: lea %s15, (-24) +; GENDYNPIC-NEXT: R_VE_PC_LO32 _GLOBAL_OFFSET_TABLE_ +; GENDYNPIC-NEXT: and %s15, %s15, (32)0 +; GENDYNPIC-NEXT: sic %s16 +; GENDYNPIC-NEXT: lea.sl %s15, (%s16, %s15) +; GENDYNPIC-NEXT: R_VE_PC_HI32 _GLOBAL_OFFSET_TABLE_ +; GENDYNPIC-NEXT: lea %s0, (-24) +; GENDYNPIC-NEXT: R_VE_TLS_GD_LO32 x +; GENDYNPIC-NEXT: and %s0, %s0, (32)0 +; GENDYNPIC-NEXT: sic %s10 +; GENDYNPIC-NEXT: lea.sl %s0, (%s10, %s0) +; GENDYNPIC-NEXT: R_VE_TLS_GD_HI32 x +; GENDYNPIC-NEXT: lea %s12, (8) +; GENDYNPIC-NEXT: R_VE_PLT_LO32 __tls_get_addr +; GENDYNPIC-NEXT: and %s12, %s12, (32)0 +; GENDYNPIC-NEXT: lea.sl %s12, (%s10, %s12) +; GENDYNPIC-NEXT: R_VE_PLT_HI32 __tls_get_addr +; GENDYNPIC-NEXT: bsic %s10, (, %s12) +; GENDYNPIC-NEXT: stl %s18, (, %s0) +; GENDYNPIC-NEXT: ld %s18, 48(, %s9) +; GENDYNPIC-NEXT: or %s11, 0, %s9 +entry: + store i32 %v, i32* @x, align 4 + ret void +} + +; Function Attrs: norecurse nounwind +define void @set_local(i32 %v) { +; GENDYN: lea %s0, (-24) +; GENDYN-NEXT: R_VE_TLS_GD_LO32 y +; GENDYN-NEXT: and %s0, %s0, (32)0 +; GENDYN-NEXT: sic %s10 +; GENDYN-NEXT: lea.sl %s0, (%s10, %s0) +; GENDYN-NEXT: R_VE_TLS_GD_HI32 y +; GENDYN-NEXT: lea %s12, (8) +; GENDYN-NEXT: R_VE_PLT_LO32 __tls_get_addr +; GENDYN-NEXT: and %s12, %s12, (32)0 +; GENDYN-NEXT: lea.sl %s12, (%s10, %s12) +; GENDYN-NEXT: R_VE_PLT_HI32 __tls_get_addr +; GENDYN-NEXT: bsic %s10, (, %s12) +; GENDYN-NEXT: stl %s18, (, %s0) +; GENDYN-NEXT: ld %s18, 48(, %s9) +; GENDYN-NEXT: or %s11, 0, %s9 +; +; GENDYNPIC: lea %s15, (-24) +; GENDYNPIC-NEXT: R_VE_PC_LO32 _GLOBAL_OFFSET_TABLE_ +; GENDYNPIC-NEXT: and %s15, %s15, (32)0 +; GENDYNPIC-NEXT: sic %s16 +; GENDYNPIC-NEXT: lea.sl %s15, (%s16, %s15) +; GENDYNPIC-NEXT: R_VE_PC_HI32 _GLOBAL_OFFSET_TABLE_ +; GENDYNPIC-NEXT: lea %s0, (-24) +; GENDYNPIC-NEXT: R_VE_TLS_GD_LO32 y +; GENDYNPIC-NEXT: and %s0, %s0, (32)0 +; GENDYNPIC-NEXT: sic %s10 +; GENDYNPIC-NEXT: lea.sl %s0, (%s10, %s0) +; GENDYNPIC-NEXT: R_VE_TLS_GD_HI32 y +; GENDYNPIC-NEXT: lea %s12, (8) +; GENDYNPIC-NEXT: R_VE_PLT_LO32 __tls_get_addr +; GENDYNPIC-NEXT: and %s12, %s12, (32)0 +; GENDYNPIC-NEXT: lea.sl %s12, (%s10, %s12) +; GENDYNPIC-NEXT: R_VE_PLT_HI32 __tls_get_addr +; GENDYNPIC-NEXT: bsic %s10, (, %s12) +; GENDYNPIC-NEXT: stl %s18, (, %s0) +; GENDYNPIC-NEXT: ld %s18, 48(, %s9) +; GENDYNPIC-NEXT: or %s11, 0, %s9 +entry: + store i32 %v, i32* @y, align 4 + ret void +} diff --git a/llvm/test/MC/VE/sym-got.s b/llvm/test/MC/VE/sym-got.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/VE/sym-got.s @@ -0,0 +1,24 @@ +# RUN: llvm-mc -triple=ve %s -o - | FileCheck %s +# RUN: llvm-mc -triple=ve -filetype=obj %s -o - | llvm-objdump -r - | FileCheck %s --check-prefix=CHECK-OBJ + + lea %s15, _GLOBAL_OFFSET_TABLE_@pc_lo(-24) + and %s15, %s15, (32)0 + sic %s16 + lea.sl %s15, _GLOBAL_OFFSET_TABLE_@pc_hi(%s16, %s15) + lea %s0, dst@got_lo + and %s0, %s0, (32)0 + lea.sl %s0, dst@got_hi(, %s0) + ld %s1, (%s0, %s15) +# CHECK: lea %s15, _GLOBAL_OFFSET_TABLE_@pc_lo(-24) +# CHECK-NEXT: and %s15, %s15, (32)0 +# CHECK-NEXT: sic %s16 +# CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_@pc_hi(%s16, %s15) +# CHECK-NEXT: lea %s0, dst@got_lo +# CHECK-NEXT: and %s0, %s0, (32)0 +# CHECK-NEXT: lea.sl %s0, dst@got_hi(, %s0) +# CHECK-NEXT: ld %s1, (%s0, %s15) + +# CHECK-OBJ: 0 R_VE_PC_LO32 _GLOBAL_OFFSET_TABLE_ +# CHECK-OBJ-NEXT: 18 R_VE_PC_HI32 _GLOBAL_OFFSET_TABLE_ +# CHECK-OBJ-NEXT: 20 R_VE_GOT_LO32 dst +# CHECK-OBJ-NEXT: 30 R_VE_GOT_HI32 dst diff --git a/llvm/test/MC/VE/sym-gotoff.s b/llvm/test/MC/VE/sym-gotoff.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/VE/sym-gotoff.s @@ -0,0 +1,24 @@ +# RUN: llvm-mc -triple=ve %s -o - | FileCheck %s +# RUN: llvm-mc -triple=ve -filetype=obj %s -o - | llvm-objdump -r - | FileCheck %s --check-prefix=CHECK-OBJ + + lea %s15, _GLOBAL_OFFSET_TABLE_@pc_lo(-24) + and %s15, %s15, (32)0 + sic %s16 + lea.sl %s15, _GLOBAL_OFFSET_TABLE_@pc_hi(%s16, %s15) + lea %s0, src@gotoff_lo + and %s0, %s0, (32)0 + lea.sl %s0, src@gotoff_hi(, %s0) + ld1b.zx %s0, (%s0, %s15) +# CHECK: lea %s15, _GLOBAL_OFFSET_TABLE_@pc_lo(-24) +# CHECK-NEXT: and %s15, %s15, (32)0 +# CHECK-NEXT: sic %s16 +# CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_@pc_hi(%s16, %s15) +# CHECK-NEXT: lea %s0, src@gotoff_lo +# CHECK-NEXT: and %s0, %s0, (32)0 +# CHECK-NEXT: lea.sl %s0, src@gotoff_hi(, %s0) +# CHECK-NEXT: ld1b.zx %s0, (%s0, %s15) + +# CHECK-OBJ: 0 R_VE_PC_LO32 _GLOBAL_OFFSET_TABLE_ +# CHECK-OBJ-NEXT: 18 R_VE_PC_HI32 _GLOBAL_OFFSET_TABLE_ +# CHECK-OBJ-NEXT: 20 R_VE_GOTOFF_LO32 src +# CHECK-OBJ-NEXT: 30 R_VE_GOTOFF_HI32 src diff --git a/llvm/test/MC/VE/sym-tls.s b/llvm/test/MC/VE/sym-tls.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/VE/sym-tls.s @@ -0,0 +1,24 @@ +# RUN: llvm-mc -triple=ve %s -o - | FileCheck %s +# RUN: llvm-mc -triple=ve -filetype=obj %s -o - | llvm-objdump -r - | FileCheck %s --check-prefix=CHECK-OBJ + + lea %s0, x@tls_gd_lo(-24) + and %s0, %s0, (32)0 + sic %s10 + lea.sl %s0, x@tls_gd_hi(%s10, %s0) + lea %s12, __tls_get_addr@plt_lo(8) + and %s12, %s12, (32)0 + lea.sl %s12, __tls_get_addr@plt_hi(%s10, %s12) + bsic %s10, (, %s12) +# CHECK: lea %s0, x@tls_gd_lo(-24) +# CHECK-NEXT: and %s0, %s0, (32)0 +# CHECK-NEXT: sic %s10 +# CHECK-NEXT: lea.sl %s0, x@tls_gd_hi(%s10, %s0) +# CHECK-NEXT: lea %s12, __tls_get_addr@plt_lo(8) +# CHECK-NEXT: and %s12, %s12, (32)0 +# CHECK-NEXT: lea.sl %s12, __tls_get_addr@plt_hi(%s10, %s12) +# CHECK-NEXT: bsic %s10, (, %s12) + +# CHECK-OBJ: 0 R_VE_TLS_GD_LO32 x +# CHECK-OBJ-NEXT: 18 R_VE_TLS_GD_HI32 x +# CHECK-OBJ-NEXT: 20 R_VE_PLT_LO32 __tls_get_addr +# CHECK-OBJ-NEXT: 30 R_VE_PLT_HI32 __tls_get_addr diff --git a/llvm/test/MC/VE/sym-tpoff.s b/llvm/test/MC/VE/sym-tpoff.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/VE/sym-tpoff.s @@ -0,0 +1,14 @@ +# RUN: llvm-mc -triple=ve %s -o - | FileCheck %s +# RUN: llvm-mc -triple=ve -filetype=obj %s -o - | llvm-objdump -r - | FileCheck %s --check-prefix=CHECK-OBJ + + lea %s34, x@tpoff_lo + and %s34, %s34, (32)0 + lea.sl %s34, x@tpoff_hi(%s34) + adds.l %s0, %s14, %s34 +# CHECK: lea %s34, x@tpoff_lo +# CHECK-NEXT: and %s34, %s34, (32)0 +# CHECK-NEXT: lea.sl %s34, x@tpoff_hi(%s34) +# CHECK-NEXT: adds.l %s0, %s14, %s34 + +# CHECK-OBJ: 0 R_VE_TPOFF_LO32 x +# CHECK-OBJ-NEXT: 10 R_VE_TPOFF_HI32 x diff --git a/llvm/test/MC/VE/symbols.s b/llvm/test/MC/VE/symbols.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/VE/symbols.s @@ -0,0 +1,15 @@ +# RUN: llvm-mc -triple=ve %s -o - | FileCheck %s +# RUN: llvm-mc -triple=ve -filetype=obj %s -o - | llvm-objdump -r - | FileCheck %s --check-prefix=CHECK-OBJ + + lea %s0, var + lea %s1, var@lo + and %s1, %s1, (32)0 + lea.sl %s1, var@hi(, %s1) +# CHECK: lea %s0, var +# CHECK-NEXT: lea %s1, var@lo +# CHECK-NEXT: and %s1, %s1, (32)0 +# CHECK-NEXT: lea.sl %s1, var@hi(, %s1) + +# CHECK-OBJ: 0 R_VE_REFLONG var +# CHECK-OBJ-NEXT: 8 R_VE_LO32 var +# CHECK-OBJ-NEXT: 18 R_VE_HI32 var