Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions llvm/include/llvm/BinaryFormat/GoObj.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ namespace GoObj {
// Go function. GoObj serialization strips it and records ABI0 separately.
inline constexpr char ABI0SymbolSuffix[] = "<ABI0>";

// Compiler-generated references to predefined Go runtime symbols carry this
// prefix followed by their decimal GoObj builtin index and a closing '>'. The
// suffix keeps those declarations distinct from runtime package definitions in
// LLVM IR. GoObj serialization strips it and normally records PkgIdxBuiltin
// plus the encoded index instead.
inline constexpr char BuiltinSymbolSuffixPrefix[] = "<builtin.";

// References resolved through //go:linkname carry this suffix instead of a
// builtin suffix. It remains orthogonal to ABI identity, so ABI0 linkname
// references end in <linkname><ABI0>. GoObj strips it and preserves
// name-based non-package reference classification.
inline constexpr char LinknameSymbolSuffix[] = "<linkname>";

// "GoNoSplt" encoded as the stable STACKMAP identifier for the function-level
// entry argument pointer map. This record is metadata-only: it is present for
// both split and nosplit functions and never denotes a callsite.
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/CommandFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct GoObjConfig {
std::vector<std::string> Experiments;
bool IsMain = false;
bool IsShared = false;
bool IsStd = false;
};

LLVM_ABI void setGoObjConfig(GoObjConfig Config);
Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/CodeGen/GoCallingConv.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "llvm/IR/Function.h"
#include "llvm/Support/Alignment.h"
#include <cstdint>
#include <string>

namespace llvm {

Expand Down Expand Up @@ -123,6 +124,12 @@ bool isFloatingPiece(Type *Ty);
void addGoObjABI0Callee(MachineInstrBuilder &MIB, MachineFunction &MF,
StringRef SymbolName);

/// Resolve a compiler-provided Go builtin declaration by its logical linker
/// name and calling convention. The declaration name carries its GoObj builtin
/// index, so target late passes never need a duplicate builtin table.
std::string getGoObjBuiltinCalleeName(MachineFunction &MF, StringRef SymbolName,
CallingConv::ID CC);

} // namespace goabi
} // namespace llvm

Expand Down
24 changes: 10 additions & 14 deletions llvm/include/llvm/MC/MCContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,7 @@ class MCContext {
std::array<uint8_t, 8> Fingerprint = {};
};

enum class GoObjSymbolRefKind : uint8_t {
Imported = 1,
Builtin = 2,
};

