summaryrefslogtreecommitdiffstats
path: root/source/slang/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/ir.cpp')
-rw-r--r--source/slang/ir.cpp549
1 files changed, 547 insertions, 2 deletions
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index 44eb7a727..9e5169bd2 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -6,9 +6,341 @@
namespace Slang
{
+#define OP(ID, MNEMONIC, ARG_COUNT, FLAGS) \
+ static const IROpInfo kIROpInfo_##ID { \
+ #MNEMONIC, ARG_COUNT, FLAGS, }
+
+#define PARENT kIROpFlag_Parent
+
+ OP(TypeType, type.type, 0, 0);
+ OP(VoidType, type.void, 0, 0);
+ OP(BlockType, type.block, 0, 0);
+ OP(VectorType, type.vector, 2, 0);
+ OP(BoolType, type.bool, 0, 0);
+ OP(Float32Type, type.f32, 0, 0);
+ OP(Int32Type, type.i32, 0, 0);
+ OP(UInt32Type, type.u32, 0, 0);
+ OP(StructType, type.struct, 0, 0);
+
+ OP(IntLit, integer_constant, 0, 0);
+ OP(FloatLit, float_constant, 0, 0);
+
+ OP(Construct, construct, 0, 0);
+
+ OP(Module, module, 0, PARENT);
+ OP(Func, func, 0, PARENT);
+ OP(Block, block, 0, PARENT);
+
+ OP(Param, param, 0, 0);
+
+ OP(FieldExtract, get_field, 1, 0);
+ OP(ReturnVal, return_val, 1, 0);
+ OP(ReturnVoid, return_void, 1, 0);
+
+#define INTRINSIC(NAME) \
+ static const IROpInfo kIROpInfo_Intrinsic_##NAME { \
+ "intrinsic." #NAME, 0, 0, };
+#include "intrinsic-defs.h"
+
+#undef PARENT
+#undef OP
+
+
+ static IROpInfo const* const kIRIntrinsicOpInfos[] =
+ {
+ nullptr,
+
+#define INTRINSIC(NAME) &kIROpInfo_Intrinsic_##NAME,
+#include "intrinsic-defs.h"
+
+ };
+
+ //
+
+ void IRUse::init(IRValue* u, IRValue* v)
+ {
+ user = u;
+ usedValue = v;
+
+ if(v)
+ {
+ nextUse = v->firstUse;
+ prevLink = &v->firstUse;
+
+ v->firstUse = this;
+ }
+ }
+
+ //
+
+ IRUse* IRInst::getArgs()
+ {
+ return &type;
+ }
+
+ //
+
+ // Add an instruction into the current scope
+ static void addInst(
+ IRBuilder* builder,
+ IRInst* inst)
+ {
+ auto parent = builder->parentInst;
+ if (!parent)
+ return;
+
+ inst->parent = parent;
+
+ if (!parent->firstChild)
+ {
+ inst->prevInst = nullptr;
+ inst->nextInst = nullptr;
+
+ parent->firstChild = inst;
+ parent->lastChild = inst;
+ }
+ else
+ {
+ auto prev = parent->lastChild;
+
+ inst->prevInst = prev;
+ inst->nextInst = nullptr;
+
+ prev->nextInst = inst;
+ parent->lastChild = inst;
+ }
+ }
+
+ // Create an IR instruction/value and initialize it.
+ //
+ // In this case `argCount` and `args` represnt the
+ // arguments *after* the type (which is a mandatory
+ // argument for all instructions).
+ static IRValue* createInstImpl(
+ IRBuilder* builder,
+ UInt size,
+ IROpInfo const* op,
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args)
+ {
+ IRValue* inst = (IRInst*) malloc(size);
+ memset(inst, 0, size);
+
+ IRUse* instArgs = inst->getArgs();
+
+ auto module = builder->module;
+ if (!module || (type && type->op == &kIROpInfo_VoidType))
+ {
+ // Can't or shouldn't assign an ID to this op
+ }
+ else
+ {
+ inst->id = ++module->idCounter;
+ }
+
+ inst->op = op;
+
+ inst->type.init(inst, type);
+
+ for( UInt aa = 0; aa < argCount; ++aa )
+ {
+ instArgs[aa+1].init(inst, args[aa]);
+ }
+
+ addInst(builder, inst);
+
+ return inst;
+ }
+
+ // Create an IR instruction/value and initialize it.
+ //
+ // For this overload, the type of the instruction is
+ // folded into the argument list (so `args[0]` needs
+ // to be the type of the instruction)
+ static IRValue* createInstImpl(
+ IRBuilder* builder,
+ UInt size,
+ IROpInfo const* op,
+ UInt argCount,
+ IRValue* const* args)
+ {
+ return createInstImpl(
+ builder,
+ size,
+ op,
+ (IRType*) args[0],
+ argCount - 1,
+ args + 1);
+ }
+
+ template<typename T>
+ static T* createInst(
+ IRBuilder* builder,
+ IROpInfo const* op,
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args)
+ {
+ return (T*)createInstImpl(
+ builder,
+ sizeof(T),
+ op,
+ type,
+ argCount,
+ args);
+ }
+
+ template<typename T>
+ static T* createInst(
+ IRBuilder* builder,
+ IROpInfo const* op,
+ IRType* type)
+ {
+ return (T*)createInstImpl(
+ builder,
+ sizeof(T),
+ op,
+ type,
+ 0,
+ nullptr);
+ }
+
+ template<typename T>
+ static T* createInst(
+ IRBuilder* builder,
+ IROpInfo const* op,
+ IRType* type,
+ IRValue* arg)
+ {
+ return (T*)createInstImpl(
+ builder,
+ sizeof(T),
+ op,
+ type,
+ 1,
+ &arg);
+ }
+
+ template<typename T>
+ static T* createInst(
+ IRBuilder* builder,
+ IROpInfo const* op,
+ IRType* type,
+ IRValue* arg1,
+ IRValue* arg2)
+ {
+ IRValue* args[] = { arg1, arg2 };
+ return (T*)createInstImpl(
+ builder,
+ sizeof(T),
+ op,
+ type,
+ 2,
+ &args[0]);
+ }
+
+ template<typename T>
+ static T* createValueWithTrailingArgs(
+ IRBuilder* builder,
+ IROpInfo const* op,
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args)
+ {
+ return (T*)createInstImpl(
+ builder,
+ sizeof(T) + argCount * sizeof(IRUse),
+ op,
+ type,
+ argCount,
+ args);
+ }
+
+
+
+ //
+
+ static IRType* getBaseTypeImpl(IRBuilder* builder, IROpInfo const* op)
+ {
+ return createInst<IRType>(
+ builder,
+ op,
+ builder->getTypeType());
+ }
+
+ IRType* IRBuilder::getBaseType(BaseType flavor)
+ {
+ switch( flavor )
+ {
+ case BaseType::Bool: return getBaseTypeImpl(this, &kIROpInfo_BoolType);
+ case BaseType::Float: return getBaseTypeImpl(this, &kIROpInfo_Float32Type);
+ case BaseType::Int: return getBaseTypeImpl(this, &kIROpInfo_Int32Type);
+ case BaseType::UInt: return getBaseTypeImpl(this, &kIROpInfo_UInt32Type);
+
+ default:
+ SLANG_UNEXPECTED("unhandled base type");
+ return nullptr;
+ }
+ }
+
IRType* IRBuilder::getBoolType()
{
- SLANG_UNIMPLEMENTED_X("IR");
+ return getBaseType(BaseType::Bool);
+ }
+
+ IRType* IRBuilder::getVectorType(IRType* elementType, IRValue* elementCount)
+ {
+ // TODO: should unique things
+ return createInst<IRVectorType>(
+ this,
+ &kIROpInfo_VectorType,
+ getTypeType(),
+ elementType,
+ elementCount);
+ }
+
+ IRType* IRBuilder::getTypeType()
+ {
+ // TODO: should unique things
+ IRType* type = createInst<IRType>(
+ this,
+ &kIROpInfo_TypeType,
+ nullptr);
+
+ // TODO: we need some way to stop this recursion,
+ // but just saying that `Type isa Type` is unfounded.
+ type->type.init(type, type);
+
+ return type;
+ }
+
+ IRType* IRBuilder::getVoidType()
+ {
+ return createInst<IRType>(
+ this,
+ &kIROpInfo_VoidType,
+ getTypeType());
+ }
+
+ IRType* IRBuilder::getBlockType()
+ {
+ return createInst<IRType>(
+ this,
+ &kIROpInfo_BlockType,
+ getTypeType());
+ }
+
+ IRType* IRBuilder::getStructType(
+ UInt fieldCount,
+ IRType* const* fieldTypes)
+ {
+ return createValueWithTrailingArgs<IRStructType>(
+ this,
+ &kIROpInfo_StructType,
+ getTypeType(),
+ fieldCount,
+ (IRValue* const*)fieldTypes);
}
IRValue* IRBuilder::getBoolValue(bool value)
@@ -18,7 +350,14 @@ namespace Slang
IRValue* IRBuilder::getIntValue(IRType* type, IRIntegerValue value)
{
- SLANG_UNIMPLEMENTED_X("IR");
+ IRIntLit* val = createInst<IRIntLit>(
+ this,
+ &kIROpInfo_IntLit,
+ type);
+
+ val->value = value;
+
+ return val;
}
IRValue* IRBuilder::getFloatValue(IRType* type, IRFloatingPointValue value)
@@ -26,4 +365,210 @@ namespace Slang
SLANG_UNIMPLEMENTED_X("IR");
}
+ IRInst* IRBuilder::emitIntrinsicInst(
+ IRType* type,
+ IntrinsicOp intrinsicOp,
+ UInt argCount,
+ IRValue* const* args)
+ {
+ return createValueWithTrailingArgs<IRInst>(
+ this,
+ kIRIntrinsicOpInfos[(int)intrinsicOp],
+ type,
+ argCount,
+ args);
+ }
+
+ IRInst* IRBuilder::emitConstructorInst(
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args)
+ {
+ return createValueWithTrailingArgs<IRInst>(
+ this,
+ &kIROpInfo_Construct,
+ type,
+ argCount,
+ args);
+ }
+
+ IRModule* IRBuilder::createModule()
+ {
+ return createInst<IRModule>(
+ this,
+ &kIROpInfo_Module,
+ nullptr);
+ }
+
+
+ IRFunc* IRBuilder::createFunc()
+ {
+ return createInst<IRFunc>(
+ this,
+ &kIROpInfo_Func,
+ nullptr);
+ }
+
+ IRBlock* IRBuilder::createBlock()
+ {
+ return createInst<IRBlock>(
+ this,
+ &kIROpInfo_Block,
+ getBlockType());
+ }
+
+ IRParam* IRBuilder::createParam(
+ IRType* type)
+ {
+ return createInst<IRParam>(
+ this,
+ &kIROpInfo_Param,
+ type);
+ }
+
+ IRInst* IRBuilder::createFieldExtract(
+ IRType* type,
+ IRValue* base,
+ UInt fieldIndex)
+ {
+ IRFieldExtract* irInst = createInst<IRFieldExtract>(
+ this,
+ &kIROpInfo_FieldExtract,
+ type,
+ base);
+
+ irInst->fieldIndex = fieldIndex;
+
+ return irInst;
+ }
+
+ IRInst* IRBuilder::createReturn(
+ IRValue* val)
+ {
+ return createInst<IRReturnVal>(
+ this,
+ &kIROpInfo_ReturnVal,
+ getVoidType(),
+ val);
+ }
+
+ IRInst* IRBuilder::createReturn()
+ {
+ return createInst<IRReturnVoid>(
+ this,
+ &kIROpInfo_ReturnVoid,
+ getVoidType());
+ }
+
+ struct IRDumpContext
+ {
+ FILE* file;
+ int indent;
+ };
+
+ static void dump(
+ IRDumpContext* context,
+ char const* text)
+ {
+ fprintf(context->file, "%s", text);
+ }
+
+ static void dump(
+ IRDumpContext* context,
+ UInt val)
+ {
+ fprintf(context->file, "%llu", (unsigned long long)val);
+ }
+
+ static void dumpIndent(
+ IRDumpContext* context)
+ {
+ for (int ii = 0; ii < context->indent; ++ii)
+ {
+ dump(context, " ");
+ }
+ }
+
+ static void dumpID(
+ IRDumpContext* context,
+ IRInst* inst)
+ {
+ if (!inst)
+ {
+ dump(context, "<null>");
+ }
+ else
+ {
+ dump(context, "%");
+ dump(context, inst->id);
+ }
+ }
+
+ static void dumpInst(
+ IRDumpContext* context,
+ IRInst* inst)
+ {
+ dumpIndent(context);
+ if (!inst)
+ {
+ dump(context, "<null>");
+ }
+
+ // TODO: need to display a name for the result...
+
+ auto op = inst->op;
+
+ if (inst->id)
+ {
+ dumpID(context, inst);
+ dump(context, " = ");
+ }
+
+ dump(context, op->name);
+
+ // TODO: dump operands
+ unsigned argCount = op->fixedArgCount + 1;
+ for (unsigned ii = 0; ii < argCount; ++ii)
+ {
+ if (ii != 0)
+ dump(context, ", ");
+ else
+ {
+ dump(context, " ");
+ }
+
+ auto argVal = inst->getArgs()[ii].usedValue;
+
+ // TODO: actually print the damn operand...
+
+ dumpID(context, argVal);
+ }
+
+ dump(context, "\n");
+
+ if (op->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);
+ }
+ context->indent--;
+ dumpIndent(context);
+ dump(context, "}\n");
+ }
+ }
+
+ void dumpIR(IRModule* module)
+ {
+ IRDumpContext context;
+ context.file = stderr;
+ context.indent = 0;
+
+ dumpInst(&context, module);
+ }
+
}