summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTim Foley <tim.foley.is@gmail.com>2017-08-17 15:22:24 -0700
committerGitHub <noreply@github.com>2017-08-17 15:22:24 -0700
commit7e05e062a0b7c39dbce6e850227d2038aca2f38e (patch)
tree53a6a509f3bba87d964ba3a5007b538db1d83a4e /source
parent1965c3f3f265c43c8d1d96bb49d0850ce5d53cc3 (diff)
parentec8175c1f0afe3f7758f70da240aba03a791c3a9 (diff)
Merge pull request #170 from tfoleyNV/ir
Add some dummy logic to print IR to HLSL
Diffstat (limited to 'source')
-rw-r--r--source/slang/emit.cpp343
-rw-r--r--source/slang/ir-inst-defs.h42
-rw-r--r--source/slang/ir.cpp288
-rw-r--r--source/slang/ir.h153
-rw-r--r--source/slang/lower-to-ir.cpp62
-rw-r--r--source/slang/slang.vcxproj1
-rw-r--r--source/slang/slang.vcxproj.filters1
7 files changed, 746 insertions, 144 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index d9b2ffcd6..6440c63a3 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -3822,8 +3822,346 @@ emitDeclImpl(decl, nullptr);
SLANG_UNEXPECTED("unhandled declaration kind");
}
}
+
+ // IR-level emit logc
+
+ String getName(IRInst* inst)
+ {
+ if(auto decoration = inst->findDecoration<IRHighLevelDeclDecoration>())
+ {
+ return getText(decoration->decl->getName());
+ }
+
+ 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(".");
+ emit(getName(fieldExtract->getField()));
+ 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 emitIRSemantics(
+ EmitContext* context,
+ IRInst* inst)
+ {
+ auto decoration = inst->findDecoration<IRHighLevelDeclDecoration>();
+ if( decoration )
+ {
+ EmitSemantics(decoration->decl);
+ }
+ }
+
+ 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(")");
+
+
+ emitIRSemantics(context, func);
+
+ // 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,
+ IRStructDecl* structType)
+ {
+ emit("struct ");
+ emit(getName(structType));
+ emit("\n{\n");
+
+ for(auto ff = structType->getFirstField(); ff; ff = ff->getNextField())
+ {
+ auto fieldType = ff->getFieldType();
+ emitIRType(context, fieldType, getName(ff));
+
+ emitIRSemantics(context, ff);
+
+ 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, (IRStructDecl*) 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 +4286,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..d594d2755
--- /dev/null
+++ b/source/slang/ir-inst-defs.h
@@ -0,0 +1,42 @@
+// 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, PARENT)
+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(StructField, field, 0, 0)
+
+INST(FieldExtract, get_field, 2, 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..8e4f789ef 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"
};
@@ -78,6 +46,43 @@ namespace Slang
return &type;
}
+ IRDecoration* IRInst::findDecorationImpl(IRDecorationOp decorationOp)
+ {
+ for( auto dd = firstDecoration; dd; dd = dd->next )
+ {
+ if(dd->op == decorationOp)
+ return dd;
+ }
+ return nullptr;
+ }
+
+ //
+
+ 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
@@ -124,18 +129,18 @@ 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);
- 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 +148,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 +180,7 @@ namespace Slang
static IRValue* createInstImpl(
IRBuilder* builder,
UInt size,
- IROpInfo const* op,
+ IROp op,
UInt argCount,
IRValue* const* args)
{
@@ -181,7 +196,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 +213,7 @@ namespace Slang
template<typename T>
static T* createInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type)
{
return (T*)createInstImpl(
@@ -213,7 +228,7 @@ namespace Slang
template<typename T>
static T* createInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
IRValue* arg)
{
@@ -229,7 +244,7 @@ namespace Slang
template<typename T>
static T* createInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
IRValue* arg1,
IRValue* arg2)
@@ -247,7 +262,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 +276,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 +363,7 @@ namespace Slang
static IRInst* findOrEmitInstImpl(
IRBuilder* builder,
UInt size,
- IROpInfo const* op,
+ IROp op,
IRType* type,
UInt argCount,
IRValue* const* args)
@@ -354,7 +390,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 +434,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 +451,7 @@ namespace Slang
template<typename T>
static T* findOrEmitInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type)
{
return (T*) findOrEmitInstImpl(
@@ -430,7 +466,7 @@ namespace Slang
template<typename T>
static T* findOrEmitInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
IRInst* arg)
{
@@ -446,7 +482,7 @@ namespace Slang
template<typename T>
static T* findOrEmitInst(
IRBuilder* builder,
- IROpInfo const* op,
+ IROp op,
IRType* type,
IRInst* arg1,
IRInst* arg2)
@@ -482,11 +518,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 +567,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 +580,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 +600,7 @@ namespace Slang
{
return findOrEmitInst<IRVectorType>(
this,
- &kIROpInfo_VectorType,
+ kIROp_VectorType,
getTypeType(),
elementType,
elementCount);
@@ -574,7 +610,7 @@ namespace Slang
{
return findOrEmitInst<IRType>(
this,
- &kIROpInfo_TypeType,
+ kIROp_TypeType,
nullptr);
}
@@ -582,7 +618,7 @@ namespace Slang
{
return findOrEmitInst<IRType>(
this,
- &kIROpInfo_VoidType,
+ kIROp_VoidType,
getTypeType());
}
@@ -590,20 +626,40 @@ namespace Slang
{
return findOrEmitInst<IRType>(
this,
- &kIROpInfo_BlockType,
+ kIROp_BlockType,
+ getTypeType());
+ }
+
+ IRStructDecl* IRBuilder::createStructType()
+ {
+ return createInst<IRStructDecl>(
+ this,
+ kIROp_StructType,
getTypeType());
}
- IRType* IRBuilder::getStructType(
- UInt fieldCount,
- IRType* const* fieldTypes)
+ IRStructField* IRBuilder::createStructField(IRType* fieldType)
{
- auto inst = createInstWithTrailingArgs<IRStructType>(
+ return createInst<IRStructField>(
this,
- &kIROpInfo_StructType,
+ kIROp_StructField,
+ fieldType);
+ }
+
+
+ IRType* IRBuilder::getFuncType(
+ UInt paramCount,
+ IRType* const* paramTypes,
+ IRType* resultType)
+ {
+ auto inst = createInstWithTrailingArgs<IRFuncType>(
+ this,
+ kIROp_FuncType,
getTypeType(),
- fieldCount,
- (IRValue* const*)fieldTypes);
+ 1,
+ (IRValue* const*) &resultType,
+ paramCount,
+ (IRValue* const*) paramTypes);
addInst(inst);
return inst;
}
@@ -617,7 +673,7 @@ namespace Slang
{
return findOrEmitConstant(
this,
- &kIROpInfo_IntLit,
+ kIROp_IntLit,
type,
sizeof(value),
&value);
@@ -627,7 +683,7 @@ namespace Slang
{
return findOrEmitConstant(
this,
- &kIROpInfo_FloatLit,
+ kIROp_FloatLit,
type,
sizeof(value),
&value);
@@ -641,7 +697,7 @@ namespace Slang
{
auto inst = createInstWithTrailingArgs<IRInst>(
this,
- kIRIntrinsicOpInfos[(int)intrinsicOp],
+ kIRIntrinsicOps[(int)intrinsicOp],
type,
argCount,
args);
@@ -656,7 +712,7 @@ namespace Slang
{
auto inst = createInstWithTrailingArgs<IRInst>(
this,
- &kIROpInfo_Construct,
+ kIROp_Construct,
type,
argCount,
args);
@@ -668,7 +724,7 @@ namespace Slang
{
return createInst<IRModule>(
this,
- &kIROpInfo_Module,
+ kIROp_Module,
nullptr);
}
@@ -677,7 +733,7 @@ namespace Slang
{
return createInst<IRFunc>(
this,
- &kIROpInfo_Func,
+ kIROp_Func,
nullptr);
}
@@ -685,7 +741,7 @@ namespace Slang
{
return createInst<IRBlock>(
this,
- &kIROpInfo_Block,
+ kIROp_Block,
getBlockType());
}
@@ -701,24 +757,23 @@ namespace Slang
{
auto inst = createInst<IRParam>(
this,
- &kIROpInfo_Param,
+ kIROp_Param,
type);
addInst(inst);
return inst;
}
IRInst* IRBuilder::emitFieldExtract(
- IRType* type,
- IRValue* base,
- UInt fieldIndex)
+ IRType* type,
+ IRValue* base,
+ IRStructField* field)
{
auto inst = createInst<IRFieldExtract>(
this,
- &kIROpInfo_FieldExtract,
+ kIROp_FieldExtract,
type,
- base);
-
- inst->fieldIndex = fieldIndex;
+ base,
+ field);
addInst(inst);
return inst;
@@ -729,7 +784,7 @@ namespace Slang
{
auto inst = createInst<IRReturnVal>(
this,
- &kIROpInfo_ReturnVal,
+ kIROp_ReturnVal,
getVoidType(),
val);
addInst(inst);
@@ -740,12 +795,38 @@ namespace Slang
{
auto inst = createInst<IRReturnVoid>(
this,
- &kIROpInfo_ReturnVoid,
+ kIROp_ReturnVoid,
getVoidType());
addInst(inst);
return inst;
}
+ IRDecoration* IRBuilder::addDecorationImpl(
+ IRInst* inst,
+ UInt decorationSize,
+ IRDecorationOp op)
+ {
+ auto decoration = (IRDecoration*) malloc(decorationSize);
+ memset(decoration, 0, decorationSize);
+
+ decoration->op = op;
+
+ decoration->next = inst->firstDecoration;
+ inst->firstDecoration = decoration;
+
+ return decoration;
+ }
+
+ IRHighLevelDeclDecoration* IRBuilder::addHighLevelDeclDecoration(IRInst* inst, Decl* decl)
+ {
+ auto decoration = addDecoration<IRHighLevelDeclDecoration>(inst, kIRDecorationOp_HighLevelDecl);
+ decoration->decl = decl;
+ return decoration;
+ }
+
+ //
+
+
struct IRDumpContext
{
FILE* file;
@@ -803,6 +884,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 +892,7 @@ namespace Slang
dump(context, " = ");
}
- dump(context, op->name);
+ dump(context, opInfo->name);
// TODO: dump operands
uint32_t argCount = inst->argCount;
@@ -832,7 +914,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..fcebf5d15 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
{
@@ -60,6 +69,22 @@ struct IRUse
void init(IRInst* user, IRInst* usedValue);
};
+enum IRDecorationOp : uint16_t
+{
+ kIRDecorationOp_HighLevelDecl,
+};
+
+// A "decoration" that gets applied to an instruction.
+// These usually don't affect semantics, but are useful
+// for preserving high-level source information.
+struct IRDecoration
+{
+ // Next decoration attached to the same instruction
+ IRDecoration* next;
+
+ IRDecorationOp op;
+};
+
typedef uint32_t IRInstID;
// In the IR, almost *everything* is an instruction,
@@ -67,7 +92,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
@@ -90,14 +115,52 @@ struct IRInst
// The first use of this value (start of a linked list)
IRUse* firstUse;
+ // The linked list of decorations attached to this instruction
+ IRDecoration* firstDecoration;
+
+ IRDecoration* findDecorationImpl(IRDecorationOp op);
+
+ template<typename T>
+ T* findDecoration()
+ {
+ return (T*) findDecorationImpl(IRDecorationOp(T::kDecorationOp));
+ }
+
+
// 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;
+ }
};
+// This type alias exists because I waffled on the name for a bit.
+// All existing uses of `IRValue` should move to `IRInst`
typedef IRInst IRValue;
+class Decl;
+
+// Associates an IR-level decoration with a source declaration
+// in the high-level AST, that can be used to extract
+// additional information that informs code emission.
+struct IRHighLevelDeclDecoration : IRDecoration
+{
+ enum { kDecorationOp = kIRDecorationOp_HighLevelDecl };
+
+ Decl* decl;
+};
+
typedef long long IRIntegerValue;
typedef double IRFloatingPointValue;
@@ -127,15 +190,35 @@ struct IRVectorType : IRType
{
IRUse elementType;
IRUse elementCount;
+
+ IRType* getElementType() { return (IRType*) elementType.usedValue; }
+ IRInst* getElementCount() { return elementCount.usedValue; }
};
-struct IRStructType : IRType
-{};
+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 IRStructField;
struct IRFieldExtract : IRInst
{
IRUse base;
- UInt fieldIndex;
+ IRUse field;
+
+ IRInst* getBase() { return base.usedValue; }
+ IRStructField* getField() { return (IRStructField*) field.usedValue; }
};
// A instruction that ends a basic block (usually because of control flow)
@@ -148,6 +231,8 @@ struct IRReturn : IRTerminatorInst
struct IRReturnVal : IRReturn
{
IRUse val;
+
+ IRInst* getVal() { return val.usedValue; }
};
struct IRReturnVoid : IRReturn
@@ -164,6 +249,20 @@ struct IRParentInst : IRInst
IRInst* lastChild;
};
+struct IRStructField : IRInst
+{
+ IRType* getFieldType() { return (IRType*) type.usedValue; }
+
+ IRStructField* getNextField() { return (IRStructField*) nextInst; }
+};
+
+struct IRStructDecl : IRParentInst
+{
+ IRStructField* getFirstField() { return (IRStructField*) firstChild; }
+ IRStructField* getLastField() { return (IRStructField*) lastChild; }
+};
+
+
// A basic block is a parent instruction that adds the constraint
// that all the children need to be "ordinary" instructions (so
// no function declarations, or nested blocks). We also expect
@@ -174,14 +273,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 +291,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.
@@ -248,9 +359,14 @@ struct IRBuilder
IRType* getTypeType();
IRType* getVoidType();
IRType* getBlockType();
- IRType* getStructType(
- UInt fieldCount,
- IRType* const* fieldTypes);
+
+ IRStructDecl* createStructType();
+ IRStructField* createStructField(IRType* fieldType);
+
+ IRType* getFuncType(
+ UInt paramCount,
+ IRType* const* paramTypes,
+ IRType* resultType);
IRValue* getBoolValue(bool value);
IRValue* getIntValue(IRType* type, IRIntegerValue value);
@@ -278,14 +394,27 @@ struct IRBuilder
IRType* type);
IRInst* emitFieldExtract(
- IRType* type,
- IRValue* base,
- UInt fieldIndex);
+ IRType* type,
+ IRValue* base,
+ IRStructField* field);
IRInst* emitReturn(
IRValue* val);
IRInst* emitReturn();
+
+ IRDecoration* addDecorationImpl(
+ IRInst* inst,
+ UInt decorationSize,
+ IRDecorationOp op);
+
+ template<typename T>
+ T* addDecoration(IRInst* inst, IRDecorationOp op)
+ {
+ return (T*) addDecorationImpl(inst, sizeof(T), op);
+ }
+
+ IRHighLevelDeclDecoration* addHighLevelDeclDecoration(IRInst* inst, Decl* decl);
};
void dumpIR(IRModule* module);
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index a01279f2e..781209dce 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -394,7 +394,7 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
LoweredValInfo extractField(
LoweredTypeInfo fieldType,
LoweredValInfo base,
- UInt fieldIndex)
+ LoweredValInfo field)
{
switch (base.flavor)
{
@@ -405,7 +405,7 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
getBuilder()->emitFieldExtract(
getSimpleType(fieldType),
irBase,
- fieldIndex));
+ (IRStructField*) getSimpleVal(field)));
}
break;
@@ -424,22 +424,8 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
{
// Okay, easy enough: we have a reference to a field of a struct type...
- // HACK: for now just scan the decl to find the right index.
- // TODO: we need to deal with the fact that the struct might get
- // tuple-ified.
- //
- UInt index = 0;
- for (auto fieldDecl : getMembersOfType<StructField>(fieldDeclRef.GetParent().As<AggTypeDecl>()))
- {
- if (fieldDecl == fieldDeclRef.getDecl())
- {
- break;
- }
-
- index++;
- }
-
- return extractField(loweredType, loweredBase, index);
+ auto loweredField = ensureDecl(context, fieldDeclRef);
+ return extractField(loweredType, loweredBase, loweredField);
}
SLANG_UNIMPLEMENTED_X("codegen for subscript expression");
@@ -559,20 +545,29 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// User-defined aggregate type: need to translate into
// a corresponding IR aggregate type.
- List<LoweredTypeInfo> fieldTypes;
- List<IRType*> irFieldTypes;
+ auto builder = getBuilder();
+ IRStructDecl* irStruct = builder->createStructType();
for (auto fieldDecl : decl->GetFields())
{
+ // TODO: need to track relationship to original fields...
+
// TODO: need to be prepared to deal with tuple-ness of fields here
auto fieldType = lowerType(context, fieldDecl->getType());
- fieldTypes.Add(fieldType);
-
switch (fieldType.flavor)
{
case LoweredTypeInfo::Flavor::Simple:
- irFieldTypes.Add(fieldType.type);
+ {
+ auto irField = builder->createStructField(getSimpleType(fieldType));
+ builder->addInst(irStruct, irField);
+
+ builder->addHighLevelDeclDecoration(irField, fieldDecl);
+
+ context->shared->declValues.Add(
+ DeclRef<StructField>(fieldDecl, nullptr),
+ LoweredValInfo::simple(irField));
+ }
break;
default:
@@ -580,13 +575,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
}
}
- // TODO: need to track relationship to original fields...
+ builder->addHighLevelDeclDecoration(irStruct, decl);
- IRType* irStructType = getBuilder()->getStructType(
- irFieldTypes.Count(),
- &irFieldTypes[0]);
+ builder->addInst(irStruct);
- return LoweredValInfo::simple(irStructType);
+ return LoweredValInfo::simple(irStruct);
}
LoweredValInfo visitFunctionDeclBase(FunctionDeclBase* decl)
@@ -608,9 +601,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,11 +617,18 @@ 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);
+ getBuilder()->addHighLevelDeclDecoration(irFunc, decl);
+
getBuilder()->addInst(irFunc);
return LoweredValInfo::simple(irFunc);
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" />