Emit global var and function records in module

* The value IDs currently aren't fetched in LLVM-matching order so we don't have
  those yet for global var initialisers
This commit is contained in:
baldurk
2021-09-21 18:04:56 +01:00
parent 6d60d96fe6
commit f6e8e78bbf
4 changed files with 238 additions and 6 deletions
@@ -123,6 +123,12 @@ struct Symbol
Symbol(SymbolType type = SymbolType::Unknown, uint64_t idx = 0) : type(type), idx(idx) {}
SymbolType type;
uint64_t idx;
bool operator<(const Symbol &o) const
{
if(type != o.type)
return type < o.type;
return idx < o.idx;
}
};
enum class GlobalFlags : uint32_t
@@ -163,6 +169,8 @@ struct GlobalVar
struct Alias
{
rdcstr name;
const Type *type = NULL;
uint64_t valID = 0;
};
// this enum is ordered to match the serialised order of these attributes
@@ -44,14 +44,32 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
{
bytebuf ret;
std::map<Symbol, uint32_t> valueId;
LLVMBC::BitcodeWriter writer(ret);
uint64_t maxAlign = 0;
uint32_t maxGlobalType = 0;
for(size_t i = 0; i < m_GlobalVars.size(); i++)
{
maxAlign = RDCMAX(m_GlobalVars[i].align, maxAlign);
RDCASSERT(m_GlobalVars[i].type->type == Type::Pointer);
uint32_t typeIndex = uint32_t(m_GlobalVars[i].type->inner - m_Types.begin());
maxGlobalType = RDCMAX(typeIndex, maxGlobalType);
}
for(size_t i = 0; i < m_Functions.size(); i++)
maxAlign = RDCMAX(m_Functions[i].align, maxAlign);
writer.ConfigureSizes(m_Types.size(), m_Sections.size(), maxAlign, maxGlobalType);
writer.BeginBlock(LLVMBC::KnownBlock::MODULE_BLOCK);
writer.Record(LLVMBC::ModuleRecord::VERSION, 1U);
{
writer.ModuleBlockInfo((uint32_t)m_Types.size());
writer.ModuleBlockInfo();
}
if(!m_AttributeGroups.empty())
@@ -245,6 +263,127 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
writer.EndBlock();
}
// COMDAT would be next, but we don't read these (DXIL seems not to use them...?)
if(!m_Triple.empty())
writer.Record(LLVMBC::ModuleRecord::TRIPLE, m_Triple);
if(!m_Datalayout.empty())
writer.Record(LLVMBC::ModuleRecord::DATALAYOUT, m_Datalayout);
// inline asm would go here
// write the sections
for(size_t i = 0; i < m_Sections.size(); i++)
writer.Record(LLVMBC::ModuleRecord::SECTIONNAME, m_Sections[i]);
if(!m_GlobalVars.empty())
writer.EmitGlobalVarAbbrev();
for(size_t i = 0; i < m_GlobalVars.size(); i++)
{
const GlobalVar &g = m_GlobalVars[i];
// global vars write the value type, not the pointer
size_t typeIndex = g.type->inner - m_Types.begin();
uint64_t linkageValue = 0;
switch(g.flags & GlobalFlags::LinkageMask)
{
case GlobalFlags::ExternalLinkage: linkageValue = 0; break;
case GlobalFlags::WeakAnyLinkage: linkageValue = 16; break;
case GlobalFlags::AppendingLinkage: linkageValue = 2; break;
case GlobalFlags::InternalLinkage: linkageValue = 3; break;
case GlobalFlags::LinkOnceAnyLinkage: linkageValue = 18; break;
case GlobalFlags::ExternalWeakLinkage: linkageValue = 7; break;
case GlobalFlags::CommonLinkage: linkageValue = 8; break;
case GlobalFlags::PrivateLinkage: linkageValue = 9; break;
case GlobalFlags::WeakODRLinkage: linkageValue = 17; break;
case GlobalFlags::LinkOnceODRLinkage: linkageValue = 19; break;
case GlobalFlags::AvailableExternallyLinkage: linkageValue = 12; break;
default: break;
}
uint64_t unnamedAddr = 0;
if(g.flags & GlobalFlags::GlobalUnnamedAddr)
unnamedAddr = 1;
else if(g.flags & GlobalFlags::LocalUnnamedAddr)
unnamedAddr = 2;
writer.Record(LLVMBC::ModuleRecord::GLOBALVAR,
{
typeIndex, uint64_t(((g.flags & GlobalFlags::IsConst) ? 1 : 0) | 0x2 |
((uint32_t)g.type->addrSpace << 2)),
g.initialiser.type != SymbolType::Unknown ? valueId[g.initialiser] + 1 : 0,
linkageValue, 32 - Bits::CountLeadingZeroes(g.align), uint64_t(g.section + 1),
// visibility
0U,
// TLS mode
0U,
// unnamed addr
unnamedAddr, (g.flags & GlobalFlags::ExternallyInitialised) ? 1U : 0U,
// DLL storage class
0U,
// comdat
0U,
});
}
for(size_t i = 0; i < m_Functions.size(); i++)
{
const Function &f = m_Functions[i];
size_t typeIndex = f.funcType - m_Types.begin();
writer.Record(LLVMBC::ModuleRecord::FUNCTION,
{
typeIndex,
// calling convention
0U,
// external/declaration
f.external ? 1U : 0U,
// linkage
0U,
// attributes
uint64_t(f.attrs ? 1U + (f.attrs - m_Attributes.begin()) : 0U),
// alignment
f.align,
// section
0U,
// visibility
0U,
// gc
0U,
// unnamed_addr
0U,
// prologuedata
0U,
// dllstorageclass
0U,
// comdat
0U,
// prefixdata
0U,
// personality
0U,
});
}
for(size_t i = 0; i < m_Aliases.size(); i++)
{
const Alias &a = m_Aliases[i];
size_t typeIndex = a.type - m_Types.begin();
writer.Record(LLVMBC::ModuleRecord::ALIAS, {
typeIndex, a.valID,
// linkage
0U,
// visibility
0U,
});
}
writer.EndBlock();
ProgramHeader header;
+80 -3
View File
@@ -262,6 +262,10 @@ BitcodeWriter::BitcodeWriter(bytebuf &buf) : b(buf)
curBlock = KnownBlock::Count;
abbrevSize = 2;
numAbbrevs = 0;
m_GlobalVarAbbrev = ~0U;
}
BitcodeWriter::~BitcodeWriter()
@@ -373,10 +377,31 @@ void BitcodeWriter::WriteAbbrevDefinition(AbbrevParam *abbrev)
}
}
void BitcodeWriter::ModuleBlockInfo(uint32_t numTypes)
void BitcodeWriter::ConfigureSizes(size_t numTypes, size_t numSections, uint64_t maxAlign,
uint32_t maxGlobalType)
{
m_NumTypeBits = 32 - Bits::CountLeadingZeroes(numTypes);
m_NumTypeBits = 32 - Bits::CountLeadingZeroes((uint32_t)numTypes);
m_GlobalTypeBits = 32 - Bits::CountLeadingZeroes(maxGlobalType);
if(numSections == 0)
m_NumSectionBits = 0;
else
m_NumSectionBits = 32 - Bits::CountLeadingZeroes((uint32_t)numSections);
if(maxAlign == 0)
{
m_AlignBits = 0;
}
else
{
uint32_t encodedAlign = 32 - Bits::CountLeadingZeroes((uint32_t)maxAlign);
m_AlignBits = 32 - Bits::CountLeadingZeroes(encodedAlign);
}
}
void BitcodeWriter::ModuleBlockInfo()
{
// these abbrevs are hardcoded in llvm, at least at dxc's version
BeginBlock(KnownBlock::BLOCKINFO);
@@ -396,6 +421,29 @@ void BitcodeWriter::ModuleBlockInfo(uint32_t numTypes)
EndBlock();
}
void BitcodeWriter::EmitGlobalVarAbbrev()
{
m_GlobalVarAbbrev = numAbbrevs;
AbbrevParam align = AbbFixed(m_AlignBits);
if(m_AlignBits == 0)
align = AbbLiteral(0);
AbbrevParam section = AbbFixed(m_NumSectionBits);
if(m_NumSectionBits == 0)
section = AbbLiteral(0);
m_GlobalVarAbbrevDef[0] = AbbLiteral(ModuleRecord::GLOBALVAR);
m_GlobalVarAbbrevDef[1] = AbbFixed(m_GlobalTypeBits);
m_GlobalVarAbbrevDef[2] = AbbVBR(6);
m_GlobalVarAbbrevDef[3] = AbbVBR(6);
m_GlobalVarAbbrevDef[4] = AbbFixed(5);
m_GlobalVarAbbrevDef[5] = align;
m_GlobalVarAbbrevDef[6] = section;
WriteAbbrevDefinition(m_GlobalVarAbbrevDef);
}
uint32_t BitcodeWriter::GetAbbrevID(uint32_t id)
{
// the id is a block-local index, starting from 0, of the abbrevs defined for that block.
@@ -422,6 +470,13 @@ void BitcodeWriter::AutoRecord(uint32_t record, bool param, uint64_t val)
case KnownBlock::VALUE_SYMTAB_BLOCK:
RDCERR("Symbol table entry needs multiple parameters");
break;
case KnownBlock::MODULE_BLOCK:
switch(ModuleRecord(record))
{
case ModuleRecord::GLOBALVAR: RDCERR("global var needs multiple parameters"); break;
default: break;
}
break;
case KnownBlock::TYPE_BLOCK:
switch(TypeRecord(record))
{
@@ -458,6 +513,21 @@ void BitcodeWriter::AutoRecord(uint32_t record, const rdcarray<uint64_t> &vals)
case KnownBlock::VALUE_SYMTAB_BLOCK:
// the selection of abbrev here depends on the data
break;
case KnownBlock::MODULE_BLOCK:
switch(ModuleRecord(record))
{
case ModuleRecord::GLOBALVAR:
{
idx = m_GlobalVarAbbrev;
// if any of the later values are non-zero, can't use the global var abbrev
for(size_t i = 6; i < vals.size(); i++)
if(vals[i] != 0)
idx = ~0U;
break;
}
default: break;
}
break;
case KnownBlock::TYPE_BLOCK:
switch(TypeRecord(record))
{
@@ -490,7 +560,14 @@ void BitcodeWriter::AutoRecord(uint32_t record, const rdcarray<uint64_t> &vals)
}
// if we got a valid abbrev, use it, otherwise emit unabbrev
if(idx < numAbbrevDefs)
if(idx == m_GlobalVarAbbrev && idx != ~0U)
{
// write the abbrev ID
b.fixed(abbrevSize, GetAbbrevID(m_GlobalVarAbbrev));
Abbrev(m_GlobalVarAbbrevDef, record, vals);
}
else if(idx < numAbbrevDefs)
{
// write the abbrev ID
b.fixed(abbrevSize, GetAbbrevID(idx));
+10 -2
View File
@@ -37,11 +37,13 @@ public:
BitcodeWriter(bytebuf &buf);
~BitcodeWriter();
void BeginBlock(KnownBlock block);
void ConfigureSizes(size_t numTypes, size_t numSections, uint64_t maxAlign, uint32_t maxGlobalType);
void BeginBlock(KnownBlock block);
void EndBlock();
void ModuleBlockInfo(uint32_t numTypes);
void ModuleBlockInfo();
void EmitGlobalVarAbbrev();
void AutoRecord(uint32_t record, bool param, uint64_t val);
void AutoRecord(uint32_t record, const rdcarray<uint64_t> &vals);
@@ -87,11 +89,17 @@ private:
BitWriter b;
uint32_t m_NumTypeBits;
uint32_t m_GlobalTypeBits;
uint32_t m_NumSectionBits;
uint32_t m_AlignBits;
size_t abbrevSize;
uint32_t numAbbrevs;
KnownBlock curBlock;
uint32_t m_GlobalVarAbbrev;
AbbrevParam m_GlobalVarAbbrevDef[10] = {};
struct BlockContext
{
KnownBlock block;