Skip to content

Commit 7cc03bd

Browse files
committedApr 11, 2019
[RISCV] Put data smaller than eight bytes to small data section
Because of gp = sdata_start_address + 0x800, gp with signed twelve-bit offset could covert most of the small data section. Linker relaxation could transfer the multiple data accessing instructions to a gp base with signed twelve-bit offset instruction. Differential Revision: https://reviews.llvm.org/D57493 llvm-svn: 358150
1 parent 98da442 commit 7cc03bd

File tree

8 files changed

+186
-0
lines changed

8 files changed

+186
-0
lines changed
 

‎llvm/include/llvm/Target/TargetLoweringObjectFile.h

+3
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
7979
/// Emit the module-level metadata that the platform cares about.
8080
virtual void emitModuleMetadata(MCStreamer &Streamer, Module &M) const {}
8181

82+
/// Get the module-level metadata that the platform cares about.
83+
virtual void getModuleMetadata(Module &M) {}
84+
8285
/// Given a constant with the SectionKind, return a section that it should be
8386
/// placed in.
8487
virtual MCSection *getSectionForConstant(const DataLayout &DL,

‎llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ bool AsmPrinter::doInitialization(Module &M) {
259259
const_cast<TargetLoweringObjectFile&>(getObjFileLowering())
260260
.Initialize(OutContext, TM);
261261

262+
const_cast<TargetLoweringObjectFile &>(getObjFileLowering())
263+
.getModuleMetadata(M);
264+
262265
OutStreamer->InitSections(false);
263266

264267
// Emit the version-min deployment target directive if needed.

‎llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp

+96
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,107 @@
88

99
#include "RISCVTargetObjectFile.h"
1010
#include "RISCVTargetMachine.h"
11+
#include "llvm/BinaryFormat/ELF.h"
12+
#include "llvm/MC/MCContext.h"
13+
#include "llvm/MC/MCSectionELF.h"
1114

1215
using namespace llvm;
1316

1417
void RISCVELFTargetObjectFile::Initialize(MCContext &Ctx,
1518
const TargetMachine &TM) {
1619
TargetLoweringObjectFileELF::Initialize(Ctx, TM);
1720
InitializeELF(TM.Options.UseInitArray);
21+
22+
SmallDataSection = getContext().getELFSection(
23+
".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC);
24+
SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS,
25+
ELF::SHF_WRITE | ELF::SHF_ALLOC);
26+
}
27+
28+
// A address must be loaded from a small section if its size is less than the
29+
// small section size threshold. Data in this section could be addressed by
30+
// using gp_rel operator.
31+
bool RISCVELFTargetObjectFile::isInSmallSection(uint64_t Size) const {
32+
// gcc has traditionally not treated zero-sized objects as small data, so this
33+
// is effectively part of the ABI.
34+
return Size > 0 && Size <= SSThreshold;
35+
}
36+
37+
// Return true if this global address should be placed into small data/bss
38+
// section.
39+
bool RISCVELFTargetObjectFile::isGlobalInSmallSection(
40+
const GlobalObject *GO, const TargetMachine &TM) const {
41+
// Only global variables, not functions.
42+
const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO);
43+
if (!GVA)
44+
return false;
45+
46+
// If the variable has an explicit section, it is placed in that section.
47+
if (GVA->hasSection()) {
48+
StringRef Section = GVA->getSection();
49+
50+
// Explicitly placing any variable in the small data section overrides
51+
// the global -G value.
52+
if (Section == ".sdata" || Section == ".sbss")
53+
return true;
54+
55+
// Otherwise reject putting the variable to small section if it has an
56+
// explicit section name.
57+
return false;
58+
}
59+
60+
if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) ||
61+
GVA->hasCommonLinkage()))
62+
return false;
63+
64+
Type *Ty = GVA->getValueType();
65+
// It is possible that the type of the global is unsized, i.e. a declaration
66+
// of a extern struct. In this case don't presume it is in the small data
67+
// section. This happens e.g. when building the FreeBSD kernel.
68+
if (!Ty->isSized())
69+
return false;
70+
71+
return isInSmallSection(
72+
GVA->getParent()->getDataLayout().getTypeAllocSize(Ty));
73+
}
74+
75+
MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal(
76+
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
77+
// Handle Small Section classification here.
78+
if (Kind.isBSS() && isGlobalInSmallSection(GO, TM))
79+
return SmallBSSSection;
80+
if (Kind.isData() && isGlobalInSmallSection(GO, TM))
81+
return SmallDataSection;
82+
83+
// Otherwise, we work the same as ELF.
84+
return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
85+
}
86+
87+
void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) {
88+
SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags;
89+
M.getModuleFlagsMetadata(ModuleFlags);
90+
91+
for (const auto &MFE : ModuleFlags) {
92+
StringRef Key = MFE.Key->getString();
93+
if (Key == "SmallDataLimit") {
94+
SSThreshold = mdconst::extract<ConstantInt>(MFE.Val)->getZExtValue();
95+
break;
96+
}
97+
}
98+
}
99+
100+
/// Return true if this constant should be placed into small data section.
101+
bool RISCVELFTargetObjectFile::isConstantInSmallSection(
102+
const DataLayout &DL, const Constant *CN) const {
103+
return isInSmallSection(DL.getTypeAllocSize(CN->getType()));
104+
}
105+
106+
MCSection *RISCVELFTargetObjectFile::getSectionForConstant(
107+
const DataLayout &DL, SectionKind Kind, const Constant *C,
108+
unsigned &Align) const {
109+
if (isConstantInSmallSection(DL, C))
110+
return SmallDataSection;
111+
112+
// Otherwise, we work the same as ELF.
113+
return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align);
18114
}

