Skip to content

Commit 9434c08

Browse files
authored
[HLSL] Implement array temporary support (#79382)
HLSL constant sized array function parameters do not decay to pointers. Instead constant sized array types are preserved as unique types for overload resolution, template instantiation and name mangling. This implements the change by adding a new `ArrayParameterType` which represents a non-decaying `ConstantArrayType`. The new type behaves the same as `ConstantArrayType` except that it does not decay to a pointer. Values of `ConstantArrayType` in HLSL decay during overload resolution via a new `HLSLArrayRValue` cast to `ArrayParameterType`. `ArrayParamterType` values are passed indirectly by-value to functions in IR generation resulting in callee generated memcpy instructions. The behavior of HLSL function calls is documented in the [draft language specification](https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf) under the Expr.Post.Call heading. Additionally the design of this implementation approach is documented in [Clang's documentation](https://clang.llvm.org/docs/HLSL/FunctionCalls.html) Resolves #70123
1 parent 92d0d6f commit 9434c08

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+606
-31
lines changed

clang/docs/HLSL/FunctionCalls.rst

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -157,22 +157,23 @@ Clang Implementation
157157
of the changes in the prototype implementation are restoring Clang-3.7 code
158158
that was previously modified to its original state.
159159

160-
The implementation in clang depends on two new AST nodes and minor extensions to
161-
Clang's existing support for Objective-C write-back arguments. The goal of this
162-
design is to capture the semantic details of HLSL function calls in the AST, and
163-
minimize the amount of magic that needs to occur during IR generation.
164-
165-
The two new AST nodes are ``HLSLArrayTemporaryExpr`` and ``HLSLOutParamExpr``,
166-
which respectively represent the temporaries used for passing arrays by value
167-
and the temporaries created for function outputs.
160+
The implementation in clang adds a new non-decaying array type, a new AST node
161+
to represent output parameters, and minor extensions to Clang's existing support
162+
for Objective-C write-back arguments. The goal of this design is to capture the
163+
semantic details of HLSL function calls in the AST, and minimize the amount of
164+
magic that needs to occur during IR generation.
168165

169166
Array Temporaries
170167
-----------------
171168

172-
The ``HLSLArrayTemporaryExpr`` represents temporary values for input
173-
constant-sized array arguments. This applies for all constant-sized array
174-
arguments regardless of whether or not the parameter is constant-sized or
175-
unsized.
169+
The new ``ArrayParameterType`` is a sub-class of ``ConstantArrayType``
170+
inheriting all the behaviors and methods of the parent except that it does not
171+
decay to a pointer during overload resolution or template type deduction.
172+
173+
An argument of ``ConstantArrayType`` can be implicitly converted to an
174+
equivalent non-decayed ``ArrayParameterType`` if the underlying canonical
175+
``ConstantArrayType`` is the same. This occurs during overload resolution
176+
instead of array to pointer decay.
176177

177178
.. code-block:: c++
178179

@@ -193,7 +194,7 @@ In the example above, the following AST is generated for the call to
193194
CallExpr 'void'
194195
|-ImplicitCastExpr 'void (*)(float [4])' <FunctionToPointerDecay>
195196
| `-DeclRefExpr 'void (float [4])' lvalue Function 'SizedArray' 'void (float [4])'
196-
`-HLSLArrayTemporaryExpr 'float [4]'
197+
`-ImplicitCastExpr 'float [4]' <HLSLArrayRValue>
197198
`-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]'
198199
199200
In the example above, the following AST is generated for the call to
@@ -204,7 +205,7 @@ In the example above, the following AST is generated for the call to
204205
CallExpr 'void'
205206
|-ImplicitCastExpr 'void (*)(float [])' <FunctionToPointerDecay>
206207
| `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])'
207-
`-HLSLArrayTemporaryExpr 'float [4]'
208+
`-ImplicitCastExpr 'float [4]' <HLSLArrayRValue>
208209
`-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]'
209210
210211
In both of these cases the argument expression is of known array size so we can
@@ -236,7 +237,7 @@ An expected AST should be something like:
236237
CallExpr 'void'
237238
|-ImplicitCastExpr 'void (*)(float [])' <FunctionToPointerDecay>
238239
| `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])'
239-
`-HLSLArrayTemporaryExpr 'float [4]'
240+
`-ImplicitCastExpr 'float [4]' <HLSLArrayRValue>
240241
`-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]'
241242
242243
Out Parameter Temporaries

clang/include/clang/AST/ASTContext.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
260260
ASTContext&>
261261
SubstTemplateTemplateParmPacks;
262262

263+
mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
264+
ArrayParameterTypes;
265+
263266
/// The set of nested name specifiers.
264267
///
265268
/// This set is managed by the NestedNameSpecifier class.
@@ -1367,6 +1370,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
13671370
/// type to the decayed type.
13681371
QualType getDecayedType(QualType Orig, QualType Decayed) const;
13691372

