summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/check.cpp32
-rw-r--r--source/slang/emit.cpp72
-rw-r--r--source/slang/expr-defs.h5
-rw-r--r--source/slang/hlsl.meta.slang21
-rw-r--r--source/slang/hlsl.meta.slang.cpp22
-rw-r--r--source/slang/ir-inst-defs.h4
-rw-r--r--source/slang/ir.cpp16
-rw-r--r--source/slang/ir.h17
-rw-r--r--source/slang/lower-to-ir.cpp570
-rw-r--r--source/slang/lower.cpp23
-rw-r--r--source/slang/parser.cpp4
11 files changed, 678 insertions, 108 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index ce9b2de55..e22db4186 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -146,13 +146,26 @@ namespace Slang
{
if (baseExpr)
{
- auto expr = new MemberExpr();
- expr->loc = loc;
- expr->BaseExpression = baseExpr;
- expr->name = declRef.GetName();
- expr->type = GetTypeForDeclRef(declRef);
- expr->declRef = declRef;
- return expr;
+ if (baseExpr->type->As<TypeType>())
+ {
+ auto expr = new StaticMemberExpr();
+ expr->loc = loc;
+ expr->BaseExpression = baseExpr;
+ expr->name = declRef.GetName();
+ expr->type = GetTypeForDeclRef(declRef);
+ expr->declRef = declRef;
+ return expr;
+ }
+ else
+ {
+ auto expr = new MemberExpr();
+ expr->loc = loc;
+ expr->BaseExpression = baseExpr;
+ expr->name = declRef.GetName();
+ expr->type = GetTypeForDeclRef(declRef);
+ expr->declRef = declRef;
+ return expr;
+ }
}
else
{
@@ -4978,6 +4991,11 @@ namespace Slang
}
}
+ RefPtr<Expr> visitStaticMemberExpr(StaticMemberExpr* expr)
+ {
+ SLANG_UNEXPECTED("should not occur in unchecked AST");
+ return expr;
+ }
RefPtr<Expr> visitMemberExpr(MemberExpr * expr)
{
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index a0cf8eb19..f6c63dff6 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -2274,6 +2274,44 @@ struct EmitVisitor
if(needClose) Emit(")");
}
+ void visitStaticMemberExpr(StaticMemberExpr* memberExpr, ExprEmitArg const& arg)
+ {
+ auto prec = kEOp_Postfix;
+ auto outerPrec = arg.outerPrec;
+ bool needClose = MaybeEmitParens(outerPrec, prec);
+
+ // TODO(tfoley): figure out a good way to reference
+ // declarations that might be generic and/or might
+ // not be generated as lexically nested declarations...
+
+ // TODO(tfoley): also, probably need to special case
+ // this for places where we are using a built-in...
+
+ auto base = memberExpr->BaseExpression;
+ if (IsBaseExpressionImplicit(base))
+ {
+ // don't emit the base expression
+ }
+ else
+ {
+ EmitExprWithPrecedence(memberExpr->BaseExpression, leftSide(outerPrec, prec));
+ Emit(".");
+ }
+
+ if (!memberExpr->declRef)
+ {
+ // This case arises when checking didn't find anything, but we were
+ // in "rewrite" mode so we blazed ahead anyway.
+ emitName(memberExpr->name);
+ }
+ else
+ {
+ emit(memberExpr->declRef.GetName());
+ }
+
+ if(needClose) Emit(")");
+ }
+
void visitMemberExpr(MemberExpr* memberExpr, ExprEmitArg const& arg)
{
auto prec = kEOp_Postfix;
@@ -4033,6 +4071,15 @@ emitDeclImpl(decl, nullptr);
}
break;
+ case kIROp_readWriteStructuredBufferType:
+ {
+ auto tt = (IRBufferType*) type;
+ emit("RWStructuredBuffer<");
+ emitIRType(context, tt->getElementType(), nullptr);
+ emit(">");
+ }
+ break;
+
case kIROp_SamplerType:
{
// TODO: actually look at the flavor and emit the right name
@@ -4308,6 +4355,13 @@ emitDeclImpl(decl, nullptr);
emitIROperand(context, inst->getArg(1));
break;
+ case kIROp_Store:
+ // TODO: this logic will really only work for a simple variable reference...
+ emitIROperand(context, inst->getArg(1));
+ emit(" = ");
+ emitIROperand(context, inst->getArg(2));
+ break;
+
case kIROp_Call:
{
emitIROperand(context, inst->getArg(1));
@@ -4322,6 +4376,13 @@ emitDeclImpl(decl, nullptr);
}
break;
+ case kIROp_BufferLoad:
+ emitIROperand(context, inst->getArg(1));
+ emit("[");
+ emitIROperand(context, inst->getArg(2));
+ emit("]");
+ break;
+
default:
emit("/* uhandled */");
break;
@@ -4345,6 +4406,17 @@ emitDeclImpl(decl, nullptr);
emit(";\n");
break;
+ case kIROp_Var:
+ {
+ auto ptrType = inst->getType();
+ auto valType = ((IRPtrType*)ptrType)->getValueType();
+
+ auto name = getName(inst);
+ emitIRType(context, valType, name);
+ emit(";\n");
+ }
+ break;
+
case kIROp_Param:
// Don't emit parameters, since they are declared as part of the function.
break;
diff --git a/source/slang/expr-defs.h b/source/slang/expr-defs.h
index 5821bddc3..81e8d9275 100644
--- a/source/slang/expr-defs.h
+++ b/source/slang/expr-defs.h
@@ -90,6 +90,11 @@ SYNTAX_CLASS(MemberExpr, DeclRefExpr)
SYNTAX_FIELD(RefPtr<Expr>, BaseExpression)
END_SYNTAX_CLASS()
+// Member looked up on a type, rather than a value
+SYNTAX_CLASS(StaticMemberExpr, DeclRefExpr)
+ SYNTAX_FIELD(RefPtr<Expr>, BaseExpression)
+END_SYNTAX_CLASS()
+
SYNTAX_CLASS(SwizzleExpr, Expr)
SYNTAX_FIELD(RefPtr<Expr>, base)
FIELD(int, elementCount)
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 3b4b85b91..7c7d3fda0 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -38,7 +38,8 @@ __generic<T> __magic_type(HLSLStructuredBufferType) struct StructuredBuffer
__intrinsic_op T Load(int location);
__intrinsic_op T Load(int location, out uint status);
- __intrinsic_op __subscript(uint index) -> T;
+ __intrinsic_op(bufferLoad)
+ __subscript(uint index) -> T;
};
__generic<T> __magic_type(HLSLConsumeStructuredBufferType) struct ConsumeStructuredBuffer
@@ -173,7 +174,13 @@ __magic_type(HLSLRWByteAddressBufferType) struct RWByteAddressBuffer
uint4 value);
};
-__generic<T> __magic_type(HLSLRWStructuredBufferType) struct RWStructuredBuffer
+__generic<T>
+__magic_type(HLSLRWStructuredBufferType)
+__intrinsic_type(${{
+ // TODO: we really need a simple way to write an "expression splice"
+ sb << kIROp_readWriteStructuredBufferType;
+}})
+struct RWStructuredBuffer
{
__intrinsic_op uint DecrementCounter();
@@ -186,7 +193,15 @@ __generic<T> __magic_type(HLSLRWStructuredBufferType) struct RWStructuredBuffer
__intrinsic_op T Load(int location);
__intrinsic_op T Load(int location, out uint status);
- __intrinsic_op __subscript(uint index) -> T { get; set; }
+ __intrinsic_op
+ __subscript(uint index) -> T
+ {
+ __intrinsic_op(bufferLoad)
+ get;
+
+ __intrinsic_op(bufferStore)
+ set;
+ }
};
__generic<T> __magic_type(HLSLPointStreamType) struct PointStream
diff --git a/source/slang/hlsl.meta.slang.cpp b/source/slang/hlsl.meta.slang.cpp
index e9e2277e6..a3744f620 100644
--- a/source/slang/hlsl.meta.slang.cpp
+++ b/source/slang/hlsl.meta.slang.cpp
@@ -38,7 +38,8 @@ sb << "\n";
sb << " __intrinsic_op T Load(int location);\n";
sb << " __intrinsic_op T Load(int location, out uint status);\n";
sb << "\n";
-sb << " __intrinsic_op __subscript(uint index) -> T;\n";
+sb << " __intrinsic_op(bufferLoad)\n";
+sb << " __subscript(uint index) -> T;\n";
sb << "};\n";
sb << "\n";
sb << "__generic<T> __magic_type(HLSLConsumeStructuredBufferType) struct ConsumeStructuredBuffer\n";
@@ -173,7 +174,14 @@ sb << " uint address,\n";
sb << " uint4 value);\n";
sb << "};\n";
sb << "\n";
-sb << "__generic<T> __magic_type(HLSLRWStructuredBufferType) struct RWStructuredBuffer\n";
+sb << "__generic<T>\n";
+sb << "__magic_type(HLSLRWStructuredBufferType)\n";
+sb << "__intrinsic_type(";
+
+ // TODO: we really need a simple way to write an "expression splice"
+ sb << kIROp_readWriteStructuredBufferType;
+sb << ")\n";
+sb << "struct RWStructuredBuffer\n";
sb << "{\n";
sb << " __intrinsic_op uint DecrementCounter();\n";
sb << "\n";
@@ -186,7 +194,15 @@ sb << "\n";
sb << " __intrinsic_op T Load(int location);\n";
sb << " __intrinsic_op T Load(int location, out uint status);\n";
sb << "\n";
-sb << " __intrinsic_op __subscript(uint index) -> T { get; set; }\n";
+sb << "\t__intrinsic_op\n";
+sb << "\t__subscript(uint index) -> T\n";
+sb << "\t{\n";
+sb << "\t\t__intrinsic_op(bufferLoad)\n";
+sb << "\t\tget;\n";
+sb << "\n";
+sb << "\t\t__intrinsic_op(bufferStore)\n";
+sb << "\t\tset;\n";
+sb << "\t}\n";
sb << "};\n";
sb << "\n";
sb << "__generic<T> __magic_type(HLSLPointStreamType) struct PointStream\n";
diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h
index 15a082aba..0ed66064a 100644
--- a/source/slang/ir-inst-defs.h
+++ b/source/slang/ir-inst-defs.h
@@ -28,6 +28,7 @@ INST(TextureType, texture_type, 2, 0)
INST(SamplerType, sampler_type, 1, 0)
INST(ConstantBufferType, constant_buffer_type, 1, 0)
INST(TextureBufferType, texture_buffer_type, 1, 0)
+INST(readWriteStructuredBufferType, readWriteStructuredBufferType, 1, 0)
INST(IntLit, integer_constant, 0, 0)
INST(FloatLit, float_constant, 0, 0)
@@ -46,6 +47,9 @@ INST(Var, var, 0, 0)
INST(Load, load, 1, 0)
INST(Store, store, 2, 0)
+INST(BufferLoad, bufferLoad, 2, 0)
+INST(BufferStore, bufferStore, 3, 0)
+
INST(FieldExtract, get_field, 2, 0)
INST(FieldAddress, get_field_addr, 2, 0)
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index eadcd34d0..9e39579f6 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -883,6 +883,22 @@ namespace Slang
return inst;
}
+ IRInst* IRBuilder::emitStore(
+ IRValue* dstPtr,
+ IRValue* srcVal)
+ {
+ auto type = getVoidType();
+ auto inst = createInst<IRStore>(
+ this,
+ kIROp_Store,
+ type,
+ dstPtr,
+ srcVal);
+
+ addInst(inst);
+ return inst;
+ }
+
IRInst* IRBuilder::emitFieldExtract(
IRType* type,
IRValue* base,
diff --git a/source/slang/ir.h b/source/slang/ir.h
index 51755f89f..1561d15a7 100644
--- a/source/slang/ir.h
+++ b/source/slang/ir.h
@@ -307,6 +307,13 @@ struct IRTextureType : IRType
IRType* getElementType() { return (IRType*) elementType.usedValue; }
};
+struct IRBufferType : IRType
+{
+ IRUse elementType;
+ IRType* getElementType() { return (IRType*) elementType.usedValue; }
+};
+
+
struct IRUniformBufferType : IRType
{
IRUse elementType;
@@ -326,6 +333,12 @@ struct IRLoad : IRInst
IRUse ptr;
};
+struct IRStore : IRInst
+{
+ IRUse ptr;
+ IRUse val;
+};
+
struct IRStructField;
struct IRFieldExtract : IRInst
{
@@ -541,6 +554,10 @@ struct IRBuilder
IRInst* emitLoad(
IRValue* ptr);
+ IRInst* emitStore(
+ IRValue* dstPtr,
+ IRValue* srcVal);
+
IRInst* emitFieldExtract(
IRType* type,
IRValue* base,
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index a8acadb59..4bdfa4438 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -8,6 +8,20 @@
namespace Slang
{
+struct BoundMemberInfo;
+
+struct SubscriptInfo : RefObject
+{
+ DeclRef<SubscriptDecl> declRef;
+};
+
+struct BoundSubscriptInfo : RefObject
+{
+ DeclRef<SubscriptDecl> declRef;
+ IRType* type;
+ List<IRValue*> args;
+};
+
struct LoweredValInfo
{
enum class Flavor
@@ -15,11 +29,17 @@ struct LoweredValInfo
None,
Simple,
Ptr,
+ BoundMember,
+ Subscript,
+ BoundSubscript,
};
union
{
- IRValue* val;
+ IRValue* val;
+ BoundMemberInfo* boundMemberInfo;
+ SubscriptInfo* subscriptInfo;
+ BoundSubscriptInfo* boundSubscriptInfo;
};
Flavor flavor;
@@ -43,7 +63,57 @@ struct LoweredValInfo
info.flavor = Flavor::Ptr;
info.val = v;
return info;
- }};
+ }
+
+ static LoweredValInfo boundMember(
+ LoweredValInfo const& base,
+ LoweredValInfo const& member);
+
+ static LoweredValInfo subscript(
+ SubscriptInfo* subscriptInfo);
+
+ static LoweredValInfo boundSubscript(
+ BoundSubscriptInfo* boundSubscriptInfo);
+};
+
+struct BoundMemberInfo
+{
+ LoweredValInfo base;
+ LoweredValInfo member;
+};
+
+LoweredValInfo LoweredValInfo::boundMember(
+ LoweredValInfo const& base,
+ LoweredValInfo const& member)
+{
+ BoundMemberInfo* boundMember = new BoundMemberInfo();
+ boundMember->base = base;
+ boundMember->member = member;
+
+ LoweredValInfo info;
+ info.flavor = Flavor::BoundMember;
+ info.boundMemberInfo = boundMember;
+ return info;
+}
+
+LoweredValInfo LoweredValInfo::subscript(
+ SubscriptInfo* subscriptInfo)
+{
+ LoweredValInfo info;
+ info.flavor = Flavor::Subscript;
+ info.subscriptInfo = subscriptInfo;
+ return info;
+}
+
+LoweredValInfo LoweredValInfo::boundSubscript(
+ BoundSubscriptInfo* boundSubscriptInfo)
+{
+ LoweredValInfo info;
+ info.flavor = Flavor::BoundSubscript;
+ info.boundSubscriptInfo = boundSubscriptInfo;
+ return info;
+}
+
struct SharedIRGenContext
{
@@ -52,6 +122,9 @@ struct SharedIRGenContext
CodeGenTarget target;
Dictionary<DeclRef<Decl>, LoweredValInfo> declValues;
+
+ // Arrays we keep around strictly for memory-management purposes
+ List<RefPtr<BoundSubscriptInfo>> boundSubscripts;
};
@@ -62,24 +135,149 @@ struct IRGenContext
IRBuilder* irBuilder;
};
-IRValue* getSimpleVal(LoweredValInfo lowered)
+LoweredValInfo ensureDecl(
+ IRGenContext* context,
+ DeclRef<Decl> const& declRef);
+
+
+IRValue* getSimpleVal(IRGenContext* context, LoweredValInfo lowered);
+
+IROp getIntrinsicOp(
+ Decl* decl,
+ IntrinsicOpModifier* intrinsicOpMod)
{
- switch(lowered.flavor)
- {
- case LoweredValInfo::Flavor::None:
- return nullptr;
+ if (int(intrinsicOpMod->op) != 0)
+ return intrinsicOpMod->op;
- case LoweredValInfo::Flavor::Simple:
- return lowered.val;
+ // No specified modifier? Then we need to look it up
+ // based on the name of the declaration...
+
+ auto name = decl->getName();
+ auto nameText = getText(name);
+
+ IROp op = findIROp(nameText.Buffer());
+ assert(op != kIROp_Invalid);
+ return op;
+}
+// Given a `LoweredValInfo` for something callable, along with a
+// bunch of arguments, emit an appropriate call to it.
+LoweredValInfo emitCallToVal(
+ IRGenContext* context,
+ IRType* type,
+ LoweredValInfo funcVal,
+ UInt argCount,
+ IRValue* const* args)
+{
+ auto builder = context->irBuilder;
+ switch (funcVal.flavor)
+ {
default:
- SLANG_UNEXPECTED("unhandled value flavor");
- return nullptr;
+ return LoweredValInfo::simple(
+ builder->emitCallInst(type, getSimpleVal(context, funcVal), argCount, args));
+ }
+}
+
+// Given a `DeclRef` for something callable, along with a bunch of
+// arguments, emit an appropriate call to it.
+LoweredValInfo emitCallToDeclRef(
+ IRGenContext* context,
+ IRType* type,
+ DeclRef<Decl> funcDeclRef,
+ UInt argCount,
+ IRValue* const* args)
+{
+ auto builder = context->irBuilder;
+
+
+ if (auto subscriptDeclRef = funcDeclRef.As<SubscriptDecl>())
+ {
+ // A reference to a subscript declaration is potentially a
+ // special case, if we have more than just a getter.
+
+ DeclRef<GetterDecl> getterDeclRef;
+ bool justAGetter = true;
+ for (auto accessorDeclRef : getMembersOfType<AccessorDecl>(subscriptDeclRef))
+ {
+ if (auto foundGetterDeclRef = accessorDeclRef.As<GetterDecl>())
+ {
+ getterDeclRef = foundGetterDeclRef;
+ }
+ else
+ {
+ justAGetter = false;
+ break;
+ }
+ }
+
+ if (!justAGetter)
+ {
+ // We can't perform an actual call right now, because
+ // this expression might appear in an r-value or l-value
+ // position (or *both* if it is being passed as an argument
+ // for an `in out` parameter!).
+ //
+ // Instead, we will construct a special-case value to
+ // represent the latent subscript operation (abstractly
+ // this is a reference to a storage location).
+
+ // The abstract storage location will need to include
+ // all the arguments being passed to the subscript operation.
+
+ RefPtr<BoundSubscriptInfo> boundSubscript = new BoundSubscriptInfo();
+ boundSubscript->declRef = subscriptDeclRef;
+ boundSubscript->type = type;
+ boundSubscript->args.AddRange(args, argCount);
+
+ context->shared->boundSubscripts.Add(boundSubscript);
+
+ return LoweredValInfo::boundSubscript(boundSubscript);
+ }
+
+ // Otherwise we are just call the getter, and so that
+ // is what we need to be emitting a call to...
+ if (getterDeclRef)
+ funcDeclRef = getterDeclRef;
+ }
+
+ auto funcDecl = funcDeclRef.getDecl();
+ if(auto intrinsicOpModifier = funcDecl->FindModifier<IntrinsicOpModifier>())
+ {
+ auto op = getIntrinsicOp(funcDecl, intrinsicOpModifier);
+
+ return LoweredValInfo::simple(builder->emitIntrinsicInst(
+ type,
+ op,
+ argCount,
+ args));
}
+ // TODO: handle target intrinsic modifier too...
+
+ if( auto ctorDeclRef = funcDeclRef.As<ConstructorDecl>() )
+ {
+ // HACK: we know all constructors are builtins for now,
+ // so we need to emit them as a call to the corresponding
+ // builtin operation.
+ return LoweredValInfo::simple(builder->emitConstructorInst(type, argCount, args));
+ }
+
+ // Fallback case is to emit an actual call.
+ LoweredValInfo funcVal = ensureDecl(context, funcDeclRef);
+ return emitCallToVal(context, type, funcVal, argCount, args);
+}
+
+LoweredValInfo emitCallToDeclRef(
+ IRGenContext* context,
+ IRType* type,
+ DeclRef<Decl> funcDeclRef,
+ List<IRValue*> const& args)
+{
+ return emitCallToDeclRef(context, type, funcDeclRef, args.Count(), args.Buffer());
}
IRValue* getSimpleVal(IRGenContext* context, LoweredValInfo lowered)
{
+top:
switch(lowered.flavor)
{
case LoweredValInfo::Flavor::None:
@@ -91,6 +289,26 @@ IRValue* getSimpleVal(IRGenContext* context, LoweredValInfo lowered)
case LoweredValInfo::Flavor::Ptr:
return context->irBuilder->emitLoad(lowered.val);
+ case LoweredValInfo::Flavor::BoundSubscript:
+ {
+ auto boundSubscriptInfo = lowered.boundSubscriptInfo;
+ auto builder = context->irBuilder;
+
+ for (auto getter : getMembersOfType<GetterDecl>(boundSubscriptInfo->declRef))
+ {
+ lowered = emitCallToDeclRef(
+ context,
+ boundSubscriptInfo->type,
+ getter,
+ boundSubscriptInfo->args);
+ goto top;
+ }
+
+ SLANG_UNEXPECTED("subscript had no getter");
+ return nullptr;
+ }
+ break;
+
default:
SLANG_UNEXPECTED("unhandled value flavor");
return nullptr;
@@ -148,7 +366,7 @@ IRValue* lowerSimpleVal(
Val* val)
{
auto lowered = lowerVal(context, val);
- return getSimpleVal(lowered);
+ return getSimpleVal(context, lowered);
}
LoweredTypeInfo lowerType(
@@ -184,13 +402,19 @@ LoweredValInfo lowerExpr(
IRGenContext* context,
Expr* expr);
+void assign(
+ IRGenContext* context,
+ LoweredValInfo const& left,
+ LoweredValInfo const& right);
+
void lowerStmt(
IRGenContext* context,
Stmt* stmt);
-LoweredValInfo ensureDecl(
- IRGenContext* context,
- DeclRef<Decl> const& declRef);
+LoweredValInfo lowerDecl(
+ IRGenContext* context,
+ DeclBase* decl,
+ Layout* layout);
//
@@ -222,7 +446,15 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
LoweredTypeInfo visitFuncType(FuncType* type)
{
LoweredValInfo loweredFunc = ensureDecl(context, type->declRef);
- return getSimpleVal(loweredFunc)->getType();
+ auto loweredFuncVal = getSimpleVal(context, loweredFunc);
+
+ // HACK: deal with the case where the decl might not
+ // lower to anything, and so we don't have a type to
+ // work with.
+ if (!loweredFuncVal)
+ return LoweredTypeInfo();
+
+ return loweredFuncVal->getType();
}
void addGenericArgs(List<IRValue*>* ioArgs, DeclRefBase declRef)
@@ -232,7 +464,7 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
{
for(auto aa : subs->args)
{
- (*ioArgs).Add(getSimpleVal(lowerVal(context, aa)));
+ (*ioArgs).Add(getSimpleVal(context, lowerVal(context, aa)));
}
subs = subs->outer;
}
@@ -380,7 +612,25 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
}
}
- // Collect the lowered arguments for a call expression
+
+ // Add arguments that appeared directly in an argument list
+ // to the list of argument values for a call.
+ void addDirectCallArgs(
+ InvokeExpr* expr,
+ List<IRValue*>* ioArgs)
+ {
+ auto& irArgs = *ioArgs;
+
+ for( auto arg : expr->Arguments )
+ {
+ auto loweredArg = lowerExpr(context, arg);
+ addArgs(&irArgs, loweredArg);
+ }
+ }
+
+ // Try to add "all" the arguments for a call to the argument list,
+ // including implicit arguments that come from (e.g.,) a member
+ // expression used to form the call.
void addCallArgs(
InvokeExpr* expr,
List<IRValue*>* ioArgs)
@@ -398,11 +648,7 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
addArgs(&irArgs, loweredBase);
}
- for( auto arg : expr->Arguments )
- {
- auto loweredArg = lowerExpr(context, arg);
- addArgs(&irArgs, loweredArg);
- }
+ addDirectCallArgs(expr, ioArgs);
}
LoweredValInfo lowerIntrinsicCall(
@@ -418,77 +664,78 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
return LoweredValInfo::simple(getBuilder()->emitIntrinsicInst(type, intrinsicOp, argCount, &irArgs[0]));
}
- LoweredValInfo lowerSimpleCall(InvokeExpr* expr)
+ void addFuncBaseArgs(
+ LoweredValInfo funcVal,
+ List<IRValue*>* ioArgs)
{
- auto type = lowerSimpleType(context, expr->type);
-
- auto loweredFunc = lowerExpr(context, expr->FunctionExpr);
-
- List<IRValue*> irArgs;
- addCallArgs(expr, &irArgs);
- UInt argCount = irArgs.Count();
-
- return LoweredValInfo::simple(getBuilder()->emitCallInst(type, getSimpleVal(loweredFunc), argCount, irArgs.Buffer()));
+ switch (funcVal.flavor)
+ {
+ default:
+ return;
+ }
}
- IROp getIntrinsicOp(
- Decl* decl,
- IntrinsicOpModifier* intrinsicOpMod)
+ LoweredValInfo lowerSimpleCall(InvokeExpr* expr)
{
- if (int(intrinsicOpMod->op) != 0)
- return intrinsicOpMod->op;
- // No specified modifier? Then we need to look it up
- // based on the name of the declaration...
-
- auto name = decl->getName();
- auto nameText = getText(name);
-
- IROp op = findIROp(nameText.Buffer());
- assert(op != kIROp_Invalid);
- return op;
}
LoweredValInfo visitInvokeExpr(InvokeExpr* expr)
{
- // TODO: need to detect calls to builtins here, so that we can expand
- // them as their own special opcodes...
+ auto type = lowerSimpleType(context, expr->type);
- auto funcExpr = expr->FunctionExpr;
- if( auto funcDeclRefExpr = funcExpr.As<DeclRefExpr>() )
- {
- auto funcDeclRef = funcDeclRefExpr->declRef;
- auto funcDecl = funcDeclRef.getDecl();
- if(auto intrinsicOpModifier = funcDecl->FindModifier<IntrinsicOpModifier>())
- {
- auto op = getIntrinsicOp(funcDecl, intrinsicOpModifier);
- return lowerIntrinsicCall(expr, op);
- //
- }
- // TODO: handle target intrinsic modifier too...
+ // We are going to look at the syntactic form of
+ // the "function" expression, so that we can avoid
+ // a lot of complexity that would come from lowering
+ // it as a general expression first, and then trying
+ // to apply it. For example, given `obj.f(a,b)` we
+ // will try to detect that we are trying to compute
+ // something like `ObjType::f(obj, a, b)` (in pseudo-code),
+ // rather than trying to construct a meaningful
+ // intermediate value for `obj.f` first.
+ //
+ // Note that this doe not preclude having support
+ // for directly generating code from `obj.f` - it
+ // just may be that such usage is more complicated.
- if( auto ctorDeclRef = funcDeclRef.As<ConstructorDecl>() )
- {
- // HACK: we know all constructors are builtins for now,
- // so we need to emit them as a call to the corresponding
- // builtin operation.
+ // Along the way, we may end up collecting additional
+ // arguments that will be part of the call.
+ List<IRValue*> irArgs;
- auto type = lowerSimpleType(context, expr->type);
- List<IRValue*> irArgs;
- for( auto arg : expr->Arguments )
- {
- auto loweredArg = lowerExpr(context, arg);
- addArgs(&irArgs, loweredArg);
- }
+ auto funcExpr = expr->FunctionExpr;
+ if (auto memberFuncExpr = funcExpr.As<MemberExpr>())
+ {
+ auto loweredBaseVal = lowerExpr(context, memberFuncExpr->BaseExpression);
+ addArgs(&irArgs, loweredBaseVal);
- UInt argCount = irArgs.Count();
+ auto funcDeclRef = memberFuncExpr->declRef;
- return LoweredValInfo::simple(getBuilder()->emitConstructorInst(type, argCount, &irArgs[0]));
- }
+ addDirectCallArgs(expr, &irArgs);
+ return emitCallToDeclRef(context, type, funcDeclRef, irArgs);
+ }
+ else if (auto staticMemberFuncExpr = funcExpr.As<StaticMemberExpr>())
+ {
+ auto funcDeclRef = staticMemberFuncExpr->declRef;
+ addDirectCallArgs(expr, &irArgs);
+ return emitCallToDeclRef(context, type, funcDeclRef, irArgs);
}
+ else if (auto varExpr = funcExpr.As<VarExpr>())
+ {
+ auto funcDeclRef = varExpr->declRef;
+ addDirectCallArgs(expr, &irArgs);
+ return emitCallToDeclRef(context, type, funcDeclRef, irArgs);
+ }
+
+ // The default case is to assume that we just have
+ // an ordinary expression, and can lower it as such.
+ LoweredValInfo funcVal = lowerExpr(context, expr->FunctionExpr);
+
+ // Now we add any direct arguments from the call expression itself.
+ addDirectCallArgs(expr, &irArgs);
- return lowerSimpleCall(expr);
+ // Delegate to the logic for invoking a value.
+ return emitCallToVal(context, type, funcVal, irArgs.Count(), irArgs.Buffer());
}
LoweredValInfo visitIndexExpr(IndexExpr* expr)
@@ -503,14 +750,14 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
{
switch (base.flavor)
{
- case LoweredValInfo::Flavor::Simple:
+ default:
{
- IRValue* irBase = base.val;
+ IRValue* irBase = getSimpleVal(context, base);
return LoweredValInfo::simple(
getBuilder()->emitFieldExtract(
getSimpleType(fieldType),
irBase,
- (IRStructField*) getSimpleVal(field)));
+ (IRStructField*) getSimpleVal(context, field)));
}
break;
@@ -524,14 +771,17 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
getBuilder()->emitFieldAddress(
getBuilder()->getPtrType(getSimpleType(fieldType)),
irBasePtr,
- (IRStructField*) getSimpleVal(field)));
+ (IRStructField*) getSimpleVal(context, field)));
}
break;
- default:
- SLANG_UNIMPLEMENTED_X("codegen for field extract");
}
}
+ LoweredValInfo visitStaticMemberExpr(StaticMemberExpr* expr)
+ {
+ return ensureDecl(context, expr->declRef);
+ }
+
LoweredValInfo visitMemberExpr(MemberExpr* expr)
{
auto loweredType = lowerType(context, expr->type);
@@ -545,6 +795,11 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
auto loweredField = ensureDecl(context, fieldDeclRef);
return extractField(loweredType, loweredBase, loweredField);
}
+ else if (auto callableDeclRef = declRef.As<CallableDecl>())
+ {
+ auto loweredFunc = ensureDecl(context, callableDeclRef);
+ return LoweredValInfo::boundMember(loweredBase, loweredFunc);
+ }
SLANG_UNIMPLEMENTED_X("codegen for subscript expression");
}
@@ -613,7 +868,20 @@ struct ExprLoweringVisitor : ExprVisitor<ExprLoweringVisitor, LoweredValInfo>
LoweredValInfo visitAssignExpr(AssignExpr* expr)
{
- SLANG_UNIMPLEMENTED_X("shared type expression during code generation");
+ // Because our representation of lowered "values"
+ // can encompass l-values explicitly, we can
+ // lower assignment easily. We just lower the left-
+ // and right-hand sides, and then peform an assignment
+ // based on the resulting values.
+ //
+ auto leftVal = lowerExpr(context, expr->left);
+ auto rightVal = lowerExpr(context, expr->right);
+ assign(context, leftVal, rightVal);
+
+ // The result value of the assignment expression is
+ // the value of the left-hand side (and it is expected
+ // to be an l-value).
+ return leftVal;
}
LoweredValInfo visitParenExpr(ParenExpr* expr)
@@ -642,18 +910,61 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor>
SLANG_UNIMPLEMENTED_X("stmt catch-all");
}
+ void visitExpressionStmt(ExpressionStmt* stmt)
+ {
+ // The statement evaluates an expression
+ // (for side effects, one assumes) and then
+ // discards the result. As such, we simply
+ // lower the expression, and don't use
+ // the result.
+ //
+ lowerExpr(context, stmt->Expression);
+ }
+
+ void visitDeclStmt(DeclStmt* stmt)
+ {
+ // For now, we lower a declaration directly
+ // into the current context.
+ //
+ // TODO: We may want to consider whether
+ // nested type/function declarations should
+ // be lowered into the global scope during
+ // IR generation, or whether they should
+ // be lifted later (pushing capture analysis
+ // down to the IR).
+ //
+ lowerDecl(context, stmt->decl, nullptr);
+ }
+
+ void visitSeqStmt(SeqStmt* stmt)
+ {
+ // To lower a sequence of statements,
+ // just lower each in order
+ for (auto ss : stmt->stmts)
+ {
+ lowerStmt(context, ss);
+ }
+ }
+
void visitBlockStmt(BlockStmt* stmt)
{
+ // To lower a block (scope) statement,
+ // just lower its body. The IR doesn't
+ // need to reflect the scoping of the AST.
lowerStmt(context, stmt->body);
}
void visitReturnStmt(ReturnStmt* stmt)
{
+ // A `return` statement turns into a return
+ // instruction. If the statement had an argument
+ // expression, then we need to lower that to
+ // a value first, and then emit the resulting value.
if( auto expr = stmt->Expression )
{
auto loweredExpr = lowerExpr(context, expr);
- getBuilder()->emitReturn(getSimpleVal(loweredExpr));
+ getBuilder()->emitReturn(getSimpleVal(context, loweredExpr));
}
else
{
@@ -676,7 +987,31 @@ void assign(
LoweredValInfo const& left,
LoweredValInfo const& right)
{
- SLANG_UNIMPLEMENTED_X("assignment");
+ switch (left.flavor)
+ {
+ case LoweredValInfo::Flavor::Ptr:
+ switch (right.flavor)
+ {
+ case LoweredValInfo::Flavor::Simple:
+ case LoweredValInfo::Flavor::Ptr:
+ {
+ auto builder = context->irBuilder;
+ builder->emitStore(
+ left.val,
+ getSimpleVal(context, right));
+ }
+ break;
+
+ default:
+ SLANG_UNIMPLEMENTED_X("assignment");
+ break;
+ }
+ break;
+
+ default:
+ SLANG_UNIMPLEMENTED_X("assignment");
+ break;
+ }
}
struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
@@ -704,6 +1039,30 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
SLANG_UNIMPLEMENTED_X("decl catch-all");
}
+ LoweredValInfo visitSubscriptDecl(SubscriptDecl* decl)
+ {
+ // A subscript operation may encompass one or more
+ // accessors, and these are what should actually
+ // get lowered (they are effectively functions).
+
+ for (auto accessor : decl->getMembersOfType<AccessorDecl>())
+ {
+ if (accessor->HasModifier<IntrinsicOpModifier>())
+ continue;
+
+ ensureDecl(context, makeDeclRef(accessor.Ptr()));
+ }
+
+ // The subscript declaration itself won't correspond
+ // to anything in the lowered program, so we don't
+ // bother creating a representation here.
+ //
+ // Note: We may want to have a specific lowered value
+ // that can represent the combination of callables
+ // that make up the subscript operation.
+ return LoweredValInfo();
+ }
+
LoweredValInfo visitVarDeclBase(VarDeclBase* decl)
{
// A user-defined variable declaration will usually turn into
@@ -818,9 +1177,22 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// set up sub context for generating our new function
+ CallableDecl* declForParameters = decl;
+ CallableDecl* declForReturnType = decl;
+ if (auto accessorDecl = dynamic_cast<AccessorDecl*>(decl))
+ {
+ auto parentDecl = accessorDecl->ParentDecl;
+ if (auto subscriptDecl = dynamic_cast<SubscriptDecl*>(parentDecl))
+ {
+ declForParameters = subscriptDecl;
+ declForReturnType = subscriptDecl;
+ }
+ }
+
+
List<IRType*> paramTypes;
- for( auto paramDecl : decl->GetParameters() )
+ for( auto paramDecl : declForParameters->GetParameters() )
{
IRType* irParamType = lowerSimpleType(context, paramDecl->getType());
paramTypes.Add(irParamType);
@@ -834,7 +1206,27 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
subContext->shared->declValues.Add(paramDeclRef, irParamVal);
}
- auto irResultType = lowerSimpleType(context, decl->ReturnType);
+ auto irResultType = lowerSimpleType(context, declForReturnType->ReturnType);
+
+ if (auto setterDecl = dynamic_cast<SetterDecl*>(decl))
+ {
+ // We are lowering a "setter" accessor inside a subscript
+ // declaration, which means we don't want to *return* the
+ // stated return type of the subscript, but instead take
+ // it as a parameter.
+ //
+ IRType* irParamType = irResultType;
+ paramTypes.Add(irParamType);
+ IRParam* irParam = subBuilder->emitParam(irParamType);
+
+ // TODO: we need some way to wire this up to the `newValue`
+ // or whatever name we give for that parameter inside
+ // the setter body.
+
+ // Instead, a setter always returns `void`
+ //
+ irResultType = getBuilder()->getVoidType();
+ }
auto irFuncType = getBuilder()->getFuncType(
paramTypes.Count(),
@@ -854,7 +1246,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
LoweredValInfo lowerDecl(
IRGenContext* context,
- Decl* decl,
+ DeclBase* decl,
Layout* layout)
{
DeclLoweringVisitor visitor;
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp
index f0d756a02..391221f47 100644
--- a/source/slang/lower.cpp
+++ b/source/slang/lower.cpp
@@ -1852,17 +1852,28 @@ struct LoweringVisitor
return &shared->compileRequest->mSink;
}
+ LoweredExpr visitStaticMemberExpr(
+ StaticMemberExpr* expr)
+ {
+ auto loweredBase = lowerExprOrTuple(expr->BaseExpression);
+ auto loweredDeclRef = translateDeclRef(expr->declRef);
+
+ // TODO: we should probably support type-type members here.
+
+ RefPtr<StaticMemberExpr> loweredExpr = new StaticMemberExpr();
+ lowerExprCommon(loweredExpr, expr);
+ loweredExpr->BaseExpression = loweredBase.getExpr();
+ loweredExpr->declRef = loweredDeclRef.As<Decl>();
+ loweredExpr->name = expr->name;
+
+ return LoweredExpr(loweredExpr);
+ }
+
LoweredExpr visitMemberExpr(
MemberExpr* expr)
{
assert(expr->BaseExpression);
auto loweredBase = lowerExprOrTuple(expr->BaseExpression);
-
- if( !loweredBase )
- {
- loweredBase = lowerExprOrTuple(expr->BaseExpression);
- }
-
assert(loweredBase);
auto loweredDeclRef = translateDeclRef(expr->declRef);
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index 8ea41641d..2381682aa 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -2121,6 +2121,8 @@ namespace Slang
static RefPtr<AccessorDecl> parseAccessorDecl(Parser* parser)
{
+ Modifiers modifiers = ParseModifiers(parser);
+
RefPtr<AccessorDecl> decl;
if( AdvanceIf(parser, "get") )
{
@@ -2136,6 +2138,8 @@ namespace Slang
return nullptr;
}
+ AddModifiers(decl, modifiers.first);
+
if( parser->tokenReader.PeekTokenType() == TokenType::LBrace )
{
decl->Body = parser->ParseBlockStatement();