‎llvm/lib/Target/RISCV/RISCVTargetObjectFile.h

+24
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,31 @@ class RISCVTargetMachine;
1616

1717
/// This implementation is used for RISCV ELF targets.
1818
class RISCVELFTargetObjectFile : public TargetLoweringObjectFileELF {
19+
MCSection *SmallDataSection;
20+
MCSection *SmallBSSSection;
21+
unsigned SSThreshold = 8;
22+
23+
public:
1924
void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
25+
26+
/// Return true if this global address should be placed into small data/bss
27+
/// section.
28+
bool isGlobalInSmallSection(const GlobalObject *GO,
29+
const TargetMachine &TM) const;
30+
31+
MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
32+
const TargetMachine &TM) const override;
33+
34+
/// Return true if this constant should be placed into small data section.
35+
bool isConstantInSmallSection(const DataLayout &DL, const Constant *CN) const;
36+
37+
MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind,
38+
const Constant *C,
39+
unsigned &Align) const override;
40+
41+
void getModuleMetadata(Module &M) override;
42+
43+
bool isInSmallSection(uint64_t Size) const;
2044
};
2145

2246
} // end namespace llvm
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32 %s
2+
; RUN: llc -mtriple=riscv64 < %s | FileCheck -check-prefix=RV64 %s
3+
4+
@v = dso_local global i32 0, align 4
5+
@r = dso_local global i64 7, align 8
6+
7+
; SmallDataLimit set to 0, so we expect no data will put in sbss and sdata.
8+
!llvm.module.flags = !{!0}
9+
!0 = !{i32 1, !"SmallDataLimit", i32 0}
10+
11+
; RV32-NOT: .section .sbss
12+
; RV32-NOT: .section .sdata
13+
; RV64-NOT: .section .sbss
14+
; RV64-NOT: .section .sdata
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32 %s
2+
; RUN: llc -mtriple=riscv64 < %s | FileCheck -check-prefix=RV64 %s
3+
4+
@v = dso_local global i32 0, align 4
5+
@r = dso_local global i64 7, align 8
6+
7+
; SmallDataLimit set to 4, so we expect @v will be put in sbss,
8+
; but @r won't be put in sdata.
9+
!llvm.module.flags = !{!0}
10+
!0 = !{i32 1, !"SmallDataLimit", i32 4}
11+
12+
; RV32: .section .sbss
13+
; RV32-NOT: .section .sdata
14+
; RV64: .section .sbss
15+
; RV64-NOT: .section .sdata
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32 %s
2+
; RUN: llc -mtriple=riscv64 < %s | FileCheck -check-prefix=RV64 %s
3+
4+
@v = dso_local global i32 0, align 4
5+
@r = dso_local global i64 7, align 8
6+
7+
; SmallDataLimit set to 8, so we expect @v will be put in sbss
8+
; and @r will be put in sdata.
9+
!llvm.module.flags = !{!0}
10+
!0 = !{i32 1, !"SmallDataLimit", i32 8}
11+
12+
; RV32: .section .sbss
13+
; RV32: .section .sdata
14+
; RV64: .section .sbss
15+
; RV64: .section .sdata
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32 %s
2+
; RUN: llc -mtriple=riscv64 < %s | FileCheck -check-prefix=RV64 %s
3+
4+
@v = internal global i32 0, align 4
5+
@r = internal global i64 7, align 8
6+
7+
; @v and @r are local symbols.
8+
; SmallDataLimit set to 8, so we expect @v will be put in sbss
9+
; and @r will be put in sdata.
10+
!llvm.module.flags = !{!0}
11+
!0 = !{i32 1, !"SmallDataLimit", i32 8}
12+
13+
; RV32: .section .sbss
14+
; RV32: .section .sdata
15+
; RV64: .section .sbss
16+
; RV64: .section .sdata

0 commit comments

Comments
 (0)
Please sign in to comment.