summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-union.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2019-10-22 14:53:21 -0700
committerGitHub <noreply@github.com>2019-10-22 14:53:21 -0700
commit6a7f4c9cef766e538a808a8f03411af2f10106e1 (patch)
tree98fc24c1c8c6ff77b86b35daab6505bbbaf69b0b /source/slang/slang-ir-union.cpp
parent365cd4d206f9a5f6e47843e005a18cf4de5bfdd5 (diff)
User IR-based layout for all IR steps (#1084)
This change builds on previous work that moves toward a more IR-based representation of layout. Those steps added some instructions for representing layout in the IR (initially just proxies for the AST layout objects), and an explicit lowering pass that could build a target-specific IR module that binds parameters and entry points to layout information. This change aims to complete that work, in the sense that the IR representation of layout is now self-contained and does not rely on having pointers back into the AST-level representation. Achieving this requires two main kinds of work: 1. Update any code that used layout information derived from the IR (most notably all the `slang-emit-*` code) to use the new IR representation and its accessors. 2. Update any code that *constructs* layouts using information derived from the IR to construct IR layouts instead. The biggest new infrastructure feature in this change is support for "attributes" in the IR (I'd welcome feedback on the naming). An attribute can either be thought of like key/value arguments that can be added to certain instructions to encode optional data, or alternatively like a decoration that is referenced as an operand instead of a child. The value of attributes over decorations is that they can affect the hash/identity of an instruction (which decorations can't), while the advantage of decorations is that they can easily be added/removed over the lifetime of an instruction (which attributes can't). We mostly use them here to represent operands that are logically optional. Once attributes are available, the encoding of layout information into the IR is mostly straightforward: * An `IRVarLayout` has a fixed operand for its type layout, and can accept a few different attributes * Zero or more `IRVarOffsetAttr`s that specify the offset of the variable for a given resource kind. These are equivalent to the `VarLayout::ResourceInfo`s at the AST level. * An optional `IRUserSemanticAttr` and `IRSystemValueSemanticAttr` to represent the (possibly derived) semantic of a varying input/output parameter. * An option `IRStageAttr` to represent the known stage for a parameter. * An `IREntryPointLayout` has a var layout for the entry point parameters (logically grouped in to a struct) and another var layout for the result parameter. * There is a small type hierarchy rooted at `IRTypeLayout` where each subtype can add fixed operands and attributes that are expected to appear. It also supports `IRTypeSizeAttr`s that serve a similar role to the `IRVarOffsetAttr`s. * Structure types maintain the mapping of fields to their var layouts using `IRStructFieldLayoutAttr`s. With the encoding in place, most of the changes in category (1) (code that just *uses* rather than *creates* layouts) was straightforward. The biggest different beyond name changes was that everything needs to be fetched using accessors instead of bare fields. It would have been possible to stage this commit and make the diffs smaller by first introducing mandatory acessors to the AST layout types. The changes in category (2) were more involved. There were a lot of places in the existing code where a `TypeLayout` or `VarLayout` would be created, and then initialized piecemeal over several lines of code (and sometimes even across functions). Because of the way that layouts need to support many optional properties, it did not seem practical to just have monolithic factory functions that took all the options as arguments, so I instead opted for a builder approach. The builders for `IRVarLayout` and `IREntryPointLayout` are both straightforward, and honestly there is no realy need for a builder for entry point layouts right now, but I was trying to future-proof in case we decidd to add some optional attributes to them. The builders for type layouts are more involved because of the inheritance hierarchy. Each concrete sub-type of type layout needs to define its own builder type that customizes the opcode, operands, and attributes of the final instruction. The refactoring that had to go into this change was a nice excuse to clean up a few ugly warts in the AST layout code that were largely there to support IR use cases. While this change adds a lot of new infrastructure code to the IR, most of the client code has stayed the same or gotten simpler. One annoying wart that remains with this change is the notion of an "offset element type layout" for parameter group types. That idea was added to deal with a legacy feature in the reflection API that we realized was a mistake, but unfortunately having that "offset" layout handy made writing a few other pieces of code simpler so that there are use cases of the feature even in the IR. Removing those uses is do-able, but requires careful refactoring so it is best left to a follow-on change. Another thing that could be considered for a follow-on change is how much information should be specified when constructing a `Builder` for an IR type layout, and how much should be allowed to be specified statefully/piecemeal. It would be nice to force all the required operands to be specified up front, but `IRParameterGroupTypeLayout::Builder` doesn't currently work that way because so much of the client code that needs it involved a lot of stateful setting and would need to be refactored heavily to provide the necessary information up front.
Diffstat (limited to 'source/slang/slang-ir-union.cpp')
-rw-r--r--source/slang/slang-ir-union.cpp32
1 files changed, 16 insertions, 16 deletions
diff --git a/source/slang/slang-ir-union.cpp b/source/slang/slang-ir-union.cpp
index d456cebee..0efca5602 100644
--- a/source/slang/slang-ir-union.cpp
+++ b/source/slang/slang-ir-union.cpp
@@ -101,7 +101,7 @@ struct DesugarUnionTypesContext
// unions in the generated IR have an associated (target-specific)
// layout.
//
- TaggedUnionTypeLayout* taggedUnionTypeLayout;
+ IRTaggedUnionTypeLayout* taggedUnionTypeLayout;
// The basic approach we will use 16-byte chunks (represented as an array
// of `uint4`s) to reprent the "bulk" of a type, and then use a single field
@@ -269,8 +269,8 @@ struct DesugarUnionTypesContext
// for fields, etc.).
//
auto taggedUnionTypeLayout = taggedUnionInfo->taggedUnionTypeLayout;
- SLANG_ASSERT(caseTagIndex < UInt(taggedUnionTypeLayout->caseTypeLayouts.getCount()));
- auto caseTypeLayout = taggedUnionTypeLayout->caseTypeLayouts[caseTagIndex];
+ SLANG_ASSERT(caseTagIndex < UInt(taggedUnionTypeLayout->getCaseCount()));
+ auto caseTypeLayout = taggedUnionTypeLayout->getCaseTypeLayout(caseTagIndex);
// At this point we know the type we are trying to extract, as well
// as its layout. We will defer the actual implementation of extraction
@@ -342,7 +342,7 @@ struct DesugarUnionTypesContext
IRType* payloadType,
// - The memory layout of that payload type.
- TypeLayout* payloadTypeLayout,
+ IRTypeLayout* payloadTypeLayout,
// - The byte offset at which we want to fetch the payload.
UInt64 payloadOffset)
@@ -366,7 +366,7 @@ struct DesugarUnionTypesContext
// there to be complete type layout information for the
// types involved.
//
- auto structTypeLayout = as<StructTypeLayout>(payloadTypeLayout);
+ auto structTypeLayout = as<IRStructTypeLayout>(payloadTypeLayout);
SLANG_ASSERT(structTypeLayout);
// We are going to emit code to extract each of the fields
@@ -384,15 +384,15 @@ struct DesugarUnionTypesContext
// IR struct and the fields of the layout still align.
//
UInt fieldIndex = fieldCounter++;
- auto fieldLayout = structTypeLayout->fields[fieldIndex];
+ auto fieldLayout = structTypeLayout->getFieldLayout(fieldIndex);
auto fieldTypeLayout = fieldLayout->getTypeLayout();
// The offset of the field can be computed from the base
// offset passed in, plus the reflection data for the field.
//
UInt64 fieldOffset = payloadOffset;
- if(auto resInfo = fieldLayout->FindResourceInfo(LayoutResourceKind::Uniform))
- fieldOffset += resInfo->index;
+ if(auto resInfo = fieldLayout->findOffsetAttr(LayoutResourceKind::Uniform))
+ fieldOffset += resInfo->getOffset();
// We make a recursive call to extract each field, expecting
// that this will bottom out eventually.
@@ -429,10 +429,10 @@ struct DesugarUnionTypesContext
// no way to query the layout of the elements of a vector
// type. Until that gets added we will kludge things here.
//
- TypeLayout* elementTypeLayout = nullptr;
+ IRTypeLayout* elementTypeLayout = nullptr;
size_t elementSize = 0;
- if(auto resInfo = payloadTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform))
- elementSize = resInfo->count.getFiniteValue() / elementCount;
+ if(auto resInfo = payloadTypeLayout->findSizeAttr(LayoutResourceKind::Uniform))
+ elementSize = resInfo->getSize().getFiniteValue() / elementCount;
// Similar to the `struct` case above, we will extract a
// value for each element of the vector, and then use
@@ -465,13 +465,13 @@ struct DesugarUnionTypesContext
// we have an individual scalar field that we need to fetch.
//
UInt64 payloadSize = 0;
- if( auto resInfo = payloadTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform) )
+ if( auto resInfo = payloadTypeLayout->findSizeAttr(LayoutResourceKind::Uniform) )
{
// TODO: somebody before this point should generate an error if
// we have a `union` type that contains a potentially unbounded
// amount of data.
//
- payloadSize = resInfo->count.getFiniteValue();
+ payloadSize = resInfo->getSize().getFiniteValue();
}
if( payloadSize != 4 )
@@ -670,9 +670,9 @@ struct DesugarUnionTypesContext
//
auto layoutDecoration = type->findDecoration<IRLayoutDecoration>();
SLANG_ASSERT(layoutDecoration);
- auto layout = layoutDecoration->getIRLayout()->getASTLayout();
+ auto layout = layoutDecoration->getLayout();
SLANG_ASSERT(layout);
- auto taggedUnionTypeLayout = as<TaggedUnionTypeLayout>(layout);
+ auto taggedUnionTypeLayout = as<IRTaggedUnionTypeLayout>(layout);
SLANG_ASSERT(taggedUnionTypeLayout);
info->taggedUnionTypeLayout = taggedUnionTypeLayout;
@@ -684,7 +684,7 @@ struct DesugarUnionTypesContext
// of the tag's alignment. We should deal with that when/if we support
// types smaller than 4 bytes in unions.
//
- auto payloadSize = taggedUnionTypeLayout->tagOffset.getFiniteValue();
+ auto payloadSize = taggedUnionTypeLayout->getTagOffset().getFiniteValue();
// We are going to be construction IR code that makes use of the `int`
// and `uint` types in several cases, so we go ahead and get a pointer