Skip to content

Commit 29d50a1

Browse files
committed
[aarch64][win] Add support for import call optimization (equivalent to MSVC /d2ImportCallOptimization)
1 parent cbff02b commit 29d50a1

21 files changed

+372
-4
lines changed

llvm/include/llvm/CodeGen/MachineFunction.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,11 @@ class LLVM_ABI MachineFunction {
354354
/// a table of valid targets for Windows EHCont Guard.
355355
std::vector<MCSymbol *> CatchretTargets;
356356

357+
/// Mapping of call instruction to the global value and target flags that it
358+
/// calls, if applicable.
359+
DenseMap<const MachineInstr *, std::pair<const GlobalValue *, unsigned>>
360+
CalledGlobalsMap;
361+
357362
/// \name Exception Handling
358363
/// \{
359364

@@ -1182,6 +1187,19 @@ class LLVM_ABI MachineFunction {
11821187
CatchretTargets.push_back(Target);
11831188
}
11841189

1190+
/// Tries to get the global and target flags for a call site, if the
1191+
/// instruction is a call to a global.
1192+
std::pair<const GlobalValue *, unsigned>
1193+
tryGetCalledGlobal(const MachineInstr *MI) const {
1194+
return CalledGlobalsMap.lookup(MI);
1195+
}
1196+
1197+
/// Notes the global and target flags for a call site.
1198+
void addCalledGlobal(const MachineInstr *MI,
1199+
std::pair<const GlobalValue *, unsigned> Details) {
1200+
CalledGlobalsMap.insert({MI, Details});
1201+
}
1202+
11851203
/// \name Exception Handling
11861204
/// \{
11871205

llvm/include/llvm/CodeGen/SelectionDAG.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ class SelectionDAG {
293293
MDNode *HeapAllocSite = nullptr;
294294
MDNode *PCSections = nullptr;
295295
MDNode *MMRA = nullptr;
296+
std::pair<const GlobalValue *, unsigned> CalledGlobal{};
296297
bool NoMerge = false;
297298
};
298299
/// Out-of-line extra information for SDNodes.
@@ -2373,6 +2374,19 @@ class SelectionDAG {
23732374
auto It = SDEI.find(Node);
23742375
return It != SDEI.end() ? It->second.MMRA : nullptr;
23752376
}
2377+
/// Set CalledGlobal to be associated with Node.
2378+
void addCalledGlobal(const SDNode *Node, const GlobalValue *GV,
2379+
unsigned OpFlags) {
2380+
SDEI[Node].CalledGlobal = {GV, OpFlags};
2381+
}
2382+
/// Return CalledGlobal associated with Node, or a nullopt if none exists.
2383+
std::optional<std::pair<const GlobalValue *, unsigned>>
2384+
getCalledGlobal(const SDNode *Node) {
2385+
auto I = SDEI.find(Node);
2386+
return I != SDEI.end()
2387+
? std::make_optional(std::move(I->second).CalledGlobal)
2388+
: std::nullopt;
2389+
}
23762390
/// Set NoMergeSiteInfo to be associated with Node if NoMerge is true.
23772391
void addNoMergeSiteInfo(const SDNode *Node, bool NoMerge) {
23782392
if (NoMerge)

llvm/include/llvm/MC/MCObjectFileInfo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ class MCObjectFileInfo {
7373
/// to emit them into.
7474
MCSection *CompactUnwindSection = nullptr;
7575

76+
/// If import call optimization is supported by the target, this is the
77+
/// section to emit import call data to.
78+
MCSection *ImportCallSection = nullptr;
79+
7680
// Dwarf sections for debug info. If a target supports debug info, these must
7781
// be set.
7882
MCSection *DwarfAbbrevSection = nullptr;
@@ -269,6 +273,7 @@ class MCObjectFileInfo {
269273
MCSection *getBSSSection() const { return BSSSection; }
270274
MCSection *getReadOnlySection() const { return ReadOnlySection; }
271275
MCSection *getLSDASection() const { return LSDASection; }
276+
MCSection *getImportCallSection() const { return ImportCallSection; }
272277
MCSection *getCompactUnwindSection() const { return CompactUnwindSection; }
273278
MCSection *getDwarfAbbrevSection() const { return DwarfAbbrevSection; }
274279
MCSection *getDwarfInfoSection() const { return DwarfInfoSection; }

llvm/include/llvm/MC/MCStreamer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,9 @@ class MCStreamer {
569569
/// \param Symbol - Symbol the image relative relocation should point to.
570570
virtual void emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset);
571571

572+
/// Emits an import call directive, used to build the import call table.
573+
virtual void emitCOFFImpCall(MCSymbol const *Symbol);
574+
572575
/// Emits an lcomm directive with XCOFF csect information.
573576
///
574577
/// \param LabelSym - Label on the block of storage.

llvm/include/llvm/MC/MCWinCOFFObjectWriter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ class WinCOFFObjectWriter final : public MCObjectWriter {
7272
const MCFixup &Fixup, MCValue Target,
7373
uint64_t &FixedValue) override;
7474
uint64_t writeObject(MCAssembler &Asm) override;
75+
void recordImportCall(const MCDataFragment &FB, const MCSymbol *Symbol);
76+
bool hasRecordedImportCalls() const;
7577
};
7678

7779
/// Construct a new Win COFF writer instance.

llvm/include/llvm/MC/MCWinCOFFStreamer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class MCWinCOFFStreamer : public MCObjectStreamer {
5858
void emitCOFFSectionIndex(MCSymbol const *Symbol) override;
5959
void emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override;
6060
void emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override;
61+
void emitCOFFImpCall(MCSymbol const *Symbol) override;
6162
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
6263
Align ByteAlignment) override;
6364
void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,

llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,9 @@ EmitSchedule(MachineBasicBlock::iterator &InsertPos) {
908908
It->setMMRAMetadata(MF, MMRA);
909909
}
910910

911+
if (auto CalledGlobal = DAG->getCalledGlobal(Node))
912+
MF.addCalledGlobal(MI, *CalledGlobal);
913+
911914
return MI;
912915
};
913916

llvm/lib/MC/MCAsmStreamer.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class MCAsmStreamer final : public MCStreamer {
209209
void emitCOFFSectionIndex(MCSymbol const *Symbol) override;
210210
void emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override;
211211
void emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override;
212+
void emitCOFFImpCall(MCSymbol const *Symbol) override;
212213
void emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size,
213214
MCSymbol *CsectSym, Align Alignment) override;
214215
void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
@@ -893,6 +894,14 @@ void MCAsmStreamer::emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {
893894
EmitEOL();
894895
}
895896

897+
void MCAsmStreamer::emitCOFFImpCall(MCSymbol const *Symbol) {
898+
assert(this->getContext().getObjectFileInfo()->getImportCallSection() &&
899+
"This target does not have a import call section");
900+
OS << "\t.impcall\t";
901+
Symbol->print(OS, MAI);
902+
EmitEOL();
903+
}
904+
896905
// We need an XCOFF-specific version of this directive as the AIX syntax
897906
// requires a QualName argument identifying the csect name and storage mapping
898907
// class to appear before the alignment if we are specifying it.

llvm/lib/MC/MCObjectFileInfo.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) {
596596
COFF::IMAGE_SCN_MEM_READ);
597597
}
598598

