diff options
Diffstat (limited to 'source/slang/ir.cpp')
| -rw-r--r-- | source/slang/ir.cpp | 644 |
1 files changed, 602 insertions, 42 deletions
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index 3a6410125..c48880cab 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -1,5 +1,6 @@ // ir.cpp #include "ir.h" +#include "ir-insts.h" #include "../core/basic.h" @@ -65,7 +66,12 @@ namespace Slang return nullptr; } - // + // IRFunc + + IRType* IRFunc::getResultType() { return getType()->getResultType(); } + UInt IRFunc::getParamCount() { return getType()->getParamCount(); } + IRType* IRFunc::getParamType(UInt index) { return getType()->getParamType(index); } + IRParam* IRFunc::getFirstParam() { @@ -81,6 +87,8 @@ namespace Slang return (IRParam*) firstInst; } + // IRParam + IRParam* IRParam::getNextParam() { auto next = nextInst; @@ -94,6 +102,36 @@ namespace Slang // + bool isTerminatorInst(IROp op) + { + switch (op) + { + default: + return false; + + case kIROp_ReturnVal: + case kIROp_ReturnVoid: + case kIROp_unconditionalBranch: + case kIROp_conditionalBranch: + case kIROp_break: + case kIROp_continue: + case kIROp_loop: + case kIROp_if: + case kIROp_ifElse: + case kIROp_loopTest: + return true; + } + } + + bool isTerminatorInst(IRInst* inst) + { + if (!inst) return false; + return isTerminatorInst(inst->op); + } + + + // + // Add an instruction to a specific parent void IRBuilder::addInst(IRParentInst* parent, IRInst* inst) { @@ -306,6 +344,28 @@ namespace Slang varArgs); } + template<typename T> + static T* createInstWithTrailingArgs( + IRBuilder* builder, + IROp op, + IRType* type, + IRValue* arg1, + UInt varArgCount, + IRValue* const* varArgs) + { + IRValue* fixedArgs[] = { arg1 }; + UInt fixedArgCount = sizeof(fixedArgs) / sizeof(fixedArgs[0]); + + return (T*)createInstImpl( + builder, + sizeof(T) + varArgCount * sizeof(IRUse), + op, + type, + fixedArgCount, + fixedArgs, + varArgCount, + varArgs); + } // bool operator==(IRInstKey const& left, IRInstKey const& right) @@ -637,6 +697,8 @@ namespace Slang { switch( flavor ) { + case BaseType::Void: return getVoidType(); + case BaseType::Bool: return getBaseTypeImpl(this, kIROp_BoolType); case BaseType::Float: return getBaseTypeImpl(this, kIROp_Float32Type); case BaseType::Int: return getBaseTypeImpl(this, kIROp_Int32Type); @@ -677,6 +739,34 @@ namespace Slang columnCount); } + IRType* IRBuilder::getArrayType(IRType* elementType, IRValue* elementCount) + { + // The client requests an unsized array by passing `nullptr` for + // the `elementCount`. + // + // We currently encode an unsized array as an ordinary array with + // zero elements. TODO: carefully consider this choice. + if (!elementCount) + { + elementCount = getIntValue( + getBaseType(BaseType::Int), + 0); + } + + return findOrEmitInst<IRArrayType>( + this, + kIROp_arrayType, + getTypeType(), + elementType, + elementCount); + } + + IRType* IRBuilder::getArrayType(IRType* elementType) + { + return getArrayType(elementType, nullptr); + } + + IRType* IRBuilder::getTypeType() { return findOrEmitInst<IRType>( @@ -753,21 +843,38 @@ namespace Slang } IRType* IRBuilder::getPtrType( - IRType* valueType) + IRType* valueType, + IRAddressSpace addressSpace) { + auto uintType = getBaseType(BaseType::UInt); + auto irAddressSpace = getIntValue(uintType, addressSpace); + auto inst = findOrEmitInst<IRPtrType>( this, kIROp_PtrType, getTypeType(), - 1, - (IRValue* const*) &valueType); + valueType, + irAddressSpace); return inst; } - IRValue* IRBuilder::getBoolValue(bool value) + IRType* IRBuilder::getPtrType( + IRType* valueType) { - SLANG_UNIMPLEMENTED_X("IR"); + return getPtrType(valueType, kIRAddressSpace_Default); + } + + + IRValue* IRBuilder::getBoolValue(bool inValue) + { + IRIntegerValue value = inValue; + return findOrEmitConstant( + this, + kIROp_boolConst, + getBoolType(), + sizeof(value), + &value); } IRValue* IRBuilder::getIntValue(IRType* type, IRIntegerValue value) @@ -883,9 +990,10 @@ namespace Slang } IRVar* IRBuilder::emitVar( - IRType* type) + IRType* type, + IRAddressSpace addressSpace) { - auto allocatedType = getPtrType(type); + auto allocatedType = getPtrType(type, addressSpace); auto inst = createInst<IRVar>( this, kIROp_Var, @@ -894,6 +1002,13 @@ namespace Slang return inst; } + + IRVar* IRBuilder::emitVar( + IRType* type) + { + return emitVar(type, kIRAddressSpace_Default); + } + IRInst* IRBuilder::emitLoad( IRValue* ptr) { @@ -996,6 +1111,83 @@ namespace Slang return inst; } + IRInst* IRBuilder::emitSwizzle( + IRType* type, + IRValue* base, + UInt elementCount, + IRValue* const* elementIndices) + { + auto inst = createInstWithTrailingArgs<IRSwizzle>( + this, + kIROp_swizzle, + type, + base, + elementCount, + elementIndices); + + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitSwizzle( + IRType* type, + IRValue* base, + UInt elementCount, + UInt const* elementIndices) + { + auto intType = getBaseType(BaseType::Int); + + IRValue* irElementIndices[4]; + for (UInt ii = 0; ii < elementCount; ++ii) + { + irElementIndices[ii] = getIntValue(intType, elementIndices[ii]); + } + + return emitSwizzle(type, base, elementCount, irElementIndices); + } + + + IRInst* IRBuilder::emitSwizzleSet( + IRType* type, + IRValue* base, + IRValue* source, + UInt elementCount, + IRValue* const* elementIndices) + { + IRValue* fixedArgs[] = { base, source }; + UInt fixedArgCount = sizeof(fixedArgs) / sizeof(fixedArgs[0]); + + auto inst = createInstWithTrailingArgs<IRSwizzleSet>( + this, + kIROp_swizzleSet, + type, + fixedArgCount, + fixedArgs, + elementCount, + elementIndices); + + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitSwizzleSet( + IRType* type, + IRValue* base, + IRValue* source, + UInt elementCount, + UInt const* elementIndices) + { + auto intType = getBaseType(BaseType::Int); + + IRValue* irElementIndices[4]; + for (UInt ii = 0; ii < elementCount; ++ii) + { + irElementIndices[ii] = getIntValue(intType, elementIndices[ii]); + } + + return emitSwizzleSet(type, base, source, elementCount, irElementIndices); + } + IRInst* IRBuilder::emitReturn( IRValue* val) { @@ -1018,6 +1210,133 @@ namespace Slang return inst; } + IRInst* IRBuilder::emitBranch( + IRBlock* block) + { + auto inst = createInst<IRUnconditionalBranch>( + this, + kIROp_unconditionalBranch, + getVoidType(), + block); + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitBreak( + IRBlock* target) + { + auto inst = createInst<IRBreak>( + this, + kIROp_break, + getVoidType(), + target); + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitContinue( + IRBlock* target) + { + auto inst = createInst<IRContinue>( + this, + kIROp_continue, + getVoidType(), + target); + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitLoop( + IRBlock* target, + IRBlock* breakBlock, + IRBlock* continueBlock) + { + IRInst* args[] = { target, breakBlock, continueBlock }; + UInt argCount = sizeof(args) / sizeof(args[0]); + + auto inst = createInst<IRLoop>( + this, + kIROp_loop, + getVoidType(), + argCount, + args); + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitBranch( + IRValue* val, + IRBlock* trueBlock, + IRBlock* falseBlock) + { + IRInst* args[] = { val, trueBlock, falseBlock }; + UInt argCount = sizeof(args) / sizeof(args[0]); + + auto inst = createInst<IRConditionalBranch>( + this, + kIROp_conditionalBranch, + getVoidType(), + argCount, + args); + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitIf( + IRValue* val, + IRBlock* trueBlock, + IRBlock* afterBlock) + { + IRInst* args[] = { val, trueBlock, afterBlock }; + UInt argCount = sizeof(args) / sizeof(args[0]); + + auto inst = createInst<IRIf>( + this, + kIROp_if, + getVoidType(), + argCount, + args); + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitIfElse( + IRValue* val, + IRBlock* trueBlock, + IRBlock* falseBlock, + IRBlock* afterBlock) + { + IRInst* args[] = { val, trueBlock, falseBlock, afterBlock }; + UInt argCount = sizeof(args) / sizeof(args[0]); + + auto inst = createInst<IRIfElse>( + this, + kIROp_ifElse, + getVoidType(), + argCount, + args); + addInst(inst); + return inst; + } + + IRInst* IRBuilder::emitLoopTest( + IRValue* val, + IRBlock* bodyBlock, + IRBlock* breakBlock) + { + IRInst* args[] = { val, bodyBlock, breakBlock }; + UInt argCount = sizeof(args) / sizeof(args[0]); + + auto inst = createInst<IRLoopTest>( + this, + kIROp_loopTest, + getVoidType(), + argCount, + args); + addInst(inst); + return inst; + } + IRDecoration* IRBuilder::addDecorationImpl( IRInst* inst, UInt decorationSize, @@ -1053,7 +1372,7 @@ namespace Slang struct IRDumpContext { - FILE* file; + StringBuilder* builder; int indent; }; @@ -1061,14 +1380,16 @@ namespace Slang IRDumpContext* context, char const* text) { - fprintf(context->file, "%s", text); + context->builder->append(text); } static void dump( IRDumpContext* context, UInt val) { - fprintf(context->file, "%llu", (unsigned long long)val); + context->builder->append(val); + +// fprintf(context->file, "%llu", (unsigned long long)val); } static void dumpIndent( @@ -1076,7 +1397,7 @@ namespace Slang { for (int ii = 0; ii < context->indent; ++ii) { - dump(context, " "); + dump(context, "\t"); } } @@ -1088,79 +1409,318 @@ namespace Slang { dump(context, "<null>"); } - else + else if(inst->id) { dump(context, "%"); dump(context, inst->id); } + else + { + dump(context, "_"); + } } - static void dumpInst( + static void dumpType( + IRDumpContext* context, + IRType* type); + + static void dumpOperand( IRDumpContext* context, IRInst* inst) { - dumpIndent(context); if (!inst) { - dump(context, "<null>"); + dump(context, "undef"); + return; } - // TODO: need to display a name for the result... + switch (inst->op) + { + case kIROp_IntLit: + dump(context, ((IRConstant*)inst)->u.intVal); + return; - auto op = inst->op; - auto opInfo = &kIROpInfos[op]; + case kIROp_FloatLit: + dump(context, ((IRConstant*)inst)->u.floatVal); + return; - if (inst->id) + case kIROp_boolConst: + dump(context, ((IRConstant*)inst)->u.intVal ? "true" : "false"); + return; + + case kIROp_TypeType: + dumpType(context, (IRType*)inst); + return; + + default: + break; + } + + auto type = inst->getType(); + if (type) { - dumpID(context, inst); - dump(context, " = "); + switch (type->op) + { + case kIROp_TypeType: + dumpType(context, (IRType*)inst); + return; + + default: + break; + } } - dump(context, opInfo->name); - // TODO: dump operands - uint32_t argCount = inst->argCount; - for (uint32_t ii = 0; ii < argCount; ++ii) + dumpID(context, inst); + } + + static void dumpType( + IRDumpContext* context, + IRType* type) + { + if (!type) { - if (ii != 0) - dump(context, ", "); - else + dumpID(context, type); + return; + } + + auto op = type->op; + auto opInfo = kIROpInfos[op]; + + switch (op) + { + case kIROp_StructType: + dumpID(context, type); + break; + + default: { - dump(context, " "); + dump(context, opInfo.name); + UInt argCount = type->getArgCount(); + + if (argCount > 1) + { + dump(context, "<"); + for (UInt aa = 1; aa < argCount; ++aa) + { + if (aa != 1) dump(context, ","); + dumpOperand(context, type->getArg(aa)); + + } + dump(context, ">"); + } } + break; + } + } - auto argVal = inst->getArgs()[ii].usedValue; + static void dumpInstTypeClause( + IRDumpContext* context, + IRType* type) + { + dump(context, "\t: "); + dumpType(context, type); - // TODO: actually print the damn operand... + } - dumpID(context, argVal); - } + static void dumpInst( + IRDumpContext* context, + IRInst* inst); - dump(context, "\n"); + static void dumpChildrenRaw( + IRDumpContext* context, + IRParentInst* parent) + { + for (auto ii = parent->firstChild; ii; ii = ii->nextInst) + { + dumpInst(context, ii); + } + } + static void dumpChildren( + IRDumpContext* context, + IRInst* inst) + { + auto op = inst->op; + auto opInfo = &kIROpInfos[op]; if (opInfo->flags & kIROpFlag_Parent) { dumpIndent(context); dump(context, "{\n"); context->indent++; auto parent = (IRParentInst*)inst; - for (auto ii = parent->firstChild; ii; ii = ii->nextInst) - { - dumpInst(context, ii); - } + dumpChildrenRaw(context, parent); context->indent--; dumpIndent(context); dump(context, "}\n"); } } + static void dumpInst( + IRDumpContext* context, + IRInst* inst) + { + if (!inst) + { + dumpIndent(context); + dump(context, "<null>"); + return; + } + + auto op = inst->op; + + // There are several ops we want to special-case here, + // so that they will be more pleasant to look at. + // + switch (op) + { + case kIROp_Module: + dumpIndent(context); + dump(context, "module\n"); + dumpChildren(context, inst); + return; + + case kIROp_Func: + { + IRFunc* func = (IRFunc*)inst; + dump(context, "\n"); + dumpIndent(context); + dump(context, "func "); + dumpID(context, func); + dump(context, "(\n"); + context->indent++; + for (auto pp = func->getFirstParam(); pp; pp = pp->getNextParam()) + { + if (pp != func->getFirstParam()) + dump(context, ",\n"); + + dumpIndent(context); + dump(context, "param "); + dumpID(context, pp); + dumpInstTypeClause(context, pp->getType()); + } + context->indent--; + dump(context, ")\n"); + + dumpIndent(context); + dump(context, "{\n"); + context->indent++; + + for (auto bb = func->getFirstBlock(); bb; bb = bb->getNextBlock()) + { + if (bb != func->getFirstBlock()) + dump(context, "\n"); + dumpInst(context, bb); + } + + context->indent--; + dump(context, "}\n"); + } + return; + + case kIROp_TypeType: + case kIROp_Param: + case kIROp_IntLit: + case kIROp_FloatLit: + case kIROp_boolConst: + // Don't dump here + return; + + case kIROp_Block: + { + IRBlock* block = (IRBlock*)inst; + + context->indent--; + dump(context, "block "); + dumpID(context, block); + dump(context, ":\n"); + context->indent++; + + dumpChildrenRaw(context, block); + } + return; + + default: + break; + } - void dumpIR(IRModule* module) + // We also want to special-case based on the *type* + // of the instruction + auto type = inst->getType(); + if (type && type->op == kIROp_TypeType) + { + // We probably don't want to print most types + // when producing "friendly" output. + switch (type->op) + { + case kIROp_StructType: + break; + + default: + return; + } + } + + + // Okay, we have a seemingly "ordinary" op now + dumpIndent(context); + + auto opInfo = &kIROpInfos[op]; + + if (type && type->op == kIROp_TypeType) + { + dump(context, "type "); + dumpID(context, inst); + dump(context, "\t= "); + } + else if (type && type->op == kIROp_VoidType) + { + } + else + { + dump(context, "let "); + dumpID(context, inst); + dumpInstTypeClause(context, type); + dump(context, "\t= "); + } + + + dump(context, opInfo->name); + + uint32_t argCount = inst->argCount; + dump(context, "("); + for (uint32_t ii = 1; ii < argCount; ++ii) + { + if (ii != 1) + dump(context, ", "); + + auto argVal = inst->getArgs()[ii].usedValue; + + dumpOperand(context, argVal); + } + dump(context, ")"); + + dump(context, "\n"); + + // The instruction might have children, + // so we need to handle those here + dumpChildren(context, inst); + } + + void printSlangIRAssembly(StringBuilder& builder, IRModule* module) { IRDumpContext context; - context.file = stderr; + context.builder = &builder; context.indent = 0; - dumpInst(&context, module); + dumpChildrenRaw(&context, module); } + String getSlangIRAssembly(IRModule* module) + { + StringBuilder sb; + printSlangIRAssembly(sb, module); + return sb; + } + + } |