struct GoObjSymbolRef {
GoObjSymbolRefKind Kind = GoObjSymbolRefKind::Imported;
struct GoObjImportedSymbolRef {
std::string PackagePrefix;
uint32_t SymIdx = 0;
uint8_t Flags2 = 0;
Expand Down Expand Up @@ -290,8 +284,8 @@ class MCContext {
/// Imported packages and their opaque linker fingerprints, in source order.
std::vector<GoObjImport> GoObjImports;

/// Indexed imported or builtin references keyed by their MC symbol.
DenseMap<const MCSymbol *, GoObjSymbolRef> GoObjSymbolRefs;
/// Indexed imported references keyed by their MC symbol.
DenseMap<const MCSymbol *, GoObjImportedSymbolRef> GoObjImportedSymbolRefs;

/// Explicit LLVM global alignments for Go object data symbols.
DenseMap<const MCSymbol *, uint32_t> GoObjSymbolAlignments;
Expand Down Expand Up @@ -852,13 +846,15 @@ class MCContext {

ArrayRef<GoObjImport> getGoObjImports() const { return GoObjImports; }

void setGoObjSymbolRef(const MCSymbol *Sym, GoObjSymbolRef Ref) {
GoObjSymbolRefs[Sym] = std::move(Ref);
void setGoObjImportedSymbolRef(const MCSymbol *Sym,
GoObjImportedSymbolRef Ref) {
GoObjImportedSymbolRefs[Sym] = std::move(Ref);
}

const GoObjSymbolRef *getGoObjSymbolRef(const MCSymbol *Sym) const {
auto It = GoObjSymbolRefs.find(Sym);
if (It == GoObjSymbolRefs.end())
const GoObjImportedSymbolRef *
getGoObjImportedSymbolRef(const MCSymbol *Sym) const {
auto It = GoObjImportedSymbolRefs.find(Sym);
if (It == GoObjImportedSymbolRefs.end())
return nullptr;
return &It->second;
}
Expand Down
63 changes: 29 additions & 34 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1153,10 +1153,15 @@ static void collectGoObjModuleMetadata(AsmPrinter &AP, const Module &M) {
// The LLVM symbol name is the sole carrier of ABI0 object identity. Keep the
// calling convention as an independent lowering contract and reject stale
// metadata or mismatched names instead of trying to repair either one.
for (const GlobalObject &GO : M.global_objects())
for (const GlobalObject &GO : M.global_objects()) {
if (GO.getMetadata("goobj.symbol.name"))
report_fatal_error(
"!goobj.symbol.name is obsolete; encode ABI0 in the symbol name");
if (GO.getMetadata("goobj.builtin"))
report_fatal_error(
"!goobj.builtin is obsolete; encode the builtin index in the symbol "
"name");
}

for (const Function &F : M) {
if (F.isIntrinsic())
Expand Down Expand Up @@ -1201,44 +1206,34 @@ static void collectGoObjModuleMetadata(AsmPrinter &AP, const Module &M) {
}

// Only the optimized relocation stream decides which declarations become
// GoObj references. Attachments retain the package-local indices that LLVM
// symbol names and MC relocations cannot reconstruct.
// GoObj references. The attachment retains the package-local index that
// LLVM symbol names and MC relocations cannot reconstruct. Builtin identity
// is encoded directly in the declaration name instead.
for (const GlobalObject &GO : M.global_objects()) {
const MDNode *Imported = GO.getMetadata("goobj.import");
const MDNode *Builtin = GO.getMetadata("goobj.builtin");
if (!Imported && !Builtin)
if (!Imported)
continue;
if (!GO.isDeclaration() || (Imported && Builtin))
if (!GO.isDeclaration() ||
GO.getName().contains(GoObj::BuiltinSymbolSuffixPrefix) ||
GO.getName().contains(GoObj::LinknameSymbolSuffix))
report_fatal_error("invalid GoObj symbol reference attachment");

MCContext::GoObjSymbolRef Ref;
if (Imported) {
if (Imported->getNumOperands() != 3)
report_fatal_error("expected !goobj.import to have three operands");
StringRef Prefix =
getGoObjMetadataString(Imported->getOperand(0), "goobj.import");
const auto *SymIdx =
mdconst::dyn_extract<ConstantInt>(Imported->getOperand(1));
const auto *Flags2 =
mdconst::dyn_extract<ConstantInt>(Imported->getOperand(2));
if (Prefix.empty() || !SymIdx || SymIdx->getValue().ugt(UINT32_MAX) ||
!Flags2 || Flags2->getValue().ugt(UINT8_MAX))
report_fatal_error("invalid !goobj.import attachment");
Ref.Kind = MCContext::GoObjSymbolRefKind::Imported;
Ref.PackagePrefix = Prefix.str();
Ref.SymIdx = static_cast<uint32_t>(SymIdx->getZExtValue());
Ref.Flags2 = static_cast<uint8_t>(Flags2->getZExtValue());
} else {
if (Builtin->getNumOperands() != 1)
report_fatal_error("expected !goobj.builtin to have one operand");
const auto *SymIdx =
mdconst::dyn_extract<ConstantInt>(Builtin->getOperand(0));
if (!SymIdx || SymIdx->getValue().ugt(UINT32_MAX))
report_fatal_error("invalid !goobj.builtin attachment");
Ref.Kind = MCContext::GoObjSymbolRefKind::Builtin;
Ref.SymIdx = static_cast<uint32_t>(SymIdx->getZExtValue());
}
AP.OutContext.setGoObjSymbolRef(AP.getSymbol(&GO), std::move(Ref));
if (Imported->getNumOperands() != 3)
report_fatal_error("expected !goobj.import to have three operands");
StringRef Prefix =
getGoObjMetadataString(Imported->getOperand(0), "goobj.import");
const auto *SymIdx =
mdconst::dyn_extract<ConstantInt>(Imported->getOperand(1));
const auto *Flags2 =
mdconst::dyn_extract<ConstantInt>(Imported->getOperand(2));
if (Prefix.empty() || !SymIdx || SymIdx->getValue().ugt(UINT32_MAX) ||
!Flags2 || Flags2->getValue().ugt(UINT8_MAX))
report_fatal_error("invalid !goobj.import attachment");
MCContext::GoObjImportedSymbolRef Ref;
Ref.PackagePrefix = Prefix.str();
Ref.SymIdx = static_cast<uint32_t>(SymIdx->getZExtValue());
Ref.Flags2 = static_cast<uint8_t>(Flags2->getZExtValue());
AP.OutContext.setGoObjImportedSymbolRef(AP.getSymbol(&GO), std::move(Ref));
}

if (const NamedMDNode *Keep = M.getNamedMetadata("goobj.keep")) {
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ CodeGenTargetMachineImpl::createMCStreamer(raw_pwrite_stream &Out,
Config.Experiments = std::move(IRConfig->Experiments);
Config.IsMain = IRConfig->IsMain;
Config.IsShared = IRConfig->IsShared;
Config.IsStd = IRConfig->IsStd;
} else {
Config.PackagePath = GoObjPackagePath;
if (!GoObjVersion.empty())
Expand Down
57 changes: 54 additions & 3 deletions llvm/lib/CodeGen/GoCallingConv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@

#include "llvm/CodeGen/GoCallingConv.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ErrorHandling.h"
#include <limits>
#include <string>
Expand All @@ -20,11 +22,60 @@ using namespace llvm;

namespace llvm::goabi {

std::string getGoObjBuiltinCalleeName(MachineFunction &MF, StringRef SymbolName,
CallingConv::ID CC) {
if (SymbolName.empty() ||
(CC != CallingConv::GoABIInternal && CC != CallingConv::GoABI0))
report_fatal_error("invalid logical Go builtin symbol");

const Module &M = *MF.getFunction().getParent();
const Function *Match = nullptr;
for (const Function &F : M) {
StringRef Candidate = F.getName();
bool IsABI0 = Candidate.consume_back(GoObj::ABI0SymbolSuffix);
if (IsABI0 != (CC == CallingConv::GoABI0) ||
!Candidate.consume_front(SymbolName) ||
!Candidate.consume_front(GoObj::BuiltinSymbolSuffixPrefix) ||
!Candidate.consume_back(">") || Candidate.empty())
continue;
uint32_t Index;
if (Candidate.getAsInteger(10, Index))
continue;
if (F.getCallingConv() != CC)
report_fatal_error(
"Go builtin declaration has invalid calling convention");
if (Match)
report_fatal_error("duplicate Go builtin declaration");
Match = &F;
}
if (Match)
return Match->getName().str();

// Native Go disables builtin-index references for -linkshared.
if (std::optional<codegen::GoObjConfig> Config = codegen::getGoObjConfig();
Config && Config->IsShared) {
std::string StorageName = SymbolName.str();
if (CC == CallingConv::GoABI0)
StorageName += GoObj::ABI0SymbolSuffix;
return StorageName;
}

// Hand-written backend fixtures predate the compiler declaration contract.
// Production Go IR is self-describing and must fail closed if its late
// helper declaration is missing.
if (M.getNamedMetadata("goobj.config"))
report_fatal_error("missing Go builtin declaration for " + SymbolName);

std::string StorageName = SymbolName.str();
if (CC == CallingConv::GoABI0)
StorageName += GoObj::ABI0SymbolSuffix;
return StorageName;
}

void addGoObjABI0Callee(MachineInstrBuilder &MIB, MachineFunction &MF,
StringRef SymbolName) {
if (SymbolName.empty() || SymbolName.ends_with(GoObj::ABI0SymbolSuffix))
report_fatal_error("invalid logical Go ABI0 symbol name");
std::string StorageName = (SymbolName + GoObj::ABI0SymbolSuffix).str();
std::string StorageName =
getGoObjBuiltinCalleeName(MF, SymbolName, CallingConv::GoABI0);
MIB.addExternalSymbol(MF.createExternalSymbolName(StorageName));
}

Expand Down
Loading
Loading