1373+
/// Return the uniqued reference to a specified array parameter type from the
1374+
/// original array type.
1375+
QualType getArrayParameterType(QualType Ty) const;
1376+
13701377
/// Return the uniqued reference to the atomic type for the specified
13711378
/// type.
13721379
QualType getAtomicType(QualType T) const;

clang/include/clang/AST/OperationKinds.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ CAST_OPERATION(IntToOCLSampler)
364364
// Truncate a vector type by dropping elements from the end (HLSL only).
365365
CAST_OPERATION(HLSLVectorTruncation)
366366

367+
// Non-decaying array RValue cast (HLSL only).
368+
CAST_OPERATION(HLSLArrayRValue)
369+
367370
//===- Binary Operations -------------------------------------------------===//
368371
// Operators listed in order of precedence.
369372
// Note that additions to this should also update the StmtVisitor class,

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,12 @@ DEF_TRAVERSE_TYPE(ConstantArrayType, {
993993
TRY_TO(TraverseStmt(const_cast<Expr*>(T->getSizeExpr())));
994994
})
995995

996+
DEF_TRAVERSE_TYPE(ArrayParameterType, {
997+
TRY_TO(TraverseType(T->getElementType()));
998+
if (T->getSizeExpr())
999+
TRY_TO(TraverseStmt(const_cast<Expr *>(T->getSizeExpr())));
1000+
})
1001+
9961002
DEF_TRAVERSE_TYPE(IncompleteArrayType,
9971003
{ TRY_TO(TraverseType(T->getElementType())); })
9981004

@@ -1260,6 +1266,11 @@ DEF_TRAVERSE_TYPELOC(ConstantArrayType, {
12601266
TRY_TO(TraverseArrayTypeLocHelper(TL));
12611267
})
12621268

1269+
DEF_TRAVERSE_TYPELOC(ArrayParameterType, {
1270+
TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
1271+
TRY_TO(TraverseArrayTypeLocHelper(TL));
1272+
})
1273+
12631274
DEF_TRAVERSE_TYPELOC(IncompleteArrayType, {
12641275
TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
12651276
TRY_TO(TraverseArrayTypeLocHelper(TL));

clang/include/clang/AST/Type.h

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2300,6 +2300,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
23002300
bool isConstantArrayType() const;
23012301
bool isIncompleteArrayType() const;
23022302
bool isVariableArrayType() const;
2303+
bool isArrayParameterType() const;
23032304
bool isDependentSizedArrayType() const;
23042305
bool isRecordType() const;
23052306
bool isClassType() const;
@@ -3334,14 +3335,15 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
33343335
return T->getTypeClass() == ConstantArray ||
33353336
T->getTypeClass() == VariableArray ||
33363337
T->getTypeClass() == IncompleteArray ||
3337-
T->getTypeClass() == DependentSizedArray;
3338+
T->getTypeClass() == DependentSizedArray ||
3339+
T->getTypeClass() == ArrayParameter;
33383340
}
33393341
};
33403342

