diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index c1a47737e334ec..3efee09694f2d5 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1237,6 +1237,9 @@ enum : unsigned { // for faster accesses SHF_HEX_GPREL = 0x10000000, + // Section must be addressible relative to GP. + SHF_V810_GPREL = 0x10000000, + // Section contains text/data which may be replicated in other sections. // Linker must retain only one copy. SHF_MIPS_NODUPES = 0x01000000, diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index d2658fdadbdc61..0f1f1ecf435a5d 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -799,6 +799,9 @@ void ScalarBitSetTraits::bitset(IO &IO, BCase(SHF_MIPS_ADDR); BCase(SHF_MIPS_STRING); break; + case ELF::EM_V810: + BCase(SHF_V810_GPREL); + break; case ELF::EM_X86_64: BCase(SHF_X86_64_LARGE); break; diff --git a/llvm/lib/Target/V810/AsmParser/V810AsmParser.cpp b/llvm/lib/Target/V810/AsmParser/V810AsmParser.cpp index e726a0d77a860e..7fe2d467d044fe 100644 --- a/llvm/lib/Target/V810/AsmParser/V810AsmParser.cpp +++ b/llvm/lib/Target/V810/AsmParser/V810AsmParser.cpp @@ -3,7 +3,10 @@ #include "MCTargetDesc/V810MCTargetDesc.h" #include "TargetInfo/V810TargetInfo.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCParser/MCAsmLexer.h" @@ -36,6 +39,7 @@ class V810AsmParser : public MCTargetAsmParser { bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; bool ParseDirective(AsmToken DirectiveID) override; + bool parseSSectionDirective(StringRef Section, unsigned Type); ParseStatus parseMEMOperand(OperandVector &Operands); ParseStatus parseBranchTargetOperand(OperandVector &Operands); @@ -353,10 +357,32 @@ bool V810AsmParser::ParseInstruction(ParseInstructionInfo &Info, } bool V810AsmParser::ParseDirective(AsmToken DirectiveID) { - // Let the MC layer handle everything + StringRef IDVal = DirectiveID.getString(); + if (IDVal == ".sbss") { + parseSSectionDirective(IDVal, ELF::SHT_NOBITS); + return false; + } + if (IDVal == ".sdata") { + parseSSectionDirective(IDVal, ELF::SHT_PROGBITS); + return false; + } + // Let the MC layer handle everything else return true; } +bool V810AsmParser::parseSSectionDirective(StringRef Section, unsigned Type) { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(getLexer().getLoc(), "unexpected token, expected end of statement"); + return false; + } + + MCSection *ELFSection = getContext().getELFSection( + Section, Type, ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_V810_GPREL); + getParser().getStreamer().switchSection(ELFSection); + + getParser().Lex(); // Eat EndOfStatement token. + return false; +} // offset[reg] // offset is an (optional) expression, reg is a register diff --git a/llvm/lib/Target/V810/V810ISelLowering.cpp b/llvm/lib/Target/V810/V810ISelLowering.cpp index 2fd90c3ea1ae1e..553ac70781be69 100644 --- a/llvm/lib/Target/V810/V810ISelLowering.cpp +++ b/llvm/lib/Target/V810/V810ISelLowering.cpp @@ -4,11 +4,11 @@ #include "MCTargetDesc/V810MCExpr.h" #include "V810RegisterInfo.h" #include "V810Subtarget.h" +#include "V810TargetObjectFile.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGNodes.h" -#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/Support/KnownBits.h" @@ -584,15 +584,14 @@ static V810CC::CondCodes FloatCondCodeToCC(ISD::CondCode CC) { } } -static bool CanBeGPRelative(const GlobalValue *GVal) { - const GlobalVariable *GVar = dyn_cast(GVal); - if (!GVar) return false; - if (GVar->isConstant()) return false; - return !GVar->hasSection() || GVar->getSection().starts_with(".sdata"); -} - bool V810TargetLowering::IsGPRelative(const GlobalValue *GVal) const { - return CanBeGPRelative(GVal) && Subtarget->enableGPRelativeRAM(); + if (!Subtarget->enableGPRelativeRAM()) { + return false; + } + const V810TargetObjectFile *TLOF = + static_cast( + getTargetMachine().getObjFileLowering()); + return TLOF->isGlobalInSmallSection(GVal->getAliaseeObject(), getTargetMachine()); } static SDValue BuildMovhiMoveaPair(SelectionDAG &DAG, const GlobalValue *GV, SDLoc DL, EVT VT, int64_t Offset) { @@ -611,7 +610,7 @@ static SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG, const V810Targe const GlobalValue *GV = GN->getGlobal(); if (TLI->IsGPRelative(GV)) { - // Every mutable global variable is stored in RAM, and every address in RAM + // The address of every global variable in the "small data" area // can be expressed by a 16-bit signed offset from the GP register (R4). SDValue RelTarget = DAG.getTargetGlobalAddress(GV, DL, GN->getValueType(0), GN->getOffset(), V810MCExpr::VK_V810_SDAOFF); SDValue Reg = DAG.getRegister(V810::R4, GN->getValueType(0)); diff --git a/llvm/lib/Target/V810/V810TargetMachine.h b/llvm/lib/Target/V810/V810TargetMachine.h index 0ef08f10ac928c..2ff51ba948aad4 100644 --- a/llvm/lib/Target/V810/V810TargetMachine.h +++ b/llvm/lib/Target/V810/V810TargetMachine.h @@ -19,6 +19,7 @@ class V810TargetMachine : public LLVMTargetMachine { bool JIT); ~V810TargetMachine() override; + const V810Subtarget *getSubtargetImpl() const; const V810Subtarget *getSubtargetImpl(const Function &F) const override; TargetPassConfig *createPassConfig(PassManagerBase &PM) override; diff --git a/llvm/lib/Target/V810/V810TargetObjectFile.cpp b/llvm/lib/Target/V810/V810TargetObjectFile.cpp index e8b70ec9c301e8..213ac500abbb74 100644 --- a/llvm/lib/Target/V810/V810TargetObjectFile.cpp +++ b/llvm/lib/Target/V810/V810TargetObjectFile.cpp @@ -1 +1,72 @@ -#include "V810TargetObjectFile.h" \ No newline at end of file +#include "V810Subtarget.h" +#include "V810TargetMachine.h" +#include "V810TargetObjectFile.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Target/TargetMachine.h" + +#define DEBUG_TYPE "v810-sdata" + +using namespace llvm; + +void V810TargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM) { + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + + SmallDataSection = + getContext().getELFSection(".sdata", ELF::SHT_PROGBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC | + ELF::SHF_V810_GPREL); + + SmallBSSSection = + getContext().getELFSection(".sbss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC | + ELF::SHF_V810_GPREL); +} + +static bool isSmallDataSection(StringRef Sec) { + return Sec.starts_with(".sdata") || Sec.starts_with(".sbss"); +} + +bool V810TargetObjectFile::isGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM) const { + const GlobalVariable *GVar = dyn_cast(GO); + if (!GVar) return false; + if (GVar->isConstant()) return false; + if (GVar->hasSection()) { + return isSmallDataSection(GVar->getSection()); + } + if (TM.getMCSubtargetInfo()->checkFeatures("+gprel")) { + // Put ALL non-constant variables in a small section + return true; + } + // It's all or nothing + return false; +} + +MCSection *V810TargetObjectFile::SelectSectionForGlobal( + const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { + + if (isGlobalInSmallSection(GO, TM)) + return selectSmallSectionForGlobal(GO, Kind, TM); + + return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); +} + +MCSection *V810TargetObjectFile::getExplicitSectionGlobal( + const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { + + if (isGlobalInSmallSection(GO, TM)) + return selectSmallSectionForGlobal(GO, Kind, TM); + + return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, Kind, TM); +} + +MCSection *V810TargetObjectFile::selectSmallSectionForGlobal(const GlobalObject *GO, + SectionKind Kind, + const TargetMachine &TM) const { + if (Kind.isBSS()) + return SmallBSSSection; + if (Kind.isData()) + return SmallDataSection; + + return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); +} \ No newline at end of file diff --git a/llvm/lib/Target/V810/V810TargetObjectFile.h b/llvm/lib/Target/V810/V810TargetObjectFile.h index bb70633d1802e2..6ee95c2a6853d2 100644 --- a/llvm/lib/Target/V810/V810TargetObjectFile.h +++ b/llvm/lib/Target/V810/V810TargetObjectFile.h @@ -2,6 +2,7 @@ #define LLVM_LIB_TARGET_V810_V810TARGETOBJECTFILE_H #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/MC/MCSectionELF.h" namespace llvm { @@ -10,7 +11,23 @@ class TargetMachine; class V810TargetObjectFile : public TargetLoweringObjectFileELF { public: - V810TargetObjectFile() = default; + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &MT) const override; + + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, + SectionKind Kind, + const TargetMachine &TM) const override; + + bool isGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM) const; +private: + MCSectionELF *SmallDataSection; + MCSectionELF *SmallBSSSection; + + MCSection *selectSmallSectionForGlobal(const GlobalObject *GO, + SectionKind Kind, + const TargetMachine &TM) const; }; } // end namespace llvm diff --git a/llvm/test/CodeGen/V810/gprel.ll b/llvm/test/CodeGen/V810/gprel.ll index 072815dd46c14f..4f0f8d95c42bf0 100644 --- a/llvm/test/CodeGen/V810/gprel.ll +++ b/llvm/test/CodeGen/V810/gprel.ll @@ -6,7 +6,7 @@ @mutable_global = external dso_local global [4 x i32], align 4 @mutable_global_struct = external dso_local global %SomeStruct, align 4 -@immutable_global = external dso_local constant i32, align 4 +@immutable_global = external dso_local constant [4 x i32], align 4 define i32 @test_gprel_read() { ; GPREL-LABEL: test_gprel_read: @@ -127,6 +127,6 @@ define i32 @test_const_read() { ; NO-GPREL-NEXT: ld.w 0[r6], r10 ; NO-GPREL-NEXT: jmp [r31] entry: - %0 = load i32, ptr @immutable_global, align 4 + %0 = load i32, ptr getelementptr inbounds ([4 x i32], ptr @immutable_global, i32 0, i32 0), align 4 ret i32 %0 } diff --git a/llvm/test/CodeGen/V810/v810-shf-gprel.s b/llvm/test/CodeGen/V810/v810-shf-gprel.s new file mode 100644 index 00000000000000..f419515cff5e9b --- /dev/null +++ b/llvm/test/CodeGen/V810/v810-shf-gprel.s @@ -0,0 +1,27 @@ +# Check that .sdata and .sbss sections have SHF_V810_GPREL flags +# and proper section types. + +# RUN: llvm-mc -filetype=obj -triple=v810-unknown-vb %s -o - \ +# RUN: | llvm-readobj -S - | FileCheck %s + + .sdata + .word 0 + + .sbss + .zero 4 + +# CHECK: Name: .sdata +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ (0x10000003) +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_V810_GPREL +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] + +# CHECK: Name: .sbss +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ (0x10000003) +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_V810_GPREL +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index bf09a7ddd73a57..cc460df3fb8c82 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1357,6 +1357,10 @@ const EnumEntry ElfMipsSectionFlags[] = { ENUM_ENT(SHF_MIPS_STRING, "") }; +const EnumEntry ElfV810SectionFlags[] = { + ENUM_ENT(SHF_V810_GPREL, "") +}; + const EnumEntry ElfX86_64SectionFlags[] = { ENUM_ENT(SHF_X86_64_LARGE, "l") }; @@ -1388,6 +1392,10 @@ getSectionFlagsForTarget(unsigned EOSAbi, unsigned EMachine) { Ret.insert(Ret.end(), std::begin(ElfMipsSectionFlags), std::end(ElfMipsSectionFlags)); break; + case EM_V810: + Ret.insert(Ret.end(), std::begin(ElfV810SectionFlags), + std::end(ElfV810SectionFlags)); + break; case EM_X86_64: Ret.insert(Ret.end(), std::begin(ElfX86_64SectionFlags), std::end(ElfX86_64SectionFlags));