diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2018-06-12 14:59:13 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-06-12 14:59:13 -0700 |
| commit | 167d8579870db18756c234755b197e4ded930b0e (patch) | |
| tree | 942f07efe9572699a62df80cadb136a1789780a6 /source/slang/lower-to-ir.cpp | |
| parent | 7852a2bf0ef5aad0f4f318507c300352c25199f2 (diff) | |
Initial support for enum declarations (#599)
Slang `enum` declarations will always be scoped, e.g.:
```hlsl
enum Color
{
Red,
Green = 2,
Blue,
}
Color c = Color.Red; // Not just `Red`
```
A user can write `enum class` as a placebo for now (to ease sharing of headers with C++).
Slang does not currently support the `::` operator for static member lookup, so it must be `Color.Green` and not `Color::Green`. Support for `::` as an alternate syntax could be added later if there is strong user demand.
An `enum` type can have a declared "tag type" using syntax like C++ `enum class`:
```hlsl
enum MyThings : uint
{
First = 0,
// ...
}
```
The `enum` cases will store their values using that type. An `enum` that doesn't declare a tag type will use the type `int` by default.
Enum cases are assigned values just like in C/C++: cases can have explicit values, but otherwise default to one more than the previous case, or zero for the first case.
All `enum` types will automatically conform to a standard-library `interface` called `__EnumType`, which is used so that basic operators like equality testing can be defined generically for all `enum` types.
This change only adds one operator at first (the `==` comparison), but other should be added later.
An `enum` case needs to be explicitly converted to an integer where needed (e.g., `int(Color.Red)`).
This is implemented by having the main integer types (`int` and `uint`) support built-in initializers that can work for *any* `enum` type (or rather, anything conforming to `__EnumType`).
Eventually these will be restricted so that an `enum` type can only be converted to its associated tag type.
IR code generation completely eliminates `enum` types and their cases.
The `enum` type will be replaced with its tag type, and the cases will be replaced with the tag values.
Currently this could leave some mess in the IR where cast operations are applied between values that actually have the same type.
Diffstat (limited to 'source/slang/lower-to-ir.cpp')
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 75 |
1 files changed, 68 insertions, 7 deletions
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 12ba94146..761fe9c91 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -2668,6 +2668,9 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> // so we need to track a bit of extra data: struct SwitchStmtInfo { + // The block that will be made to contain the `switch` statement + IRBlock* initialBlock = nullptr; + // The label for the `default` case, if any. IRBlock* defaultLabel = nullptr; @@ -2757,12 +2760,21 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> // for the best. // // TODO: figure out something cleaner. - auto caseVal = getSimpleVal(context, lowerRValueExpr(context, caseStmt->expr)); + + // Actually, one gotcha is that if we ever allow non-constant + // expressions here (or anything that requires instructions + // to be emitted to yield its value), then those instructions + // need to go into an appropriate block. + + IRGenContext subContext = *context; + IRBuilder subBuilder = *getBuilder(); + subBuilder.setInsertInto(info->initialBlock); + subContext.irBuilder = &subBuilder; + auto caseVal = getSimpleVal(context, lowerRValueExpr(&subContext, caseStmt->expr)); // Figure out where we are branching to. auto label = getLabelForCase(info); - // Add this `case` to the list for the enclosing `switch`. info->cases.Add(caseVal); info->cases.Add(label); @@ -2863,6 +2875,7 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> // Iterate over the body of the statement, looking // for `case` or `default` statements: SwitchStmtInfo info; + info.initialBlock = initialBlock; info.defaultLabel = nullptr; lowerSwitchCases(stmt->body, &info); @@ -3760,6 +3773,59 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> setMangledName(inst, context->getSession()->getNameObj(name)); } + LoweredValInfo visitEnumCaseDecl(EnumCaseDecl* decl) + { + // A case within an `enum` decl will lower to a value + // of the `enum`'s "tag" type. + // + // TODO: a bit more work will be needed if we allow for + // enum cases that have payloads, because then we need + // a function that constructs the value given arguments. + + IRBuilder subBuilderStorage = *getBuilder(); + IRBuilder* subBuilder = &subBuilderStorage; + + // Emit any generics that should wrap the actual type. + emitOuterGenerics(subBuilder, decl, decl); + + IRGenContext subContextStorage = *context; + IRGenContext* subContext = &subContextStorage; + subContext->irBuilder = subBuilder; + + return lowerRValueExpr(subContext, decl->initExpr); + } + + LoweredValInfo visitEnumDecl(EnumDecl* decl) + { + // Given a declaration of a type, we need to make sure + // to output "witness tables" for any interfaces this + // type has declared conformance to. + for( auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>() ) + { + ensureDecl(context, inheritanceDecl); + } + + IRBuilder subBuilderStorage = *getBuilder(); + IRBuilder* subBuilder = &subBuilderStorage; + emitOuterGenerics(subBuilder, decl, decl); + + IRGenContext subContextStorage = *context; + IRGenContext* subContext = &subContextStorage; + subContext->irBuilder = subBuilder; + + // An `enum` declaration will currently lower directly to its "tag" + // type, so that any references to the `enum` become referenes to + // the tag type instead. + // + // TODO: if we ever support `enum` types with payloads, we would + // need to make the `enum` lower to some kind of custom "tagged union" + // type. + + IRType* loweredTagType = lowerType(subContext, decl->tagType); + + return LoweredValInfo::simple(finishOuterGenerics(subBuilder, loweredTagType)); + } + LoweredValInfo visitAggTypeDecl(AggTypeDecl* decl) { // Don't generate an IR `struct` for intrinsic types @@ -3768,11 +3834,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return LoweredValInfo(); } - if(getMangledName(decl) == "_ST03int") - { - decl = decl; - } - // Given a declaration of a type, we need to make sure // to output "witness tables" for any interfaces this // type has declared conformance to. |
