Start emitting function blocks, with attached metadata and constants

* We now track the values in a simple array so getting value IDs amounts to just
  getting an index in this array. This avoids the need to iterate in an llvm-
  identical way to enumerate values. That does mean that we need to insert new
  values into the array in the correct order, which isn't too bad.
This commit is contained in:
baldurk
2021-09-21 18:04:57 +01:00
parent 3b8dee0233
commit 410ee1472b
4 changed files with 203 additions and 148 deletions
@@ -2191,6 +2191,7 @@ Program::Program(const byte *bytes, size_t length)
f.instructions[i].resultID = (uint32_t)resultID++;
}
f.values.assign(m_Values.data() + prevNumSymbols, m_Values.size() - prevNumSymbols);
m_Values.resize(prevNumSymbols);
}
else
@@ -589,6 +589,7 @@ struct Function
rdcarray<Instruction> args;
rdcarray<Instruction> instructions;
rdcarray<Value> values;
rdcarray<Block> blocks;
rdcarray<Constant> constants;
@@ -41,19 +41,21 @@ DXIL::ProgramEditor::~ProgramEditor()
DXBC::DXBCContainer::ReplaceDXILBytecode(m_OutBlob, EncodeProgram());
}
#define getTypeID(t) uint64_t(t - m_Types.begin())
#define getMetaID(m) uint64_t(m - m_Metadata.begin())
#define getMetaIDOrNull(m) (m ? (uint64_t(m - m_Metadata.begin()) + 1) : 0)
bytebuf DXIL::ProgramEditor::EncodeProgram() const
{
#define getValueID(v) uint64_t(values.indexOf(v))
rdcarray<Value> values = m_Values;
bytebuf ret;
LLVMBC::BitcodeWriter writer(ret);
LLVMBC::BitcodeWriter::Config cfg = {};
#define getTypeID(t) uint64_t(t - m_Types.begin())
#define getMetaID(m) uint64_t(m - m_Metadata.begin())
#define getMetaIDOrNull(m) (m ? (uint64_t(m - m_Metadata.begin()) + 1) : 0)
#define getValueID(v) uint64_t(123)
for(size_t i = 0; i < m_GlobalVars.size(); i++)
{
cfg.maxAlign = RDCMAX(m_GlobalVars[i].align, cfg.maxAlign);
@@ -420,111 +422,13 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
// the symbols for constants start after the global variables and functions which we just
// outputted
if(!m_Constants.empty())
{
bool inblock = false;
writer.BeginBlock(LLVMBC::KnownBlock::CONSTANTS_BLOCK);
const Type *curType = NULL;
EncodeConstants(writer, values, m_Constants);
for(size_t i = 0; i < m_Constants.size(); i++)
{
if(!inblock)
{
inblock = true;
writer.BeginBlock(LLVMBC::KnownBlock::CONSTANTS_BLOCK);
}
const Constant &c = m_Constants[i];
if(c.type != curType)
{
writer.Record(LLVMBC::ConstantsRecord::SETTYPE, getTypeID(c.type));
curType = c.type;
}
if(c.nullconst)
{
writer.Record(LLVMBC::ConstantsRecord::CONST_NULL);
}
else if(c.undef)
{
writer.Record(LLVMBC::ConstantsRecord::UNDEF);
}
else if(c.op == Operation::GetElementPtr)
{
rdcarray<uint64_t> vals;
vals.reserve(c.members.size() * 2 + 1);
// DXC's version of llvm always writes the explicit type here
vals.push_back(getTypeID(c.type));
for(size_t m = 0; m < c.members.size(); m++)
{
vals.push_back(getTypeID(c.members[m].GetType()));
vals.push_back(getValueID(c.members[m]));
}
writer.Record(LLVMBC::ConstantsRecord::EVAL_GEP, vals);
}
else if(c.op != Operation::NoOp)
{
uint64_t cast = EncodeCast(c.op);
RDCASSERT(cast != ~0U);
writer.Record(
LLVMBC::ConstantsRecord::EVAL_CAST,
{EncodeCast(c.op), getTypeID(c.type), getTypeID(c.inner->type), getValueID(c.inner)});
}
else if(c.type->scalarType == Type::Int)
{
writer.Record(LLVMBC::ConstantsRecord::INTEGER, LLVMBC::BitWriter::svbr(c.val.s64v[0]));
}
else if(c.type->scalarType == Type::Float)
{
writer.Record(LLVMBC::ConstantsRecord::FLOAT, c.val.u64v[0]);
}
else if(!c.str.empty())
{
if(c.str.indexOf('\0') < 0)
{
writer.Record(LLVMBC::ConstantsRecord::CSTRING, c.str);
}
else
{
writer.Record(LLVMBC::ConstantsRecord::STRING, c.str);
}
}
else if(c.data)
{
rdcarray<uint64_t> vals;
vals.reserve(c.members.size());
if(c.type->type == Type::Vector)
{
for(uint32_t m = 0; m < c.type->elemCount; m++)
vals.push_back(c.type->bitWidth <= 32 ? c.val.u32v[m] : c.val.u64v[m]);
}
else
{
for(size_t m = 0; m < c.members.size(); m++)
vals.push_back(c.members[m].literal);
}
writer.Record(LLVMBC::ConstantsRecord::DATA, vals);
}
else if(c.type->type == Type::Vector || c.type->type == Type::Array ||
c.type->type == Type::Struct)
{
rdcarray<uint64_t> vals;
vals.reserve(c.members.size());
for(size_t m = 0; m < c.members.size(); m++)
vals.push_back(getValueID(c.members[m]));
writer.Record(LLVMBC::ConstantsRecord::AGGREGATE, vals);
}
}
if(inblock)
writer.EndBlock();
writer.EndBlock();
}
if(!m_Metadata.empty())
@@ -533,49 +437,10 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
writer.EmitMetaDataAbbrev();
EncodeMetadata(writer, values, m_Metadata);
rdcarray<uint64_t> vals;
bool errored = false;
for(size_t i = 0; i < m_Metadata.size(); i++)
{
if(m_Metadata[i].isString)
{
writer.Record(LLVMBC::MetaDataRecord::STRING_OLD, m_Metadata[i].str);
}
else if(m_Metadata[i].isConstant)
{
writer.Record(LLVMBC::MetaDataRecord::VALUE,
{getTypeID(m_Metadata[i].type), getValueID(m_Metadata[i].value)});
}
else if(m_Metadata[i].dwarf || m_Metadata[i].debugLoc)
{
if(!errored)
RDCERR("Unexpected debug metadata node - expect to only encode stripped DXIL chunks");
errored = true;
// replace this with the first NULL constant value
for(size_t c = 0; c < m_Constants.size(); c++)
{
if(m_Constants[c].nullconst)
{
writer.Record(LLVMBC::MetaDataRecord::VALUE,
{getTypeID(m_Constants[c].type), (uint64_t)c});
}
}
}
else
{
vals.clear();
for(size_t m = 0; m < m_Metadata[i].children.size(); m++)
vals.push_back(getMetaIDOrNull(m_Metadata[i].children[m]));
writer.Record(m_Metadata[i].isDistinct ? LLVMBC::MetaDataRecord::DISTINCT_NODE
: LLVMBC::MetaDataRecord::NODE,
vals);
}
}
for(size_t i = 0; i < m_NamedMeta.size(); i++)
{
writer.Record(LLVMBC::MetaDataRecord::NAME, m_NamedMeta[i].name);
@@ -645,6 +510,40 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
writer.EndBlock();
}
for(const Function &f : m_Functions)
{
if(f.external)
continue;
values.append(f.values);
writer.BeginBlock(LLVMBC::KnownBlock::FUNCTION_BLOCK);
writer.Record(LLVMBC::FunctionRecord::DECLAREBLOCKS, f.blocks.size());
if(!f.constants.empty())
{
writer.BeginBlock(LLVMBC::KnownBlock::CONSTANTS_BLOCK);
EncodeConstants(writer, values, f.constants);
writer.EndBlock();
}
if(!f.metadata.empty())
{
writer.BeginBlock(LLVMBC::KnownBlock::METADATA_BLOCK);
EncodeMetadata(writer, values, f.metadata);
writer.EndBlock();
}
writer.EndBlock();
values.resize(values.size() - f.values.size());
}
writer.EndBlock();
ProgramHeader header;
@@ -663,3 +562,147 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
return ret;
}
void DXIL::ProgramEditor::EncodeConstants(LLVMBC::BitcodeWriter &writer,
const rdcarray<Value> &values,
const rdcarray<Constant> &constants) const
{
const Type *curType = NULL;
for(const Constant &c : constants)
{
if(c.type != curType)
{
writer.Record(LLVMBC::ConstantsRecord::SETTYPE, getTypeID(c.type));
curType = c.type;
}
if(c.nullconst)
{
writer.Record(LLVMBC::ConstantsRecord::CONST_NULL);
}
else if(c.undef)
{
writer.Record(LLVMBC::ConstantsRecord::UNDEF);
}
else if(c.op == Operation::GetElementPtr)
{
rdcarray<uint64_t> vals;
vals.reserve(c.members.size() * 2 + 1);
// DXC's version of llvm always writes the explicit type here
vals.push_back(getTypeID(c.members[0].GetType()->inner));
for(size_t m = 0; m < c.members.size(); m++)
{
vals.push_back(getTypeID(c.members[m].GetType()));
vals.push_back(getValueID(c.members[m]));
}
writer.Record(LLVMBC::ConstantsRecord::EVAL_GEP, vals);
}
else if(c.op != Operation::NoOp)
{
uint64_t cast = EncodeCast(c.op);
RDCASSERT(cast != ~0U);
writer.Record(LLVMBC::ConstantsRecord::EVAL_CAST,
{EncodeCast(c.op), getTypeID(c.type), getTypeID(c.inner->type),
getValueID(Value(c.inner))});
}
else if(c.data)
{
rdcarray<uint64_t> vals;
vals.reserve(c.members.size());
if(c.type->type == Type::Vector)
{
for(uint32_t m = 0; m < c.type->elemCount; m++)
vals.push_back(c.type->bitWidth <= 32 ? c.val.u32v[m] : c.val.u64v[m]);
}
else
{
for(size_t m = 0; m < c.members.size(); m++)
vals.push_back(c.members[m].literal);
}
writer.Record(LLVMBC::ConstantsRecord::DATA, vals);
}
else if(c.type->type == Type::Vector || c.type->type == Type::Array ||
c.type->type == Type::Struct)
{
rdcarray<uint64_t> vals;
vals.reserve(c.members.size());
for(size_t m = 0; m < c.members.size(); m++)
vals.push_back(getValueID(c.members[m]));
writer.Record(LLVMBC::ConstantsRecord::AGGREGATE, vals);
}
else if(c.type->scalarType == Type::Int)
{
writer.Record(LLVMBC::ConstantsRecord::INTEGER, LLVMBC::BitWriter::svbr(c.val.s64v[0]));
}
else if(c.type->scalarType == Type::Float)
{
writer.Record(LLVMBC::ConstantsRecord::FLOAT, c.val.u64v[0]);
}
else if(!c.str.empty())
{
if(c.str.indexOf('\0') < 0)
{
writer.Record(LLVMBC::ConstantsRecord::CSTRING, c.str);
}
else
{
writer.Record(LLVMBC::ConstantsRecord::STRING, c.str);
}
}
}
}
void DXIL::ProgramEditor::EncodeMetadata(LLVMBC::BitcodeWriter &writer, const rdcarray<Value> &values,
const rdcarray<Metadata> &meta) const
{
rdcarray<uint64_t> vals;
bool errored = false;
for(size_t i = 0; i < meta.size(); i++)
{
if(meta[i].isString)
{
writer.Record(LLVMBC::MetaDataRecord::STRING_OLD, meta[i].str);
}
else if(meta[i].isConstant)
{
writer.Record(LLVMBC::MetaDataRecord::VALUE,
{getTypeID(meta[i].type), getValueID(meta[i].value)});
}
else if(meta[i].dwarf || meta[i].debugLoc)
{
if(!errored)
RDCERR("Unexpected debug metadata node - expect to only encode stripped DXIL chunks");
errored = true;
// replace this with the first NULL constant value
for(size_t c = 0; c < m_Constants.size(); c++)
{
if(m_Constants[c].nullconst)
{
writer.Record(LLVMBC::MetaDataRecord::VALUE, {getTypeID(m_Constants[c].type), (uint64_t)c});
}
}
}
else
{
vals.clear();
for(size_t m = 0; m < meta[i].children.size(); m++)
vals.push_back(getMetaIDOrNull(meta[i].children[m]));
writer.Record(
meta[i].isDistinct ? LLVMBC::MetaDataRecord::DISTINCT_NODE : LLVMBC::MetaDataRecord::NODE,
vals);
}
}
}
@@ -31,6 +31,11 @@ namespace DXBC
class DXBCContainer;
};
namespace LLVMBC
{
class BitcodeWriter;
};
namespace DXIL
{
class ProgramEditor : public Program
@@ -43,6 +48,11 @@ private:
bytebuf &m_OutBlob;
bytebuf EncodeProgram() const;
void EncodeConstants(LLVMBC::BitcodeWriter &writer, const rdcarray<Value> &values,
const rdcarray<Constant> &constants) const;
void EncodeMetadata(LLVMBC::BitcodeWriter &writer, const rdcarray<Value> &values,
const rdcarray<Metadata> &meta) const;
};
}; // namespace DXIL