Encode function instructions

This commit is contained in:
baldurk
2021-09-03 13:20:41 +01:00
parent 410ee1472b
commit 29c16d17e8
7 changed files with 668 additions and 20 deletions
+20 -2
View File
@@ -236,18 +236,36 @@ void FreeAlignedBuffer(byte *buf)
uint32_t Log2Floor(uint32_t value)
{
RDCASSERT(value > 0);
if(!value)
return ~0U;
return 31 - Bits::CountLeadingZeroes(value);
}
#if ENABLED(RDOC_X64)
uint64_t Log2Floor(uint64_t value)
{
RDCASSERT(value > 0);
if(!value)
return ~0ULL;
return 63 - Bits::CountLeadingZeroes(value);
}
#endif
uint32_t Log2Ceil(uint32_t value)
{
if(!value)
return ~0U;
return 32 - Bits::CountLeadingZeroes(value - 1);
}
#if ENABLED(RDOC_X64)
uint64_t Log2Ceil(uint64_t value)
{
if(!value)
return ~0ULL;
return 64 - Bits::CountLeadingZeroes(value - 1);
}
#endif
// deliberately leak so it doesn't get destroyed before our static RenderDoc destructor needs it
static rdcstr *logfile = new rdcstr;
static FileIO::LogFileHandle *logfileHandle = NULL;
+20
View File
@@ -293,8 +293,10 @@ byte *AllocAlignedBuffer(uint64_t size, uint64_t alignment = 64);
void FreeAlignedBuffer(byte *buf);
uint32_t Log2Floor(uint32_t value);
uint32_t Log2Ceil(uint32_t value);
#if ENABLED(RDOC_X64)
uint64_t Log2Floor(uint64_t value);
uint64_t Log2Ceil(uint64_t value);
#endif
// super ugly - on apple size_t is a separate type, so we need a new overload
@@ -307,6 +309,24 @@ inline size_t Log2Floor(size_t value)
return (size_t)Log2Floor((uint32_t)value);
#endif
}
inline size_t Log2Ceil(size_t value)
{
#if ENABLED(RDOC_X64)
return (size_t)Log2Ceil((uint64_t)value);
#else
return (size_t)Log2Ceil((uint32_t)value);
#endif
}
inline size_t Log2(size_t value)
{
#if ENABLED(RDOC_X64)
return (size_t)Log2((uint64_t)value);
#else
return (size_t)Log2((uint32_t)value);
#endif
}
#endif
/////////////////////////////////////////////////
@@ -1200,10 +1200,24 @@ Program::Program(const byte *bytes, size_t length)
uint64_t callingFlags = op.get<uint64_t>();
if(callingFlags & (1ULL << 17))
{
inst.opFlags = op.get<InstructionFlags>();
RDCASSERT(inst.opFlags != InstructionFlags::NoFlags);
callingFlags &= ~(1ULL << 17);
}
const Type *funcCallType = NULL;
if(callingFlags & (1ULL << 15))
op.get<uint64_t>(); // funcCallType
{
funcCallType = op.getType(); // funcCallType
callingFlags &= ~(1ULL << 15);
}
RDCASSERTMSG("Calling flags should only have at most two known bits set",
callingFlags == 0, callingFlags);
Value v = op.getSymbol();
@@ -1216,6 +1230,11 @@ Program::Program(const byte *bytes, size_t length)
inst.funcCall = v.function;
inst.type = inst.funcCall->funcType->inner->inner;
if(funcCallType)
{
RDCASSERT(funcCallType == inst.funcCall->funcType->inner);
}
for(size_t i = 0; op.remaining() > 0; i++)
{
if(inst.funcCall->funcType->inner->members[i]->type == Type::Metadata)
@@ -1355,6 +1374,8 @@ Program::Program(const byte *bytes, size_t length)
// fast math flags overlap
inst.opFlags = InstructionFlags(flags);
}
RDCASSERT(inst.opFlags != InstructionFlags::NoFlags);
}
f.instructions.push_back(inst);
@@ -1366,7 +1387,11 @@ Program::Program(const byte *bytes, size_t length)
inst.op = Operation::Unreachable;
inst.type = GetVoidType();
curBlock++;
f.instructions.push_back(inst);
}
else if(op.type == FunctionRecord::INST_ALLOCA)
{
@@ -1383,15 +1408,18 @@ Program::Program(const byte *bytes, size_t length)
RDCASSERT(inst.type->type == Type::Pointer);
// type of the size - ignored
(void)op.getType();
const Type *sizeType = op.getType();
// size
inst.args.push_back(op.getSymbolAbsolute());
RDCASSERT(sizeType == inst.args.back().GetType());
uint64_t align = op.get<uint64_t>();
if(align & 0x20)
{
// argument alloca
inst.opFlags |= InstructionFlags::ArgumentAlloca;
}
if((align & 0x40) == 0)
{
@@ -1557,8 +1585,12 @@ Program::Program(const byte *bytes, size_t length)
// fast math flags
if(op.remaining() > 0)
{
inst.opFlags = op.get<InstructionFlags>();
RDCASSERTNOTEQUAL((uint64_t)inst.opFlags, 0);
}
inst.type = GetBoolType();
// if we're comparing vectors, the return type is an equal sized bool vector
@@ -544,6 +544,8 @@ enum class InstructionFlags : uint32_t
FailureRelease = (0x4 << 15),
FailureAcquireRelease = (0x5 << 15),
FailureSequentiallyConsistent = (0x6 << 15),
ArgumentAlloca = 1 << 18,
};
BITMASK_OPERATORS(InstructionFlags);
@@ -41,13 +41,19 @@ DXIL::ProgramEditor::~ProgramEditor()
DXBC::DXBCContainer::ReplaceDXILBytecode(m_OutBlob, EncodeProgram());
}
#define getAttribID(a) uint64_t(a - m_Attributes.begin())
#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 getMetaIDOrNull(m) (m ? (getMetaID(m) + 1) : 0ULL)
#define getFunctionMetaID(m) \
uint64_t(m >= m_Metadata.begin() && m < m_Metadata.end() ? m - m_Metadata.begin() \
: m - f.metadata.begin())
#define getFunctionMetaIDOrNull(m) (m ? (getFunctionMetaID(m) + 1) : 0ULL)
#define getValueID(v) uint64_t(values.indexOf(v))
bytebuf DXIL::ProgramEditor::EncodeProgram() const
{
#define getValueID(v) uint64_t(values.indexOf(v))
rdcarray<Value> values = m_Values;
bytebuf ret;
@@ -92,12 +98,11 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
// stop once we pass constants
if(m_Values[i].type != ValueType::Constant)
break;
cfg.numGlobalConsts++;
}
cfg.numTypes = m_Types.size();
cfg.numSections = m_Sections.size();
cfg.numGlobalValues = m_Values.size();
writer.ConfigureSizes(cfg);
@@ -353,7 +358,7 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
typeIndex, uint64_t(((g.flags & GlobalFlags::IsConst) ? 1 : 0) | 0x2 |
((uint32_t)g.type->addrSpace << 2)),
g.initialiser ? getValueID(Value(g.initialiser)) + 1 : 0, linkageValue,
32 - Bits::CountLeadingZeroes(g.align), uint64_t(g.section + 1),
Log2Floor((uint32_t)g.align) + 1, uint64_t(g.section + 1),
// visibility
0U,
// TLS mode
@@ -510,6 +515,38 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
writer.EndBlock();
}
#define encodeRelativeValueID(v) \
{ \
uint64_t valID = getValueID(v); \
if(valID <= instValueID) \
{ \
vals.push_back(instValueID - valID); \
} \
else \
{ \
forwardRefs = true; \
/* signed integer two's complement for negative */ \
/* values referencing forward from the instruction */ \
vals.push_back(0x100000000ULL - (valID - instValueID)); \
vals.push_back(getTypeID(v.GetType())); \
} \
}
// some cases don't encode the type even for forward refs, if it's implicit (e.g. second parameter
// in a binop). This also doesn't count as a forward ref for the case of breaking the abbrev use
#define encodeRelativeValueIDTypeless(v) \
{ \
uint64_t valID = getValueID(v); \
if(valID <= instValueID) \
{ \
vals.push_back(instValueID - valID); \
} \
else \
{ \
vals.push_back(0x100000000ULL - (valID - instValueID)); \
} \
}
for(const Function &f : m_Functions)
{
if(f.external)
@@ -539,6 +576,488 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const
writer.EndBlock();
}
// value IDs for instructions start after all the constants
uint32_t instValueID = uint32_t(m_Values.size() + f.constants.size() + f.args.size());
uint32_t debugLoc = ~0U;
bool forwardRefs = false;
rdcarray<uint64_t> vals;
for(const Instruction &inst : f.instructions)
{
forwardRefs = false;
vals.clear();
switch(inst.op)
{
case Operation::NoOp: RDCERR("Unexpected no-op encoding"); continue;
case Operation::Call:
{
vals.push_back(inst.paramAttrs ? getAttribID(inst.paramAttrs) + 1 : 0);
// always emit func type
uint64_t flags = 1 << 15;
if(inst.opFlags != InstructionFlags::NoFlags)
flags |= 1 << 17;
vals.push_back(flags);
if(inst.opFlags != InstructionFlags::NoFlags)
vals.push_back((uint64_t)inst.opFlags);
vals.push_back(getTypeID(inst.funcCall->funcType->inner));
encodeRelativeValueID(Value(inst.funcCall));
for(size_t a = 0; a < inst.args.size(); a++)
{
if(inst.args[a].type == ValueType::Metadata)
{
vals.push_back(getFunctionMetaID(inst.args[a].meta));
}
else
{
encodeRelativeValueIDTypeless(inst.args[a]);
}
}
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_CALL, vals, forwardRefs);
break;
}
case Operation::Trunc:
case Operation::ZExt:
case Operation::SExt:
case Operation::FToU:
case Operation::FToS:
case Operation::UToF:
case Operation::SToF:
case Operation::FPTrunc:
case Operation::FPExt:
case Operation::PtrToI:
case Operation::IToPtr:
case Operation::Bitcast:
case Operation::AddrSpaceCast:
{
encodeRelativeValueID(inst.args[0]);
vals.push_back(getTypeID(inst.type));
vals.push_back(EncodeCast(inst.op));
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_CAST, vals, forwardRefs);
break;
}
case Operation::ExtractVal:
{
encodeRelativeValueID(inst.args[0]);
for(size_t i = 1; i < inst.args.size(); i++)
vals.push_back(inst.args[i].literal);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_EXTRACTVAL, vals, forwardRefs);
break;
}
case Operation::Ret:
{
if(!inst.args.empty())
{
encodeRelativeValueID(inst.args[0]);
}
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_RET, vals, forwardRefs);
break;
}
case Operation::FAdd:
case Operation::FSub:
case Operation::FMul:
case Operation::FDiv:
case Operation::FRem:
case Operation::Add:
case Operation::Sub:
case Operation::Mul:
case Operation::UDiv:
case Operation::SDiv:
case Operation::URem:
case Operation::SRem:
case Operation::ShiftLeft:
case Operation::LogicalShiftRight:
case Operation::ArithShiftRight:
case Operation::And:
case Operation::Or:
case Operation::Xor:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueIDTypeless(inst.args[1]);
const Type *t = inst.args[0].GetType();
const bool isFloatOp = (t->scalarType == Type::Float);
uint64_t opcode = 0;
switch(inst.op)
{
case Operation::FAdd:
case Operation::Add: opcode = 0; break;
case Operation::FSub:
case Operation::Sub: opcode = 1; break;
case Operation::FMul:
case Operation::Mul: opcode = 2; break;
case Operation::UDiv: opcode = 3; break;
case Operation::FDiv:
case Operation::SDiv: opcode = 4; break;
case Operation::URem: opcode = 5; break;
case Operation::FRem:
case Operation::SRem: opcode = 6; break;
case Operation::ShiftLeft: opcode = 7; break;
case Operation::LogicalShiftRight: opcode = 8; break;
case Operation::ArithShiftRight: opcode = 9; break;
case Operation::And: opcode = 10; break;
case Operation::Or: opcode = 11; break;
case Operation::Xor: opcode = 12; break;
default: break;
}
vals.push_back(opcode);
if(inst.opFlags != InstructionFlags::NoFlags)
{
uint64_t flags = 0;
if(inst.op == Operation::Add || inst.op == Operation::Sub ||
inst.op == Operation::Mul || inst.op == Operation::ShiftLeft)
{
if(inst.opFlags & InstructionFlags::NoSignedWrap)
flags |= 0x2;
if(inst.opFlags & InstructionFlags::NoUnsignedWrap)
flags |= 0x1;
vals.push_back(flags);
}
else if(inst.op == Operation::SDiv || inst.op == Operation::UDiv ||
inst.op == Operation::LogicalShiftRight || inst.op == Operation::ArithShiftRight)
{
if(inst.opFlags & InstructionFlags::Exact)
flags |= 0x1;
vals.push_back(flags);
}
else if(isFloatOp)
{
// fast math flags overlap
vals.push_back(uint64_t(inst.opFlags));
}
}
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_BINOP, vals, forwardRefs);
break;
}
case Operation::Unreachable:
{
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_UNREACHABLE, {}, false);
break;
}
case Operation::Alloca:
{
vals.push_back(getTypeID(inst.type->inner));
vals.push_back(getTypeID(inst.args[0].GetType()));
vals.push_back(getValueID(inst.args[0]));
uint64_t alignAndFlags = Log2Floor(inst.align) + 1;
// DXC always sets this bit, as the type is ap ointer
alignAndFlags |= 1U << 6;
if(inst.opFlags & InstructionFlags::ArgumentAlloca)
alignAndFlags |= 1U << 5;
vals.push_back(alignAndFlags);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_ALLOCA, vals, forwardRefs);
break;
}
case Operation::GetElementPtr:
{
vals.push_back((inst.opFlags & InstructionFlags::InBounds) ? 1U : 0U);
vals.push_back(getTypeID(inst.args[0].GetType()->inner));
for(size_t i = 0; i < inst.args.size(); i++)
{
encodeRelativeValueID(inst.args[i]);
}
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_GEP, vals, forwardRefs);
break;
}
case Operation::Load:
{
encodeRelativeValueID(inst.args[0]);
vals.push_back(getTypeID(inst.type));
vals.push_back(Log2Floor(inst.align) + 1);
vals.push_back((inst.opFlags & InstructionFlags::Volatile) ? 1U : 0U);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_LOAD, vals, forwardRefs);
break;
}
case Operation::Store:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueID(inst.args[1]);
vals.push_back(Log2Floor(inst.align) + 1);
vals.push_back((inst.opFlags & InstructionFlags::Volatile) ? 1U : 0U);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_STORE, vals, forwardRefs);
break;
}
case Operation::FOrdFalse:
case Operation::FOrdEqual:
case Operation::FOrdGreater:
case Operation::FOrdGreaterEqual:
case Operation::FOrdLess:
case Operation::FOrdLessEqual:
case Operation::FOrdNotEqual:
case Operation::FOrd:
case Operation::FUnord:
case Operation::FUnordEqual:
case Operation::FUnordGreater:
case Operation::FUnordGreaterEqual:
case Operation::FUnordLess:
case Operation::FUnordLessEqual:
case Operation::FUnordNotEqual:
case Operation::FOrdTrue:
case Operation::IEqual:
case Operation::INotEqual:
case Operation::UGreater:
case Operation::UGreaterEqual:
case Operation::ULess:
case Operation::ULessEqual:
case Operation::SGreater:
case Operation::SGreaterEqual:
case Operation::SLess:
case Operation::SLessEqual:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueIDTypeless(inst.args[1]);
uint64_t opcode = 0;
switch(inst.op)
{
case Operation::FOrdFalse: opcode = 0; break;
case Operation::FOrdEqual: opcode = 1; break;
case Operation::FOrdGreater: opcode = 2; break;
case Operation::FOrdGreaterEqual: opcode = 3; break;
case Operation::FOrdLess: opcode = 4; break;
case Operation::FOrdLessEqual: opcode = 5; break;
case Operation::FOrdNotEqual: opcode = 6; break;
case Operation::FOrd: opcode = 7; break;
case Operation::FUnord: opcode = 8; break;
case Operation::FUnordEqual: opcode = 9; break;
case Operation::FUnordGreater: opcode = 10; break;
case Operation::FUnordGreaterEqual: opcode = 11; break;
case Operation::FUnordLess: opcode = 12; break;
case Operation::FUnordLessEqual: opcode = 13; break;
case Operation::FUnordNotEqual: opcode = 14; break;
case Operation::FOrdTrue: opcode = 15; break;
case Operation::IEqual: opcode = 32; break;
case Operation::INotEqual: opcode = 33; break;
case Operation::UGreater: opcode = 34; break;
case Operation::UGreaterEqual: opcode = 35; break;
case Operation::ULess: opcode = 36; break;
case Operation::ULessEqual: opcode = 37; break;
case Operation::SGreater: opcode = 38; break;
case Operation::SGreaterEqual: opcode = 39; break;
case Operation::SLess: opcode = 40; break;
case Operation::SLessEqual: opcode = 41; break;
default: break;
}
vals.push_back(opcode);
if(inst.opFlags != InstructionFlags::NoFlags)
vals.push_back((uint64_t)inst.opFlags);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_CMP2, vals, forwardRefs);
break;
}
case Operation::Select:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueIDTypeless(inst.args[1]);
encodeRelativeValueID(inst.args[2]);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_VSELECT, vals, forwardRefs);
break;
}
case Operation::ExtractElement:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueID(inst.args[1]);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_EXTRACTELT, vals, forwardRefs);
break;
}
case Operation::InsertElement:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueIDTypeless(inst.args[1]);
encodeRelativeValueID(inst.args[2]);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_INSERTELT, vals, forwardRefs);
break;
}
case Operation::ShuffleVector:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueIDTypeless(inst.args[1]);
encodeRelativeValueID(inst.args[2]);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_SHUFFLEVEC, vals, forwardRefs);
break;
}
case Operation::InsertValue:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueID(inst.args[1]);
for(size_t i = 2; i < inst.args.size(); i++)
vals.push_back(inst.args[i].literal);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_INSERTVAL, vals, forwardRefs);
break;
}
case Operation::Branch:
{
vals.push_back(uint64_t(inst.args[0].block - f.blocks.begin()));
if(inst.args.size() > 1)
{
vals.push_back(uint64_t(inst.args[1].block - f.blocks.begin()));
encodeRelativeValueIDTypeless(inst.args[2]);
}
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_BR, vals, forwardRefs);
break;
}
case Operation::Phi:
{
vals.push_back(getTypeID(inst.type));
for(size_t i = 0; i < inst.args.size(); i += 2)
{
uint64_t valID = getValueID(inst.args[i]);
int64_t valRef = int64_t(instValueID) - int64_t(valID);
vals.push_back(LLVMBC::BitWriter::svbr(valRef));
vals.push_back(uint64_t(inst.args[i + 1].block - f.blocks.begin()));
}
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_PHI, vals, forwardRefs);
break;
}
case Operation::Switch:
{
vals.push_back(getTypeID(inst.args[0].GetType()));
encodeRelativeValueIDTypeless(inst.args[0]);
vals.push_back(uint64_t(inst.args[1].block - f.blocks.begin()));
for(size_t i = 2; i < inst.args.size(); i += 2)
{
vals.push_back(getValueID(inst.args[i]));
vals.push_back(uint64_t(inst.args[i + 1].block - f.blocks.begin()));
}
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_SWITCH, vals, forwardRefs);
break;
}
case Operation::Fence:
{
vals.push_back(((uint64_t)inst.opFlags & (uint64_t)InstructionFlags::SuccessOrderMask) >>
12U);
vals.push_back((inst.opFlags & InstructionFlags::SingleThread) ? 0U : 1U);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_FENCE, vals, forwardRefs);
break;
}
case Operation::CompareExchange:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueID(inst.args[1]);
encodeRelativeValueIDTypeless(inst.args[2]);
vals.push_back((inst.opFlags & InstructionFlags::Volatile) ? 1U : 0U);
vals.push_back(((uint64_t)inst.opFlags & (uint64_t)InstructionFlags::SuccessOrderMask) >>
12U);
vals.push_back((inst.opFlags & InstructionFlags::SingleThread) ? 0U : 1U);
vals.push_back(((uint64_t)inst.opFlags & (uint64_t)InstructionFlags::FailureOrderMask) >>
15U);
vals.push_back((inst.opFlags & InstructionFlags::Weak) ? 1U : 0U);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_CMPXCHG, vals, forwardRefs);
break;
}
case Operation::LoadAtomic:
{
encodeRelativeValueID(inst.args[0]);
vals.push_back(getTypeID(inst.type));
vals.push_back(Log2Floor(inst.align) + 1);
vals.push_back((inst.opFlags & InstructionFlags::Volatile) ? 1U : 0U);
vals.push_back(((uint64_t)inst.opFlags & (uint64_t)InstructionFlags::SuccessOrderMask) >>
12U);
vals.push_back((inst.opFlags & InstructionFlags::SingleThread) ? 0U : 1U);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_LOADATOMIC, vals, forwardRefs);
break;
}
case Operation::StoreAtomic:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueID(inst.args[1]);
vals.push_back(Log2Floor(inst.align) + 1);
vals.push_back((inst.opFlags & InstructionFlags::Volatile) ? 1U : 0U);
vals.push_back(((uint64_t)inst.opFlags & (uint64_t)InstructionFlags::SuccessOrderMask) >>
12U);
vals.push_back((inst.opFlags & InstructionFlags::SingleThread) ? 0U : 1U);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_STOREATOMIC, vals, forwardRefs);
break;
}
case Operation::AtomicExchange:
case Operation::AtomicAdd:
case Operation::AtomicSub:
case Operation::AtomicAnd:
case Operation::AtomicNand:
case Operation::AtomicOr:
case Operation::AtomicXor:
case Operation::AtomicMax:
case Operation::AtomicMin:
case Operation::AtomicUMax:
case Operation::AtomicUMin:
{
encodeRelativeValueID(inst.args[0]);
encodeRelativeValueIDTypeless(inst.args[1]);
uint64_t opcode = 0;
switch(inst.op)
{
case Operation::AtomicExchange: opcode = 0; break;
case Operation::AtomicAdd: opcode = 1; break;
case Operation::AtomicSub: opcode = 2; break;
case Operation::AtomicAnd: opcode = 3; break;
case Operation::AtomicNand: opcode = 4; break;
case Operation::AtomicOr: opcode = 5; break;
case Operation::AtomicXor: opcode = 6; break;
case Operation::AtomicMax: opcode = 7; break;
case Operation::AtomicMin: opcode = 8; break;
case Operation::AtomicUMax: opcode = 9; break;
case Operation::AtomicUMin: opcode = 10; break;
default: break;
}
vals.push_back(opcode);
vals.push_back((inst.opFlags & InstructionFlags::Volatile) ? 1U : 0U);
vals.push_back(((uint64_t)inst.opFlags & (uint64_t)InstructionFlags::SuccessOrderMask) >>
12U);
vals.push_back((inst.opFlags & InstructionFlags::SingleThread) ? 0U : 1U);
writer.RecordInstruction(LLVMBC::FunctionRecord::INST_ATOMICRMW, vals, forwardRefs);
break;
}
}
// instruction IDs are the values (i.e. all instructions that return non-void are a value)
if(inst.type != m_VoidType)
instValueID++;
// no debug location? omit
if(inst.debugLoc == ~0U)
continue;
// same as last time? emit 'again' record
if(inst.debugLoc == debugLoc)
writer.Record(LLVMBC::FunctionRecord::DEBUG_LOC_AGAIN);
// new debug location
const DebugLocation &loc = m_DebugLocations[inst.debugLoc];
writer.Record(LLVMBC::FunctionRecord::DEBUG_LOC,
{
loc.line, loc.col, getFunctionMetaIDOrNull(loc.scope),
getFunctionMetaIDOrNull(loc.inlinedAt),
});
debugLoc = inst.debugLoc;
}
writer.EndBlock();
values.resize(values.size() - f.values.size());
+66 -10
View File
@@ -342,7 +342,8 @@ void BitcodeWriter::BeginBlock(KnownBlock block)
abbrevSize = newAbbrevSize;
blockStack.push_back({block, offs});
curAbbrevs.swap(blockStack.back().abbrevs);
if(!blockStack.empty())
curAbbrevs.swap(blockStack.back().abbrevs);
// emit known abbrevs here that aren't in blockinfo
switch(block)
@@ -396,6 +397,8 @@ void BitcodeWriter::EndBlock()
b.PatchLengthWord(offs, uint32_t(lengthInBytes / 4));
curAbbrevs = blockStack.back().abbrevs;
blockStack.pop_back();
if(blockStack.empty())
{
@@ -405,7 +408,6 @@ void BitcodeWriter::EndBlock()
else
{
curBlock = blockStack.back().block;
curAbbrevs = blockStack.back().abbrevs;
abbrevSize = GetBlockAbbrevSize(curBlock);
}
}
@@ -429,7 +431,7 @@ void BitcodeWriter::WriteAbbrevDefinition(AbbrevParam *abbrev)
if(param.value == MagicFixedSizeNumTypes)
param.value = m_Cfg.numTypes;
if(param.value == MagicFixedSizeNumConstants)
param.value = m_Cfg.numGlobalConsts;
param.value = m_Cfg.numGlobalValues;
const bool lit = param.encoding == AbbrevEncoding::Literal;
b.fixed<bool>(1, lit);
@@ -450,18 +452,18 @@ void BitcodeWriter::ConfigureSizes(Config cfg)
{
m_Cfg = cfg;
m_Cfg.numTypes = 32 - Bits::CountLeadingZeroes((uint32_t)m_Cfg.numTypes);
m_Cfg.numGlobalConsts = 32 - Bits::CountLeadingZeroes((uint32_t)m_Cfg.numGlobalConsts);
m_Cfg.numTypes = Log2Ceil((uint32_t)m_Cfg.numTypes + 1);
m_Cfg.numGlobalValues = Log2Ceil((uint32_t)m_Cfg.numGlobalValues + 1);
m_Cfg.maxGlobalType = 32 - Bits::CountLeadingZeroes(m_Cfg.maxGlobalType);
m_Cfg.maxGlobalType = Log2Ceil(m_Cfg.maxGlobalType + 1);
if(m_Cfg.numSections > 0)
m_Cfg.numSections = 32 - Bits::CountLeadingZeroes((uint32_t)m_Cfg.numSections);
m_Cfg.numSections = Log2Ceil((uint32_t)m_Cfg.numSections + 1);
if(m_Cfg.maxAlign > 0)
{
uint32_t encodedAlign = 32 - Bits::CountLeadingZeroes((uint32_t)cfg.maxAlign);
m_Cfg.maxAlign = 32 - Bits::CountLeadingZeroes(encodedAlign);
uint32_t encodedAlign = Log2Floor((uint32_t)cfg.maxAlign) + 1;
m_Cfg.maxAlign = Log2Ceil(encodedAlign + 1);
}
}
@@ -772,6 +774,60 @@ void BitcodeWriter::RecordSymTabEntry(size_t id, const rdcstr &str, bool basicBl
Abbrev(ValueSymtabAbbrevDefs[(uint32_t)abbrev], (uint32_t)record, vals);
}
void BitcodeWriter::RecordInstruction(FunctionRecord record, const rdcarray<uint64_t> &vals,
bool forwardRefs)
{
uint32_t idx = ~0U;
switch(record)
{
case FunctionRecord::INST_RET:
if(vals.empty())
idx = (uint32_t)FunctionAbbrev::RetVoid;
else
idx = (uint32_t)FunctionAbbrev::RetValue;
break;
case FunctionRecord::INST_GEP: idx = (uint32_t)FunctionAbbrev::GEP; break;
case FunctionRecord::INST_UNREACHABLE: idx = (uint32_t)FunctionAbbrev::Unreachable; break;
case FunctionRecord::INST_LOAD:
if(!forwardRefs)
idx = (uint32_t)FunctionAbbrev::Load;
break;
case FunctionRecord::INST_CAST:
if(!forwardRefs)
idx = (uint32_t)FunctionAbbrev::Cast;
break;
case FunctionRecord::INST_BINOP:
if(!forwardRefs)
{
idx = (uint32_t)FunctionAbbrev::BinOp;
// binop with no forward refs is:
// [0]: first param (no type)
// [1]: second param
// [2]: binop itself
// then if there is a 4th val, that is flags
if(vals.size() == 4)
idx = (uint32_t)FunctionAbbrev::BinOpFlags;
}
break;
default: break;
}
// if we got a valid abbrev, use it, otherwise emit unabbrev
if(idx != ~0U)
{
// write the abbrev ID
b.fixed(abbrevSize, GetAbbrevID(idx));
Abbrev(curAbbrevs[idx], (uint32_t)record, vals);
}
else
{
Unabbrev((uint32_t)record, false, vals);
}
}
void BitcodeWriter::Abbrev(AbbrevParam *abbr, uint32_t record, uint64_t val)
{
WriteAbbrevParam(abbr[0], record);
@@ -833,7 +889,7 @@ void BitcodeWriter::WriteAbbrevParam(const AbbrevParam &abbrev, uint64_t val)
if(abbrev.value == MagicFixedSizeNumTypes)
width = m_Cfg.numTypes;
else if(abbrev.value == MagicFixedSizeNumConstants)
width = m_Cfg.numGlobalConsts;
width = m_Cfg.numGlobalValues;
b.fixed((size_t)width, val);
}
else if(abbrev.encoding == AbbrevEncoding::VBR)
+2 -1
View File
@@ -40,7 +40,7 @@ public:
struct Config
{
size_t numTypes;
size_t numGlobalConsts;
size_t numGlobalValues;
size_t numSections;
uint64_t maxAlign;
uint32_t maxGlobalType;
@@ -88,6 +88,7 @@ public:
}
void RecordSymTabEntry(size_t id, const rdcstr &str, bool basicBlock = false);
void RecordInstruction(FunctionRecord record, const rdcarray<uint64_t> &vals, bool forwardRefs);
private:
void WriteAbbrevDefinition(AbbrevParam *abbrev);