Skip to content
Open
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
5 changes: 5 additions & 0 deletions llvm/include/llvm/BinaryFormat/ELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,11 @@ enum {
SHN_MIPS_SUNDEFINED = 0xff04 // Undefined symbols for global data area
};

// x86-64 speciifc section index
enum {
SHN_X86_64_LCOMMON = 0xff02, // Large FORTRAN COMMON variables
};

// ELF Relocation types for Mips
enum {
#include "ELFRelocs/Mips.def"
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/MCELFStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class MCELFStreamer : public MCObjectStreamer {
bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;
void emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;

void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
void emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name,
Expand Down
8 changes: 8 additions & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,14 @@ class LLVM_ABI MCStreamer {
virtual void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) = 0;

/// Emit a large common (.largecomm) symbol.
///
/// \param Symbol - The common symbol to emit.
/// \param Size - The size of the common symbol.
/// \param ByteAlignment - The alignment of the common symbol in bytes.
virtual void emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment);

/// Emit a local common (.lcomm) symbol.
///
/// \param Symbol - The common symbol to emit.
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/MC/MCSymbolELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class MCSymbolELF : public MCSymbol {
void setMemtag(bool Tagged);
bool isMemtag() const;

void setIsLargeCommon();
bool isLargeCommon() const;

private:
void setIsBindingSet() const;
};
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Object/ELFTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> {
return getType() == ELF::STT_COMMON || st_shndx == ELF::SHN_COMMON;
}

bool isLargeCommon() const { return st_shndx == ELF::SHN_X86_64_LCOMMON; }

bool isDefined() const { return !isUndefined(); }

bool isProcessorSpecific() const {
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Target/TargetLoweringObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo {
return nullptr;
}

virtual MCSection *LargeSectionForCommon(const GlobalObject *GO,
SectionKind Kind,
const TargetMachine &TM) const {
return nullptr;
}

protected:
virtual MCSection *SelectSectionForGlobal(const GlobalObject *GO,
SectionKind Kind,
Expand Down
17 changes: 13 additions & 4 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,11 +782,18 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
OutContext.reportError(SMLoc(), "symbol '" + Twine(GVSym->getName()) +
"' is already defined");

SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM);

// Place the large common variables in the .lbss section for the medium and
// large code models on x86_64. (AMD64 ABI, 9.2.5 COMMON blocks)
MCSection *LargeCommonSec =
getObjFileLowering().LargeSectionForCommon(GV, GVKind, TM);
if (LargeCommonSec)
OutStreamer->switchSection(LargeCommonSec);

if (MAI->hasDotTypeDotSizeDirective())
OutStreamer->emitSymbolAttribute(EmittedSym, MCSA_ELF_TypeObject);

SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM);

const DataLayout &DL = GV->getDataLayout();
uint64_t Size = DL.getTypeAllocSize(GV->getValueType());

Expand All @@ -802,10 +809,12 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
if (GVKind.isCommon()) {
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
// .comm _foo, 42, 4
OutStreamer->emitCommonSymbol(GVSym, Size, Alignment);
if (LargeCommonSec)
OutStreamer->emitLargeCommonSymbol(GVSym, Size, Alignment);
else
OutStreamer->emitCommonSymbol(GVSym, Size, Alignment);
return;
}

// Determine to which section this global should be emitted.
MCSection *TheSection = getObjFileLowering().SectionForGlobal(GV, GVKind, TM);

Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/MC/ELFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSectionELF.h"
Expand Down Expand Up @@ -544,7 +545,10 @@ void ELFWriter::computeSymbolTable(const RevGroupMapTy &RevGroupMap) {
auto Shndx = Symbol.getIndex();
if (!Shndx) {
assert(!Local);
Shndx = ELF::SHN_COMMON;
if (Symbol.isLargeCommon())
Shndx = ELF::SHN_X86_64_LCOMMON;
else
Shndx = ELF::SHN_COMMON;
}
MSD.SectionIndex = Shndx;
} else if (Symbol.isUndefined()) {
Expand Down
16 changes: 15 additions & 1 deletion llvm/lib/MC/MCAsmStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,8 @@ class MCAsmStreamer final : public MCStreamer {
void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;

void emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) override;
/// Emit a local common (.lcomm) symbol.
///
/// @param Symbol - The common symbol to emit.
Expand Down Expand Up @@ -1075,6 +1076,19 @@ void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
}
}

void MCAsmStreamer::emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) {
OS << "\t.largecomm\t";
Symbol->print(OS, MAI);
OS << ',' << Size;

if (MAI->getCOMMDirectiveAlignmentIsInBytes())
OS << ',' << ByteAlignment.value();
else
OS << ',' << Log2(ByteAlignment);
EmitEOL();
}

void MCAsmStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlign) {
OS << "\t.lcomm\t";
Expand Down
17 changes: 17 additions & 0 deletions llvm/lib/MC/MCELFStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,23 @@ bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
return true;
}

void MCELFStreamer::emitLargeCommonSymbol(MCSymbol *S, uint64_t Size,
Align ByteAlignment) {
auto *Symbol = static_cast<MCSymbolELF *>(S);
getAssembler().registerSymbol(*Symbol);

if (!Symbol->isBindingSet())
Symbol->setBinding(ELF::STB_GLOBAL);

Symbol->setType(ELF::STT_OBJECT);

if (Symbol->declareCommon(Size, ByteAlignment))
report_fatal_error(Twine("Symbol: ") + Symbol->getName() +
" redeclared as different type");
Symbol->setIsLargeCommon();
Symbol->setSize(MCConstantExpr::create(Size, getContext()));
}

void MCELFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
Align ByteAlignment) {
auto *Symbol = static_cast<MCSymbolELF *>(S);
Expand Down
50 changes: 50 additions & 0 deletions llvm/lib/MC/MCParser/ELFAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class ELFAsmParser : public MCAsmParserExtension {
&ELFAsmParser::parseDirectiveSymbolAttribute>(".hidden");
addDirectiveHandler<&ELFAsmParser::parseDirectiveSubsection>(".subsection");
addDirectiveHandler<&ELFAsmParser::parseDirectiveCGProfile>(".cg_profile");
addDirectiveHandler<&ELFAsmParser::parseDirectiveLargecomm>(".largecomm");
}

// FIXME: Part of this logic is duplicated in the MCELFStreamer. What is
Expand Down Expand Up @@ -126,6 +127,7 @@ class ELFAsmParser : public MCAsmParserExtension {
bool parseDirectiveSymbolAttribute(StringRef, SMLoc);
bool parseDirectiveSubsection(StringRef, SMLoc);
bool parseDirectiveCGProfile(StringRef, SMLoc);
bool parseDirectiveLargecomm(StringRef, SMLoc);

private:
bool parseSectionName(StringRef &SectionName);
Expand Down Expand Up @@ -886,6 +888,54 @@ bool ELFAsmParser::parseDirectiveCGProfile(StringRef S, SMLoc Loc) {
return MCAsmParserExtension::parseDirectiveCGProfile(S, Loc);
}

bool ELFAsmParser::parseDirectiveLargecomm(StringRef, SMLoc Loc) {
if (getParser().checkForValidSection())
return true;

MCSymbol *Sym;
if (getParser().parseSymbol(Sym))
return TokError("expected identifier in directive");

if (getLexer().isNot(AsmToken::Comma))
return TokError("expected a comma");
Lex();

int64_t Size;
SMLoc SizeLoc = getLexer().getLoc();
if (getParser().parseAbsoluteExpression(Size))
return true;

int64_t Pow2Alignment = 0;
SMLoc Pow2AlignmentLoc;
if (getLexer().is(AsmToken::Comma)) {
Lex();
Pow2AlignmentLoc = getLexer().getLoc();
if (getParser().parseAbsoluteExpression(Pow2Alignment))
return true;

// If this target takes alignments in bytes (not log) validate and convert.
if (getLexer().getMAI().getCOMMDirectiveAlignmentIsInBytes()) {
if (!isPowerOf2_64(Pow2Alignment))
return Error(Pow2AlignmentLoc, "alignment must be a power of 2");
Pow2Alignment = Log2_64(Pow2Alignment);
}
}

if (parseEOL())
return true;

if (Size < 0)
return Error(SizeLoc, "size must be non-negative");

Sym->redefineIfPossible();
if (!Sym->isUndefined())
return Error(Loc, "invalid symbol redefinition");

getStreamer().emitLargeCommonSymbol(Sym, Size, Align(1ULL << Pow2Alignment));

return false;
}

namespace llvm {

MCAsmParserExtension *createELFAsmParser() {
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,8 @@ void MCStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
StringRef Name, bool KeepOriginalSym) {}
void MCStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) {}
void MCStreamer::emitLargeCommonSymbol(MCSymbol *Symbol, uint64_t Size,
Align ByteAlignment) {}
void MCStreamer::emitZerofill(MCSection *, MCSymbol *, uint64_t, Align, SMLoc) {
}
void MCStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/MC/MCSymbolELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ enum {

// One bit.
ELF_IsMemoryTagged_Shift = 13,

// One bit.
ELF_LargeCommon_Shift = 14,
};
}

Expand Down Expand Up @@ -206,4 +209,13 @@ void MCSymbolELF::setMemtag(bool Tagged) {
else
setFlags(OtherFlags);
}

bool MCSymbolELF::isLargeCommon() const {
return getFlags() & (0x1 << ELF_LargeCommon_Shift);
}

void MCSymbolELF::setIsLargeCommon() {
uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_LargeCommon_Shift);
setFlags(OtherFlags | (1 << ELF_LargeCommon_Shift));
}
}
13 changes: 13 additions & 0 deletions llvm/lib/Target/X86/X86TargetObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

