summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-08-17 13:40:50 -0700
committerTim Foley <tfoley@nvidia.com>2017-08-17 13:44:02 -0700
commitad19484792dcc5a1fb90720614830c66c4b9712d (patch)
tree45e5c5152b4d5deca3125d9fb8159d114bc09d14 /source
parent1965c3f3f265c43c8d1d96bb49d0850ce5d53cc3 (diff)
Add some dummy logic to print IR to HLSL
- Change IR instructions to just hold an integer opcode instead of a pointer to the "info" structure - Externalize definition of IR instructions to a header file, and use the "X macro" approach to allow generating different definitions - Add notion of function types to the IR, so that we can easily query the result type of a function - Add some convenience accesors to allow walking the IR in a strongly-typed manner (e.g., iterate over the parameters of a function) - TODO: these should really be changed to assert the type of things, as least in debug builds - Add very basic logic to `emit.cpp` so that it can walk the generated IR and start printing it back as HLSL - This isn't meant to be usable as-is, but it is a step toward where we need to go
Diffstat (limited to 'source')
-rw-r--r--source/slang/emit.cpp325
-rw-r--r--source/slang/ir-inst-defs.h41
-rw-r--r--source/slang/ir.cpp224
-rw-r--r--source/slang/ir.h73
-rw-r--r--source/slang/lower-to-ir.cpp11
-rw-r--r--source/slang/slang.vcxproj1
-rw-r--r--source/slang/slang.vcxproj.filters1
7 files changed, 582 insertions, 94 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index d9b2ffcd6..35020249b 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -3822,8 +3822,328 @@ emitDeclImpl(decl, nullptr);
SLANG_UNEXPECTED("unhandled declaration kind");
}
}
+
+ // IR-level emit logc
+
+ String getName(IRInst* inst)
+ {
+ StringBuilder sb;
+ sb << "_S";
+ sb << inst->id;
+ return sb.ProduceString();
+ }
+
+ struct IRDeclaratorInfo
+ {
+ enum class Flavor
+ {
+ Simple,
+ };
+
+ Flavor flavor;
+ String const* name;
+ };
+
+ void emitDeclarator(
+ EmitContext* context,
+ IRDeclaratorInfo* declarator)
+ {
+ if(!declarator)
+ return;
+
+ switch( declarator->flavor )
+ {
+ case IRDeclaratorInfo::Flavor::Simple:
+ emit(" ");
+ emit(*declarator->name);
+ break;
+ }
+ }
+
+ void emitIRSimpleType(
+ EmitContext* context,
+ IRType* type)
+ {
+ switch(type->op)
+ {
+ #define CASE(ID, NAME) \
+ case kIROp_##ID: emit(#NAME); break
+
+ CASE(Float32Type, float);
+ CASE(Int32Type, int);
+ CASE(UInt32Type, uint);
+
+ #undef CASE
+
+ default:
+ SLANG_UNIMPLEMENTED_X("type case for emit");
+ break;
+ }
+
+ }
+
+ void emitIRSimpleValue(
+ EmitContext* context,
+ IRInst* inst)
+ {
+ switch(inst->op)
+ {
+ case kIROp_IntLit:
+ emit(((IRConstant*) inst)->u.intVal);
+ break;
+
+ case kIROp_FloatLit:
+ emit(((IRConstant*) inst)->u.floatVal);
+ break;
+
+ default:
+ SLANG_UNIMPLEMENTED_X("val case for emit");
+ break;
+ }
+
+ }
+
+
+ void emitIRVectorType(
+ EmitContext* context,
+ IRVectorType* type)
+ {
+ // TODO: this is a GLSL-vs-HLSL decision point
+
+ emitIRSimpleType(context, type->getElementType());
+ emitIRSimpleValue(context, type->getElementCount());
+ }
+
+ void emitIRType(
+ EmitContext* context,
+ IRType* type,
+ IRDeclaratorInfo* declarator)
+ {
+ switch( type->op )
+ {
+ case kIROp_VectorType:
+ emitIRVectorType(context, (IRVectorType*) type);
+ emitDeclarator(context, declarator);
+ break;
+
+ case kIROp_StructType:
+ emit(getName(type));
+ emitDeclarator(context, declarator);
+ break;
+
+ default:
+ emitIRSimpleType(context, type);
+ emitDeclarator(context, declarator);
+ break;
+ }
+ }
+
+ void emitIRType(
+ EmitContext* context,
+ IRType* type,
+ String const& name)
+ {
+ IRDeclaratorInfo declarator;
+ declarator.flavor = IRDeclaratorInfo::Flavor::Simple;
+ declarator.name = &name;
+
+ emitIRType(context, type, &declarator);
+ }
+
+ void emitIRType(
+ EmitContext* context,
+ IRType* type)
+ {
+ emitIRType(context, type, (IRDeclaratorInfo*) nullptr);
+ }
+
+ void emitIROperand(
+ EmitContext* context,
+ IRInst* inst)
+ {
+ emit(getName(inst));
+ }
+
+ void emitIRArgs(
+ EmitContext* context,
+ IRInst* inst)
+ {
+ UInt argCount = inst->argCount - 1;
+ IRUse* args = inst->getArgs() + 1;
+
+ emit("(");
+ for(UInt aa = 0; aa < argCount; ++aa)
+ {
+ if(aa != 0) emit(", ");
+ emitIROperand(context, args[aa].usedValue);
+ }
+ emit(")");
+ }
+
+ void emitIRInstResultDecl(
+ EmitContext* context,
+ IRInst* inst)
+ {
+ emitIRType(context, inst->getType(), getName(inst));
+ emit(" = ");
+ }
+
+ void emitIRInst(
+ EmitContext* context,
+ IRInst* inst)
+ {
+ // TODO: need to be able to `switch` on the IR opcode here,
+ // so there is some work to be done.
+ switch(inst->op)
+ {
+ case kIROp_Param:
+ // Don't emit parameters, since they are declared as part of the function.
+ break;
+
+ case kIROp_Construct:
+ // Simple constructor call
+ emitIRInstResultDecl(context, inst);
+ emitIRType(context, inst->getType());
+ emitIRArgs(context, inst);
+ emit(";\n");
+ break;
+
+ case kIROp_FieldExtract:
+ {
+ // Extract field from aggregate
+
+ IRFieldExtract* fieldExtract = (IRFieldExtract*) inst;
+
+ emitIRInstResultDecl(context, inst);
+ emitIROperand(context, fieldExtract->getBase());
+ emit(".field");
+ emit(fieldExtract->fieldIndex);
+ emit(";\n");
+ }
+ break;
+
+ case kIROp_ReturnVoid:
+ emit("return;\n");
+ break;
+
+ case kIROp_ReturnVal:
+ emit("return ");
+ emitIROperand(context, ((IRReturnVal*) inst)->getVal());
+ emit(";\n");
+ break;
+
+ default:
+ emit("// uhandled\n");
+ break;
+ }
+ }
+
+ void emitIRFunc(
+ EmitContext* context,
+ IRFunc* func)
+ {
+ auto funcType = func->getType();
+ auto resultType = func->getResultType();
+
+ auto name = getName(func);
+
+ emitIRType(context, resultType, name);
+
+ emit("(");
+ auto firstParam = func->getFirstParam();
+ for( auto pp = firstParam; pp; pp = pp->getNextParam() )
+ {
+ if(pp != firstParam)
+ emit(", ");
+
+ auto paramName = getName(pp);
+ emitIRType(context, pp->getType(), paramName);
+ }
+ emit(")");
+
+ // TODO: encode declaration vs. definition
+ bool isDefinition = true;
+ if(isDefinition)
+ {
+ emit("\n{\n");
+
+ // Need to emit the operations in the blocks of the function
+ for( auto bb = func->getFirstBlock(); bb; bb = bb->getNextBlock() )
+ {
+ // TODO: need to handle control flow and so forth...
+ for( auto ii = bb->firstChild; ii; ii = ii->nextInst )
+ {
+ emitIRInst(context, ii);
+ }
+ }
+
+ emit("}\n");
+ }
+ else
+ {
+ emit(";\n");
+ }
+ }
+
+ void emitIRStruct(
+ EmitContext* context,
+ IRStructType* structType)
+ {
+ emit("struct ");
+ emit(getName(structType));
+ emit("\n{\n");
+ auto fieldCount = structType->getFieldCount();
+ for( UInt ff = 0; ff < fieldCount; ++ff )
+ {
+ auto fieldType = structType->getFieldType(ff);
+
+ String fieldName = "field";
+ fieldName.append(ff);
+
+ emitIRType(context, fieldType, fieldName);
+ emit(";\n");
+ }
+ emit("};\n");
+ }
+
+ void emitIRGlobalInst(
+ EmitContext* context,
+ IRInst* inst)
+ {
+ // TODO: need to be able to `switch` on the IR opcode here,
+ // so there is some work to be done.
+ switch(inst->op)
+ {
+ case kIROp_Func:
+ emitIRFunc(context, (IRFunc*) inst);
+ break;
+
+ case kIROp_StructType:
+ emitIRStruct(context, (IRStructType*) inst);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ void emitIRModule(
+ EmitContext* context,
+ IRModule* module)
+ {
+ for(auto ii = module->firstChild; ii; ii = ii->nextInst )
+ {
+ emitIRGlobalInst(context, ii);
+ }
+ }
+
+
};
+//
+
+
+//
EntryPointLayout* findEntryPointLayout(
ProgramLayout* programLayout,
@@ -3948,6 +4268,11 @@ String emitEntryPoint(
dumpIR(lowered);
+ // TODO: do we want to emit directly from IR, or translate the
+ // IR back into AST for emission?
+
+ visitor.emitIRModule(&context, lowered);
+
throw 99;
}
diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h
new file mode 100644
index 000000000..8445e5a1e
--- /dev/null
+++ b/source/slang/ir-inst-defs.h
@@ -0,0 +1,41 @@
+// ir-inst-defs.h
+
+#ifndef INST
+#error Must #define `INST` before including `ir-inst-defs.h`
+#endif
+
+#define PARENT kIROpFlag_Parent
+
+INST(TypeType, type.type, 0, 0)
+INST(VoidType, type.void, 0, 0)
+INST(BlockType, type.block, 0, 0)
+INST(VectorType, type.vector, 2, 0)
+INST(BoolType, type.bool, 0, 0)
+INST(Float32Type, type.f32, 0, 0)
+INST(Int32Type, type.i32, 0, 0)
+INST(UInt32Type, type.u32, 0, 0)
+INST(StructType, type.struct, 0, 0)
+INST(FuncType, func_type, 0, 0)
+
+INST(IntLit, integer_constant, 0, 0)
+INST(FloatLit, float_constant, 0, 0)
+
+INST(Construct, construct, 0, 0)
+
+INST(Module, module, 0, PARENT)
+INST(Func, func, 0, PARENT)
+INST(Block, block, 0, PARENT)
+
+INST(Param, param, 0, 0)
+
+INST(FieldExtract, get_field, 1, 0)
+INST(ReturnVal, return_val, 1, 0)
+INST(ReturnVoid, return_void, 1, 0)
+
+#define INTRINSIC(NAME) \
+ INST(Intrinsic_##NAME, intrinsic.NAME, 0, 0)
+#include "intrinsic-defs.h"
+
+#undef PARENT
+#undef INST
+
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index c40b0f048..d2c3f5ba5 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -6,51 +6,19 @@
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 const IROpInfo kIROpInfos[] =
+ {
+#define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) \
+ { #MNEMONIC, ARG_COUNT, FLAGS, },
+#include "ir-inst-defs.h"
+ };
- static IROpInfo const* const kIRIntrinsicOpInfos[] =
+ static const IROp kIRIntrinsicOps[] =
{
- nullptr,
+ (IROp) 0,
-#define INTRINSIC(NAME) &kIROpInfo_Intrinsic_##NAME,
+#define INTRINSIC(NAME) kIROp_Intrinsic_##NAME,
#include "intrinsic-defs.h"
};
@@ -80,6 +48,33 @@ namespace Slang
//
+ IRParam* IRFunc::getFirstParam()
+ {
+ auto entryBlock = getFirstBlock();
+ if(!entryBlock) return nullptr;
+
+ auto firstInst = entryBlock->firstChild;
+ if(!firstInst) return nullptr;
+
+ if(firstInst->op != kIROp_Param)
+ return nullptr;
+
+ return (IRParam*) firstInst;
+ }
+
+ IRParam* IRParam::getNextParam()
+ {
+ auto next = nextInst;
+ if(!next) return nullptr;
+
+ if(next->op != kIROp_Param)
+ return nullptr;
+
+ return (IRParam*) next;
+ }
+
+ //
+
// Add an instruction to a specific parent
void IRBuilder::addInst(IRParentInst* parent, IRInst* inst)
{
@@ -124,10 +119,12 @@ namespace Slang
static IRValue* createInstImpl(
IRBuilder* builder,
UInt size,
- IROpInfo const* op,
+ IROp op,
IRType* type,
- UInt argCount,
- IRValue* const* args)
+ UInt fixedArgCount,
+ IRValue* const* fixedArgs,
+ UInt varArgCount = 0,
+ IRValue* const* varArgs = nullptr)
{
IRValue* inst = (IRInst*) malloc(size);
memset(inst, 0, size);
@@ -135,7 +132,7 @@ namespace Slang
IRUse* instArgs = inst->getArgs();
auto module = builder->getModule();
- if (!module || (type && type->op == &kIROpInfo_VoidType))
+ if (!module || (type && type->op == kIROp_VoidType))
{
// Can't or shouldn't assign an ID to this op
}
@@ -143,15 +140,25 @@ namespace Slang
{
inst->id = ++module->idCounter;
}
- inst->argCount = argCount + 1;
+ inst->argCount = fixedArgCount + varArgCount + 1;
inst->op = op;
- inst->type.init(inst, type);
+ auto operand = inst->getArgs();
- for( UInt aa = 0; aa < argCount; ++aa )
+ operand->init(inst, type);
+ operand++;
+
+ for( UInt aa = 0; aa < fixedArgCount; ++aa )
{
- instArgs[aa+1].init(inst, args[aa]);
+ operand->init(inst, fixedArgs[aa]);
+ operand++;
+ }
+
+ for( UInt aa = 0; aa < varArgCount; ++aa )
+ {
+ operand->init(inst, varArgs[aa]);
+ operand++;
}
return inst;
@@ -165,7 +172,7 @@ namespace Slang
static IRValue* createInstImpl(
IRBuilder* builder,
UInt size,
- IROpInfo const* op,
+ IROp op,
UInt argCount,
IRValue* const* args)
{
@@ -181,7 +188,7 @@ namespace Slang
template<typename T>
static T* createInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
UInt argCount,
IRValue* const* args)
@@ -198,7 +205,7 @@ namespace Slang
template<typename T>
static T* createInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type)
{
return (T*)createInstImpl(
@@ -213,7 +220,7 @@ namespace Slang
template<typename T>
static T* createInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
IRValue* arg)
{
@@ -229,7 +236,7 @@ namespace Slang
template<typename T>
static T* createInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
IRValue* arg1,
IRValue* arg2)
@@ -247,7 +254,7 @@ namespace Slang
template<typename T>
static T* createInstWithTrailingArgs(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
UInt argCount,
IRValue* const* args)
@@ -261,6 +268,27 @@ namespace Slang
args);
}
+ template<typename T>
+ static T* createInstWithTrailingArgs(
+ IRBuilder* builder,
+ IROp op,
+ IRType* type,
+ UInt fixedArgCount,
+ IRValue* const* fixedArgs,
+ UInt varArgCount,
+ IRValue* const* varArgs)
+ {
+ return (T*)createInstImpl(
+ builder,
+ sizeof(T) + varArgCount * sizeof(IRUse),
+ op,
+ type,
+ fixedArgCount,
+ fixedArgs,
+ varArgCount,
+ varArgs);
+ }
+
//
bool operator==(IRInstKey const& left, IRInstKey const& right)
@@ -327,7 +355,7 @@ namespace Slang
static IRInst* findOrEmitInstImpl(
IRBuilder* builder,
UInt size,
- IROpInfo const* op,
+ IROp op,
IRType* type,
UInt argCount,
IRValue* const* args)
@@ -354,7 +382,7 @@ namespace Slang
parent = builder->parentInst;
}
- if( parent->op == &kIROpInfo_Func )
+ if( parent->op == kIROp_Func )
{
// We are trying to insert into a function, and we should really
// be inserting into its entry block.
@@ -398,7 +426,7 @@ namespace Slang
template<typename T>
static T* findOrEmitInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
UInt argCount,
IRValue* const* args)
@@ -415,7 +443,7 @@ namespace Slang
template<typename T>
static T* findOrEmitInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type)
{
return (T*) findOrEmitInstImpl(
@@ -430,7 +458,7 @@ namespace Slang
template<typename T>
static T* findOrEmitInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
IRInst* arg)
{
@@ -446,7 +474,7 @@ namespace Slang
template<typename T>
static T* findOrEmitInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
IRInst* arg1,
IRInst* arg2)
@@ -482,11 +510,11 @@ namespace Slang
}
static IRConstant* findOrEmitConstant(
- IRBuilder* builder,
- IROpInfo const* op,
- IRType* type,
- UInt valueSize,
- void const* value)
+ IRBuilder* builder,
+ IROp op,
+ IRType* type,
+ UInt valueSize,
+ void const* value)
{
// First, we need to pick a good insertion point
// for the instruction, which we do by looking
@@ -531,7 +559,7 @@ namespace Slang
//
- static IRType* getBaseTypeImpl(IRBuilder* builder, IROpInfo const* op)
+ static IRType* getBaseTypeImpl(IRBuilder* builder, IROp op)
{
auto inst = findOrEmitInst<IRType>(
builder,
@@ -544,10 +572,10 @@ namespace Slang
{
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);
+ case BaseType::Bool: return getBaseTypeImpl(this, kIROp_BoolType);
+ case BaseType::Float: return getBaseTypeImpl(this, kIROp_Float32Type);
+ case BaseType::Int: return getBaseTypeImpl(this, kIROp_Int32Type);
+ case BaseType::UInt: return getBaseTypeImpl(this, kIROp_UInt32Type);
default:
SLANG_UNEXPECTED("unhandled base type");
@@ -564,7 +592,7 @@ namespace Slang
{
return findOrEmitInst<IRVectorType>(
this,
- &kIROpInfo_VectorType,
+ kIROp_VectorType,
getTypeType(),
elementType,
elementCount);
@@ -574,7 +602,7 @@ namespace Slang
{
return findOrEmitInst<IRType>(
this,
- &kIROpInfo_TypeType,
+ kIROp_TypeType,
nullptr);
}
@@ -582,7 +610,7 @@ namespace Slang
{
return findOrEmitInst<IRType>(
this,
- &kIROpInfo_VoidType,
+ kIROp_VoidType,
getTypeType());
}
@@ -590,7 +618,7 @@ namespace Slang
{
return findOrEmitInst<IRType>(
this,
- &kIROpInfo_BlockType,
+ kIROp_BlockType,
getTypeType());
}
@@ -600,7 +628,7 @@ namespace Slang
{
auto inst = createInstWithTrailingArgs<IRStructType>(
this,
- &kIROpInfo_StructType,
+ kIROp_StructType,
getTypeType(),
fieldCount,
(IRValue* const*)fieldTypes);
@@ -608,6 +636,23 @@ namespace Slang
return inst;
}
+ IRType* IRBuilder::getFuncType(
+ UInt paramCount,
+ IRType* const* paramTypes,
+ IRType* resultType)
+ {
+ auto inst = createInstWithTrailingArgs<IRFuncType>(
+ this,
+ kIROp_FuncType,
+ getTypeType(),
+ 1,
+ (IRValue* const*) &resultType,
+ paramCount,
+ (IRValue* const*) paramTypes);
+ addInst(inst);
+ return inst;
+ }
+
IRValue* IRBuilder::getBoolValue(bool value)
{
SLANG_UNIMPLEMENTED_X("IR");
@@ -617,7 +662,7 @@ namespace Slang
{
return findOrEmitConstant(
this,
- &kIROpInfo_IntLit,
+ kIROp_IntLit,
type,
sizeof(value),
&value);
@@ -627,7 +672,7 @@ namespace Slang
{
return findOrEmitConstant(
this,
- &kIROpInfo_FloatLit,
+ kIROp_FloatLit,
type,
sizeof(value),
&value);
@@ -641,7 +686,7 @@ namespace Slang
{
auto inst = createInstWithTrailingArgs<IRInst>(
this,
- kIRIntrinsicOpInfos[(int)intrinsicOp],
+ kIRIntrinsicOps[(int)intrinsicOp],
type,
argCount,
args);
@@ -656,7 +701,7 @@ namespace Slang
{
auto inst = createInstWithTrailingArgs<IRInst>(
this,
- &kIROpInfo_Construct,
+ kIROp_Construct,
type,
argCount,
args);
@@ -668,7 +713,7 @@ namespace Slang
{
return createInst<IRModule>(
this,
- &kIROpInfo_Module,
+ kIROp_Module,
nullptr);
}
@@ -677,7 +722,7 @@ namespace Slang
{
return createInst<IRFunc>(
this,
- &kIROpInfo_Func,
+ kIROp_Func,
nullptr);
}
@@ -685,7 +730,7 @@ namespace Slang
{
return createInst<IRBlock>(
this,
- &kIROpInfo_Block,
+ kIROp_Block,
getBlockType());
}
@@ -701,7 +746,7 @@ namespace Slang
{
auto inst = createInst<IRParam>(
this,
- &kIROpInfo_Param,
+ kIROp_Param,
type);
addInst(inst);
return inst;
@@ -714,7 +759,7 @@ namespace Slang
{
auto inst = createInst<IRFieldExtract>(
this,
- &kIROpInfo_FieldExtract,
+ kIROp_FieldExtract,
type,
base);
@@ -729,7 +774,7 @@ namespace Slang
{
auto inst = createInst<IRReturnVal>(
this,
- &kIROpInfo_ReturnVal,
+ kIROp_ReturnVal,
getVoidType(),
val);
addInst(inst);
@@ -740,7 +785,7 @@ namespace Slang
{
auto inst = createInst<IRReturnVoid>(
this,
- &kIROpInfo_ReturnVoid,
+ kIROp_ReturnVoid,
getVoidType());
addInst(inst);
return inst;
@@ -803,6 +848,7 @@ namespace Slang
// TODO: need to display a name for the result...
auto op = inst->op;
+ auto opInfo = &kIROpInfos[op];
if (inst->id)
{
@@ -810,7 +856,7 @@ namespace Slang
dump(context, " = ");
}
- dump(context, op->name);
+ dump(context, opInfo->name);
// TODO: dump operands
uint32_t argCount = inst->argCount;
@@ -832,7 +878,7 @@ namespace Slang
dump(context, "\n");
- if (op->flags & kIROpFlag_Parent)
+ if (opInfo->flags & kIROpFlag_Parent)
{
dumpIndent(context);
dump(context, "{\n");
diff --git a/source/slang/ir.h b/source/slang/ir.h
index 0a0c8d612..e583997fd 100644
--- a/source/slang/ir.h
+++ b/source/slang/ir.h
@@ -27,6 +27,15 @@ enum : IROpFlags
kIROpFlag_Parent = 1 << 0,
};
+enum IROp : uint16_t
+{
+
+#define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) \
+ kIROp_##ID,
+
+#include "ir-inst-defs.h"
+};
+
// A logical operation/opcode in the IR
struct IROpInfo
{
@@ -67,7 +76,7 @@ typedef uint32_t IRInstID;
struct IRInst
{
// The operation that this value represents
- IROpInfo const* op;
+ IROp op;
// A unique ID to represent the op when printing
// (or zero to indicate that the value of this
@@ -93,7 +102,19 @@ struct IRInst
// The type of this value
IRUse type;
+ IRType* getType() { return (IRType*) type.usedValue; }
+
+ UInt getArgCount()
+ {
+ return argCount;
+ }
+
IRUse* getArgs();
+
+ IRInst* getArg(UInt index)
+ {
+ return getArgs()[index].usedValue;
+ }
};
typedef IRInst IRValue;
@@ -127,15 +148,40 @@ struct IRVectorType : IRType
{
IRUse elementType;
IRUse elementCount;
+
+ IRType* getElementType() { return (IRType*) elementType.usedValue; }
+ IRInst* getElementCount() { return elementCount.usedValue; }
};
struct IRStructType : IRType
-{};
+{
+
+ UInt getFieldCount() { return getArgCount() - 1; }
+ IRType* getFieldType(UInt index) { return (IRType*) getArg(index + 1); }
+};
+
+struct IRFuncType : IRType
+{
+ IRUse resultType;
+ // parameter tyeps are varargs...
+
+ IRType* getResultType() { return (IRType*) resultType.usedValue; }
+ UInt getParamCount()
+ {
+ return getArgCount() - 2;
+ }
+ IRType* getParamType(UInt index)
+ {
+ return (IRType*) getArg(2 + index);
+ }
+};
struct IRFieldExtract : IRInst
{
IRUse base;
UInt fieldIndex;
+
+ IRInst* getBase() { return base.usedValue; }
};
// A instruction that ends a basic block (usually because of control flow)
@@ -148,6 +194,8 @@ struct IRReturn : IRTerminatorInst
struct IRReturnVal : IRReturn
{
IRUse val;
+
+ IRInst* getVal() { return val.usedValue; }
};
struct IRReturnVoid : IRReturn
@@ -174,14 +222,16 @@ struct IRBlock : IRParentInst
// Note that in a valid program, every block must end with
// a "terminator" instruction, so these should be non-NULL,
// and `last` should actually be an `IRTerminatorInst`.
- IRInst* firstChild;
- IRInst* lastChild;
+
+ IRBlock* getPrevBlock() { return (IRBlock*) prevInst; }
+ IRBlock* getNextBlock() { return (IRBlock*) nextInst; }
};
// A function parameter is represented by an instruction
// in the entry block of a function.
struct IRParam : IRInst
{
+ IRParam* getNextParam();
};
// A function is a parent to zero or more blocks of instructions.
@@ -190,6 +240,16 @@ struct IRParam : IRInst
// an instruction (e.g., a call).
struct IRFunc : IRParentInst
{
+ IRFuncType* getType() { return (IRFuncType*) type.usedValue; }
+
+ IRType* getResultType() { return getType()->getResultType(); }
+ UInt getParamCount() { return getType()->getParamCount(); }
+ IRType* getParamType(UInt index) { return getType()->getParamType(index); }
+
+ IRBlock* getFirstBlock() { return (IRBlock*) firstChild; }
+ IRBlock* getLastBlock() { return (IRBlock*) lastChild; }
+
+ IRParam* getFirstParam();
};
// A module is a parent to functions, global variables, types, etc.
@@ -252,6 +312,11 @@ struct IRBuilder
UInt fieldCount,
IRType* const* fieldTypes);
+ IRType* getFuncType(
+ UInt paramCount,
+ IRType* const* paramTypes,
+ IRType* resultType);
+
IRValue* getBoolValue(bool value);
IRValue* getIntValue(IRType* type, IRIntegerValue value);
IRValue* getFloatValue(IRType* type, IRFloatingPointValue value);
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index a01279f2e..ed8ed3318 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -608,9 +608,13 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// set up sub context for generating our new function
+ List<IRType*> paramTypes;
+
for( auto paramDecl : decl->GetParameters() )
{
IRType* irParamType = lowerSimpleType(context, paramDecl->getType());
+ paramTypes.Add(irParamType);
+
IRParam* irParam = subBuilder->emitParam(irParamType);
DeclRef<ParamDecl> paramDeclRef = makeDeclRef(paramDecl.Ptr());
@@ -620,8 +624,13 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
subContext->shared->declValues.Add(paramDeclRef, irParamVal);
}
- auto irResultType = lowerType(context, decl->ReturnType);
+ auto irResultType = lowerSimpleType(context, decl->ReturnType);
+ auto irFuncType = getBuilder()->getFuncType(
+ paramTypes.Count(),
+ &paramTypes[0],
+ irResultType);
+ irFunc->type.init(irFunc, irFuncType);
lowerStmt(subContext, decl->Body);
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index 94a6004e0..c8a564f2c 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -172,6 +172,7 @@
<ClInclude Include="emit.h" />
<ClInclude Include="expr-defs.h" />
<ClInclude Include="intrinsic-defs.h" />
+ <ClInclude Include="ir-inst-defs.h" />
<ClInclude Include="ir.h" />
<ClInclude Include="lexer.h" />
<ClInclude Include="lookup.h" />
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index 14358e42e..d8fdf1fc1 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -39,6 +39,7 @@
<ClInclude Include="name.h" />
<ClInclude Include="ir.h" />
<ClInclude Include="lower-to-ir.h" />
+ <ClInclude Include="ir-inst-defs.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="check.cpp" />