Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[202y] Propose adding C++11-style constructors #325

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions proposals/NNNN-constructors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Constructors

* Proposal: [NNNN](NNNN-constructors.md)
* Author(s): [Chris Bieneman](https://github.com/llvm-beanz)
* Sponsor: [Chris Bieneman](https://github.com/llvm-beanz)
* Status: **Under Consideration**
* Planned Version: 202y

## Introduction

As user defined data structures get more common and complex, the absence of
constructors and destructors is more and more awkward. This proposal seeks to
bring the full features of C++ initialization and destruction into HLSL.

## Motivation

Constructors are incredibly useful for ensuring data initialization and
implementing common patterns like Resource-Acquisition-Is-Initialization (RAII).

## Proposed solution

Introduce the following features to HLSL:
* C++ Constructors and Destructors
* C++ 11 Delegating Constructors
* C++ 11 Default and Deleted methods
* C++ 11 Default initializers
* Clang __attribute__((constructor)) and __attribute__((destructor))

Constructor syntax will match C++ 11 constructor syntax including support for
delegating constructors. It will be available on all user-defined data types
that support constructors in C++.

## Detailed design

### Global Construction

HLSL global constructors will be ordered following C++ conventions.
Constant-evaluated initializers occur first, followed by non-constant
initializers which are ordered by declaration order in the translation unit.

Each entry function will call the global constructors before executing any
further instructions and the global destructor immediately before returning.

In library shaders, the entry translation unit's global constructors are
executed after the linked library global constructors, and the entry's global
destructors are executed before linked library global destructors.

Non-trivial global constructors **will not** be stripped from library shaders.
Meaning, an unused global with a non-trivial constructor will be linked into the
final linked shader binary. This conforms to the C++ standard definitions for
static storage duration (see: ISO C++ Standard _basic.stc.static_).

Due to the inherent performance drawbacks of global construction, warnings will
be issued by default for any code that introduces a non-trivial global
constructor.

### Constructing Groupshared

Constructor initialization of `groupshared` objects will be followed by a memory
barrier and group sync. This comes with inherent performance costs, so shader
authors should use constructors with `groupshared` objects sparingly.

A `groupshared` user defined object that does not have a constructor, or has a
constructor that does not initialize any of its fields, will not incur the
memory barrier.

Due to the inherent performance drawbacks of `groupshared` construction,
warnings will be issued by default for any code that introduces a `groupshared`
object constructor.

### Constructors and Semantic Annotations

When a user defined data type contains members which are annotated with semantic
attributes and the data structure is initialized as a global or as a parameter
to the entry function, the semantic will be applied to the field after the
default constructor executes.

For example:

```c++
struct VSIn {
uint ID : SV_VertexID;
float F;

VSIn() : ID(0), F(1.0) {}
};

float4 main(in VSIn In) : SV_Position
{
// In.vid is SV_VertexID, In.f is 1.0
VSIn In2;
// In2.vid is 0, In.f is 1.0
}
```

Currently HLSL requires that all members of a user defined data type passed into
an entry function must have semantic annotations to initialize the structure.
With the addition of constructors and default value initialization, HLSL will
instead require that every field either have a semantic annotation, or a default
initialization through either a default constructor or a default initializer.

HLSL will also introduce default initialization and defaulted and deleted
constructors. Default initialization is incompatible with HLSL annotations, and
can only be used on variable declarations that either use C++ attributes for
annotations, or have no annotation (see:
[proposal for C++ Attributes](0002-cxx-attributes.md)).

For example:

```c++
struct VSIn {
uint ID : SV_VertexID = 2; // invalid
uint ID = 2 : SV_VertexID; // invalid
[[hlsl::SV_VertexID]] uint ID = 2; // valid
float F = 1.0; // valid

VSIn() = default;
};

float4 main(in VSIn In) : SV_Position
{
// In.vid is SV_VertexID, In.f is 1.0
VSIn In2;
// In2.vid is 0, In.f is 1.0
}
```