Skip to content

Commit 762646e

Browse files
committed
[HLSL] Pass arrays by value
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.
1 parent 2377beb commit 762646e

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

+616
-42
lines changed

clang/docs/HLSL/FunctionCalls.rst

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -157,22 +157,24 @@ 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 non-array type which represents an array
170+
value. It is only applied to constant-sized array ``ParmVarDecl`` nodes. Much
171+
like a ``DecayedType`` it stores both the original ``ConstantArrayType`` and a
172+
decayed ``PointerType``, which is used during code generation.
173+
174+
An argument of ``ConstantArrayType`` can be implicitly converted to an
175+
equivalent non-decayed ``ArrayParameterType`` if the underlying canonical
176+
``ConstantArrayType``s are the same. This occurs during overload resolution
177+
instead of array to pointer decay.
176178
177179
.. code-block:: c++
178180
@@ -193,7 +195,7 @@ In the example above, the following AST is generated for the call to
193195
CallExpr 'void'
194196
|-ImplicitCastExpr 'void (*)(float [4])' <FunctionToPointerDecay>
195197
| `-DeclRefExpr 'void (float [4])' lvalue Function 'SizedArray' 'void (float [4])'
196-
`-HLSLArrayTemporaryExpr 'float [4]'
198+
`-ImplicitCastExpr 'float [4]' <HLSLArrayRValue>
197199
`-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]'
198200
199201
In the example above, the following AST is generated for the call to
@@ -204,7 +206,7 @@ In the example above, the following AST is generated for the call to
204206
CallExpr 'void'
205207
|-ImplicitCastExpr 'void (*)(float [])' <FunctionToPointerDecay>
206208
| `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])'
207-
`-HLSLArrayTemporaryExpr 'float [4]'
209+
`-ImplicitCastExpr 'float [4]' <HLSLArrayRValue>
208210
`-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]'
209211
210212
In both of these cases the argument expression is of known array size so we can
@@ -236,7 +238,7 @@ An expected AST should be something like:
236238
CallExpr 'void'
237239
|-ImplicitCastExpr 'void (*)(float [])' <FunctionToPointerDecay>
238240
| `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])'
239-
`-HLSLArrayTemporaryExpr 'float [4]'
241+
`-ImplicitCastExpr 'float [4]' <HLSLArrayRValue>
240242
`-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]'
241243
242244
Out Parameter Temporaries

clang/include/clang/AST/ASTContext.h

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

261+
mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
262+
ArrayParameterTypes;
263+
261264
/// The set of nested name specifiers.
262265
///
263266
/// This set is managed by the NestedNameSpecifier class.
@@ -1360,6 +1363,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
13601363
/// type to the decayed type.
13611364
QualType getDecayedType(QualType Orig, QualType Decayed) const;
13621365

1366+
/// Return the uniqued reference to a specified array parameter type from the
1367+
/// original array type.
1368+
QualType getArrayParameterType(QualType Ty) const;
1369+
13631370
/// Return the uniqued reference to the atomic type for the specified
13641371
/// type.
13651372
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

@@ -1254,6 +1260,11 @@ DEF_TRAVERSE_TYPELOC(ConstantArrayType, {
12541260
TRY_TO(TraverseArrayTypeLocHelper(TL));
12551261
})
12561262

1263+
DEF_TRAVERSE_TYPELOC(ArrayParameterType, {
1264+
TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
1265+
TRY_TO(TraverseArrayTypeLocHelper(TL));
1266+
})
1267+
12571268
DEF_TRAVERSE_TYPELOC(IncompleteArrayType, {
12581269
TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
12591270
TRY_TO(TraverseArrayTypeLocHelper(TL));

clang/include/clang/AST/Type.h

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,6 +2277,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
22772277
bool isConstantArrayType() const;
22782278
bool isIncompleteArrayType() const;
22792279
bool isVariableArrayType() const;
2280+
bool isArrayParameterType() const;
22802281
bool isDependentSizedArrayType() const;
22812282
bool isRecordType() const;
22822283
bool isClassType() const;
@@ -3173,41 +3174,46 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
31733174
return T->getTypeClass() == ConstantArray ||
31743175
T->getTypeClass() == VariableArray ||
31753176
T->getTypeClass() == IncompleteArray ||
3176-
T->getTypeClass() == DependentSizedArray;
3177+
T->getTypeClass() == DependentSizedArray ||
3178+
T->getTypeClass() == ArrayParameter;
31773179
}
31783180
};
31793181

