diff options
| author | Tim Foley <tim.foley.is@gmail.com> | 2017-08-17 15:22:24 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-08-17 15:22:24 -0700 |
| commit | 7e05e062a0b7c39dbce6e850227d2038aca2f38e (patch) | |
| tree | 53a6a509f3bba87d964ba3a5007b538db1d83a4e /source | |
| parent | 1965c3f3f265c43c8d1d96bb49d0850ce5d53cc3 (diff) | |
| parent | ec8175c1f0afe3f7758f70da240aba03a791c3a9 (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.cpp | 343 | ||||
| -rw-r--r-- | source/slang/ir-inst-defs.h | 42 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 288 | ||||
| -rw-r--r-- | source/slang/ir.h | 153 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 62 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj | 1 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj.filters | 1 |
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(), + ¶mTypes[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" /> |