33413343
/// Represents the canonical version of C arrays with a specified constant size.
33423344
/// For example, the canonical type for 'int A[4 + 4*100]' is a
33433345
/// ConstantArrayType where the element type is 'int' and the size is 404.
3344-
class ConstantArrayType final : public ArrayType {
3346+
class ConstantArrayType : public ArrayType {
33453347
friend class ASTContext; // ASTContext creates these.
33463348

33473349
struct ExternalSize {
@@ -3382,6 +3384,19 @@ class ConstantArrayType final : public ArrayType {
33823384
const Expr *SzExpr, ArraySizeModifier SzMod,
33833385
unsigned Qual);
33843386

3387+
protected:
3388+
ConstantArrayType(TypeClass Tc, const ConstantArrayType *ATy, QualType Can)
3389+
: ArrayType(Tc, ATy->getElementType(), Can, ATy->getSizeModifier(),
3390+
ATy->getIndexTypeQualifiers().getAsOpaqueValue(), nullptr) {
3391+
ConstantArrayTypeBits.HasExternalSize =
3392+
ATy->ConstantArrayTypeBits.HasExternalSize;
3393+
if (!ConstantArrayTypeBits.HasExternalSize) {
3394+
ConstantArrayTypeBits.SizeWidth = ATy->ConstantArrayTypeBits.SizeWidth;
3395+
Size = ATy->Size;
3396+
} else
3397+
SizePtr = ATy->SizePtr;
3398+
}
3399+
33853400
public:
33863401
/// Return the constant array size as an APInt.
33873402
llvm::APInt getSize() const {
@@ -3453,7 +3468,22 @@ class ConstantArrayType final : public ArrayType {
34533468
ArraySizeModifier SizeMod, unsigned TypeQuals);
34543469

34553470
static bool classof(const Type *T) {
3456-
return T->getTypeClass() == ConstantArray;
3471+
return T->getTypeClass() == ConstantArray ||
3472+
T->getTypeClass() == ArrayParameter;
3473+
}
3474+
};
3475+
3476+
/// Represents a constant array type that does not decay to a pointer when used
3477+
/// as a function parameter.
3478+
class ArrayParameterType : public ConstantArrayType {
3479+
friend class ASTContext; // ASTContext creates these.
3480+
3481+
ArrayParameterType(const ConstantArrayType *ATy, QualType CanTy)
3482+
: ConstantArrayType(ArrayParameter, ATy, CanTy) {}
3483+
3484+
public:
3485+
static bool classof(const Type *T) {
3486+
return T->getTypeClass() == ArrayParameter;
34573487
}
34583488
};
34593489

@@ -7185,7 +7215,8 @@ inline bool QualType::isCanonicalAsParam() const {
71857215
if (T->isVariablyModifiedType() && T->hasSizedVLAType())
71867216
return false;
71877217

7188-
return !isa<FunctionType>(T) && !isa<ArrayType>(T);
7218+
return !isa<FunctionType>(T) &&
7219+
(!isa<ArrayType>(T) || isa<ArrayParameterType>(T));
71897220
}
71907221

71917222
inline bool QualType::isConstQualified() const {
@@ -7450,6 +7481,10 @@ inline bool Type::isVariableArrayType() const {
74507481
return isa<VariableArrayType>(CanonicalType);
74517482
}
74527483

7484+
inline bool Type::isArrayParameterType() const {
7485+
return isa<ArrayParameterType>(CanonicalType);
7486+
}
7487+
74537488
inline bool Type::isDependentSizedArrayType() const {
74547489
return isa<DependentSizedArrayType>(CanonicalType);
74557490
}
@@ -7813,7 +7848,7 @@ inline bool Type::isTypedefNameType() const {
78137848

78147849
/// Determines whether this type can decay to a pointer type.
78157850
inline bool Type::canDecayToPointerType() const {
7816-
return isFunctionType() || isArrayType();
7851+
return isFunctionType() || (isArrayType() && !isArrayParameterType());
78177852
}
78187853

78197854
inline bool Type::hasPointerRepresentation() const {

clang/include/clang/AST/TypeLoc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,11 @@ class ConstantArrayTypeLoc :
16111611
ConstantArrayType> {
16121612
};
16131613

1614+
/// Wrapper for source info for array parameter types.
1615+
class ArrayParameterTypeLoc
1616+
: public InheritingConcreteTypeLoc<
1617+
ConstantArrayTypeLoc, ArrayParameterTypeLoc, ArrayParameterType> {};
1618+
16141619
class IncompleteArrayTypeLoc :
16151620
public InheritingConcreteTypeLoc<ArrayTypeLoc,
16161621
IncompleteArrayTypeLoc,

clang/include/clang/AST/TypeProperties.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,13 @@ let Class = ConstantArrayType in {
136136
}]>;
137137
}
138138

139+
let Class = ArrayParameterType in {
140+
def : Creator<[{ return ctx.getAdjustedParameterType(
141+
ctx.getConstantArrayType(elementType,sizeValue,
142+
size,sizeModifier,
143+
indexQualifiers.getCVRQualifiers())); }]>;
144+
}
145+
139146
let Class = IncompleteArrayType in {
140147
def : Creator<[{
141148
return ctx.getIncompleteArrayType(elementType, sizeModifier,

clang/include/clang/Basic/TypeNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def ConstantArrayType : TypeNode<ArrayType>;
6464
def IncompleteArrayType : TypeNode<ArrayType>;
6565
def VariableArrayType : TypeNode<ArrayType>;
6666
def DependentSizedArrayType : TypeNode<ArrayType>, AlwaysDependent;
67+
def ArrayParameterType : TypeNode<ConstantArrayType>;
6768
def DependentSizedExtVectorType : TypeNode<Type>, AlwaysDependent;
6869
def DependentAddressSpaceType : TypeNode<Type>, AlwaysDependent;
6970
def VectorType : TypeNode<Type>;

clang/include/clang/Sema/Overload.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ class Sema;
198198
/// HLSL vector truncation.
199199
ICK_HLSL_Vector_Truncation,
200200

201+
/// HLSL non-decaying array rvalue cast.
202+
ICK_HLSL_Array_RValue,
203+
201204
/// The number of conversion kinds
202205
ICK_Num_Conversion_Kinds,
203206
};

clang/include/clang/Serialization/TypeBitCodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,6 @@ TYPE_BIT_CODE(Using, USING, 54)
6666
TYPE_BIT_CODE(BTFTagAttributed, BTFTAG_ATTRIBUTED, 55)
6767
TYPE_BIT_CODE(PackIndexing, PACK_INDEXING, 56)
6868
TYPE_BIT_CODE(CountAttributed, COUNT_ATTRIBUTED, 57)
69+
TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 58)
6970

7071
#undef TYPE_BIT_CODE

0 commit comments

Comments
 (0)