Skip to content

Commit

Permalink
Arm64EC entry/exit thunks, consolidated. (#79067)
Browse files Browse the repository at this point in the history
This combines the previously posted patches with some additional work
I've done to more closely match MSVC output.

Most of the important logic here is implemented in
AArch64Arm64ECCallLowering. The purpose of the
AArch64Arm64ECCallLowering is to take "normal" IR we'd generate for
other targets, and generate most of the Arm64EC-specific bits:
generating thunks, mangling symbols, generating aliases, and generating
the .hybmp$x table. This is all done late for a few reasons: to
consolidate the logic as much as possible, and to ensure the IR exposed
to optimization passes doesn't contain complex arm64ec-specific
constructs.

The other changes are supporting changes, to handle the new constructs
generated by that pass.

There's a global llvm.arm64ec.symbolmap representing the .hybmp$x
entries for the thunks. This gets handled directly by the AsmPrinter
because it needs symbol indexes that aren't available before that.

There are two new calling conventions used to represent calls to and
from thunks: ARM64EC_Thunk_X64 and ARM64EC_Thunk_Native. There are a few
changes to handle the associated exception-handling info,
SEH_SaveAnyRegQP and SEH_SaveAnyRegQPX.

I've intentionally left out handling for structs with small
non-power-of-two sizes, because that's easily separated out. The rest of
my current work is here. I squashed my current patches because they were
split in ways that didn't really make sense. Maybe I could split out
some bits, but it's hard to meaningfully test most of the parts
independently.

Thanks to @dpaoliello for extensive testing and suggestions.

(Originally posted as https://reviews.llvm.org/D157547 .)
  • Loading branch information
efriedma-quic committed Jan 23, 2024
1 parent f1d3ebc commit a6065f0
Show file tree
Hide file tree
Showing 31 changed files with 2,362 additions and 46 deletions.
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CGCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
if (getCodeGenOpts().OptimizationLevel == 0)
return true;

// Disable this optimization for ARM64EC. FIXME: This probably should work,
// but getting the symbol table correct is complicated.
if (getTarget().getTriple().isWindowsArm64EC())
return true;

// If sanitizing memory to check for use-after-dtor, do not emit as
// an alias, unless this class owns no members.
if (getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
Expand Down
10 changes: 10 additions & 0 deletions llvm/include/llvm/IR/CallingConv.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,16 @@ namespace CallingConv {
/// Used by GraalVM. Two additional registers are reserved.
GRAAL = 107,

/// Calling convention used in the ARM64EC ABI to implement calls between
/// x64 code and thunks. This is basically the x64 calling convention using
/// ARM64 register names. The first parameter is mapped to x9.
ARM64EC_Thunk_X64 = 108,

/// Calling convention used in the ARM64EC ABI to implement calls between
/// ARM64 code and thunks. This is just the ARM64 calling convention,
/// except that the first parameter is mapped to x9.
ARM64EC_Thunk_Native = 109,

/// The highest possible ID. Must be some 2^k - 1.
MaxID = 1023
};
Expand Down
33 changes: 33 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2892,6 +2892,39 @@ bool AsmPrinter::emitSpecialLLVMGlobal(const GlobalVariable *GV) {
GV->hasAvailableExternallyLinkage())
return true;

if (GV->getName() == "llvm.arm64ec.symbolmap") {
// For ARM64EC, print the table that maps between symbols and the
// corresponding thunks to translate between x64 and AArch64 code.
// This table is generated by AArch64Arm64ECCallLowering.
OutStreamer->switchSection(OutContext.getCOFFSection(
".hybmp$x", COFF::IMAGE_SCN_LNK_INFO, SectionKind::getMetadata()));
auto *Arr = cast<ConstantArray>(GV->getInitializer());
for (auto &U : Arr->operands()) {
auto *C = cast<Constant>(U);
auto *Src = cast<Function>(C->getOperand(0)->stripPointerCasts());
auto *Dst = cast<Function>(C->getOperand(1)->stripPointerCasts());
int Kind = cast<ConstantInt>(C->getOperand(2))->getZExtValue();

if (Src->hasDLLImportStorageClass()) {
// For now, we assume dllimport functions aren't directly called.
// (We might change this later to match MSVC.)
OutStreamer->emitCOFFSymbolIndex(
OutContext.getOrCreateSymbol("__imp_" + Src->getName()));
OutStreamer->emitCOFFSymbolIndex(getSymbol(Dst));
OutStreamer->emitInt32(Kind);
} else {
// FIXME: For non-dllimport functions, MSVC emits the same entry
// twice, for reasons I don't understand. I have to assume the linker
// ignores the redundant entry; there aren't any reasonable semantics
// to attach to it.
OutStreamer->emitCOFFSymbolIndex(getSymbol(Src));
OutStreamer->emitCOFFSymbolIndex(getSymbol(Dst));
OutStreamer->emitInt32(Kind);
}
}
return true;
}

if (!GV->hasAppendingLinkage()) return false;

assert(GV->hasInitializer() && "Not a special LLVM global!");
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/AArch64/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ FunctionPass *createAArch64PostSelectOptimize();
FunctionPass *createAArch64StackTaggingPass(bool IsOptNone);
FunctionPass *createAArch64StackTaggingPreRAPass();
ModulePass *createAArch64GlobalsTaggingPass();
ModulePass *createAArch64Arm64ECCallLoweringPass();

void initializeAArch64A53Fix835769Pass(PassRegistry&);
void initializeAArch64A57FPLoadBalancingPass(PassRegistry&);
Expand Down Expand Up @@ -109,6 +110,7 @@ void initializeFalkorMarkStridedAccessesLegacyPass(PassRegistry&);
void initializeLDTLSCleanupPass(PassRegistry&);
void initializeSMEABIPass(PassRegistry &);
void initializeSVEIntrinsicOptsPass(PassRegistry &);
void initializeAArch64Arm64ECCallLoweringPass(PassRegistry &);
} // end namespace llvm

#endif

0 comments on commit a6065f0

Please sign in to comment.