#include "X86TargetObjectFile.h"
#include "MCTargetDesc/X86MCAsmInfo.h"
#include "X86TargetMachine.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Target/TargetMachine.h"

Expand Down Expand Up @@ -71,3 +74,13 @@ const MCExpr *X86_64ELFTargetObjectFile::getIndirectSymViaGOTPCRel(
const MCExpr *Off = MCConstantExpr::create(FinalOffset, getContext());
return MCBinaryExpr::createAdd(Res, Off, getContext());
}

MCSection *X86_64ELFTargetObjectFile::LargeSectionForCommon(
const GlobalObject *GV, SectionKind Kind, const TargetMachine &TM) const {
auto &X86_TM = static_cast<const X86TargetMachine &>(TM);
if (GV && Kind.isCommon() && TM.isLargeGlobalValue(GV) && !X86_TM.isJIT()) {
unsigned Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_X86_64_LARGE;
return getContext().getELFSection(".lbss", ELF::SHT_NOBITS, Flags);
}
return nullptr;
}
3 changes: 3 additions & 0 deletions llvm/lib/Target/X86/X86TargetObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ namespace llvm {
const MCValue &MV, int64_t Offset,
MachineModuleInfo *MMI,
MCStreamer &Streamer) const override;

MCSection *LargeSectionForCommon(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
};

} // end namespace llvm
Expand Down
50 changes: 50 additions & 0 deletions llvm/test/MC/X86/largecomm.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
; RUN: llc -filetype=asm -code-model=medium %s --large-data-threshold=65636 -o - | FileCheck %s --check-prefix=CHECKASM-MEDIUM
; RUN: llc -filetype=asm -code-model=large %s -o - | FileCheck %s --check-prefix=CHECKASM-LARGE

; CHECKASM-MEDIUM: .section .lbss,"awl",@nobits
; CHECKASM-MEDIUM-NEXT: .type __BLNK__,@object # @__BLNK__
; CHECKASM-MEDIUM-NEXT: .largecomm __BLNK__,48394093832,8
; CHECKASM-MEDIUM-NEXT: .type ccc_,@object # @ccc_
; CHECKASM-MEDIUM-NEXT: .comm ccc_,8,8

; CHECKASM-LARGE: .section .lbss,"awl",@nobits
; CHECKASM-LARGE-NEXT: .type __BLNK__,@object # @__BLNK__
; CHECKASM-LARGE-NEXT: .largecomm __BLNK__,48394093832,8
; CHECKASM-LARGE-NEXT: .type ccc_,@object # @ccc_
; CHECKASM-LARGE-NEXT: .largecomm ccc_,8,8

source_filename = "FIRModule"
target triple = "x86_64-unknown-linux-gnu"

@__BLNK__ = common global [48394093832 x i8] zeroinitializer, align 8
@ccc_ = common global [8 x i8] zeroinitializer, align 8
@_QFECn1 = internal constant i32 77777
@_QFECn2 = internal constant i32 77777

define void @_QQmain() #0 {
store double 1.000000e+00, ptr @ccc_, align 8
store double 2.000000e+00, ptr getelementptr inbounds nuw (i8, ptr @__BLNK__, i64 61600176), align 8
ret void
}

declare void @_FortranAProgramStart(i32, ptr, ptr, ptr) #1

declare void @_FortranAProgramEndStatement() #1

define i32 @main(i32 %0, ptr %1, ptr %2) #0 {
call void @_FortranAProgramStart(i32 %0, ptr %1, ptr %2, ptr null)
call void @_QQmain()
call void @_FortranAProgramEndStatement()
ret i32 0
}

attributes #0 = { "frame-pointer"="all" "target-cpu"="x86-64" }
attributes #1 = { "frame-pointer"="all" }

!llvm.ident = !{!0}
!llvm.module.flags = !{!1, !2, !3}

!0 = !{!"flang version 22.0.0 (https://github.com/llvm/llvm-project.git e1afe25356b8d2ee14f5f88bdb6c2a1526ed14ef)"}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 8, !"PIC Level", i32 2}
!3 = !{i32 7, !"PIE Level", i32 2}