599+
if (T.getArch() == Triple::aarch64) {
600+
ImportCallSection =
601+
Ctx->getCOFFSection(".impcall", COFF::IMAGE_SCN_LNK_INFO);
602+
}
603+
599604
// Debug info.
600605
COFFDebugSymbolsSection =
601606
Ctx->getCOFFSection(".debug$S", (COFF::IMAGE_SCN_MEM_DISCARDABLE |

llvm/lib/MC/MCParser/COFFAsmParser.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "llvm/BinaryFormat/COFF.h"
1313
#include "llvm/MC/MCContext.h"
1414
#include "llvm/MC/MCDirectives.h"
15+
#include "llvm/MC/MCObjectFileInfo.h"
1516
#include "llvm/MC/MCParser/MCAsmLexer.h"
1617
#include "llvm/MC/MCParser/MCAsmParserExtension.h"
1718
#include "llvm/MC/MCSectionCOFF.h"
@@ -70,6 +71,7 @@ class COFFAsmParser : public MCAsmParserExtension {
7071
addDirectiveHandler<&COFFAsmParser::parseDirectiveSymbolAttribute>(
7172
".weak_anti_dep");
7273
addDirectiveHandler<&COFFAsmParser::parseDirectiveCGProfile>(".cg_profile");
74+
addDirectiveHandler<&COFFAsmParser::parseDirectiveImpCall>(".impcall");
7375

7476
// Win64 EH directives.
7577
addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveStartProc>(
@@ -126,6 +128,7 @@ class COFFAsmParser : public MCAsmParserExtension {
126128
bool parseDirectiveLinkOnce(StringRef, SMLoc);
127129
bool parseDirectiveRVA(StringRef, SMLoc);
128130
bool parseDirectiveCGProfile(StringRef, SMLoc);
131+
bool parseDirectiveImpCall(StringRef, SMLoc);
129132

130133
// Win64 EH directives.
131134
bool parseSEHDirectiveStartProc(StringRef, SMLoc);
@@ -577,6 +580,24 @@ bool COFFAsmParser::parseDirectiveSymIdx(StringRef, SMLoc) {
577580
return false;
578581
}
579582

583+
bool COFFAsmParser::parseDirectiveImpCall(StringRef, SMLoc) {
584+
if (!getContext().getObjectFileInfo()->getImportCallSection())
585+
return TokError("target does not have an import call section");
586+
587+
StringRef SymbolID;
588+
if (getParser().parseIdentifier(SymbolID))
589+
return TokError("expected identifier in directive");
590+
591+
if (getLexer().isNot(AsmToken::EndOfStatement))
592+
return TokError("unexpected token in directive");
593+
594+
MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
595+
596+
Lex();
597+
getStreamer().emitCOFFImpCall(Symbol);
598+
return false;
599+
}
600+
580601
/// ::= [ identifier ]
581602
bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
582603
StringRef TypeId = getTok().getIdentifier();

llvm/lib/MC/MCStreamer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,8 @@ void MCStreamer::emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {}
10231023

10241024
void MCStreamer::emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {}
10251025

1026+
void MCStreamer::emitCOFFImpCall(MCSymbol const *Symbol) {}
1027+
10261028
/// EmitRawText - If this file is backed by an assembly streamer, this dumps
10271029
/// the specified string in the output .s file. This capability is
10281030
/// indicated by the hasRawTextSupport() predicate.

llvm/lib/MC/MCWinCOFFStreamer.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,15 @@ void MCWinCOFFStreamer::emitCOFFImgRel32(const MCSymbol *Symbol,
280280
DF->appendContents(4, 0);
281281
}
282282

283+
void MCWinCOFFStreamer::emitCOFFImpCall(MCSymbol const *Symbol) {
284+
assert(this->getContext().getObjectFileInfo()->getImportCallSection() &&
285+
"This target does not have a import call section");
286+
287+
auto *DF = getOrCreateDataFragment();
288+
getAssembler().registerSymbol(*Symbol);
289+
getWriter().recordImportCall(*DF, Symbol);
290+
}
291+
283292
void MCWinCOFFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
284293
Align ByteAlignment) {
285294
auto *Symbol = cast<MCSymbolCOFF>(S);

llvm/lib/MC/WinCOFFObjectWriter.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/MC/MCExpr.h"
2424
#include "llvm/MC/MCFixup.h"
2525
#include "llvm/MC/MCFragment.h"
26+
#include "llvm/MC/MCObjectFileInfo.h"
2627
#include "llvm/MC/MCObjectWriter.h"
2728
#include "llvm/MC/MCSection.h"
2829
#include "llvm/MC/MCSectionCOFF.h"
@@ -147,6 +148,13 @@ class llvm::WinCOFFWriter {
147148
bool UseBigObj;
148149
bool UseOffsetLabels = false;
149150

151+
struct ImportCall {
152+
unsigned CallsiteOffset;
153+
const MCSymbol *CalledSymbol;
154+
};
155+
using importcall_map = MapVector<MCSection *, std::vector<ImportCall>>;
156+
importcall_map SectionToImportCallsMap;
157+
150158
public:
151159
enum DwoMode {
152160
AllSections,
@@ -163,6 +171,11 @@ class llvm::WinCOFFWriter {
163171
const MCFixup &Fixup, MCValue Target,
164172
uint64_t &FixedValue);
165173
uint64_t writeObject(MCAssembler &Asm);
174+
void generateAArch64ImportCallSection(llvm::MCAssembler &Asm);
175+
void recordImportCall(const MCDataFragment &FB, const MCSymbol *Symbol);
176+
bool hasRecordedImportCalls() const {
177+
return !SectionToImportCallsMap.empty();
178+
}
166179

167180
private:
168181
COFFSymbol *createSymbol(StringRef Name);
@@ -1097,6 +1110,17 @@ uint64_t WinCOFFWriter::writeObject(MCAssembler &Asm) {
10971110
}
10981111
}
10991112

1113+
// Create the contents of the import call section.
1114+
if (hasRecordedImportCalls()) {
1115+
switch (Asm.getContext().getTargetTriple().getArch()) {
1116+
case Triple::aarch64:
1117+
generateAArch64ImportCallSection(Asm);
1118+
break;
1119+
default:
1120+
llvm_unreachable("unsupported architecture for import call section");
1121+
}
1122+
}
1123+
11001124
assignFileOffsets(Asm);
11011125

11021126
// MS LINK expects to be able to use this timestamp to implement their
@@ -1143,6 +1167,51 @@ uint64_t WinCOFFWriter::writeObject(MCAssembler &Asm) {
11431167
return W.OS.tell() - StartOffset;
11441168
}
11451169

1170+
void llvm::WinCOFFWriter::generateAArch64ImportCallSection(
1171+
llvm::MCAssembler &Asm) {
1172+
auto *ImpCallSection =
1173+
Asm.getContext().getObjectFileInfo()->getImportCallSection();
1174+
1175+
if (!SectionMap.contains(ImpCallSection)) {
1176+
Asm.getContext().reportError(SMLoc(),
1177+
".impcall directives were used, but no "
1178+
"existing .impcall section exists");
1179+
return;
1180+
}
1181+
1182+
auto *Frag = cast<MCDataFragment>(ImpCallSection->curFragList()->Head);
1183+
raw_svector_ostream OS(Frag->getContents());
1184+
1185+
// Layout of this section is:
1186+
// Per section that contains calls to imported functions:
1187+
// uint32_t SectionSize: Size in bytes for information in this section.
1188+
// uint32_t Section Number
1189+
// Per call to imported function in section:
1190+
// uint32_t Kind: the kind of imported function.
1191+
// uint32_t BranchOffset: the offset of the branch instruction in its
1192+
// parent section.
1193+
// uint32_t TargetSymbolId: the symbol id of the called function.
1194+
1195+
// Per section that contained eligible targets...
1196+
for (auto &[Section, Targets] : SectionToImportCallsMap) {
1197+
unsigned SectionSize = sizeof(uint32_t) * (2 + 3 * Targets.size());
1198+
support::endian::write(OS, SectionSize, W.Endian);
1199+
support::endian::write(OS, SectionMap.at(Section)->Number, W.Endian);
1200+
for (auto &[BranchOffset, TargetSymbol] : Targets) {
1201+
// Kind is always IMAGE_REL_ARM64_DYNAMIC_IMPORT_CALL (0x13).
1202+
support::endian::write(OS, 0x13, W.Endian);
1203+
support::endian::write(OS, BranchOffset, W.Endian);
1204+
support::endian::write(OS, TargetSymbol->getIndex(), W.Endian);
1205+
}
1206+
}
1207+
}
1208+
1209+
void WinCOFFWriter::recordImportCall(const MCDataFragment &FB,
1210+
const MCSymbol *Symbol) {
1211+
auto &SectionData = SectionToImportCallsMap[FB.getParent()];
1212+
SectionData.push_back(ImportCall{unsigned(FB.getContents().size()), Symbol});
1213+
}
1214+
11461215
//------------------------------------------------------------------------------
11471216
// WinCOFFObjectWriter class implementation
11481217

@@ -1194,6 +1263,15 @@ uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm) {
11941263
return TotalSize;
11951264
}
11961265

1266+
void WinCOFFObjectWriter::recordImportCall(const MCDataFragment &FB,
1267+
const MCSymbol *Symbol) {
1268+
ObjWriter->recordImportCall(FB, Symbol);
1269+
}
1270+
1271+
bool WinCOFFObjectWriter::hasRecordedImportCalls() const {
1272+
return ObjWriter->hasRecordedImportCalls();
1273+
}
1274+
11971275
MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_)
11981276
: Machine(Machine_) {}
11991277

0 commit comments

Comments
 (0)