31803182
/// Represents the canonical version of C arrays with a specified constant size.
31813183
/// For example, the canonical type for 'int A[4 + 4*100]' is a
31823184
/// ConstantArrayType where the element type is 'int' and the size is 404.
3183-
class ConstantArrayType final
3184-
: public ArrayType,
3185-
private llvm::TrailingObjects<ConstantArrayType, const Expr *> {
3185+
class ConstantArrayType : public ArrayType {
31863186
friend class ASTContext; // ASTContext creates these.
3187-
friend TrailingObjects;
31883187

31893188
llvm::APInt Size; // Allows us to unique the type.
3189+
const Expr *SizeExpr;
31903190

31913191
ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
31923192
const Expr *sz, ArraySizeModifier sm, unsigned tq)
31933193
: ArrayType(ConstantArray, et, can, sm, tq, sz), Size(size) {
31943194
ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr;
31953195
if (ConstantArrayTypeBits.HasStoredSizeExpr) {
31963196
assert(!can.isNull() && "canonical constant array should not have size");
3197-
*getTrailingObjects<const Expr*>() = sz;
3197+
SizeExpr = sz;
31983198
}
31993199
}
32003200

3201-
unsigned numTrailingObjects(OverloadToken<const Expr*>) const {
3202-
return ConstantArrayTypeBits.HasStoredSizeExpr;
3201+
protected:
3202+
ConstantArrayType(TypeClass tc, QualType et, QualType can,
3203+
const llvm::APInt &size, const Expr *sz,
3204+
ArraySizeModifier sm, unsigned tq)
3205+
: ArrayType(tc, et, can, sm, tq, sz), Size(size) {
3206+
ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr;
3207+
if (ConstantArrayTypeBits.HasStoredSizeExpr) {
3208+
assert(!can.isNull() && "canonical constant array should not have size");
3209+
SizeExpr = sz;
3210+
}
32033211
}
32043212

32053213
public:
32063214
const llvm::APInt &getSize() const { return Size; }
32073215
const Expr *getSizeExpr() const {
3208-
return ConstantArrayTypeBits.HasStoredSizeExpr
3209-
? *getTrailingObjects<const Expr *>()
3210-
: nullptr;
3216+
return ConstantArrayTypeBits.HasStoredSizeExpr ? SizeExpr : nullptr;
32113217
}
32123218
bool isSugared() const { return false; }
32133219
QualType desugar() const { return QualType(this, 0); }
@@ -3235,7 +3241,25 @@ class ConstantArrayType final
32353241
unsigned TypeQuals);
32363242

32373243
static bool classof(const Type *T) {
3238-
return T->getTypeClass() == ConstantArray;
3244+
return T->getTypeClass() == ConstantArray ||
3245+
T->getTypeClass() == ArrayParameter;
3246+
}
3247+
};
3248+
3249+
/// Represents a constant array type that does not decay to a pointer when used
3250+
/// as a function parameter.
3251+
class ArrayParameterType : public ConstantArrayType {
3252+
friend class ASTContext; // ASTContext creates these.
3253+
3254+
ArrayParameterType(const ConstantArrayType *ATy, QualType CanTy)
3255+
: ConstantArrayType(ArrayParameter, ATy->getElementType(), CanTy,
3256+
ATy->getSize(), ATy->getSizeExpr(),
3257+
ATy->getSizeModifier(),
3258+
ATy->getIndexTypeQualifiers().getAsOpaqueValue()) {}
3259+
3260+
public:
3261+
static bool classof(const Type *T) {
3262+
return T->getTypeClass() == ArrayParameter;
32393263
}
32403264
};
32413265

@@ -6967,7 +6991,8 @@ inline bool QualType::isCanonicalAsParam() const {
69676991
if (T->isVariablyModifiedType() && T->hasSizedVLAType())
69686992
return false;
69696993

6970-
return !isa<FunctionType>(T) && !isa<ArrayType>(T);
6994+
return !isa<FunctionType>(T) &&
6995+
(!isa<ArrayType>(T) || isa<ArrayParameterType>(T));
69716996
}
69726997

69736998
inline bool QualType::isConstQualified() const {
@@ -7232,6 +7257,10 @@ inline bool Type::isVariableArrayType() const {
72327257
return isa<VariableArrayType>(CanonicalType);
72337258
}
72347259

7260+
inline bool Type::isArrayParameterType() const {
7261+
return isa<ArrayParameterType>(CanonicalType);
7262+
}
7263+
72357264
inline bool Type::isDependentSizedArrayType() const {
72367265
return isa<DependentSizedArrayType>(CanonicalType);
72377266
}
@@ -7587,7 +7616,7 @@ inline bool Type::isTypedefNameType() const {
75877616

75887617
/// Determines whether this type can decay to a pointer type.
75897618
inline bool Type::canDecayToPointerType() const {
7590-
return isFunctionType() || isArrayType();
7619+
return isFunctionType() || (isArrayType() && !isArrayParameterType());
75917620
}
75927621

75937622
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
@@ -1585,6 +1585,11 @@ class ConstantArrayTypeLoc :
15851585
ConstantArrayType> {
15861586
};
15871587

1588+
/// Wrapper for source info for array parameter types.
1589+
class ArrayParameterTypeLoc
1590+
: public InheritingConcreteTypeLoc<
1591+
ConstantArrayTypeLoc, ArrayParameterTypeLoc, ArrayParameterType> {};
1592+
15881593
class IncompleteArrayTypeLoc :
15891594
public InheritingConcreteTypeLoc<ArrayTypeLoc,
15901595
IncompleteArrayTypeLoc,

clang/include/clang/AST/TypeProperties.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ let Class = ConstantArrayType in {
117117
}]>;
118118
}
119119

120+
let Class = ArrayParameterType in {
121+
def : Creator<[{ return ctx.getAdjustedParameterType(
122+
ctx.getConstantArrayType(elementType,sizeValue,
123+
size,sizeModifier,
124+
indexQualifiers.getCVRQualifiers())); }]>;
125+
}
126+
120127
let Class = IncompleteArrayType in {
121128
def : Creator<[{
122129
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
@@ -65,6 +65,7 @@ TYPE_BIT_CODE(DependentSizedMatrix, DEPENDENT_SIZE_MATRIX, 53)
6565
TYPE_BIT_CODE(Using, USING, 54)
6666
TYPE_BIT_CODE(BTFTagAttributed, BTFTAG_ATTRIBUTED, 55)
6767
TYPE_BIT_CODE(PackIndexing, PACK_INDEXING, 56)
68+
TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 57)
6869

6970

7071
#undef TYPE_BIT_CODE

0 commit comments

Comments
 (0)