Skip to content

Commit 1d8109a

Browse files
llvm-beanzinbelichekotabogner
authored andcommitted
[HLSL] Implement HLSL intialization list support (llvm#123141)
This PR implements HLSL's initialization list behvaior as specified in the draft language specifcation under [*Decl.Init.Agg*](https://microsoft.github.io/hlsl-specs/specs/hlsl.html#Decl.Init.Agg). This behavior is a bit unusual for C/C++ because intermediate braces in initializer lists are ignored and a whole array of additional conversions occur unintuitively to how initializaiton works in C. The implementaiton in this PR generates a valid C/C++ initialization list AST for the HLSL initializer so that there are no changes required to Clang's CodeGen to support this. This design will also allow us to use Clang's rewrite to convert HLSL initializers to valid C/C++ initializers that are equivalent. It does have the downside that it will generate often redundant accesses during codegen. The IR optimizer is extremely good at eliminating those so this will have no impact on the final executable performance. There is some opportunity for optimizing the initializer list generation that we could consider in subsequent commits. One notable opportunity would be to identify aggregate objects that occur in the same place in both initializers and do not require converison, those aggregates could be initialized as aggregates rather than fully scalarized. Closes llvm#56067 --------- Co-authored-by: Finn Plummer <[email protected]> Co-authored-by: Helena Kotas <[email protected]> Co-authored-by: Justin Bogner <[email protected]>
1 parent f1be4fb commit 1d8109a

File tree

17 files changed

+2369
-13
lines changed

17 files changed

+2369
-13
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12626,6 +12626,9 @@ def err_hlsl_pointers_unsupported : Error<
1262612626
"%select{pointers|references}0 are unsupported in HLSL">;
1262712627
def err_hlsl_missing_resource_class : Error<"HLSL resource needs to have [[hlsl::resource_class()]] attribute">;
1262812628
def err_hlsl_attribute_needs_intangible_type: Error<"attribute %0 can be used only on HLSL intangible type %1">;
12629+
def err_hlsl_incorrect_num_initializers: Error<
12630+
"too %select{few|many}0 initializers in list for type %1 "
12631+
"(expected %2 but found %3)">;
1262912632

1263012633
def err_hlsl_operator_unsupported : Error<
1263112634
"the '%select{&|*|->}0' operator is unsupported in HLSL">;

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
namespace clang {
2727
class AttributeCommonInfo;
2828
class IdentifierInfo;
29+
class InitializedEntity;
30+
class InitializationKind;
2931
class ParsedAttr;
3032
class Scope;
3133
class VarDecl;
@@ -149,6 +151,9 @@ class SemaHLSL : public SemaBase {
149151

150152
QualType getInoutParameterType(QualType Ty);
151153

154+
bool TransformInitList(const InitializedEntity &Entity,
155+
const InitializationKind &Kind, InitListExpr *Init);
156+
152157
private:
153158
// HLSL resource type attributes need to be processed all at once.
154159
// This is a list to collect them.

clang/lib/AST/DeclCXX.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,18 @@ void CXXRecordDecl::addedMember(Decl *D) {
14621462
if (Using->getDeclName().getCXXOverloadedOperator() == OO_Equal)
14631463
data().HasInheritedAssignment = true;
14641464
}
1465+
1466+
// HLSL: All user-defined data types are aggregates and use aggregate
1467+
// initialization, meanwhile most, but not all built-in types behave like
1468+
// aggregates. Resource types, and some other HLSL types that wrap handles
1469+
// don't behave like aggregates. We can identify these as different because we
1470+
// implicitly define "special" member functions, which aren't spellable in
1471+
// HLSL. This all _needs_ to change in the future. There are two
1472+
// relevant HLSL feature proposals that will depend on this changing:
1473+
// * 0005-strict-initializer-lists.md
1474+
// * https://github.com/microsoft/hlsl-specs/pull/325
1475+
if (getLangOpts().HLSL)
1476+
data().Aggregate = data().UserDeclaredSpecialMembers == 0;
14651477
}
14661478

14671479
bool CXXRecordDecl::isLiteral() const {

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5551,6 +5551,12 @@ CodeGenFunction::getOrCreateOpaqueRValueMapping(const OpaqueValueExpr *e) {
55515551
return EmitAnyExpr(e->getSourceExpr());
55525552
}
55535553

5554+
bool CodeGenFunction::isOpaqueValueEmitted(const OpaqueValueExpr *E) {
5555+
if (OpaqueValueMapping::shouldBindAsLValue(E))
5556+
return OpaqueLValues.contains(E);
5557+
return OpaqueRValues.contains(E);
5558+
}
5559+
55545560
RValue CodeGenFunction::EmitRValueForField(LValue LV,
55555561
const FieldDecl *FD,
55565562
SourceLocation Loc) {

clang/lib/CodeGen/CGExprAgg.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "CGCXXABI.h"
14+
#include "CGHLSLRuntime.h"
1415
#include "CGObjCRuntime.h"
1516
#include "CGRecordLayout.h"
1617
#include "CodeGenFunction.h"
@@ -1776,6 +1777,18 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
17761777
}
17771778
#endif
17781779

1780+
// HLSL initialization lists in the AST are an expansion which can contain
1781+
// side-effecting expressions wrapped in opaque value expressions. To properly
1782+
// emit these we need to emit the opaque values before we emit the argument
1783+
// expressions themselves. This is a little hacky, but it prevents us needing
1784+
// to do a bigger AST-level change for a language feature that we need
1785+
// deprecate in the near future. See related HLSL language proposals:
1786+
// * 0005-strict-initializer-lists.md
1787+
// * https://github.com/microsoft/hlsl-specs/pull/325
1788+
if (CGF.getLangOpts().HLSL && isa<InitListExpr>(ExprToVisit))
1789+
CGF.CGM.getHLSLRuntime().emitInitListOpaqueValues(
1790+
CGF, cast<InitListExpr>(ExprToVisit));
1791+
17791792
AggValueSlot Dest = EnsureSlot(ExprToVisit->getType());
17801793

17811794
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), ExprToVisit->getType());

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414

1515
#include "CGHLSLRuntime.h"
1616
#include "CGDebugInfo.h"
17+
#include "CodeGenFunction.h"
1718
#include "CodeGenModule.h"
1819
#include "TargetInfo.h"
1920
#include "clang/AST/Decl.h"
21+
#include "clang/AST/RecursiveASTVisitor.h"
2022
#include "clang/Basic/TargetOptions.h"
2123
#include "llvm/IR/GlobalVariable.h"
2224
#include "llvm/IR/LLVMContext.h"
@@ -617,3 +619,33 @@ llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
617619
llvm_unreachable("Convergence token should have been emitted.");
618620
return nullptr;
619621
}
622+
623+
class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
624+
public:
625+
llvm::SmallPtrSet<OpaqueValueExpr *, 8> OVEs;
626+
OpaqueValueVisitor() {}
627+
628+
bool VisitOpaqueValueExpr(OpaqueValueExpr *E) {
629+
OVEs.insert(E);
630+
return true;
631+
}
632+
};
633+
634+
void CGHLSLRuntime::emitInitListOpaqueValues(CodeGenFunction &CGF,
635+
InitListExpr *E) {
636+
637+
typedef CodeGenFunction::OpaqueValueMappingData OpaqueValueMappingData;
638+
OpaqueValueVisitor Visitor;
639+
Visitor.TraverseStmt(E);
640+
for (auto *OVE : Visitor.OVEs) {
641+
if (CGF.isOpaqueValueEmitted(OVE))
642+
continue;
643+
if (OpaqueValueMappingData::shouldBindAsLValue(OVE)) {
644+
LValue LV = CGF.EmitLValue(OVE->getSourceExpr());
645+
OpaqueValueMappingData::bind(CGF, OVE, LV);
646+
} else {
647+
RValue RV = CGF.EmitAnyExpr(OVE->getSourceExpr());
648+
OpaqueValueMappingData::bind(CGF, OVE, RV);
649+
}
650+
}
651+
}

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class StructType;
5555
namespace clang {
5656
class VarDecl;
5757
class ParmVarDecl;
58+
class InitListExpr;
5859
class HLSLBufferDecl;
5960
class HLSLResourceBindingAttr;
6061
class Type;
@@ -65,6 +66,7 @@ class FunctionDecl;
6566
namespace CodeGen {
6667

6768
class CodeGenModule;
69+
class CodeGenFunction;
6870

6971
class CGHLSLRuntime {
7072
public:
@@ -161,6 +163,8 @@ class CGHLSLRuntime {
161163

162164
llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
163165

166+
void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E);
167+
164168
private:
165169
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
166170
llvm::hlsl::ResourceClass RC,

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3011,6 +3011,10 @@ class CodeGenFunction : public CodeGenTypeCache {
30113011
/// otherwise create one.
30123012
RValue getOrCreateOpaqueRValueMapping(const OpaqueValueExpr *e);
30133013

3014+
/// isOpaqueValueEmitted - Return true if the opaque value expression has
3015+
/// already been emitted.
3016+
bool isOpaqueValueEmitted(const OpaqueValueExpr *E);
3017+
30143018
/// Get the index of the current ArrayInitLoopExpr, if any.
30153019
llvm::Value *getArrayInitIndex() { return ArrayInitIndex; }
30163020

clang/lib/Sema/SemaChecking.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11679,8 +11679,12 @@ static void AnalyzeImplicitConversions(
1167911679
// Propagate whether we are in a C++ list initialization expression.
1168011680
// If so, we do not issue warnings for implicit int-float conversion
1168111681
// precision loss, because C++11 narrowing already handles it.
11682-
bool IsListInit = Item.IsListInit ||
11683-
(isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus);
11682+
//
11683+
// HLSL's initialization lists are special, so they shouldn't observe the C++
11684+
// behavior here.
11685+
bool IsListInit =
11686+
Item.IsListInit || (isa<InitListExpr>(OrigE) &&
11687+
S.getLangOpts().CPlusPlus && !S.getLangOpts().HLSL);
1168411688

1168511689
if (E->isTypeDependent() || E->isValueDependent())
1168611690
return;

0 commit comments

Comments
 (0)