From 58d706a9e3e33a49cd17f2fce0fad0adb6e076ce Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 8 Mar 2023 13:37:53 -0600 Subject: [PATCH 01/98] Experimental reimplementation of `out` and `inout` This change rewrites `out` and `inout` parameters to be implemented on the AST. The parameter copying behavior is modeled on the AST and generated through codegen. Instead of using the previously existing infrastructure for generating HLSL's copy-in/copy-out semantaics, this change generates temporaries based on the AST, uses AST-based analysis for optimziation, and uses the Objective-C indirect writeback support for copy-out. --- .../clang/AST/DataRecursiveASTVisitor.h | 2 + tools/clang/include/clang/AST/Expr.h | 35 +++++++++ .../include/clang/AST/RecursiveASTVisitor.h | 1 + tools/clang/include/clang/Basic/StmtNodes.td | 1 + tools/clang/lib/AST/ASTDumper.cpp | 8 ++ tools/clang/lib/AST/Decl.cpp | 4 +- tools/clang/lib/AST/Expr.cpp | 5 ++ tools/clang/lib/AST/ExprClassification.cpp | 2 + tools/clang/lib/AST/HlslTypes.cpp | 35 +++++---- tools/clang/lib/AST/StmtPrinter.cpp | 4 + tools/clang/lib/AST/StmtProfile.cpp | 7 +- tools/clang/lib/CodeGen/CGCall.cpp | 14 ++-- tools/clang/lib/CodeGen/CGCall.h | 8 -- tools/clang/lib/CodeGen/CGExpr.cpp | 32 ++++---- tools/clang/lib/CodeGen/CGExprCXX.cpp | 62 ++------------- tools/clang/lib/CodeGen/CGHLSLMS.cpp | 14 ---- tools/clang/lib/CodeGen/CGHLSLRuntime.h | 1 - tools/clang/lib/CodeGen/CodeGenFunction.h | 1 + tools/clang/lib/Sema/HLSLOutParamBuilder.h | 77 +++++++++++++++++++ tools/clang/lib/Sema/SemaExpr.cpp | 6 ++ tools/clang/lib/Sema/TreeTransform.h | 14 ++++ 21 files changed, 214 insertions(+), 119 deletions(-) create mode 100644 tools/clang/lib/Sema/HLSLOutParamBuilder.h diff --git a/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h b/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h index 50955d8ec3..6905c275ef 100644 --- a/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h +++ b/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h @@ -2146,6 +2146,8 @@ DEF_TRAVERSE_STMT(ExpressionTraitExpr, DEF_TRAVERSE_STMT(ExtMatrixElementExpr, {}) DEF_TRAVERSE_STMT(HLSLVectorElementExpr, {}) + +DEF_TRAVERSE_STMT(HLSLOutParamExpr, {}) // HLSL Change end. DEF_TRAVERSE_STMT(VAArgExpr, { diff --git a/tools/clang/include/clang/AST/Expr.h b/tools/clang/include/clang/AST/Expr.h index 26eff309f7..f0ddc1d6a4 100644 --- a/tools/clang/include/clang/AST/Expr.h +++ b/tools/clang/include/clang/AST/Expr.h @@ -4752,6 +4752,41 @@ class HLSLVectorElementExpr : public Expr { // Iterators child_range children() { return child_range(&Base, &Base + 1); } }; + +class HLSLOutParamExpr : public Expr { + Expr *Base; + bool IsInOut; + bool CanElide; + +public: + HLSLOutParamExpr(QualType Ty, Expr *Base, bool IsInOut = false, + bool CanElide = false) + : Expr(HLSLOutParamExprClass, Ty, VK_LValue, OK_Ordinary, + Base->isTypeDependent(), Base->isValueDependent(), + Base->isInstantiationDependent(), + Base->containsUnexpandedParameterPack()), + Base(Base), IsInOut(IsInOut), CanElide(CanElide) {} + + const Expr *getBase() const { return Base; } + Expr *getBase() { return Base; } + void setBase(Expr *E) { Base = E; } + + bool isInOut() const { return IsInOut; } + bool canElide() const { return CanElide; } + + SourceLocation getLocStart() const LLVM_READONLY { + return Base->getLocStart(); + } + + SourceLocation getLocEnd() const LLVM_READONLY { return Base->getLocEnd(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == HLSLOutParamExprClass; + } + + // Iterators + child_range children() { return child_range((Stmt**)&Base, (Stmt**)&Base + 1); } +}; // HLSL Change Ends /// BlockExpr - Adaptor class for mixing a BlockDecl with expressions. diff --git a/tools/clang/include/clang/AST/RecursiveASTVisitor.h b/tools/clang/include/clang/AST/RecursiveASTVisitor.h index c8c79664c8..a613313f6b 100644 --- a/tools/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/tools/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2269,6 +2269,7 @@ DEF_TRAVERSE_STMT(DesignatedInitUpdateExpr, {}) DEF_TRAVERSE_STMT(ExtVectorElementExpr, {}) DEF_TRAVERSE_STMT(ExtMatrixElementExpr, {}) // HLSL Change DEF_TRAVERSE_STMT(HLSLVectorElementExpr, {}) // HLSL Change +DEF_TRAVERSE_STMT(HLSLOutParamExpr, {}) // HLSL Change DEF_TRAVERSE_STMT(GNUNullExpr, {}) DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {}) DEF_TRAVERSE_STMT(NoInitExpr, {}) diff --git a/tools/clang/include/clang/Basic/StmtNodes.td b/tools/clang/include/clang/Basic/StmtNodes.td index 71f3829c97..c0caaa723d 100644 --- a/tools/clang/include/clang/Basic/StmtNodes.td +++ b/tools/clang/include/clang/Basic/StmtNodes.td @@ -89,6 +89,7 @@ def PseudoObjectExpr : DStmt; def ExtMatrixElementExpr : DStmt; def HLSLVectorElementExpr : DStmt; def DiscardStmt : Stmt; +def HLSLOutParamExpr : DStmt; // HLSL Change Ends // Atomic expressions diff --git a/tools/clang/lib/AST/ASTDumper.cpp b/tools/clang/lib/AST/ASTDumper.cpp index a29b7dea6b..9a10058602 100644 --- a/tools/clang/lib/AST/ASTDumper.cpp +++ b/tools/clang/lib/AST/ASTDumper.cpp @@ -509,6 +509,7 @@ namespace { void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node); void VisitExtMatrixElementExpr(const ExtMatrixElementExpr *Node); // HLSL Change void VisitHLSLVectorElementExpr(const HLSLVectorElementExpr *Node); // HLSL Change + void VisitHLSLOutParamExpr(const HLSLOutParamExpr *Node); // HLSL Change void VisitBinaryOperator(const BinaryOperator *Node); void VisitCompoundAssignOperator(const CompoundAssignOperator *Node); void VisitAddrLabelExpr(const AddrLabelExpr *Node); @@ -2027,6 +2028,13 @@ void ASTDumper::VisitHLSLVectorElementExpr(const HLSLVectorElementExpr *Node) { VisitExpr(Node); OS << " " << Node->getAccessor().getNameStart(); } + +void ASTDumper::VisitHLSLOutParamExpr(const HLSLOutParamExpr *Node) { + VisitExpr(Node); + OS << (Node->isInOut() ? " inout" : " out"); + if (Node->canElide()) + OS << " can elide"; +} // HLSL Change Ends void ASTDumper::VisitBinaryOperator(const BinaryOperator *Node) { diff --git a/tools/clang/lib/AST/Decl.cpp b/tools/clang/lib/AST/Decl.cpp index 39b3ac768d..c8cdc265ff 100644 --- a/tools/clang/lib/AST/Decl.cpp +++ b/tools/clang/lib/AST/Decl.cpp @@ -2372,9 +2372,7 @@ unsigned ParmVarDecl::getParameterIndexLarge() const { void ParmVarDecl::updateOutParamToRefType(ASTContext &C) { // Aggregate type will be indirect param convert to pointer type. // So don't update to ReferenceType. - if ((!getType()->isArrayType() && !getType()->isRecordType()) || - hlsl::IsHLSLVecMatType(getType())) - setType(C.getLValueReferenceType(getType(), false)); + setType(C.getLValueReferenceType(getType(), false)); // Add restrict to out param. QualType QT = getType(); QT.addRestrict(); diff --git a/tools/clang/lib/AST/Expr.cpp b/tools/clang/lib/AST/Expr.cpp index 0e2ec8c6c2..d18c618e96 100644 --- a/tools/clang/lib/AST/Expr.cpp +++ b/tools/clang/lib/AST/Expr.cpp @@ -3079,6 +3079,11 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, return true; break; + // HLSL Change - Begin + case HLSLOutParamExprClass: + return true; + // HLSL Change - End + case InitListExprClass: // FIXME: The children for an InitListExpr doesn't include the array filler. if (const Expr *E = cast(this)->getArrayFiller()) diff --git a/tools/clang/lib/AST/ExprClassification.cpp b/tools/clang/lib/AST/ExprClassification.cpp index e50a01e21a..afeb1c8258 100644 --- a/tools/clang/lib/AST/ExprClassification.cpp +++ b/tools/clang/lib/AST/ExprClassification.cpp @@ -321,6 +321,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { if (cast(E)->isArrow()) return Cl::CL_LValue; return ClassifyInternal(Ctx, cast(E)->getBase()); + case Expr::HLSLOutParamExprClass: + return Cl::CL_LValue; // HLSL Change Ends // Simply look at the actual default argument. diff --git a/tools/clang/lib/AST/HlslTypes.cpp b/tools/clang/lib/AST/HlslTypes.cpp index 344eb65469..ffcbe582b9 100644 --- a/tools/clang/lib/AST/HlslTypes.cpp +++ b/tools/clang/lib/AST/HlslTypes.cpp @@ -52,7 +52,7 @@ ConvertHLSLVecMatTypeToExtVectorType(const clang::ASTContext &context, } bool IsHLSLVecMatType(clang::QualType type) { - const Type *Ty = type.getCanonicalType().getTypePtr(); + const Type *Ty = type.getNonReferenceType().getCanonicalType().getTypePtr(); if (const RecordType *RT = dyn_cast(Ty)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast(RT->getDecl())) { @@ -67,7 +67,8 @@ bool IsHLSLVecMatType(clang::QualType type) { } bool IsHLSLMatType(clang::QualType type) { - const clang::Type *Ty = type.getCanonicalType().getTypePtr(); + const clang::Type *Ty = + type.getNonReferenceType().getCanonicalType().getTypePtr(); if (const RecordType *RT = dyn_cast(Ty)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast(RT->getDecl())) { @@ -80,7 +81,8 @@ bool IsHLSLMatType(clang::QualType type) { } bool IsHLSLVecType(clang::QualType type) { - const clang::Type *Ty = type.getCanonicalType().getTypePtr(); + const clang::Type *Ty = + type.getNonReferenceType().getCanonicalType().getTypePtr(); if (const RecordType *RT = dyn_cast(Ty)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast(RT->getDecl())) { @@ -93,7 +95,8 @@ bool IsHLSLVecType(clang::QualType type) { } bool IsHLSLNumericOrAggregateOfNumericType(clang::QualType type) { - const clang::Type *Ty = type.getCanonicalType().getTypePtr(); + const clang::Type *Ty = + type.getNonReferenceType().getCanonicalType().getTypePtr(); if (isa(Ty)) { if (IsHLSLVecMatType(type)) return true; @@ -110,7 +113,8 @@ bool IsHLSLNumericOrAggregateOfNumericType(clang::QualType type) { } bool IsHLSLNumericUserDefinedType(clang::QualType type) { - const clang::Type *Ty = type.getCanonicalType().getTypePtr(); + const clang::Type *Ty = + type.getNonReferenceType().getCanonicalType().getTypePtr(); if (const RecordType *RT = dyn_cast(Ty)) { const RecordDecl *RD = RT->getDecl(); if (!IsUserDefinedRecordType(type)) @@ -148,7 +152,7 @@ bool IsHLSLBuiltinRayAttributeStruct(clang::QualType QT) { // Aggregate types are arrays and user-defined structs bool IsHLSLAggregateType(clang::QualType type) { - type = type.getCanonicalType(); + type = type.getCanonicalType().getNonReferenceType(); if (isa(type)) return true; @@ -448,7 +452,7 @@ clang::QualType GetHLSLMatElementType(clang::QualType type) { } // TODO: Add type cache to ASTContext. bool IsHLSLInputPatchType(QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); if (const RecordType *RT = dyn_cast(type)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast( @@ -461,7 +465,7 @@ bool IsHLSLInputPatchType(QualType type) { return false; } bool IsHLSLOutputPatchType(QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); if (const RecordType *RT = dyn_cast(type)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast( @@ -474,7 +478,7 @@ bool IsHLSLOutputPatchType(QualType type) { return false; } bool IsHLSLPointStreamType(QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); if (const RecordType *RT = dyn_cast(type)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast( @@ -486,7 +490,7 @@ bool IsHLSLPointStreamType(QualType type) { return false; } bool IsHLSLLineStreamType(QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); if (const RecordType *RT = dyn_cast(type)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast( @@ -498,7 +502,7 @@ bool IsHLSLLineStreamType(QualType type) { return false; } bool IsHLSLTriangleStreamType(QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); if (const RecordType *RT = dyn_cast(type)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast( @@ -510,7 +514,7 @@ bool IsHLSLTriangleStreamType(QualType type) { return false; } bool IsHLSLStreamOutputType(QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); if (const RecordType *RT = dyn_cast(type)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast( @@ -526,6 +530,7 @@ bool IsHLSLStreamOutputType(QualType type) { return false; } bool IsHLSLResourceType(clang::QualType type) { + type = type.getNonReferenceType().getCanonicalType(); if (const RecordType *RT = type->getAs()) { StringRef name = RT->getDecl()->getName(); if (name == "Texture1D" || name == "RWTexture1D") @@ -855,7 +860,7 @@ bool IsIncompleteHLSLResourceArrayType(clang::ASTContext &context, } QualType GetHLSLResourceTemplateParamType(QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); const RecordType *RT = cast(type); const ClassTemplateSpecializationDecl *templateDecl = cast(RT->getAsCXXRecordDecl()); @@ -867,7 +872,7 @@ QualType GetHLSLInputPatchElementType(QualType type) { return GetHLSLResourceTemplateParamType(type); } unsigned GetHLSLInputPatchCount(QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); const RecordType *RT = cast(type); const ClassTemplateSpecializationDecl *templateDecl = cast(RT->getAsCXXRecordDecl()); @@ -878,7 +883,7 @@ clang::QualType GetHLSLOutputPatchElementType(QualType type) { return GetHLSLResourceTemplateParamType(type); } unsigned GetHLSLOutputPatchCount(QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); const RecordType *RT = cast(type); const ClassTemplateSpecializationDecl *templateDecl = cast(RT->getAsCXXRecordDecl()); diff --git a/tools/clang/lib/AST/StmtPrinter.cpp b/tools/clang/lib/AST/StmtPrinter.cpp index c99aeafc18..0bdbe849c8 100644 --- a/tools/clang/lib/AST/StmtPrinter.cpp +++ b/tools/clang/lib/AST/StmtPrinter.cpp @@ -1389,6 +1389,10 @@ void StmtPrinter::VisitHLSLVectorElementExpr(HLSLVectorElementExpr *Node) { OS << "."; OS << Node->getAccessor().getName(); } +void StmtPrinter::VisitHLSLOutParamExpr(HLSLOutParamExpr *Node) { + OS << (Node->isInOut() ? "inout " : "out "); + PrintExpr(Node->getBase()); +} // HLSL Change Ends void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { OS << '('; diff --git a/tools/clang/lib/AST/StmtProfile.cpp b/tools/clang/lib/AST/StmtProfile.cpp index f5331d6db5..a7a39553b6 100644 --- a/tools/clang/lib/AST/StmtProfile.cpp +++ b/tools/clang/lib/AST/StmtProfile.cpp @@ -788,7 +788,7 @@ void StmtProfiler::VisitExtVectorElementExpr(const ExtVectorElementExpr *S) { VisitName(&S->getAccessor()); } -// HLSL Change +// HLSL Change Begin void StmtProfiler::VisitExtMatrixElementExpr(const ExtMatrixElementExpr *S) { VisitExpr(S); VisitName(&S->getAccessor()); @@ -798,6 +798,11 @@ void StmtProfiler::VisitHLSLVectorElementExpr(const HLSLVectorElementExpr *S) { VisitName(&S->getAccessor()); } +void StmtProfiler::VisitHLSLOutParamExpr(const HLSLOutParamExpr *S) { + VisitExpr(S); +} +// HLSL Change End + void StmtProfiler::VisitBlockExpr(const BlockExpr *S) { VisitExpr(S); VisitDecl(S->getBlockDecl()); diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index f781e66a0d..c701d20d1e 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -2579,7 +2579,6 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, args.add(convertTempToRValue(local, type, loc), type); } -#if 0 // HLSL Change - no ObjC support static bool isProvablyNull(llvm::Value *addr) { return isa(addr); } @@ -2659,7 +2658,6 @@ static void emitWritebacks(CodeGenFunction &CGF, for (const auto &I : args.writebacks()) emitWriteback(CGF, I); } -#endif // HLSL Change - no ObjC support static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF, const CallArgList &CallArgs) { @@ -3000,6 +2998,14 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, return args.add(RV, type); } } + + // Add writeback for HLSLOutParamExpr. + if (const HLSLOutParamExpr *OE = dyn_cast(E)) { + LValue LV = EmitLValue(E); + if (!OE->canElide()) + args.addWriteback(EmitLValue(OE->getBase()), LV.getAddress(), nullptr); + return args.add(RValue::get(LV.getAddress()), type); + } // HLSL Change Ends. assert(E->getObjectKind() == OK_Ordinary); return args.add(EmitReferenceBindingToExpr(E), type); @@ -3670,14 +3676,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (Builder.isNamePreserving() && !CI->getType()->isVoidTy()) CI->setName("call"); -#if 0 // HLSL Change - no ObjC support // Emit any writebacks immediately. Arguably this should happen // after any return-value munging. if (CallArgs.hasWritebacks()) emitWritebacks(*this, CallArgs); -#else - assert(!CallArgs.hasWritebacks() && "writebacks are unavailable in HLSL"); -#endif // HLSL Change - no ObjC support // The stack cleanup for inalloca arguments has to run out of the normal // lexical order, so deactivate it and run it manually here. diff --git a/tools/clang/lib/CodeGen/CGCall.h b/tools/clang/lib/CodeGen/CGCall.h index 4524087358..7a4708e5cc 100644 --- a/tools/clang/lib/CodeGen/CGCall.h +++ b/tools/clang/lib/CodeGen/CGCall.h @@ -84,25 +84,17 @@ namespace CodeGen { void addFrom(const CallArgList &other) { insert(end(), other.begin(), other.end()); -#if 0 // HLSL Change - no ObjC support Writebacks.insert(Writebacks.end(), other.Writebacks.begin(), other.Writebacks.end()); -#else - assert(!other.hasWritebacks() && "writeback is unreachable in HLSL"); -#endif // HLSL Change - no ObjC support } void addWriteback(LValue srcLV, llvm::Value *temporary, llvm::Value *toUse) { -#if 0 // HLSL Change - no ObjC support Writeback writeback; writeback.Source = srcLV; writeback.Temporary = temporary; writeback.ToUse = toUse; Writebacks.push_back(writeback); -#else - llvm_unreachable("addWriteback is unreachable in HLSL"); -#endif // HLSL Change - no ObjC support } bool hasWritebacks() const { return !Writebacks.empty(); } diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index 85469ecfb9..645659030f 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -920,6 +920,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitExtMatrixElementExpr(cast(E)); case Expr::HLSLVectorElementExprClass: return EmitHLSLVectorElementExpr(cast(E)); + case Expr::HLSLOutParamExprClass: + return EmitHLSLOutParamExpr(cast(E)); case Expr::CXXThisExprClass: return MakeAddrLValue(LoadCXXThis(), E->getType()); // HLSL Change Ends @@ -2961,6 +2963,20 @@ CodeGenFunction::EmitExtMatrixElementExpr(const ExtMatrixElementExpr *E) { *this, ResultTy, {matBase, CV}, E->getBase()->getType()); return MakeAddrLValue(Result, E->getType()); } + +LValue CodeGenFunction::EmitHLSLOutParamExpr(const HLSLOutParamExpr *E) { + if (E->canElide()) + return EmitLValue(E->getBase()); + llvm::Type *Ty = ConvertType(E->getType()); + llvm::AllocaInst *OutTemp = CreateTempAlloca(Ty, "out_param"); + if (E->isInOut()) { + LValue InitialState = EmitLValue(E->getBase()); + llvm::LoadInst *Ld = Builder.CreateLoad(InitialState.getAddress(), "in_val"); + (void)Builder.CreateStore(Ld, OutTemp); + } + return MakeAddrLValue(OutTemp, E->getType()); +} + LValue CodeGenFunction::EmitHLSLVectorElementExpr(const HLSLVectorElementExpr *E) { // Emit the base vector as an l-value. @@ -3940,28 +3956,16 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, // HLSL Change Begins llvm::SmallVector castArgList; llvm::SmallVector lifetimeCleanupList; - // The argList of the CallExpr, may be update for out parameter - llvm::SmallVector argList(E->arg_begin(), E->arg_end()); - ConstExprIterator argBegin = argList.data(); - ConstExprIterator argEnd = argList.data() + E->getNumArgs(); // out param conversion CodeGenFunction::HLSLOutParamScope OutParamScope(*this); - auto MapTemp = [&](const VarDecl *LocalVD, llvm::Value *TmpArg) { - OutParamScope.addTemp(LocalVD, TmpArg); - }; - if (getLangOpts().HLSL) { - if (const FunctionDecl *FD = E->getDirectCallee()) - CGM.getHLSLRuntime().EmitHLSLOutParamConversionInit(*this, FD, E, - castArgList, argList, lifetimeCleanupList, MapTemp); - } // HLSL Change Ends CallArgList Args; if (Chain) Args.add(RValue::get(Builder.CreateBitCast(Chain, CGM.VoidPtrTy)), CGM.getContext().VoidPtrTy); - EmitCallArgs(Args, dyn_cast(FnType), argBegin, argEnd, // HLSL Change - use updated argList - E->getDirectCallee(), /*ParamsToSkip*/ 0); + EmitCallArgs(Args, dyn_cast(FnType), E->arg_begin(), + E->arg_end(), E->getDirectCallee(), /*ParamsToSkip*/ 0); const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall( Args, FnType, /*isChainCall=*/Chain); diff --git a/tools/clang/lib/CodeGen/CGExprCXX.cpp b/tools/clang/lib/CodeGen/CGExprCXX.cpp index 2efde7c30f..39ad63ddc7 100644 --- a/tools/clang/lib/CodeGen/CGExprCXX.cpp +++ b/tools/clang/lib/CodeGen/CGExprCXX.cpp @@ -28,9 +28,7 @@ using namespace CodeGen; static RequiredArgs commonEmitCXXMemberOrOperatorCall( CodeGenFunction &CGF, const CXXMethodDecl *MD, llvm::Value *Callee, ReturnValueSlot ReturnValue, llvm::Value *This, llvm::Value *ImplicitParam, - QualType ImplicitParamTy, const CallExpr *CE, CallArgList &Args, - ArrayRef argList// HLSL Change - use updated argList for out parameter. - ) { + QualType ImplicitParamTy, const CallExpr *CE, CallArgList &Args) { assert(CE == nullptr || isa(CE) || isa(CE)); assert(MD->isInstance() && @@ -62,9 +60,7 @@ static RequiredArgs commonEmitCXXMemberOrOperatorCall( if (CE) { // Special case: skip first argument of CXXOperatorCall (it is "this"). unsigned ArgsToSkip = isa(CE) ? 1 : 0; - CGF.EmitCallArgs(Args, FPT, - argList.begin() + ArgsToSkip, // HLSL Change - use updated argList for out parameter. - argList.end(), // HLSL Change - use updated argList for out parameter. + CGF.EmitCallArgs(Args, FPT, CE->arg_begin() + ArgsToSkip, CE->arg_end(), CE->getDirectCallee()); } else { assert( @@ -80,36 +76,11 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorCall( const CallExpr *CE) { const FunctionProtoType *FPT = MD->getType()->castAs(); CallArgList Args; - - // HLSL Change Begins - llvm::SmallVector castArgList; - llvm::SmallVector lifetimeCleanupList; - // The argList of the CallExpr, may be update for out parameter - llvm::SmallVector argList(CE->arg_begin(), CE->arg_end()); - // out param conversion - CodeGenFunction::HLSLOutParamScope OutParamScope(*this); - auto MapTemp = [&](const VarDecl *LocalVD, llvm::Value *TmpArg) { - OutParamScope.addTemp(LocalVD, TmpArg); - }; - if (getLangOpts().HLSL) { - if (const FunctionDecl *FD = CE->getDirectCallee()) - CGM.getHLSLRuntime().EmitHLSLOutParamConversionInit(*this, FD, CE, - castArgList, argList, lifetimeCleanupList, MapTemp); - } - // HLSL Change Ends - RequiredArgs required = commonEmitCXXMemberOrOperatorCall( *this, MD, Callee, ReturnValue, This, ImplicitParam, ImplicitParamTy, CE, - Args, argList); // HLSL Change - use updated argList. - RValue CallVal = EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required), + Args); + return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required), Callee, ReturnValue, Args, MD); - // HLSL Change Begins - // out param conversion - // conversion and copy back after the call - if (getLangOpts().HLSL) - CGM.getHLSLRuntime().EmitHLSLOutParamConversionCopyBack(*this, castArgList, lifetimeCleanupList); - // HLSL Change Ends - return CallVal; } RValue CodeGenFunction::EmitCXXStructorCall( @@ -117,33 +88,10 @@ RValue CodeGenFunction::EmitCXXStructorCall( llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy, const CallExpr *CE, StructorType Type) { CallArgList Args; - // HLSL Change Begins - llvm::SmallVector castArgList; - llvm::SmallVector lifetimeCleanupList; - // The argList of the CallExpr, may be update for out parameter - llvm::SmallVector argList(CE->arg_begin(), CE->arg_end()); - // out param conversion - CodeGenFunction::HLSLOutParamScope OutParamScope(*this); - auto MapTemp = [&](const VarDecl *LocalVD, llvm::Value *TmpArg) { - OutParamScope.addTemp(LocalVD, TmpArg); - }; - if (getLangOpts().HLSL) { - if (const FunctionDecl *FD = CE->getDirectCallee()) - CGM.getHLSLRuntime().EmitHLSLOutParamConversionInit(*this, FD, CE, - castArgList, argList, lifetimeCleanupList, MapTemp); - } - // HLSL Change Ends commonEmitCXXMemberOrOperatorCall(*this, MD, Callee, ReturnValue, This, - ImplicitParam, ImplicitParamTy, CE, Args, - argList); // HLSL Change - use updated argList. + ImplicitParam, ImplicitParamTy, CE, Args); RValue CallVal = EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(MD, Type), Callee, ReturnValue, Args, MD); - // HLSL Change Begins - // out param conversion - // conversion and copy back after the call - if (getLangOpts().HLSL) - CGM.getHLSLRuntime().EmitHLSLOutParamConversionCopyBack(*this, castArgList, lifetimeCleanupList); - // HLSL Change Ends return CallVal; } diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 91d5c86dce..28819a313e 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -241,7 +241,6 @@ class CGMSHLSLRuntime : public CGHLSLRuntime { void EmitHLSLOutParamConversionInit( CodeGenFunction &CGF, const FunctionDecl *FD, const CallExpr *E, llvm::SmallVector &castArgList, - llvm::SmallVector &argList, llvm::SmallVector &lifetimeCleanupList, const std::function &TmpArgMap) override; @@ -5972,7 +5971,6 @@ void CGMSHLSLRuntime::EmitHLSLRootSignature(HLSLRootSignatureAttr *RSA, void CGMSHLSLRuntime::EmitHLSLOutParamConversionInit( CodeGenFunction &CGF, const FunctionDecl *FD, const CallExpr *E, llvm::SmallVector &castArgList, - llvm::SmallVector &argList, llvm::SmallVector &lifetimeCleanupList, const std::function &TmpArgMap) { // Special case: skip first argument of CXXOperatorCall (it is "this"). @@ -6022,8 +6020,6 @@ void CGMSHLSLRuntime::EmitHLSLOutParamConversionInit( if (const ImplicitCastExpr *cast = dyn_cast(cCast->getSubExpr())) { if (cast->getCastKind() == CastKind::CK_LValueToRValue) { - // update the arg - argList[ArgIdx] = cast->getSubExpr(); continue; } } @@ -6152,16 +6148,6 @@ void CGMSHLSLRuntime::EmitHLSLOutParamConversionInit( CGF.getContext().getTrivialTypeSourceInfo(ParamTy), StorageClass::SC_Auto); - // Aggregate type will be indirect param convert to pointer type. - // So don't update to ReferenceType, use RValue for it. - const DeclRefExpr *tmpRef = DeclRefExpr::Create( - CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), tmpArg, - /*enclosing*/ false, tmpArg->getLocation(), ParamTy, - (isAggregateType || isObject) ? VK_RValue : VK_LValue); - - // must update the arg, since we did emit Arg, else we get double emit. - argList[ArgIdx] = tmpRef; - // create alloc for the tmp arg Value *tmpArgAddr = nullptr; BasicBlock *InsertBlock = CGF.Builder.GetInsertBlock(); diff --git a/tools/clang/lib/CodeGen/CGHLSLRuntime.h b/tools/clang/lib/CodeGen/CGHLSLRuntime.h index 3e27951e86..bbc0416554 100644 --- a/tools/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/tools/clang/lib/CodeGen/CGHLSLRuntime.h @@ -83,7 +83,6 @@ class CGHLSLRuntime { virtual void EmitHLSLOutParamConversionInit( CodeGenFunction &CGF, const FunctionDecl *FD, const CallExpr *E, llvm::SmallVector &castArgList, - llvm::SmallVector &argList, llvm::SmallVector &lifetimeCleanupList, const std::function &TmpArgMap) = 0; virtual void EmitHLSLOutParamConversionCopyBack( diff --git a/tools/clang/lib/CodeGen/CodeGenFunction.h b/tools/clang/lib/CodeGen/CodeGenFunction.h index be9c2389ef..b3249427a0 100644 --- a/tools/clang/lib/CodeGen/CodeGenFunction.h +++ b/tools/clang/lib/CodeGen/CodeGenFunction.h @@ -2466,6 +2466,7 @@ class CodeGenFunction : public CodeGenTypeCache { LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); LValue EmitExtMatrixElementExpr(const ExtMatrixElementExpr *E); // HLSL Change LValue EmitHLSLVectorElementExpr(const HLSLVectorElementExpr *E); // HLSL Change + LValue EmitHLSLOutParamExpr(const HLSLOutParamExpr *E); // HLSL Change LValue EmitMemberExpr(const MemberExpr *E); LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h new file mode 100644 index 0000000000..bfe1f7b0e0 --- /dev/null +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -0,0 +1,77 @@ +//===--- HLSLOutParamBuilder.h - Helper for HLSLOutParamExpr ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_SEMA_HLSLOUTPARAMBUILDER_H +#define CLANG_SEMA_HLSLOUTPARAMBUILDER_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/StmtVisitor.h" +#include "llvm/ADT/DenseSet.h" + +namespace clang { + +class HLSLOutParamBuilder { + llvm::DenseSet SeenVars; + + // not copyable + HLSLOutParamBuilder(const HLSLOutParamBuilder &) = delete; + HLSLOutParamBuilder &operator=(const HLSLOutParamBuilder &) = delete; + + class DeclFinder : public StmtVisitor { + public: + NamedDecl *Decl = nullptr; + bool MultipleFound = false; + + DeclFinder() = default; + + void VisitStmt(Stmt *S) { VisitChildren(S); } + + void VisitDeclRefExpr(DeclRefExpr *DRE) { + if (MultipleFound) + return; + if (Decl) + MultipleFound = true; + Decl = DRE->getFoundDecl(); + return; + } + + void VisitChildren(Stmt *S) { + for (Stmt *SubStmt : S->children()) + if (SubStmt) + this->Visit(SubStmt); + } + }; + +public: + HLSLOutParamBuilder() = default; + + HLSLOutParamExpr *Create(ASTContext &Ctx, ParmVarDecl *P, Expr *Base) { + DeclFinder DF; + DF.Visit(Base); + + // If the analysis returned multiple possible decls, or no decl, or we've + // seen the decl before, generate a HLSLOutParamExpr that can't be elided. + if (DF.MultipleFound || DF.Decl == nullptr || SeenVars.count(DF.Decl) > 0) + return new (Ctx) HLSLOutParamExpr(Base->getType(), Base, + P->hasAttr()); + // Add the decl to the seen list, and generate a HLSLOutParamExpr that can + // be elided. + SeenVars.insert(DF.Decl); + return new (Ctx) HLSLOutParamExpr(Base->getType(), Base, + P->hasAttr(), true); + } +}; + +} // namespace clang + +#endif // CLANG_SEMA_HLSLOUTPARAMBUILDER_H diff --git a/tools/clang/lib/Sema/SemaExpr.cpp b/tools/clang/lib/Sema/SemaExpr.cpp index 78959317da..1173bcce51 100644 --- a/tools/clang/lib/Sema/SemaExpr.cpp +++ b/tools/clang/lib/Sema/SemaExpr.cpp @@ -45,6 +45,7 @@ #include "clang/Sema/Template.h" #include "llvm/Support/ConvertUTF.h" #include "clang/Sema/SemaHLSL.h" // HLSL Change +#include "HLSLOutParamBuilder.h" // HLSL Change using namespace clang; using namespace sema; @@ -4640,6 +4641,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, unsigned NumParams = Proto->getNumParams(); bool Invalid = false; unsigned ArgIx = 0; + HLSLOutParamBuilder HLSLBuilder; // HLSL Change // Continue to check argument types (even if we have too few/many args). for (unsigned i = FirstParam; i < NumParams; i++) { QualType ProtoArgType = Proto->getParamType(i); @@ -4682,6 +4684,10 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, return true; Arg = ArgE.getAs(); + // HLSL Change Begin - Optimize out parameters. + if (Param->isModifierOut()) + Arg = HLSLBuilder.Create(Context, Param, Arg); + // HLSL Change End - Optimize out paramters. } else { assert(Param && "can't use default arguments without a known callee"); diff --git a/tools/clang/lib/Sema/TreeTransform.h b/tools/clang/lib/Sema/TreeTransform.h index 7b23823f72..11d682b1c3 100644 --- a/tools/clang/lib/Sema/TreeTransform.h +++ b/tools/clang/lib/Sema/TreeTransform.h @@ -8193,6 +8193,20 @@ TreeTransform::TransformHLSLVectorElementExpr(HLSLVectorElementExpr *E) E->getAccessorLoc(), E->getAccessor()); } + +template +ExprResult +TreeTransform::TransformHLSLOutParamExpr(HLSLOutParamExpr *E) { + ExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) + return E; + + return new (getSema().Context) + HLSLOutParamExpr(E->getType(), Base.get(), E->isInOut(), E->canElide()); +} // HLSL Change Ends template From dff5116ece2c3e9b8fd10912cf795f898af0249b Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 8 Mar 2023 16:47:51 -0600 Subject: [PATCH 02/98] Catch one more place we used non-LValues for UDTs 'cbieneman/rewrite-out-params' on '617b5097828'. --- tools/clang/lib/Sema/SemaHLSL.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 3070578929..6b97e251b2 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -1745,12 +1745,7 @@ AddHLSLIntrinsicFunction(ASTContext &context, NamespaceDecl *NS, if (paramMods[i - 1].isAnyOut() || paramMods[i - 1].GetKind() == hlsl::ParameterModifier::Kind::Ref) { QualType Ty = functionArgQualTypes[i]; - // Aggregate type will be indirect param convert to pointer type. - // Don't need add reference for it. - if ((!Ty->isArrayType() && !Ty->isRecordType()) || - hlsl::IsHLSLVecMatType(Ty)) { - functionArgQualTypes[i] = context.getLValueReferenceType(Ty); - } + functionArgQualTypes[i] = context.getLValueReferenceType(Ty); } } From d9f680ba39ff79d27cb92b849b7dd9ab5a144b17 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 8 Mar 2023 16:48:27 -0600 Subject: [PATCH 03/98] Add LValueToRvalue cast on HLSL Conversions if required 'cbieneman/rewrite-out-params' on '617b5097828'. --- tools/clang/lib/Sema/SemaExprCXX.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/Sema/SemaExprCXX.cpp b/tools/clang/lib/Sema/SemaExprCXX.cpp index f46bb0ad9f..dfd7705460 100644 --- a/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -3452,9 +3452,21 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_HLSLVector_Splat: case ICK_HLSLVector_Scalar: case ICK_HLSLVector_Truncation: - case ICK_HLSLVector_Conversion: - From = hlsl::PerformHLSLConversion(this, From, ToType.getUnqualifiedType(), SCS, CCK).get(); + case ICK_HLSLVector_Conversion: { + ExprResult FromRes = hlsl::PerformHLSLConversion( + this, From, ToType.getUnqualifiedType(), SCS, CCK); + if (FromRes.isInvalid()) + return ExprError(); + From = FromRes.get(); + // If this isn't going to a reference we also need an LValueToRValue cast + if (!ToType->isReferenceType()) { + ExprResult FromRes = DefaultLvalueConversion(From); + if (FromRes.isInvalid()) + return ExprError(); + From = FromRes.get(); + } break; + } // HLSL Change Ends case ICK_TransparentUnionConversion: { From b514bef765daeb022072dc188a4ae1659664af3b Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 8 Mar 2023 16:48:34 -0600 Subject: [PATCH 04/98] Derived to base cast is a bitcast since HLSL is single inheritance... 'cbieneman/rewrite-out-params' on '617b5097828'. --- tools/clang/lib/CodeGen/CGExpr.cpp | 31 ++---------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index 645659030f..7dc869e29b 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -3551,7 +3551,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { llvm::Value *bitcast = Builder.CreateBitCast(LV.getAddress(), ResultType); return MakeAddrLValue(bitcast, ToType); } - case CK_FlatConversion: { + case CK_FlatConversion: + case CK_HLSLDerivedToBase:{ // Just bitcast. QualType ToType = getContext().getLValueReferenceType(E->getType()); @@ -3567,34 +3568,6 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { Builder.AllowFolding = originAllowFolding; return MakeAddrLValue(bitcast, ToType); } - case CK_HLSLDerivedToBase: { - // HLSL only single inheritance. - // Just GEP. - QualType ToType = getContext().getLValueReferenceType(E->getType()); - - LValue LV = EmitLValue(E->getSubExpr()); - llvm::Value *This = LV.getAddress(); - - // gep to target type - llvm::Type *ResultType = ConvertType(ToType); - unsigned level = 0; - llvm::Type *ToTy = ResultType->getPointerElementType(); - llvm::Type *FromTy = This->getType()->getPointerElementType(); - // For empty struct, just bitcast. - if (FromTy->getStructNumElements()== 0) { - llvm::Value *bitcast = Builder.CreateBitCast(This, ResultType); - return MakeAddrLValue(bitcast, ToType); - } - - while (ToTy != FromTy) { - FromTy = FromTy->getStructElementType(0); - ++level; - } - llvm::Value *zeroIdx = Builder.getInt32(0); - SmallVector IdxList(level + 1, zeroIdx); - llvm::Value *GEP = Builder.CreateInBoundsGEP(This, IdxList); - return MakeAddrLValue(GEP, ToType); - } case CK_HLSLMatrixSplat: case CK_HLSLMatrixToScalarCast: case CK_HLSLMatrixTruncationCast: From a230109ab30cee1c0585300c715a4a2b31e6bca7 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 8 Mar 2023 20:42:06 -0600 Subject: [PATCH 05/98] Code cleanup. Delete dead code and format some other code. 'cbieneman/rewrite-out-params' on '617b5097828'. --- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 20 +++++++------------- tools/clang/lib/Sema/SemaExprCXX.cpp | 6 +++--- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index bfe1f7b0e0..9e741d91b4 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -29,27 +29,19 @@ class HLSLOutParamBuilder { class DeclFinder : public StmtVisitor { public: - NamedDecl *Decl = nullptr; + ValueDecl *Decl = nullptr; bool MultipleFound = false; DeclFinder() = default; - void VisitStmt(Stmt *S) { VisitChildren(S); } - void VisitDeclRefExpr(DeclRefExpr *DRE) { if (MultipleFound) return; if (Decl) MultipleFound = true; - Decl = DRE->getFoundDecl(); + Decl = cast(DRE->getFoundDecl()); return; } - - void VisitChildren(Stmt *S) { - for (Stmt *SubStmt : S->children()) - if (SubStmt) - this->Visit(SubStmt); - } }; public: @@ -61,9 +53,11 @@ class HLSLOutParamBuilder { // If the analysis returned multiple possible decls, or no decl, or we've // seen the decl before, generate a HLSLOutParamExpr that can't be elided. - if (DF.MultipleFound || DF.Decl == nullptr || SeenVars.count(DF.Decl) > 0) - return new (Ctx) HLSLOutParamExpr(Base->getType(), Base, - P->hasAttr()); + if (DF.MultipleFound || DF.Decl == nullptr || + DF.Decl->getType().getQualifiers().hasAddressSpace() || + SeenVars.count(DF.Decl) > 0) + return new (Ctx) + HLSLOutParamExpr(Base->getType(), Base, P->hasAttr()); // Add the decl to the seen list, and generate a HLSLOutParamExpr that can // be elided. SeenVars.insert(DF.Decl); diff --git a/tools/clang/lib/Sema/SemaExprCXX.cpp b/tools/clang/lib/Sema/SemaExprCXX.cpp index dfd7705460..16176950cd 100644 --- a/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -3453,8 +3453,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_HLSLVector_Scalar: case ICK_HLSLVector_Truncation: case ICK_HLSLVector_Conversion: { - ExprResult FromRes = hlsl::PerformHLSLConversion( - this, From, ToType.getUnqualifiedType(), SCS, CCK); + ExprResult FromRes = + hlsl::PerformHLSLConversion(this, From, ToType, SCS, CCK); if (FromRes.isInvalid()) return ExprError(); From = FromRes.get(); @@ -3467,7 +3467,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } break; } - // HLSL Change Ends + // HLSL Change Ends case ICK_TransparentUnionConversion: { ExprResult FromRes = From; From 2b6924f83a894eb0d876865ae5536940f741e7f5 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 9 Mar 2023 10:55:31 -0600 Subject: [PATCH 06/98] Simplify derived to base c cast --- tools/clang/lib/Sema/SemaCast.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tools/clang/lib/Sema/SemaCast.cpp b/tools/clang/lib/Sema/SemaCast.cpp index 10668dc388..2d42e4ae7a 100644 --- a/tools/clang/lib/Sema/SemaCast.cpp +++ b/tools/clang/lib/Sema/SemaCast.cpp @@ -2477,7 +2477,28 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, TypeSourceInfo *CastTypeInfo, SourceLocation RPLoc, Expr *CastExpr) { - CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); + // HLSL Change Begin - HLSL Derived to base casts should be lvalues. + QualType DstType = CastTypeInfo->getType(); + QualType SrcType = CastExpr->getType(); + if (getLangOpts().HLSL && isa(*DstType) && + isa(*SrcType)) { + const auto *DstRT = DstType->getAs(); + const auto *SrcRT = SrcType->getAs(); + const auto *DstRD = dyn_cast(DstRT->getDecl()); + const auto *SrcRD = dyn_cast(SrcRT->getDecl()); + if (SrcRD->isDerivedFrom(DstRD)) { + if (SrcType.getQualifiers().hasAddressSpace()) { + Qualifiers Q = DstType.getQualifiers(); + Q.addAddressSpace(SrcType.getQualifiers().getAddressSpace()); + DstType = Context.getQualifiedType(DstType, Q); + } + return CStyleCastExpr::Create(Context, DstType, VK_LValue, + CK_HLSLDerivedToBase, CastExpr, nullptr, + CastTypeInfo, LPLoc, RPLoc); + } + } + CastOperation Op(*this, DstType, CastExpr); + // HLSL Change End - HLSL Derived to base casts should be lvalues. Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd()); From 97a25ed553d80d5dbe63d9a7713f7fa089d16bc8 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 9 Mar 2023 10:55:45 -0600 Subject: [PATCH 07/98] make writeback provably non-null for hlsl --- tools/clang/lib/CodeGen/CGCall.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index c701d20d1e..67e077dae9 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -2599,7 +2599,7 @@ static void emitWriteback(CodeGenFunction &CGF, // If the argument wasn't provably non-null, we need to null check // before doing the store. - bool provablyNonNull = isProvablyNonNull(srcAddr); + bool provablyNonNull = CGF.getLangOpts().HLSL || isProvablyNonNull(srcAddr); if (!provablyNonNull) { llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback"); contBB = CGF.createBasicBlock("icr.done"); From 2b8573bf4335f64c640b393c89d6d1ab46081403 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 9 Mar 2023 11:05:09 -0600 Subject: [PATCH 08/98] Delete old copy-in/copy-out code 'cbieneman/rewrite-out-params' on '4cf0f6c6504'. --- tools/clang/lib/CodeGen/CGExpr.cpp | 7 - tools/clang/lib/CodeGen/CGHLSLMS.cpp | 348 ------------------------ tools/clang/lib/CodeGen/CGHLSLRuntime.h | 8 - 3 files changed, 363 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index 7dc869e29b..cc5394396d 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -3970,13 +3970,6 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, } RValue CallVal = EmitCall(FnInfo, Callee, ReturnValue, Args, TargetDecl); - // HLSL Change Begins - // out param conversion - // conversion and copy back after the call - if (getLangOpts().HLSL) - CGM.getHLSLRuntime().EmitHLSLOutParamConversionCopyBack(*this, castArgList, lifetimeCleanupList); - // HLSL Change Ends - return CallVal; } diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 28819a313e..075ac94b0b 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -238,20 +238,9 @@ class CGMSHLSLRuntime : public CGHLSLRuntime { RValue EmitHLSLBuiltinCallExpr(CodeGenFunction &CGF, const FunctionDecl *FD, const CallExpr *E, ReturnValueSlot ReturnValue) override; - void EmitHLSLOutParamConversionInit( - CodeGenFunction &CGF, const FunctionDecl *FD, const CallExpr *E, - llvm::SmallVector &castArgList, - llvm::SmallVector &lifetimeCleanupList, - const std::function &TmpArgMap) - override; - void EmitHLSLOutParamConversionCopyBack( - CodeGenFunction &CGF, llvm::SmallVector &castArgList, - llvm::SmallVector &lifetimeCleanupList) override; - Value *EmitHLSLMatrixOperationCall(CodeGenFunction &CGF, const clang::Expr *E, llvm::Type *RetType, ArrayRef paramList) override; - void EmitHLSLDiscard(CodeGenFunction &CGF) override; BranchInst *EmitHLSLCondBreak(CodeGenFunction &CGF, llvm::Function *F, llvm::BasicBlock *DestBB, @@ -5968,343 +5957,6 @@ void CGMSHLSLRuntime::EmitHLSLRootSignature(HLSLRootSignatureAttr *RSA, } } -void CGMSHLSLRuntime::EmitHLSLOutParamConversionInit( - CodeGenFunction &CGF, const FunctionDecl *FD, const CallExpr *E, - llvm::SmallVector &castArgList, - llvm::SmallVector &lifetimeCleanupList, - const std::function &TmpArgMap) { - // Special case: skip first argument of CXXOperatorCall (it is "this"). - unsigned ArgsToSkip = isa(E) ? 1 : 0; - llvm::SmallSet ArgVals; - for (uint32_t i = 0; i < FD->getNumParams(); i++) { - const ParmVarDecl *Param = FD->getParamDecl(i); - uint32_t ArgIdx = i + ArgsToSkip; - const Expr *Arg = E->getArg(ArgIdx); - QualType ParamTy = Param->getType().getNonReferenceType(); - bool isObject = dxilutil::IsHLSLObjectType(CGF.ConvertTypeForMem(ParamTy)); - bool bAnnotResource = false; - if (isObject) { - if (isGLCMismatch(Param->getType(), Arg->getType(), Arg, - Arg->getExprLoc(), CGM.getDiags())) { - // NOTE: if function is noinline, resource parameter is not allowed. - // Here assume function will be always inlined. - // This can only take care resource as parameter. When parameter is - // struct with resource member, glc cannot mismatch because the - // struct type will always match. - // Add annotate handle here. - bAnnotResource = true; - } - } - bool isVector = hlsl::IsHLSLVecType(ParamTy); - bool isArray = ParamTy->isArrayType(); - // Check for array of matrix - QualType ParamElTy = ParamTy; - while (ParamElTy->isArrayType()) - ParamElTy = ParamElTy->getAsArrayTypeUnsafe()->getElementType(); - bool isMatrix = hlsl::IsHLSLMatType(ParamElTy); - bool isAggregateType = - !isObject && - (isArray || (ParamTy->isRecordType() && !(isMatrix || isVector))); - - bool EmitRValueAgg = false; - bool RValOnRef = false; - if (!Param->isModifierOut()) { - if (!isAggregateType && !isObject) { - if (Arg->isRValue() && Param->getType()->isReferenceType()) { - // RValue on a reference type. - if (const CStyleCastExpr *cCast = dyn_cast(Arg)) { - // TODO: Evolving this to warn then fail in future language - // versions. Allow special case like cast uint to uint for - // back-compat. - if (cCast->getCastKind() == CastKind::CK_NoOp) { - if (const ImplicitCastExpr *cast = - dyn_cast(cCast->getSubExpr())) { - if (cast->getCastKind() == CastKind::CK_LValueToRValue) { - continue; - } - } - } - } - // EmitLValue will report error. - // Mark RValOnRef to create tmpArg for it. - RValOnRef = true; - } else { - continue; - } - } else if (isAggregateType) { - // aggregate in-only - emit RValue, unless LValueToRValue cast - EmitRValueAgg = true; - if (const ImplicitCastExpr *cast = dyn_cast(Arg)) { - if (cast->getCastKind() == CastKind::CK_LValueToRValue) { - EmitRValueAgg = false; - } - } - } else { - // Must be object - DXASSERT(isObject, - "otherwise, flow condition changed, breaking assumption"); - // in-only objects should be skipped to preserve previous behavior. - if (!bAnnotResource) - continue; - } - } - - // Skip unbounded array, since we cannot preserve copy-in copy-out - // semantics for these. - if (ParamTy->isIncompleteArrayType()) { - continue; - } - - if (!Param->isModifierOut() && !RValOnRef) { - // No need to copy arg to in-only param for hlsl intrinsic. - if (const FunctionDecl *Callee = E->getDirectCallee()) { - if (Callee->hasAttr()) - continue; - } - } - - // get original arg - // FIXME: This will not emit in correct argument order with the other - // arguments. This should be integrated into - // CodeGenFunction::EmitCallArg if possible. - RValue argRV; // emit this if aggregate arg on in-only param - LValue argLV; // otherwise, we may emit this - llvm::Value *argAddr = nullptr; - QualType argType = Arg->getType(); - CharUnits argAlignment; - if (EmitRValueAgg) { - argRV = CGF.EmitAnyExprToTemp(Arg); - argAddr = argRV.getAggregateAddr(); // must be alloca - argAlignment = - CharUnits::fromQuantity(cast(argAddr)->getAlignment()); - argLV = - LValue::MakeAddr(argAddr, ParamTy, argAlignment, CGF.getContext()); - } else { - argLV = CGF.EmitLValue(Arg); - if (argLV.isSimple()) - argAddr = argLV.getAddress(); - - bool mustCopy = bAnnotResource; - - // If matrix orientation changes, we must copy here - // TODO: A high level intrinsic for matrix array copy with orientation - // change would be much easier to optimize/eliminate at high level - // after inline. - if (!mustCopy && isMatrix) { - mustCopy = !AreMatrixArrayOrientationMatching( - CGF.getContext(), *m_pHLModule, argType, ParamTy); - } - - if (!mustCopy) { - // When there's argument need to lower like buffer/cbuffer load, need to - // copy to let the lower not happen on argument when calle is noinline - // or extern functions. Will do it in HLLegalizeParameter after known - // which functions are extern but before inline. - Value *Ptr = argAddr; - while (GEPOperator *GEP = dyn_cast_or_null(Ptr)) { - Ptr = GEP->getPointerOperand(); - } - // Skip copy-in copy-out when safe. - // The unsafe case will be global variable alias with parameter. - // Then global variable is updated in the function, the parameter will - // be updated silently. For non global variable or constant global - // variable, it should be safe. - bool SafeToSkip = false; - if (GlobalVariable *GV = dyn_cast_or_null(Ptr)) { - SafeToSkip = - ParamTy.isConstQualified() && - (m_ConstVarAnnotationMap.count(GV) > 0 || GV->isConstant()); - } - if (Ptr) { - if (isa(Ptr) && 0 == ArgVals.count(Ptr)) - SafeToSkip = true; - else if (const auto *A = dyn_cast(Ptr)) - SafeToSkip = A->hasNoAliasAttr() && 0 == ArgVals.count(Ptr); - } - - if (argAddr && SafeToSkip) { - ArgVals.insert(Ptr); - llvm::Type *ToTy = CGF.ConvertType(ParamTy.getNonReferenceType()); - if (argAddr->getType()->getPointerElementType() == ToTy && - // Check clang Type for case like int cast to unsigned. - ParamTy.getNonReferenceType().getCanonicalType().getTypePtr() == - Arg->getType().getCanonicalType().getTypePtr()) - continue; - } - } - - argType = - argLV.getType(); // TBD: Can this be different than Arg->getType()? - argAlignment = argLV.getAlignment(); - } - // After emit Arg, we must update the argList[i], - // otherwise we get double emit of the expression. - - // create temp Var - VarDecl *tmpArg = - VarDecl::Create(CGF.getContext(), const_cast(FD), - SourceLocation(), SourceLocation(), - /*IdentifierInfo*/ nullptr, ParamTy, - CGF.getContext().getTrivialTypeSourceInfo(ParamTy), - StorageClass::SC_Auto); - - // create alloc for the tmp arg - Value *tmpArgAddr = nullptr; - BasicBlock *InsertBlock = CGF.Builder.GetInsertBlock(); - Function *F = InsertBlock->getParent(); - - // Make sure the alloca is in entry block to stop inline create stacksave. - IRBuilder<> AllocaBuilder(dxilutil::FindAllocaInsertionPt(F)); - tmpArgAddr = AllocaBuilder.CreateAlloca(CGF.ConvertTypeForMem(ParamTy)); - - if (CGM.getCodeGenOpts().HLSLEnableLifetimeMarkers) { - const uint64_t AllocaSize = - CGM.getDataLayout().getTypeAllocSize(CGF.ConvertTypeForMem(ParamTy)); - CGF.EmitLifetimeStart(AllocaSize, tmpArgAddr); - } - - // add it to local decl map - TmpArgMap(tmpArg, tmpArgAddr); - - LValue tmpLV = - LValue::MakeAddr(tmpArgAddr, ParamTy, argAlignment, CGF.getContext()); - - // save for cast after call - if (Param->isModifierOut()) { - castArgList.emplace_back(tmpLV); - castArgList.emplace_back(argLV); - if (isVector && !hlsl::IsHLSLVecType(argType)) { - // This assumes only implicit casts because explicit casts can only - // produce RValues currently and out parameters are LValues. - DiagnosticsEngine &Diags = CGM.getDiags(); - Diags.Report(Param->getLocation(), - diag::warn_hlsl_implicit_vector_truncation); - } - } - - // save to generate lifetime end after call - if (CGM.getCodeGenOpts().HLSLEnableLifetimeMarkers) - lifetimeCleanupList.emplace_back(tmpLV); - - // cast before the call - if (Param->isModifierIn() && - // Don't copy object - !isObject) { - QualType ArgTy = Arg->getType(); - Value *outVal = nullptr; - if (!isAggregateType) { - if (!IsHLSLMatType(ParamTy)) { - RValue outRVal = CGF.EmitLoadOfLValue(argLV, SourceLocation()); - outVal = outRVal.getScalarVal(); - } else { - DXASSERT(argAddr, "should be RV or simple LV"); - outVal = EmitHLSLMatrixLoad(CGF, argAddr, ArgTy); - } - - llvm::Type *ToTy = tmpArgAddr->getType()->getPointerElementType(); - if (HLMatrixType::isa(ToTy)) { - Value *castVal = CGF.Builder.CreateBitCast(outVal, ToTy); - EmitHLSLMatrixStore(CGF, castVal, tmpArgAddr, ParamTy); - } else { - if (outVal->getType()->isVectorTy()) { - Value *castVal = - ConvertScalarOrVector(CGF, outVal, argType, ParamTy); - castVal = CGF.EmitToMemory(castVal, ParamTy); - CGF.Builder.CreateStore(castVal, tmpArgAddr); - } else { - // This allows for splatting, unlike the above. - SimpleFlatValCopy(CGF, outVal, argType, tmpArgAddr, ParamTy); - } - } - } else { - DXASSERT(argAddr, "should be RV or simple LV"); - SmallVector idxList; - EmitHLSLAggregateCopy(CGF, argAddr, tmpArgAddr, idxList, ArgTy, ParamTy, - argAddr->getType()); - } - } else if (bAnnotResource) { - DxilResourceProperties RP = BuildResourceProperty(Arg->getType()); - CopyAndAnnotateResourceArgument(argAddr, tmpArgAddr, RP, *m_pHLModule, - CGF); - mismatchGLCArgSet.insert(tmpArgAddr); - } - } -} - -void CGMSHLSLRuntime::EmitHLSLOutParamConversionCopyBack( - CodeGenFunction &CGF, llvm::SmallVector &castArgList, - llvm::SmallVector &lifetimeCleanupList) { - for (uint32_t i = 0; i < castArgList.size(); i += 2) { - // cast after the call - LValue tmpLV = castArgList[i]; - LValue argLV = castArgList[i + 1]; - QualType ArgTy = argLV.getType().getNonReferenceType(); - QualType ParamTy = tmpLV.getType().getNonReferenceType(); - - Value *tmpArgAddr = tmpLV.getAddress(); - - Value *outVal = nullptr; - - bool isAggregateTy = hlsl::IsHLSLAggregateType(ArgTy); - - bool isObject = dxilutil::IsHLSLObjectType( - tmpArgAddr->getType()->getPointerElementType()); - if (!isObject) { - if (!isAggregateTy) { - if (!IsHLSLMatType(ParamTy)) - outVal = CGF.Builder.CreateLoad(tmpArgAddr); - else - outVal = EmitHLSLMatrixLoad(CGF, tmpArgAddr, ParamTy); - - outVal = CGF.EmitFromMemory(outVal, ParamTy); - - llvm::Type *ToTy = CGF.ConvertType(ArgTy); - llvm::Type *FromTy = outVal->getType(); - Value *castVal = outVal; - if (ToTy == FromTy) { - // Don't need cast. - } else if (ToTy->getScalarType() == FromTy->getScalarType()) { - if (ToTy->getScalarType() == ToTy) { - DXASSERT(FromTy->isVectorTy(), "must be vector"); - castVal = CGF.Builder.CreateExtractElement(outVal, (uint64_t)0); - } else { - DXASSERT(!FromTy->isVectorTy(), "must be scalar type"); - DXASSERT(ToTy->isVectorTy() && ToTy->getVectorNumElements() == 1, - "must be vector of 1 element"); - castVal = UndefValue::get(ToTy); - castVal = - CGF.Builder.CreateInsertElement(castVal, outVal, (uint64_t)0); - } - } else { - castVal = ConvertScalarOrVector(CGF, outVal, tmpLV.getType(), - argLV.getType()); - } - if (!HLMatrixType::isa(ToTy)) - CGF.EmitStoreThroughLValue(RValue::get(castVal), argLV); - else { - Value *destPtr = argLV.getAddress(); - EmitHLSLMatrixStore(CGF, castVal, destPtr, ArgTy); - } - } else { - SmallVector idxList; - EmitHLSLAggregateCopy(CGF, tmpLV.getAddress(), argLV.getAddress(), - idxList, ParamTy, ArgTy, - argLV.getAddress()->getType()); - } - } else if (mismatchGLCArgSet.find(tmpArgAddr) == mismatchGLCArgSet.end()) { - tmpArgAddr->replaceAllUsesWith(argLV.getAddress()); - } - } - - for (LValue &tmpLV : lifetimeCleanupList) { - QualType ParamTy = tmpLV.getType().getNonReferenceType(); - Value *tmpArgAddr = tmpLV.getAddress(); - const uint64_t AllocaSize = - CGM.getDataLayout().getTypeAllocSize(CGF.ConvertTypeForMem(ParamTy)); - CGF.EmitLifetimeEnd(CGF.Builder.getInt64(AllocaSize), tmpArgAddr); - } -} - ScopeInfo *CGMSHLSLRuntime::GetScopeInfo(Function *F) { auto it = m_ScopeMap.find(F); if (it == m_ScopeMap.end()) diff --git a/tools/clang/lib/CodeGen/CGHLSLRuntime.h b/tools/clang/lib/CodeGen/CGHLSLRuntime.h index bbc0416554..2a2cf6c68e 100644 --- a/tools/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/tools/clang/lib/CodeGen/CGHLSLRuntime.h @@ -80,14 +80,6 @@ class CGHLSLRuntime { virtual llvm::Constant *EmitHLSLConstInitListExpr(CodeGenModule &CGM, InitListExpr *E) = 0; - virtual void EmitHLSLOutParamConversionInit( - CodeGenFunction &CGF, const FunctionDecl *FD, const CallExpr *E, - llvm::SmallVector &castArgList, - llvm::SmallVector &lifetimeCleanupList, - const std::function &TmpArgMap) = 0; - virtual void EmitHLSLOutParamConversionCopyBack( - CodeGenFunction &CGF, llvm::SmallVector &castArgList, - llvm::SmallVector &lifetimeCleanupList) = 0; virtual void MarkPotentialResourceTemp(CodeGenFunction &CGF, llvm::Value *V, clang::QualType QaulTy) = 0; virtual llvm::Value * From ecfa3f6e252452c562757377117ef988be264417 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 9 Mar 2023 12:30:06 -0600 Subject: [PATCH 09/98] Emit conversion sequence in OutParamBuilder --- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 25 +++++++++++++++++----- tools/clang/lib/Sema/SemaExpr.cpp | 8 +++++-- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index 9e741d91b4..dd1ff233df 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -16,6 +16,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Sema/Sema.h" #include "llvm/ADT/DenseSet.h" namespace clang { @@ -47,7 +48,21 @@ class HLSLOutParamBuilder { public: HLSLOutParamBuilder() = default; - HLSLOutParamExpr *Create(ASTContext &Ctx, ParmVarDecl *P, Expr *Base) { + ExprResult Create(Sema &Sema, ParmVarDecl *P, Expr *Base) { + ASTContext &Ctx = Sema.getASTContext(); + + QualType Ty = P->getType().getNonLValueExprType(Ctx); + + // If the types mismatch we _may_ have some casting to perform. + if (Ty != Base->getType()) { + ExprResult Res = Sema.PerformImplicitConversion(Base, Ty, Sema::AA_Passing); + if (Res.isInvalid()) + return ExprError(); + Base = Res.get(); + return ExprResult( + new (Ctx) HLSLOutParamExpr(Ty, Base, P->hasAttr())); + } + DeclFinder DF; DF.Visit(Base); @@ -56,13 +71,13 @@ class HLSLOutParamBuilder { if (DF.MultipleFound || DF.Decl == nullptr || DF.Decl->getType().getQualifiers().hasAddressSpace() || SeenVars.count(DF.Decl) > 0) - return new (Ctx) - HLSLOutParamExpr(Base->getType(), Base, P->hasAttr()); + return ExprResult( + new (Ctx) HLSLOutParamExpr(Ty, Base, P->hasAttr())); // Add the decl to the seen list, and generate a HLSLOutParamExpr that can // be elided. SeenVars.insert(DF.Decl); - return new (Ctx) HLSLOutParamExpr(Base->getType(), Base, - P->hasAttr(), true); + return ExprResult(new (Ctx) HLSLOutParamExpr( + Ty, Base, P->hasAttr(), true)); } }; diff --git a/tools/clang/lib/Sema/SemaExpr.cpp b/tools/clang/lib/Sema/SemaExpr.cpp index 1173bcce51..15c77d48be 100644 --- a/tools/clang/lib/Sema/SemaExpr.cpp +++ b/tools/clang/lib/Sema/SemaExpr.cpp @@ -4685,8 +4685,12 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, Arg = ArgE.getAs(); // HLSL Change Begin - Optimize out parameters. - if (Param->isModifierOut()) - Arg = HLSLBuilder.Create(Context, Param, Arg); + if (Param->isModifierOut()) { + ArgE = HLSLBuilder.Create(*this, Param, Arg); + if (ArgE.isInvalid()) + return true; + Arg = ArgE.getAs(); + } // HLSL Change End - Optimize out paramters. } else { assert(Param && "can't use default arguments without a known callee"); From 146a6b2340952c0d18b1921180ae756011692b2d Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 9 Mar 2023 17:12:04 -0600 Subject: [PATCH 10/98] WIP --- tools/clang/include/clang/AST/Expr.h | 11 +++++++++-- tools/clang/lib/CodeGen/CGCall.cpp | 8 ++++++-- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 15 +++++++++++---- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/tools/clang/include/clang/AST/Expr.h b/tools/clang/include/clang/AST/Expr.h index f0ddc1d6a4..73eeac6be9 100644 --- a/tools/clang/include/clang/AST/Expr.h +++ b/tools/clang/include/clang/AST/Expr.h @@ -4755,6 +4755,7 @@ class HLSLVectorElementExpr : public Expr { class HLSLOutParamExpr : public Expr { Expr *Base; + Expr *Writeback; bool IsInOut; bool CanElide; @@ -4765,12 +4766,16 @@ class HLSLOutParamExpr : public Expr { Base->isTypeDependent(), Base->isValueDependent(), Base->isInstantiationDependent(), Base->containsUnexpandedParameterPack()), - Base(Base), IsInOut(IsInOut), CanElide(CanElide) {} + Base(Base), Writeback(nullptr), IsInOut(IsInOut), CanElide(CanElide) {} const Expr *getBase() const { return Base; } Expr *getBase() { return Base; } void setBase(Expr *E) { Base = E; } + const Expr *getWriteback() const { return Writeback; } + Expr *getWriteback() { return Writeback; } + void setWriteback(Expr *E) { Writeback = E; } + bool isInOut() const { return IsInOut; } bool canElide() const { return CanElide; } @@ -4785,7 +4790,9 @@ class HLSLOutParamExpr : public Expr { } // Iterators - child_range children() { return child_range((Stmt**)&Base, (Stmt**)&Base + 1); } + child_range children() { + return child_range((Stmt **)&Base, (Stmt **)&Base + (Writeback ? 2 : 1)); + } }; // HLSL Change Ends diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index 67e077dae9..8d005d31a2 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -3002,8 +3002,12 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, // Add writeback for HLSLOutParamExpr. if (const HLSLOutParamExpr *OE = dyn_cast(E)) { LValue LV = EmitLValue(E); - if (!OE->canElide()) - args.addWriteback(EmitLValue(OE->getBase()), LV.getAddress(), nullptr); + if (!OE->canElide()) { + if (const Expr *WB = OE->getWriteback()) + args.addWriteback(EmitLValue(WB), LV.getAddress(), nullptr); + else + args.addWriteback(EmitLValue(OE->getBase()), LV.getAddress(), nullptr); + } return args.add(RValue::get(LV.getAddress()), type); } // HLSL Change Ends. diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index dd1ff233df..206a612a25 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -55,12 +55,19 @@ class HLSLOutParamBuilder { // If the types mismatch we _may_ have some casting to perform. if (Ty != Base->getType()) { - ExprResult Res = Sema.PerformImplicitConversion(Base, Ty, Sema::AA_Passing); + ExprResult Res = + Sema.PerformImplicitConversion(Base, Ty, Sema::AA_Passing); if (Res.isInvalid()) return ExprError(); - Base = Res.get(); - return ExprResult( - new (Ctx) HLSLOutParamExpr(Ty, Base, P->hasAttr())); + Expr *NewBase = new (Ctx) MaterializeTemporaryExpr(Ty, Res.get(), true); + HLSLOutParamExpr *OutExpr = + new (Ctx) HLSLOutParamExpr(Ty, NewBase, P->hasAttr()); + Res = Sema.PerformImplicitConversion(NewBase, Base->getType(), + Sema::AA_Passing); + if (Res.isInvalid()) + return ExprError(); + OutExpr->setWriteback(Res.get()); + return ExprResult(OutExpr); } DeclFinder DF; From c9a82994dcf1f3a00ac3c07370541965310599d0 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 13 Mar 2023 10:46:06 -0500 Subject: [PATCH 11/98] Working with writeback casting I need to clean up the lvalue bindings in CGF, but otherwise this is going in the right direction. --- tools/clang/include/clang/AST/Expr.h | 21 +++++++++++++++++--- tools/clang/lib/AST/ASTDumper.cpp | 7 +++++++ tools/clang/lib/AST/ExprConstant.cpp | 1 + tools/clang/lib/CodeGen/CGCall.cpp | 23 +++++++++++++++------- tools/clang/lib/CodeGen/CGCall.h | 5 ++++- tools/clang/lib/CodeGen/CGExpr.cpp | 16 ++++++++++----- tools/clang/lib/CodeGen/CGExprScalar.cpp | 7 +++++-- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 12 +++++++---- 8 files changed, 70 insertions(+), 22 deletions(-) diff --git a/tools/clang/include/clang/AST/Expr.h b/tools/clang/include/clang/AST/Expr.h index 73eeac6be9..3df758ead5 100644 --- a/tools/clang/include/clang/AST/Expr.h +++ b/tools/clang/include/clang/AST/Expr.h @@ -824,6 +824,7 @@ class OpaqueValueExpr : public Expr { friend class ASTStmtReader; Expr *SourceExpr; SourceLocation Loc; + bool SourceIsParent; // HLSL Change public: OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, @@ -835,8 +836,7 @@ class OpaqueValueExpr : public Expr { (SourceExpr && SourceExpr->isValueDependent()), T->isInstantiationDependentType(), false), - SourceExpr(SourceExpr), Loc(Loc) { - } + SourceExpr(SourceExpr), Loc(Loc), SourceIsParent(false) {} // HLSL Change /// Given an expression which invokes a copy constructor --- i.e. a /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups --- @@ -875,6 +875,11 @@ class OpaqueValueExpr : public Expr { static bool classof(const Stmt *T) { return T->getStmtClass() == OpaqueValueExprClass; } + + // HLSL Change start + bool sourceIsParent() const { return SourceIsParent; } + void setSourceIsParent(bool B = true) { SourceIsParent = B; } + // HLSL Change end }; /// \brief A reference to a declared variable, function, enum, etc. @@ -4756,6 +4761,8 @@ class HLSLVectorElementExpr : public Expr { class HLSLOutParamExpr : public Expr { Expr *Base; Expr *Writeback; + Expr *SrcLV; + OpaqueValueExpr *OpaqueVal; bool IsInOut; bool CanElide; @@ -4776,6 +4783,14 @@ class HLSLOutParamExpr : public Expr { Expr *getWriteback() { return Writeback; } void setWriteback(Expr *E) { Writeback = E; } + const Expr *getSrcLV() const { return SrcLV; } + Expr *getSrcLV() { return SrcLV; } + void setSrcLV(Expr *E) { SrcLV = E; } + + const OpaqueValueExpr *getOpaqueValue() const { return OpaqueVal; } + OpaqueValueExpr *getOpaqueValue() { return OpaqueVal; } + void setOpaqueValue(OpaqueValueExpr *E) { OpaqueVal = E; } + bool isInOut() const { return IsInOut; } bool canElide() const { return CanElide; } @@ -4791,7 +4806,7 @@ class HLSLOutParamExpr : public Expr { // Iterators child_range children() { - return child_range((Stmt **)&Base, (Stmt **)&Base + (Writeback ? 2 : 1)); + return child_range((Stmt **)&Base, (Stmt **)&Base + 1); } }; // HLSL Change Ends diff --git a/tools/clang/lib/AST/ASTDumper.cpp b/tools/clang/lib/AST/ASTDumper.cpp index 9a10058602..1effe0dbd7 100644 --- a/tools/clang/lib/AST/ASTDumper.cpp +++ b/tools/clang/lib/AST/ASTDumper.cpp @@ -2034,6 +2034,8 @@ void ASTDumper::VisitHLSLOutParamExpr(const HLSLOutParamExpr *Node) { OS << (Node->isInOut() ? " inout" : " out"); if (Node->canElide()) OS << " can elide"; + if (const auto *WB = Node->getWriteback()) + dumpStmt(WB); } // HLSL Change Ends @@ -2060,6 +2062,11 @@ void ASTDumper::VisitBlockExpr(const BlockExpr *Node) { void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { VisitExpr(Node); + // HLSL Change start + if (Node->sourceIsParent()) + return; + // HLSL Change end + if (Expr *Source = Node->getSourceExpr()) dumpStmt(Source); } diff --git a/tools/clang/lib/AST/ExprConstant.cpp b/tools/clang/lib/AST/ExprConstant.cpp index 5e8d4700bd..2e654bbde1 100644 --- a/tools/clang/lib/AST/ExprConstant.cpp +++ b/tools/clang/lib/AST/ExprConstant.cpp @@ -9026,6 +9026,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::ExtVectorElementExprClass: case Expr::ExtMatrixElementExprClass: // HLSL Change case Expr::HLSLVectorElementExprClass: // HLSL Change + case Expr::HLSLOutParamExprClass: // HLSL Change case Expr::DesignatedInitExprClass: case Expr::NoInitExprClass: case Expr::DesignatedInitUpdateExprClass: diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index 8d005d31a2..d409f41122 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -2595,11 +2595,23 @@ static void emitWriteback(CodeGenFunction &CGF, assert(!isProvablyNull(srcAddr) && "shouldn't have writeback for provably null argument"); + if (CGF.getLangOpts().HLSL) { + RValue TmpVal; + if (writeback.CastExpr) + TmpVal = CGF.EmitAnyExprToTemp(writeback.CastExpr); + else { + llvm::Value *value = CGF.Builder.CreateLoad(writeback.Temporary); + TmpVal = RValue::get(value); + } + CGF.EmitStoreThroughLValue(TmpVal, srcLV); + return; + } + llvm::BasicBlock *contBB = nullptr; // If the argument wasn't provably non-null, we need to null check // before doing the store. - bool provablyNonNull = CGF.getLangOpts().HLSL || isProvablyNonNull(srcAddr); + bool provablyNonNull = isProvablyNonNull(srcAddr); if (!provablyNonNull) { llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback"); contBB = CGF.createBasicBlock("icr.done"); @@ -3002,12 +3014,9 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, // Add writeback for HLSLOutParamExpr. if (const HLSLOutParamExpr *OE = dyn_cast(E)) { LValue LV = EmitLValue(E); - if (!OE->canElide()) { - if (const Expr *WB = OE->getWriteback()) - args.addWriteback(EmitLValue(WB), LV.getAddress(), nullptr); - else - args.addWriteback(EmitLValue(OE->getBase()), LV.getAddress(), nullptr); - } + if (!OE->canElide()) + args.addWriteback(EmitLValue(OE->getSrcLV()), LV.getAddress(), nullptr, + OE->getWriteback()); return args.add(RValue::get(LV.getAddress()), type); } // HLSL Change Ends. diff --git a/tools/clang/lib/CodeGen/CGCall.h b/tools/clang/lib/CodeGen/CGCall.h index 7a4708e5cc..9aa1f2d790 100644 --- a/tools/clang/lib/CodeGen/CGCall.h +++ b/tools/clang/lib/CodeGen/CGCall.h @@ -68,6 +68,8 @@ namespace CodeGen { /// A value to "use" after the writeback, or null. llvm::Value *ToUse; + + const Expr *CastExpr; // HLSL Change }; struct CallArgCleanup { @@ -89,11 +91,12 @@ namespace CodeGen { } void addWriteback(LValue srcLV, llvm::Value *temporary, - llvm::Value *toUse) { + llvm::Value *toUse, const Expr *castExpr = nullptr) { Writeback writeback; writeback.Source = srcLV; writeback.Temporary = temporary; writeback.ToUse = toUse; + writeback.CastExpr = castExpr; Writebacks.push_back(writeback); } diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index cc5394396d..0788b8f87a 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -2970,11 +2970,17 @@ LValue CodeGenFunction::EmitHLSLOutParamExpr(const HLSLOutParamExpr *E) { llvm::Type *Ty = ConvertType(E->getType()); llvm::AllocaInst *OutTemp = CreateTempAlloca(Ty, "out_param"); if (E->isInOut()) { - LValue InitialState = EmitLValue(E->getBase()); - llvm::LoadInst *Ld = Builder.CreateLoad(InitialState.getAddress(), "in_val"); - (void)Builder.CreateStore(Ld, OutTemp); - } - return MakeAddrLValue(OutTemp, E->getType()); + RValue InVal = EmitAnyExprToTemp(E->getBase()); + llvm::Value *V = + InVal.isScalar() + ? InVal.getScalarVal() + : Builder.CreateLoad(InVal.getAggregateAddr(), "in_val"); + (void)Builder.CreateStore(V, OutTemp); + } + LValue Result = MakeAddrLValue(OutTemp, E->getType()); + if (auto *OpV = E->getOpaqueValue()) + OpaqueValueMappingData::bind(*this, OpV, Result); + return Result; } LValue diff --git a/tools/clang/lib/CodeGen/CGExprScalar.cpp b/tools/clang/lib/CodeGen/CGExprScalar.cpp index 0cb993e6f4..2a832b4de4 100644 --- a/tools/clang/lib/CodeGen/CGExprScalar.cpp +++ b/tools/clang/lib/CodeGen/CGExprScalar.cpp @@ -334,8 +334,11 @@ class ScalarExprEmitter Value *VisitConvertVectorExpr(ConvertVectorExpr *E); Value *VisitMemberExpr(MemberExpr *E); Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } - Value *VisitExtMatrixElementExpr(Expr *E) { return EmitLoadOfLValue(E); } // HLSL Change - Value *VisitHLSLVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } // HLSL Change + + // HLSL Change Begin + Value *VisitExtMatrixElementExpr(Expr *E) { return EmitLoadOfLValue(E); } + Value *VisitHLSLVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } + // HLSL Change end Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return EmitLoadOfLValue(E); } diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index 206a612a25..81055364ea 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -59,14 +59,18 @@ class HLSLOutParamBuilder { Sema.PerformImplicitConversion(Base, Ty, Sema::AA_Passing); if (Res.isInvalid()) return ExprError(); - Expr *NewBase = new (Ctx) MaterializeTemporaryExpr(Ty, Res.get(), true); - HLSLOutParamExpr *OutExpr = - new (Ctx) HLSLOutParamExpr(Ty, NewBase, P->hasAttr()); - Res = Sema.PerformImplicitConversion(NewBase, Base->getType(), + HLSLOutParamExpr *OutExpr = new (Ctx) + HLSLOutParamExpr(Ty, Res.get(), P->hasAttr()); + auto *OpV = new (Ctx) OpaqueValueExpr(P->getLocStart(), Ty, VK_LValue, + OK_Ordinary, OutExpr); + Res = Sema.PerformImplicitConversion(OpV, Base->getType(), Sema::AA_Passing); if (Res.isInvalid()) return ExprError(); OutExpr->setWriteback(Res.get()); + OutExpr->setSrcLV(Base); + OutExpr->setOpaqueValue(OpV); + OpV->setSourceIsParent(); return ExprResult(OutExpr); } From 7d9296abe25ba30975a9d97d808a0c38071b6c9f Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 13 Mar 2023 18:56:47 -0500 Subject: [PATCH 12/98] Use the Base if SrcLV is not set SrcLV is Base with its casts stripped, but we only initialize it if we have a writeback cast sequence, otherwise we can just use Base. --- tools/clang/include/clang/AST/Expr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/clang/include/clang/AST/Expr.h b/tools/clang/include/clang/AST/Expr.h index 3df758ead5..dd3db9f54a 100644 --- a/tools/clang/include/clang/AST/Expr.h +++ b/tools/clang/include/clang/AST/Expr.h @@ -4783,8 +4783,8 @@ class HLSLOutParamExpr : public Expr { Expr *getWriteback() { return Writeback; } void setWriteback(Expr *E) { Writeback = E; } - const Expr *getSrcLV() const { return SrcLV; } - Expr *getSrcLV() { return SrcLV; } + const Expr *getSrcLV() const { return SrcLV ? SrcLV : Base; } + Expr *getSrcLV() { return SrcLV ? SrcLV : Base; } void setSrcLV(Expr *E) { SrcLV = E; } const OpaqueValueExpr *getOpaqueValue() const { return OpaqueVal; } From 5d887819da5811d242de75112b81a1197a23892d Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 13 Mar 2023 18:57:11 -0500 Subject: [PATCH 13/98] Revive pointer array decay... yolo! --- tools/clang/lib/CodeGen/CGExpr.cpp | 46 +++++------------------------- tools/clang/lib/Sema/SemaExpr.cpp | 32 +++++++-------------- 2 files changed, 17 insertions(+), 61 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index 0788b8f87a..0f8507e999 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -2697,12 +2697,6 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, if (Idx->getType() != IntPtrTy) Idx = Builder.CreateIntCast(Idx, IntPtrTy, IdxSigned, "idxprom"); - // HLSL Change Starts - const Expr *Array = isSimpleArrayDecayOperand(E->getBase()); - assert((!getLangOpts().HLSL || nullptr == Array) && - "else array decay snuck in AST for HLSL"); - // HLSL Change Ends - // We know that the pointer points to a type of the correct size, unless the // size is a VLA or Objective-C interface. llvm::Value *Address = nullptr; @@ -2750,7 +2744,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, Address = EmitCastToVoidPtr(Base); Address = Builder.CreateGEP(Address, Idx, "arrayidx"); Address = Builder.CreateBitCast(Address, Base->getType()); - } else if (!getLangOpts().HLSL && Array) { // HLSL Change - No Array to pointer decay for HLSL + } else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) { // If this is A[i] where A is an array, the frontend will have decayed the // base to be a ArrayToPointerDecay implicit cast. While correct, it is // inefficient at -O0 to emit a "gep A, 0, 0" when codegen'ing it, then a @@ -2776,38 +2770,12 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, else Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, "arrayidx"); } else { - // HLSL Change Starts - const ArrayType *AT = dyn_cast(E->getBase()->getType()->getCanonicalTypeUnqualified()); - if (getContext().getLangOpts().HLSL && AT) { - LValue ArrayLV; - // For simple multidimensional array indexing, set the 'accessed' flag for - // better bounds-checking of the base expression. - if (const auto *ASE = dyn_cast(E->getBase())) - ArrayLV = EmitArraySubscriptExpr(ASE, /*Accessed*/ true); - else - ArrayLV = EmitLValue(E->getBase()); - llvm::Value *ArrayPtr = ArrayLV.getAddress(); - - llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0); - llvm::Value *Args[] = { Zero, Idx }; - - // Propagate the alignment from the array itself to the result. - ArrayAlignment = ArrayLV.getAlignment(); - - if (getLangOpts().isSignedOverflowDefined()) - Address = Builder.CreateGEP(ArrayPtr, Args, "arrayidx"); - else - Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, "arrayidx"); - - } else { - // HLSL Change Ends - // The base must be a pointer, which is not an aggregate. Emit it. - llvm::Value *Base = EmitScalarExpr(E->getBase()); - if (getLangOpts().isSignedOverflowDefined()) - Address = Builder.CreateGEP(Base, Idx, "arrayidx"); - else - Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx"); - } // HLSL Change + // The base must be a pointer, which is not an aggregate. Emit it. + llvm::Value *Base = EmitScalarExpr(E->getBase()); + if (getLangOpts().isSignedOverflowDefined()) + Address = Builder.CreateGEP(Base, Idx, "arrayidx"); + else + Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx"); } QualType T = E->getBase()->getType()->getPointeeType(); diff --git a/tools/clang/lib/Sema/SemaExpr.cpp b/tools/clang/lib/Sema/SemaExpr.cpp index 15c77d48be..6051462760 100644 --- a/tools/clang/lib/Sema/SemaExpr.cpp +++ b/tools/clang/lib/Sema/SemaExpr.cpp @@ -516,7 +516,7 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) { } E = ImpCastExprToType(E, Context.getPointerType(Ty), CK_FunctionToPointerDecay).get(); - } else if (Ty->isArrayType() && !getLangOpts().HLSL) { // HLSL Change - HLSL does not have pointers; do not decay arrays + } else if (Ty->isArrayType()) { // In C90 mode, arrays only promote to pointers if the array expression is // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has // type 'array of type' is converted to an expression that has type 'pointer @@ -4286,27 +4286,15 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, // wasn't promoted because of the C90 rule that doesn't // allow promoting non-lvalue arrays. Warn, then // force the promotion here. - // HLSL Change Starts - arrays won't decay - if (getLangOpts().HLSL) { - BaseExpr = LHSExp; - IndexExpr = RHSExp; - ResultType = LHSTy->getAsArrayTypeUnsafe()->getElementType(); - // We need to make sure to preserve qualifiers on array types, since these - // are in effect references. - if (LHSTy.hasQualifiers()) - ResultType.setLocalFastQualifiers(LHSTy.getQualifiers().getFastQualifiers()); - } else { - // HLSL Change Ends - Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << - LHSExp->getSourceRange(); - LHSExp = ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy), - CK_ArrayToPointerDecay).get(); - LHSTy = LHSExp->getType(); - - BaseExpr = LHSExp; - IndexExpr = RHSExp; - ResultType = LHSTy->getAs()->getPointeeType(); - } // HLSL Change - end else block + Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << + LHSExp->getSourceRange(); + LHSExp = ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy), + CK_ArrayToPointerDecay).get(); + LHSTy = LHSExp->getType(); + + BaseExpr = LHSExp; + IndexExpr = RHSExp; + ResultType = LHSTy->getAs()->getPointeeType(); } else if (RHSTy->isArrayType()) { // Same as previous, except for 123[f().a] case Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << From 73d731e3d20800f9fbac0e6b7f796553e8ff8015 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 13 Mar 2023 20:37:01 -0500 Subject: [PATCH 14/98] Initialize all fields to nullptr --- tools/clang/include/clang/AST/Expr.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/clang/include/clang/AST/Expr.h b/tools/clang/include/clang/AST/Expr.h index dd3db9f54a..615d07ab5d 100644 --- a/tools/clang/include/clang/AST/Expr.h +++ b/tools/clang/include/clang/AST/Expr.h @@ -4773,7 +4773,8 @@ class HLSLOutParamExpr : public Expr { Base->isTypeDependent(), Base->isValueDependent(), Base->isInstantiationDependent(), Base->containsUnexpandedParameterPack()), - Base(Base), Writeback(nullptr), IsInOut(IsInOut), CanElide(CanElide) {} + Base(Base), Writeback(nullptr), SrcLV(nullptr), OpaqueVal(nullptr), + IsInOut(IsInOut), CanElide(CanElide) {} const Expr *getBase() const { return Base; } Expr *getBase() { return Base; } From 4ac79e7e2cf184c643b3197f83380eff439fbf2e Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 13 Mar 2023 20:38:01 -0500 Subject: [PATCH 15/98] SrcLV isn't always simple This handles SrcLV for non-simple values where the address might not be available. --- tools/clang/lib/CodeGen/CGCall.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index d409f41122..9c1262d6ca 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -2591,10 +2591,7 @@ static bool isProvablyNonNull(llvm::Value *addr) { static void emitWriteback(CodeGenFunction &CGF, const CallArgList::Writeback &writeback) { const LValue &srcLV = writeback.Source; - llvm::Value *srcAddr = srcLV.getAddress(); - assert(!isProvablyNull(srcAddr) && - "shouldn't have writeback for provably null argument"); - + if (CGF.getLangOpts().HLSL) { RValue TmpVal; if (writeback.CastExpr) @@ -2603,10 +2600,18 @@ static void emitWriteback(CodeGenFunction &CGF, llvm::Value *value = CGF.Builder.CreateLoad(writeback.Temporary); TmpVal = RValue::get(value); } - CGF.EmitStoreThroughLValue(TmpVal, srcLV); + if (TmpVal.isScalar()) + CGF.EmitStoreThroughLValue(TmpVal, srcLV); + else + CGF.EmitAggregateCopy(srcLV.getAddress(), TmpVal.getAggregateAddr(), + srcLV.getType()); return; } + llvm::Value *srcAddr = srcLV.getAddress(); + assert(!isProvablyNull(srcAddr) && + "shouldn't have writeback for provably null argument"); + llvm::BasicBlock *contBB = nullptr; // If the argument wasn't provably non-null, we need to null check From 57d35ea27065ba5265919f7f5c190247f87d90c4 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 13 Mar 2023 20:38:28 -0500 Subject: [PATCH 16/98] Look through HLSLOutParamExpr in SemaDXR --- tools/clang/lib/Sema/SemaDXR.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/clang/lib/Sema/SemaDXR.cpp b/tools/clang/lib/Sema/SemaDXR.cpp index d0a72b2844..bde418c647 100644 --- a/tools/clang/lib/Sema/SemaDXR.cpp +++ b/tools/clang/lib/Sema/SemaDXR.cpp @@ -1013,6 +1013,9 @@ DiagnosePayloadAccess(Sema &S, DxrShaderDiagnoseInfo &Info, const Stmt *IgnoreParensAndDecay(const Stmt *S) { for (;;) { switch (S->getStmtClass()) { + case Expr::HLSLOutParamExprClass: + S = cast(S)->getBase(); + break; case Stmt::ParenExprClass: S = cast(S)->getSubExpr(); break; From 194cca7f83e1caa97fc34ee7fa0da3273f4bed85 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 13 Mar 2023 20:38:39 -0500 Subject: [PATCH 17/98] Look through reference type --- tools/clang/lib/AST/HlslTypes.cpp | 6 +++++- tools/clang/lib/CodeGen/CGHLSLMS.cpp | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/clang/lib/AST/HlslTypes.cpp b/tools/clang/lib/AST/HlslTypes.cpp index ffcbe582b9..66c23e6eaa 100644 --- a/tools/clang/lib/AST/HlslTypes.cpp +++ b/tools/clang/lib/AST/HlslTypes.cpp @@ -599,6 +599,7 @@ bool IsHLSLDynamicResourceType(clang::QualType type) { } bool IsHLSLBufferViewType(clang::QualType type) { + type = type.getNonReferenceType(); if (const RecordType *RT = type->getAs()) { StringRef name = RT->getDecl()->getName(); if (name == "ConstantBuffer" || name == "TextureBuffer") @@ -608,6 +609,7 @@ bool IsHLSLBufferViewType(clang::QualType type) { } bool IsHLSLStructuredBufferType(clang::QualType type) { + type = type.getNonReferenceType(); if (const RecordType *RT = type->getAs()) { StringRef name = RT->getDecl()->getName(); if (name == "StructuredBuffer" || name == "RWStructuredBuffer") @@ -626,6 +628,7 @@ bool IsHLSLSubobjectType(clang::QualType type) { } bool IsUserDefinedRecordType(clang::QualType QT) { + QT = QT.getNonReferenceType(); const clang::Type *Ty = QT.getCanonicalType().getTypePtr(); if (const RecordType *RT = dyn_cast(Ty)) { const RecordDecl *RD = RT->getDecl(); @@ -782,7 +785,7 @@ bool GetHLSLSubobjectKind(clang::QualType type, } bool IsHLSLRayQueryType(clang::QualType type) { - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); if (const RecordType *RT = dyn_cast(type)) { if (const ClassTemplateSpecializationDecl *templateDecl = dyn_cast( @@ -797,6 +800,7 @@ bool IsHLSLRayQueryType(clang::QualType type) { QualType GetHLSLResourceResultType(QualType type) { // Don't canonicalize the type as to not lose snorm in Buffer + type = type.getNonReferenceType(); const RecordType *RT = type->getAs(); const RecordDecl *RD = RT->getDecl(); diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 075ac94b0b..892beaceec 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -1283,6 +1283,7 @@ unsigned CGMSHLSLRuntime::AddTypeAnnotation(QualType Ty, return 0; } else { unsigned arraySize = 0; + Ty = Ty.getNonReferenceType(); QualType arrayElementTy = Ty; if (Ty->isConstantArrayType()) { const ConstantArrayType *arrayTy = From a3d55fc2d19e9ea521d4c5aea75676cedea4dd71 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 13 Mar 2023 21:10:17 -0500 Subject: [PATCH 18/98] Cannot convert RValue to LValue... --- tools/clang/lib/Sema/SemaHLSL.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 6b97e251b2..6ee145b2ac 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -8891,6 +8891,10 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, if (source->isFunctionType()) return false; + // We cannot convert from non-lvalue to lvalue references. + if (target->isLValueReferenceType() && !sourceExpr->isLValue()) + return false; + // Convert to an r-value to begin with, with an exception for strings // since they are not first-class values and we want to preserve them as // literals. From e00e98c808cc7673d3ecabeb4d6b65424b3af9d9 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 14 Mar 2023 08:33:17 -0500 Subject: [PATCH 19/98] Another non-reference type lookup --- tools/clang/lib/CodeGen/CGHLSLMS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 892beaceec..afbc2e401d 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -1900,7 +1900,7 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) { const ParmVarDecl *parmDecl = FD->getParamDecl(ParmIdx); - QualType fieldTy = parmDecl->getType(); + QualType fieldTy = parmDecl->getType().getNonReferenceType(); // Save object properties for parameters. AddValToPropertyMap(ArgIt, fieldTy); From 09a14f0c9ea291b8d574a2fba2291c2f7d8b2935 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 14 Mar 2023 08:33:42 -0500 Subject: [PATCH 20/98] Short cut NoOp cast to be LValue --- tools/clang/lib/Sema/SemaCast.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/clang/lib/Sema/SemaCast.cpp b/tools/clang/lib/Sema/SemaCast.cpp index 2d42e4ae7a..10d50229db 100644 --- a/tools/clang/lib/Sema/SemaCast.cpp +++ b/tools/clang/lib/Sema/SemaCast.cpp @@ -2480,6 +2480,11 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, // HLSL Change Begin - HLSL Derived to base casts should be lvalues. QualType DstType = CastTypeInfo->getType(); QualType SrcType = CastExpr->getType(); + if (getLangOpts().HLSL && SrcType.getCanonicalType() == DstType.getCanonicalType()) { + return CStyleCastExpr::Create(Context, DstType, VK_LValue, + CK_NoOp, CastExpr, nullptr, + CastTypeInfo, LPLoc, RPLoc); + } if (getLangOpts().HLSL && isa(*DstType) && isa(*SrcType)) { const auto *DstRT = DstType->getAs(); From 7fdd41243c6dc7ec9eaa9dbecc599286b5020601 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 14 Mar 2023 08:51:58 -0500 Subject: [PATCH 21/98] More non-resource --- tools/clang/lib/AST/HlslTypes.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/AST/HlslTypes.cpp b/tools/clang/lib/AST/HlslTypes.cpp index 66c23e6eaa..03630c236e 100644 --- a/tools/clang/lib/AST/HlslTypes.cpp +++ b/tools/clang/lib/AST/HlslTypes.cpp @@ -139,7 +139,7 @@ bool IsHLSLCopyableAnnotatableRecord(clang::QualType QT) { } bool IsHLSLBuiltinRayAttributeStruct(clang::QualType QT) { - QT = QT.getCanonicalType(); + QT = QT.getNonReferenceType().getCanonicalType(); const clang::Type *Ty = QT.getTypePtr(); if (const RecordType *RT = dyn_cast(Ty)) { const RecordDecl *RD = RT->getDecl(); @@ -249,6 +249,7 @@ bool HasHLSLUNormSNorm(clang::QualType type, bool *pIsSNorm) { } bool HasHLSLGloballyCoherent(clang::QualType type) { + type = type.getNonReferenceType(); const AttributedType *AT = type->getAs(); while (AT) { AttributedType::Kind kind = AT->getAttrKind(); @@ -723,7 +724,7 @@ bool GetHLSLSubobjectKind(clang::QualType type, DXIL::SubobjectKind &subobjectKind, DXIL::HitGroupType &hgType) { hgType = (DXIL::HitGroupType)(-1); - type = type.getCanonicalType(); + type = type.getNonReferenceType().getCanonicalType(); if (const RecordType *RT = type->getAs()) { StringRef name = RT->getDecl()->getName(); switch (name.size()) { @@ -850,6 +851,7 @@ unsigned GetHLSLResourceTemplateUInt(clang::QualType type) { bool IsIncompleteHLSLResourceArrayType(clang::ASTContext &context, clang::QualType type) { + type = type.getNonReferenceType(); if (type->isIncompleteArrayType()) { const IncompleteArrayType *IAT = context.getAsIncompleteArrayType(type); type = IAT->getElementType(); From fcba139797c5e80c3ac38fd02bc6b8f8a0b56844 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 14 Mar 2023 14:11:08 -0500 Subject: [PATCH 22/98] Simplify c-style casting expressions This change simplifies the casting chain for HLSL C-style casts that are either derived to base conversions or casting an object to itself. In both cases HLSL defines returning lvalues. This change collapses the cast chains down. Before this change all the CStyleCastExprs were genreated as `NoOp` casts with `ImplicitCastExpr` cast chains leading up to them. tools/clang/test/HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl --- tools/clang/lib/Sema/SemaCast.cpp | 69 ++++++++------- .../hlsl/classes/derived-to-base-casting.hlsl | 83 +++++++++++++++++++ 2 files changed, 123 insertions(+), 29 deletions(-) create mode 100644 tools/clang/test/HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl diff --git a/tools/clang/lib/Sema/SemaCast.cpp b/tools/clang/lib/Sema/SemaCast.cpp index 10d50229db..09264b61e2 100644 --- a/tools/clang/lib/Sema/SemaCast.cpp +++ b/tools/clang/lib/Sema/SemaCast.cpp @@ -80,6 +80,9 @@ namespace { void CheckReinterpretCast(); void CheckStaticCast(); void CheckDynamicCast(); + // HLSL Change begin + void CheckHLSLCStyleCast(bool FunctionalCast, bool ListInitialization); + // HLSL Change end void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization); void CheckCStyleCast(); @@ -2058,7 +2061,36 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // So we finish by allowing everything that remains - it's got to be two // object pointers. return TC_Success; -} +} + +// HLSL Change Begin +void CastOperation::CheckHLSLCStyleCast(bool FunctionalStyle, + bool ListInitialization) { + QualType SrcType = SrcExpr.get()->getType(); + if (SrcType.getCanonicalType() == DestType.getCanonicalType()) { + ValueKind = VK_LValue; + Kind = CK_NoOp; + ResultType = DestType; + return; + } + if (isa(*DestType) && isa(*SrcType)) { + CXXBasePaths Paths; + if (Self.IsDerivedFrom(SrcType, DestType, Paths)) { + ResultType = DestType; + if (SrcType.getQualifiers().hasAddressSpace()) { + Qualifiers Q = DestType.getQualifiers(); + Q.addAddressSpace(SrcType.getQualifiers().getAddressSpace()); + ResultType = Self.getASTContext().getQualifiedType(DestType, Q); + } + Self.BuildBasePathArray(Paths, BasePath); + ValueKind = VK_LValue; + Kind = CK_HLSLDerivedToBase; + return; + } + } + CheckCXXCStyleCast(FunctionalStyle, ListInitialization); +} +// HLSL Change End void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, bool ListInitialization) { @@ -2477,42 +2509,21 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, TypeSourceInfo *CastTypeInfo, SourceLocation RPLoc, Expr *CastExpr) { - // HLSL Change Begin - HLSL Derived to base casts should be lvalues. - QualType DstType = CastTypeInfo->getType(); - QualType SrcType = CastExpr->getType(); - if (getLangOpts().HLSL && SrcType.getCanonicalType() == DstType.getCanonicalType()) { - return CStyleCastExpr::Create(Context, DstType, VK_LValue, - CK_NoOp, CastExpr, nullptr, - CastTypeInfo, LPLoc, RPLoc); - } - if (getLangOpts().HLSL && isa(*DstType) && - isa(*SrcType)) { - const auto *DstRT = DstType->getAs(); - const auto *SrcRT = SrcType->getAs(); - const auto *DstRD = dyn_cast(DstRT->getDecl()); - const auto *SrcRD = dyn_cast(SrcRT->getDecl()); - if (SrcRD->isDerivedFrom(DstRD)) { - if (SrcType.getQualifiers().hasAddressSpace()) { - Qualifiers Q = DstType.getQualifiers(); - Q.addAddressSpace(SrcType.getQualifiers().getAddressSpace()); - DstType = Context.getQualifiedType(DstType, Q); - } - return CStyleCastExpr::Create(Context, DstType, VK_LValue, - CK_HLSLDerivedToBase, CastExpr, nullptr, - CastTypeInfo, LPLoc, RPLoc); - } - } - CastOperation Op(*this, DstType, CastExpr); - // HLSL Change End - HLSL Derived to base casts should be lvalues. + CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd()); - if (getLangOpts().CPlusPlus) { + // HLSL Change begin + if (getLangOpts().HLSL) { + Op.CheckHLSLCStyleCast(/*FunctionalStyle=*/ false, + isa(CastExpr)); + } else if (getLangOpts().CPlusPlus) { Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false, isa(CastExpr)); } else { Op.CheckCStyleCast(); } + // HLSL Change if (Op.SrcExpr.isInvalid()) return ExprError(); diff --git a/tools/clang/test/HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl new file mode 100644 index 0000000000..1b16084270 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl @@ -0,0 +1,83 @@ +// RUN: %dxc -T lib_6_4 -ast-dump %s | FileCheck %s + + +struct Base { + int b; +}; + +struct Derived : Base { + int d; +}; + +struct DerivedAgain : Derived { + int a; +}; + +void DerivedToBase() { + DerivedAgain da1, da2; + + (Base)da1 = (Base)da2; + (Derived)da1 = (Derived)da2; + (DerivedAgain)da1 = (DerivedAgain)da2; +} + +// CHECK: FunctionDecl {{0x[0-9a-fA-F]+}} line:16:6 DerivedToBase 'void ()' +// CHECK-NEXT: CompoundStmt {{0x[0-9a-fA-F]+}} +// CHECK-NEXT: DeclStmt {{0x[0-9a-fA-F]+}} +// CHECK-NEXT: VarDecl {{0x[0-9a-fA-F]+}} col:16 used da1 'DerivedAgain' +// CHECK-NEXT: VarDecl {{0x[0-9a-fA-F]+}} col:21 used da2 'DerivedAgain' +// CHECK-NEXT: BinaryOperator {{0x[0-9a-fA-F]+}} 'Base' '=' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'Base' lvalue Base)> +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da1' 'DerivedAgain' +// CHECK-NEXT: ImplicitCastExpr {{0x[0-9a-fA-F]+}} 'Base' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'Base' lvalue Base)> +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da2' 'DerivedAgain' +// CHECK-NEXT: BinaryOperator {{0x[0-9a-fA-F]+}} 'Derived' '=' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'Derived' lvalue +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da1' 'DerivedAgain' +// CHECK-NEXT: ImplicitCastExpr {{0x[0-9a-fA-F]+}} 'Derived' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'Derived' lvalue +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da2' 'DerivedAgain' +// CHECK-NEXT: BinaryOperator {{0x[0-9a-fA-F]+}} 'DerivedAgain' '=' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da1' 'DerivedAgain' +// CHECK-NEXT: ImplicitCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da2' 'DerivedAgain' + +groupshared DerivedAgain daGS; + +// CHECK-NEXT: VarDecl {{0x[0-9a-fA-F]+}} col:26 used daGS '__attribute__((address_space(3))) DerivedAgain' +// CHECK-NEXT: HLSLGroupSharedAttr {{0x[0-9a-fA-F]+}} + +void DerivedToBaseGS() { + DerivedAgain da1; + + (Base)da1 = (Base)daGS; + (Derived)da1 = (Derived)daGS; + (DerivedAgain)da1 = (DerivedAgain)daGS; +} + +// CHECK: FunctionDecl {{0x[0-9a-fA-F]+}} line:53:6 DerivedToBaseGS 'void ()' +// CHECK-NEXT: CompoundStmt {{0x[0-9a-fA-F]+}} +// CHECK-NEXT: DeclStmt {{0x[0-9a-fA-F]+}} +// CHECK-NEXT: VarDecl {{0x[0-9a-fA-F]+}} col:16 used da1 'DerivedAgain' +// CHECK-NEXT: BinaryOperator {{0x[0-9a-fA-F]+}} 'Base' '=' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'Base' lvalue Base)> +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da1' 'DerivedAgain' +// CHECK-NEXT: ImplicitCastExpr {{0x[0-9a-fA-F]+}} 'Base' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} '__attribute__((address_space(3))) Base' lvalue Base)> +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} '__attribute__((address_space(3))) DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'daGS' '__attribute__((address_space(3))) DerivedAgain' +// CHECK-NEXT: BinaryOperator {{0x[0-9a-fA-F]+}} 'Derived' '=' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'Derived' lvalue +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da1' 'DerivedAgain' +// CHECK-NEXT: ImplicitCastExpr {{0x[0-9a-fA-F]+}} 'Derived' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} '__attribute__((address_space(3))) Derived' lvalue +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} '__attribute__((address_space(3))) DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'daGS' '__attribute__((address_space(3))) DerivedAgain' +// CHECK-NEXT: BinaryOperator {{0x[0-9a-fA-F]+}} 'DerivedAgain' '=' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da1' 'DerivedAgain' +// CHECK-NEXT: ImplicitCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' +// CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue +// CHECK-NEXT: ImplicitCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' +// CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} '__attribute__((address_space(3))) DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'daGS' '__attribute__((address_space(3))) DerivedAgain' From 33c929b84e12e6c106e33095c831fbd79270ef46 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 15 Mar 2023 13:58:42 -0500 Subject: [PATCH 23/98] Rewriting teh HLSL resource parameter annotation --- tools/clang/lib/CodeGen/CGCall.cpp | 13 +++++++++++++ tools/clang/lib/CodeGen/CGHLSLMS.cpp | 15 +++++++++++++++ tools/clang/lib/CodeGen/CGHLSLRuntime.h | 1 + 3 files changed, 29 insertions(+) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index 9c1262d6ca..04caf56da1 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -3068,6 +3068,19 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, return; } + // HLSL Change begin + // This is a bit hacky... Ideally this would be part of the resource type's + // copy constructor, but we don't have constructors worked out so instead + // performing this on LValueToRValue conversion is the next best thing :(. + if (hlsl::IsHLSLResourceType(E->getType()) && isa(E) && + cast(E)->getCastKind() == CK_LValueToRValue) { + LValue Val = CGM.getHLSLRuntime().EmitResourceParamAnnotation( + *this, cast(E)); + args.add(Val.asAggregateRValue(), type); + return; + } + // HLSL Change end + if (HasAggregateEvalKind && isa(E) && cast(E)->getCastKind() == CK_LValueToRValue) { LValue L = EmitLValue(cast(E)->getSubExpr()); diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index afbc2e401d..dd90cb6a5d 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -212,6 +212,7 @@ class CGMSHLSLRuntime : public CGHLSLRuntime { void ConstructFieldAttributedAnnotation(DxilFieldAnnotation &fieldAnnotation, QualType fieldTy, bool bDefaultRowMajor); + LValue EmitResourceParamAnnotation(CodeGenFunction& CGF, const CastExpr *E) override; std::unordered_map m_ConstVarAnnotationMap; StringSet<> m_PreciseOutputSet; @@ -6006,6 +6007,20 @@ Scope *CGMSHLSLRuntime::MarkScopeEnd(CodeGenFunction &CGF) { return nullptr; } +LValue CGMSHLSLRuntime::EmitResourceParamAnnotation(CodeGenFunction &CGF, + const CastExpr *E) { + LValue LV = CGF.EmitLValue(E->getSubExpr()); + IRBuilder<> Builder(dxilutil::FindAllocaInsertionPt( + CGF.Builder.GetInsertBlock()->getParent())); + llvm::Value *TmpAddr = + Builder.CreateAlloca(CGF.ConvertTypeForMem(E->getType())); + DxilResourceProperties RP = BuildResourceProperty(E->getType()); + CopyAndAnnotateResourceArgument(LV.getAddress(), TmpAddr, RP, *m_pHLModule, + CGF); + return LValue::MakeAddr(TmpAddr, E->getType(), LV.getAlignment(), + CGF.getContext()); +} + CGHLSLRuntime *CodeGen::CreateMSHLSLRuntime(CodeGenModule &CGM) { return new CGMSHLSLRuntime(CGM); } diff --git a/tools/clang/lib/CodeGen/CGHLSLRuntime.h b/tools/clang/lib/CodeGen/CGHLSLRuntime.h index 2a2cf6c68e..66b6f978e9 100644 --- a/tools/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/tools/clang/lib/CodeGen/CGHLSLRuntime.h @@ -45,6 +45,7 @@ class ReturnStmt; class Attr; class VarDecl; class HLSLRootSignatureAttr; +class CastExpr; namespace CodeGen { class CodeGenModule; From 9660c22228e5e6e34e9f47c011d7717407fd2cf9 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 15 Mar 2023 13:59:07 -0500 Subject: [PATCH 24/98] rename temporary parameters to be more HLSL-specific --- tools/clang/lib/CodeGen/CGExpr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index 0f8507e999..b1f76f983c 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -2936,13 +2936,13 @@ LValue CodeGenFunction::EmitHLSLOutParamExpr(const HLSLOutParamExpr *E) { if (E->canElide()) return EmitLValue(E->getBase()); llvm::Type *Ty = ConvertType(E->getType()); - llvm::AllocaInst *OutTemp = CreateTempAlloca(Ty, "out_param"); + llvm::AllocaInst *OutTemp = CreateTempAlloca(Ty, "hlsl.out"); if (E->isInOut()) { RValue InVal = EmitAnyExprToTemp(E->getBase()); llvm::Value *V = InVal.isScalar() ? InVal.getScalarVal() - : Builder.CreateLoad(InVal.getAggregateAddr(), "in_val"); + : Builder.CreateLoad(InVal.getAggregateAddr(), "hlsl.in"); (void)Builder.CreateStore(V, OutTemp); } LValue Result = MakeAddrLValue(OutTemp, E->getType()); From b747fffef4f9616f0a5b7d5aa91eebfa59a3adff Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 15 Mar 2023 13:59:20 -0500 Subject: [PATCH 25/98] Update test error message --- .../HLSLFileCheck/hlsl/intrinsics/atomic/atomic_cast1.hlsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/atomic/atomic_cast1.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/atomic/atomic_cast1.hlsl index 45ba62a770..c891c60626 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/atomic/atomic_cast1.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/atomic/atomic_cast1.hlsl @@ -1,7 +1,7 @@ // RUN: %dxc -E main -T cs_6_0 %s | FileCheck %s // Make sure cast lvalue not work. -// CHECK: cannot compile this unexpected cast lvalue +// CHECK: cannot initialize a parameter of type 'int &' with an rvalue of type 'int' RWBuffer buffer; @@ -10,4 +10,4 @@ void main() { float unused; InterlockedOr((int)buffer[0], 1, unused); -} \ No newline at end of file +} From 05248223382841fda0b3e9c54a3035afcae87acf Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 15 Mar 2023 13:59:30 -0500 Subject: [PATCH 26/98] Update copy-in/copy-out test --- .../functions/arguments/copyin-copyout.hlsl | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl index 6693b1a3f9..f38302b13c 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl @@ -16,33 +16,33 @@ void fn() { } // CHECK: define internal void @"\01?fn{{[@$?.A-Za-z0-9_]+}}"() -// CHECK: [[Tmp1:%[0-9A-Z]+]] = alloca float -// CHECK: [[Tmp2:%[0-9A-Z]+]] = alloca float // CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 // CHECK: [[Y:%[0-9A-Z]+]] = alloca float, align 4 // CHECK: [[Z:%[0-9A-Z]+]] = alloca float, align 4 +// CHECK: [[Tmp1:%[0-9a-z.]+]] = alloca float +// CHECK: [[Tmp2:%[0-9a-z.]+]] = alloca float // First call has no copy-in/copy out parameters since all parameters are unique. // CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Z]]) // Second call, copies X for parameter 2. // CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 -// CHECK: store float [[TmpX]], float* [[Tmp2]] +// CHECK: store float [[TmpX]], float* [[Tmp1]] -// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp2]], float* dereferenceable(4) [[Z]]) +// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp1]], float* dereferenceable(4) [[Z]]) // Second call, saves parameter 2 to X after the call. -// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp2]] +// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp1]] // CHECK: store float [[TmpX]], float* [[X]] // The third call copies X for the third parameter. // CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 -// CHECK: store float [[TmpX]], float* [[Tmp1]] +// CHECK: store float [[TmpX]], float* [[Tmp2]] -// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Tmp1]]) +// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Tmp2]]) // The third call stores parameter 3 to X after the call. -// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp1]] +// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp2]] // CHECK: store float [[TmpX]], float* [[X]] void fn2() { @@ -50,22 +50,22 @@ void fn2() { CalledFunction(X, X, X); } -// CHECK: [[Tmp1:%[0-9A-Z]+]] = alloca float -// CHECK: [[Tmp2:%[0-9A-Z]+]] = alloca float // CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 +// CHECK: [[Tmp1:%[0-9a-z.]+]] = alloca float +// CHECK: [[Tmp2:%[0-9a-z.]+]] = alloca float // X gets copied in for both parameters two and three. // CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 -// CHECK: store float [[TmpX]], float* [[Tmp2]] -// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 // CHECK: store float [[TmpX]], float* [[Tmp1]] +// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 +// CHECK: store float [[TmpX]], float* [[Tmp2]] // CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp2]], float* dereferenceable(4) [[Tmp1]]) // X gets restored from parameter 2 _then_ parameter 3, so the last paramter is // the final value of X. -// CHECK: [[X2:%[0-9A-Z]+]] = load float, float* [[Tmp2]] +// CHECK: [[X2:%[0-9A-Z]+]] = load float, float* [[Tmp1]] // CHECK: store float [[X2]], float* [[X]] -// CHECK: [[X1:%[0-9A-Z]+]] = load float, float* [[Tmp1]] +// CHECK: [[X1:%[0-9A-Z]+]] = load float, float* [[Tmp2]] // CHECK: store float [[X1]], float* [[X]], align 4 // line:31 col:3 From 8c4e5457cb16337b5397b3b04e58207c7a3fc16d Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 15 Mar 2023 14:10:34 -0500 Subject: [PATCH 27/98] Updating test with dereferenceable --- .../HLSLFileCheck/hlsl/functions/arguments/parameter_types.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/parameter_types.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/parameter_types.hlsl index 9f8bf9753d..aa5dd854e1 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/parameter_types.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/parameter_types.hlsl @@ -1,7 +1,7 @@ // RUN: %dxc -E main -T cs_6_0 -fcgl %s | FileCheck %s // CHECK: float %a, <4 x float> %b, %struct.T* %t, %class.matrix.float.2.3 %m, [3 x <2 x float>]* %n -// CHECK: float* noalias dereferenceable(4) %a, <4 x float>* noalias dereferenceable(16) %b, %struct.T* noalias %t, %class.matrix.float.2.3* noalias dereferenceable(24) %m, [3 x <2 x float>]* noalias %n +// CHECK: float* noalias dereferenceable(4) %a, <4 x float>* noalias dereferenceable(16) %b, %struct.T* noalias dereferenceable(20) %t, %class.matrix.float.2.3* noalias dereferenceable(24) %m, [3 x <2 x float>]* noalias dereferenceable(24) %n struct T{ float a; From d21defa9602a272e70f1fdd2d962f90fb843ecb8 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 15 Mar 2023 18:33:33 -0500 Subject: [PATCH 28/98] Add a new AST node to represent array temporaries --- .../clang/AST/DataRecursiveASTVisitor.h | 2 + tools/clang/include/clang/AST/Expr.h | 41 +++++++++++++++++-- .../include/clang/AST/RecursiveASTVisitor.h | 1 + tools/clang/include/clang/Basic/StmtNodes.td | 1 + tools/clang/lib/AST/ASTDumper.cpp | 5 +++ tools/clang/lib/AST/Expr.cpp | 14 +++++++ tools/clang/lib/AST/ExprClassification.cpp | 2 + tools/clang/lib/AST/ExprConstant.cpp | 1 + tools/clang/lib/AST/StmtPrinter.cpp | 2 + tools/clang/lib/AST/StmtProfile.cpp | 5 +++ tools/clang/lib/CodeGen/CGExprAgg.cpp | 8 ++++ tools/clang/lib/CodeGen/CodeGenFunction.h | 8 ++-- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 10 ++--- tools/clang/lib/Sema/SemaExpr.cpp | 7 ++++ tools/clang/lib/Sema/TreeTransform.h | 17 +++++++- 15 files changed, 111 insertions(+), 13 deletions(-) diff --git a/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h b/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h index 6905c275ef..6e037cbe7a 100644 --- a/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h +++ b/tools/clang/include/clang/AST/DataRecursiveASTVisitor.h @@ -2148,6 +2148,8 @@ DEF_TRAVERSE_STMT(ExtMatrixElementExpr, {}) DEF_TRAVERSE_STMT(HLSLVectorElementExpr, {}) DEF_TRAVERSE_STMT(HLSLOutParamExpr, {}) + +DEF_TRAVERSE_STMT(HLSLArrayTemporaryExpr, {}) // HLSL Change end. DEF_TRAVERSE_STMT(VAArgExpr, { diff --git a/tools/clang/include/clang/AST/Expr.h b/tools/clang/include/clang/AST/Expr.h index 615d07ab5d..ccc5f68e8f 100644 --- a/tools/clang/include/clang/AST/Expr.h +++ b/tools/clang/include/clang/AST/Expr.h @@ -4766,9 +4766,7 @@ class HLSLOutParamExpr : public Expr { bool IsInOut; bool CanElide; -public: - HLSLOutParamExpr(QualType Ty, Expr *Base, bool IsInOut = false, - bool CanElide = false) + HLSLOutParamExpr(QualType Ty, Expr *Base, bool IsInOut, bool CanElide) : Expr(HLSLOutParamExprClass, Ty, VK_LValue, OK_Ordinary, Base->isTypeDependent(), Base->isValueDependent(), Base->isInstantiationDependent(), @@ -4776,6 +4774,10 @@ class HLSLOutParamExpr : public Expr { Base(Base), Writeback(nullptr), SrcLV(nullptr), OpaqueVal(nullptr), IsInOut(IsInOut), CanElide(CanElide) {} +public: + static HLSLOutParamExpr *Create(const ASTContext &C, QualType Ty, Expr *Base, + bool IsInOut = false, bool CanElide = false); + const Expr *getBase() const { return Base; } Expr *getBase() { return Base; } void setBase(Expr *E) { Base = E; } @@ -4810,6 +4812,39 @@ class HLSLOutParamExpr : public Expr { return child_range((Stmt **)&Base, (Stmt **)&Base + 1); } }; + +class HLSLArrayTemporaryExpr : public Expr { + Expr *Base; + + HLSLArrayTemporaryExpr(Expr *Base) + : Expr(HLSLArrayTemporaryExprClass, Base->getType(), VK_RValue, + OK_Ordinary, Base->isTypeDependent(), Base->isValueDependent(), + Base->isInstantiationDependent(), + Base->containsUnexpandedParameterPack()), + Base(Base) {} + +public: + static HLSLArrayTemporaryExpr *Create(const ASTContext &C, Expr *Base); + + const Expr *getBase() const { return Base; } + Expr *getBase() { return Base; } + void setBase(Expr *E) { Base = E; } + + SourceLocation getLocStart() const LLVM_READONLY { + return Base->getLocStart(); + } + + SourceLocation getLocEnd() const LLVM_READONLY { return Base->getLocEnd(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == HLSLArrayTemporaryExprClass; + } + + // Iterators + child_range children() { + return child_range((Stmt **)&Base, (Stmt **)&Base + 1); + } +}; // HLSL Change Ends /// BlockExpr - Adaptor class for mixing a BlockDecl with expressions. diff --git a/tools/clang/include/clang/AST/RecursiveASTVisitor.h b/tools/clang/include/clang/AST/RecursiveASTVisitor.h index a613313f6b..1689e9e4ec 100644 --- a/tools/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/tools/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2270,6 +2270,7 @@ DEF_TRAVERSE_STMT(ExtVectorElementExpr, {}) DEF_TRAVERSE_STMT(ExtMatrixElementExpr, {}) // HLSL Change DEF_TRAVERSE_STMT(HLSLVectorElementExpr, {}) // HLSL Change DEF_TRAVERSE_STMT(HLSLOutParamExpr, {}) // HLSL Change +DEF_TRAVERSE_STMT(HLSLArrayTemporaryExpr, {}) // HLSL Change DEF_TRAVERSE_STMT(GNUNullExpr, {}) DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {}) DEF_TRAVERSE_STMT(NoInitExpr, {}) diff --git a/tools/clang/include/clang/Basic/StmtNodes.td b/tools/clang/include/clang/Basic/StmtNodes.td index c0caaa723d..8860002729 100644 --- a/tools/clang/include/clang/Basic/StmtNodes.td +++ b/tools/clang/include/clang/Basic/StmtNodes.td @@ -90,6 +90,7 @@ def ExtMatrixElementExpr : DStmt; def HLSLVectorElementExpr : DStmt; def DiscardStmt : Stmt; def HLSLOutParamExpr : DStmt; +def HLSLArrayTemporaryExpr : DStmt; // HLSL Change Ends // Atomic expressions diff --git a/tools/clang/lib/AST/ASTDumper.cpp b/tools/clang/lib/AST/ASTDumper.cpp index 1effe0dbd7..3edc1ccd2f 100644 --- a/tools/clang/lib/AST/ASTDumper.cpp +++ b/tools/clang/lib/AST/ASTDumper.cpp @@ -510,6 +510,7 @@ namespace { void VisitExtMatrixElementExpr(const ExtMatrixElementExpr *Node); // HLSL Change void VisitHLSLVectorElementExpr(const HLSLVectorElementExpr *Node); // HLSL Change void VisitHLSLOutParamExpr(const HLSLOutParamExpr *Node); // HLSL Change + void VisitHLSLArrayTemporaryExpr(const HLSLArrayTemporaryExpr *Node); void VisitBinaryOperator(const BinaryOperator *Node); void VisitCompoundAssignOperator(const CompoundAssignOperator *Node); void VisitAddrLabelExpr(const AddrLabelExpr *Node); @@ -2037,6 +2038,10 @@ void ASTDumper::VisitHLSLOutParamExpr(const HLSLOutParamExpr *Node) { if (const auto *WB = Node->getWriteback()) dumpStmt(WB); } + +void ASTDumper::VisitHLSLArrayTemporaryExpr(const HLSLArrayTemporaryExpr *Node) { + VisitExpr(Node); +} // HLSL Change Ends void ASTDumper::VisitBinaryOperator(const BinaryOperator *Node) { diff --git a/tools/clang/lib/AST/Expr.cpp b/tools/clang/lib/AST/Expr.cpp index d18c618e96..c04ee3e00b 100644 --- a/tools/clang/lib/AST/Expr.cpp +++ b/tools/clang/lib/AST/Expr.cpp @@ -4362,6 +4362,20 @@ ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(const ASTContext &C, getMethod, setMethod, RB); } +// HLSL Change begin + +HLSLOutParamExpr *HLSLOutParamExpr::Create(const ASTContext &C, QualType Ty, + Expr *Base, bool IsInOut, + bool CanElide) { + return new (C) HLSLOutParamExpr(Ty, Base, IsInOut, CanElide); +} + +HLSLArrayTemporaryExpr * +HLSLArrayTemporaryExpr::Create(const ASTContext &C, Expr *Base) { + return new (C) HLSLArrayTemporaryExpr(Base); +} +// HLSL Change end + AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef args, QualType t, AtomicOp op, SourceLocation RP) : Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary, diff --git a/tools/clang/lib/AST/ExprClassification.cpp b/tools/clang/lib/AST/ExprClassification.cpp index afeb1c8258..69948f61fe 100644 --- a/tools/clang/lib/AST/ExprClassification.cpp +++ b/tools/clang/lib/AST/ExprClassification.cpp @@ -323,6 +323,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { return ClassifyInternal(Ctx, cast(E)->getBase()); case Expr::HLSLOutParamExprClass: return Cl::CL_LValue; + case Expr::HLSLArrayTemporaryExprClass: + return Cl::CL_PRValue; // HLSL Change Ends // Simply look at the actual default argument. diff --git a/tools/clang/lib/AST/ExprConstant.cpp b/tools/clang/lib/AST/ExprConstant.cpp index 2e654bbde1..b307016950 100644 --- a/tools/clang/lib/AST/ExprConstant.cpp +++ b/tools/clang/lib/AST/ExprConstant.cpp @@ -9027,6 +9027,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::ExtMatrixElementExprClass: // HLSL Change case Expr::HLSLVectorElementExprClass: // HLSL Change case Expr::HLSLOutParamExprClass: // HLSL Change + case Expr::HLSLArrayTemporaryExprClass: // HLSL Change case Expr::DesignatedInitExprClass: case Expr::NoInitExprClass: case Expr::DesignatedInitUpdateExprClass: diff --git a/tools/clang/lib/AST/StmtPrinter.cpp b/tools/clang/lib/AST/StmtPrinter.cpp index 0bdbe849c8..4b5d801a61 100644 --- a/tools/clang/lib/AST/StmtPrinter.cpp +++ b/tools/clang/lib/AST/StmtPrinter.cpp @@ -1393,6 +1393,8 @@ void StmtPrinter::VisitHLSLOutParamExpr(HLSLOutParamExpr *Node) { OS << (Node->isInOut() ? "inout " : "out "); PrintExpr(Node->getBase()); } + +void StmtPrinter::VisitHLSLArrayTemporaryExpr(HLSLArrayTemporaryExpr *Node) {} // HLSL Change Ends void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { OS << '('; diff --git a/tools/clang/lib/AST/StmtProfile.cpp b/tools/clang/lib/AST/StmtProfile.cpp index a7a39553b6..3b9b74c5c5 100644 --- a/tools/clang/lib/AST/StmtProfile.cpp +++ b/tools/clang/lib/AST/StmtProfile.cpp @@ -801,6 +801,11 @@ void StmtProfiler::VisitHLSLVectorElementExpr(const HLSLVectorElementExpr *S) { void StmtProfiler::VisitHLSLOutParamExpr(const HLSLOutParamExpr *S) { VisitExpr(S); } + +void StmtProfiler::VisitHLSLArrayTemporaryExpr( + const HLSLArrayTemporaryExpr *S) { + VisitExpr(S); +} // HLSL Change End void StmtProfiler::VisitBlockExpr(const BlockExpr *S) { diff --git a/tools/clang/lib/CodeGen/CGExprAgg.cpp b/tools/clang/lib/CodeGen/CGExprAgg.cpp index ac44ad3d68..7ab735a2ce 100644 --- a/tools/clang/lib/CodeGen/CGExprAgg.cpp +++ b/tools/clang/lib/CodeGen/CGExprAgg.cpp @@ -202,6 +202,8 @@ class AggExprEmitter : public StmtVisitor { void VisitAtomicExpr(AtomicExpr *E) { CGF.EmitAtomicExpr(E, EnsureSlot(E->getType()).getAddr()); } + + void VisitHLSLArrayTemporaryExpr(HLSLArrayTemporaryExpr *E); // HLSL Change }; } // end anonymous namespace. @@ -541,6 +543,12 @@ void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType, // Visitor Methods //===----------------------------------------------------------------------===// +// HLSL Change Begin +void AggExprEmitter::VisitHLSLArrayTemporaryExpr(HLSLArrayTemporaryExpr *E) { + Visit(E->getBase()); +} +// HLSL Change End + void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){ Visit(E->GetTemporaryExpr()); } diff --git a/tools/clang/lib/CodeGen/CodeGenFunction.h b/tools/clang/lib/CodeGen/CodeGenFunction.h index b3249427a0..bcec980bff 100644 --- a/tools/clang/lib/CodeGen/CodeGenFunction.h +++ b/tools/clang/lib/CodeGen/CodeGenFunction.h @@ -2464,9 +2464,11 @@ class CodeGenFunction : public CodeGenTypeCache { LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E, bool Accessed = false); LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); - LValue EmitExtMatrixElementExpr(const ExtMatrixElementExpr *E); // HLSL Change - LValue EmitHLSLVectorElementExpr(const HLSLVectorElementExpr *E); // HLSL Change - LValue EmitHLSLOutParamExpr(const HLSLOutParamExpr *E); // HLSL Change + // HLSL Change begin + LValue EmitExtMatrixElementExpr(const ExtMatrixElementExpr *E); + LValue EmitHLSLVectorElementExpr(const HLSLVectorElementExpr *E); + LValue EmitHLSLOutParamExpr(const HLSLOutParamExpr *E); + // HLSL Change end LValue EmitMemberExpr(const MemberExpr *E); LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index 81055364ea..14e2c698ef 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -59,8 +59,8 @@ class HLSLOutParamBuilder { Sema.PerformImplicitConversion(Base, Ty, Sema::AA_Passing); if (Res.isInvalid()) return ExprError(); - HLSLOutParamExpr *OutExpr = new (Ctx) - HLSLOutParamExpr(Ty, Res.get(), P->hasAttr()); + HLSLOutParamExpr *OutExpr = HLSLOutParamExpr::Create( + Ctx, Ty, Res.get(), P->hasAttr()); auto *OpV = new (Ctx) OpaqueValueExpr(P->getLocStart(), Ty, VK_LValue, OK_Ordinary, OutExpr); Res = Sema.PerformImplicitConversion(OpV, Base->getType(), @@ -83,12 +83,12 @@ class HLSLOutParamBuilder { DF.Decl->getType().getQualifiers().hasAddressSpace() || SeenVars.count(DF.Decl) > 0) return ExprResult( - new (Ctx) HLSLOutParamExpr(Ty, Base, P->hasAttr())); + HLSLOutParamExpr::Create(Ctx, Ty, Base, P->hasAttr())); // Add the decl to the seen list, and generate a HLSLOutParamExpr that can // be elided. SeenVars.insert(DF.Decl); - return ExprResult(new (Ctx) HLSLOutParamExpr( - Ty, Base, P->hasAttr(), true)); + return ExprResult(HLSLOutParamExpr::Create( + Ctx, Ty, Base, P->hasAttr(), true)); } }; diff --git a/tools/clang/lib/Sema/SemaExpr.cpp b/tools/clang/lib/Sema/SemaExpr.cpp index 6051462760..87e0004a87 100644 --- a/tools/clang/lib/Sema/SemaExpr.cpp +++ b/tools/clang/lib/Sema/SemaExpr.cpp @@ -4666,6 +4666,13 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, if (CFAudited) Entity.setParameterCFAudited(); + // HLSL Change begin + // If this is an array and not an oputput, generate an array temporary + // expression here rather than an RValue cast. + if (ProtoArgType->isArrayType() && !Param->isModifierOut()) + Arg = HLSLArrayTemporaryExpr::Create(getASTContext(), Arg); + // HLSL Change end + ExprResult ArgE = PerformCopyInitialization( Entity, SourceLocation(), Arg, IsListInitialization, AllowExplicit); if (ArgE.isInvalid()) diff --git a/tools/clang/lib/Sema/TreeTransform.h b/tools/clang/lib/Sema/TreeTransform.h index 11d682b1c3..86e5537f46 100644 --- a/tools/clang/lib/Sema/TreeTransform.h +++ b/tools/clang/lib/Sema/TreeTransform.h @@ -8204,8 +8204,21 @@ TreeTransform::TransformHLSLOutParamExpr(HLSLOutParamExpr *E) { if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) return E; - return new (getSema().Context) - HLSLOutParamExpr(E->getType(), Base.get(), E->isInOut(), E->canElide()); + return HLSLOutParamExpr::Create(getSema().Context, E->getType(), Base.get(), + E->isInOut(), E->canElide()); +} + +template +ExprResult TreeTransform::TransformHLSLArrayTemporaryExpr( + HLSLArrayTemporaryExpr *E) { + ExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) + return E; + + return HLSLArrayTemporaryExpr::Create(getSema().Context, Base.get()); } // HLSL Change Ends From 99688397617779a134b2ed4eca402115a43a5ebc Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 16 Mar 2023 11:19:43 -0500 Subject: [PATCH 29/98] Fix copy-in/copy-out for member operators --- tools/clang/lib/Sema/SemaOverload.cpp | 17 ++++++++++++++++- .../arguments/copyin-copyout-operators.hlsl | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/Sema/SemaOverload.cpp b/tools/clang/lib/Sema/SemaOverload.cpp index 887fbca6f9..7583c3a2c9 100644 --- a/tools/clang/lib/Sema/SemaOverload.cpp +++ b/tools/clang/lib/Sema/SemaOverload.cpp @@ -30,6 +30,7 @@ #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/SemaHLSL.h" // HLSL Change #include "clang/AST/HlslTypes.h" // HLSL Change +#include "HLSLOutParamBuilder.h" // HLSL Change #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -12259,13 +12260,20 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, TheCall->setArg(0, Object.get()); // Check the argument types. + HLSLOutParamBuilder HLSLBuilder; // HLSL Change for (unsigned i = 0; i != NumParams; i++) { Expr *Arg; if (i < Args.size()) { Arg = Args[i]; // Pass the argument. - + // HLSL Change begin - Convert Array parameters. + // If this is an array and not an oputput, generate an array temporary + // expression here rather than an RValue cast. + ParmVarDecl *Param = Method->getParamDecl(i); + if (Arg->getType()->isArrayType() && !Param->isModifierOut()) + Arg = HLSLArrayTemporaryExpr::Create(getASTContext(), Arg); + // HLSL Change end - Convert Array parameters. ExprResult InputInit = PerformCopyInitialization(InitializedEntity::InitializeParameter( Context, @@ -12274,6 +12282,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, IsError |= InputInit.isInvalid(); Arg = InputInit.getAs(); + // HLSL Change Begin + if (!IsError && Param->isModifierOut()) { + ExprResult ArgE = HLSLBuilder.Create(*this, Param, Arg); + IsError |= ArgE.isInvalid(); + Arg = ArgE.getAs(); + } + // HLSL Change End } else { ExprResult DefArg = BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i)); diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-operators.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-operators.hlsl index 9018362226..ffd1c1d8ef 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-operators.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-operators.hlsl @@ -18,11 +18,11 @@ void fn() { } // CHECK: define internal void @"\01?fn{{[@$?.A-Za-z0-9_]+}}"() -// CHECK: [[Tmp1:%[0-9A-Z]+]] = alloca float // CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 // CHECK: [[Z:%[0-9A-Z]+]] = alloca float, align 4 // CHECK: [[Y:%[0-9A-Z]+]] = alloca i32, align 4 // CHECK: [[D:%[0-9A-Z]+]] = alloca %struct.Doggo +// CHECK: [[Tmp1:%[0-9a-z.]+]] = alloca float // First call has no copy-in/copy out parameters since all parameters are unique. // CHECK: call void @"\01??RDoggo{{[@$?.A-Za-z0-9_]+}}"(%struct.Doggo* [[D]], float* dereferenceable(4) [[X]], i32* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Z]]) From f6d5fc4d587471fbfa584fb78fcea2a0e6cb0063 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 16 Mar 2023 16:09:20 -0500 Subject: [PATCH 30/98] Don't run the parameter legalizaiton pass This should all be done at the AST level --- include/dxc/HLSL/DxilGenerationPass.h | 3 - lib/HLSL/CMakeLists.txt | 1 - lib/HLSL/HLLegalizeParameter.cpp | 330 ---------------------- lib/Transforms/IPO/PassManagerBuilder.cpp | 3 - utils/hct/hctdb.py | 1 - 5 files changed, 338 deletions(-) delete mode 100644 lib/HLSL/HLLegalizeParameter.cpp diff --git a/include/dxc/HLSL/DxilGenerationPass.h b/include/dxc/HLSL/DxilGenerationPass.h index c77ddab3d0..dc35d61820 100644 --- a/include/dxc/HLSL/DxilGenerationPass.h +++ b/include/dxc/HLSL/DxilGenerationPass.h @@ -125,9 +125,6 @@ void initializeCleanupDxBreakPass(llvm::PassRegistry &); FunctionPass *createDxilLoopDeletionPass(bool NoSink); void initializeDxilLoopDeletionPass(llvm::PassRegistry &); -ModulePass *createHLLegalizeParameter(); -void initializeHLLegalizeParameterPass(llvm::PassRegistry &); - bool AreDxilResourcesDense(llvm::Module *M, hlsl::DxilResourceBase **ppNonDense); diff --git a/lib/HLSL/CMakeLists.txt b/lib/HLSL/CMakeLists.txt index 0f1e3fd381..4883470eaf 100644 --- a/lib/HLSL/CMakeLists.txt +++ b/lib/HLSL/CMakeLists.txt @@ -36,7 +36,6 @@ add_llvm_library(LLVMHLSL DxcOptimizer.cpp HLDeadFunctionElimination.cpp HLExpandStoreIntrinsics.cpp - HLLegalizeParameter.cpp HLLowerUDT.cpp HLMatrixBitcastLowerPass.cpp HLMatrixLowerPass.cpp diff --git a/lib/HLSL/HLLegalizeParameter.cpp b/lib/HLSL/HLLegalizeParameter.cpp deleted file mode 100644 index 141f163e15..0000000000 --- a/lib/HLSL/HLLegalizeParameter.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// // -// HLLegalizeParameter.cpp // -// Copyright (C) Microsoft Corporation. All rights reserved. // -// This file is distributed under the University of Illinois Open Source // -// License. See LICENSE.TXT for details. // -// // -// Legalize in parameter has write and out parameter has read. // -// Must be call before inline pass. // -/////////////////////////////////////////////////////////////////////////////// - -#include "dxc/DXIL/DxilOperations.h" -#include "dxc/DXIL/DxilTypeSystem.h" -#include "dxc/DXIL/DxilUtil.h" -#include "dxc/HLSL/DxilGenerationPass.h" -#include "dxc/HLSL/HLModule.h" -#include "dxc/HLSL/HLUtil.h" - -#include "llvm/IR/IntrinsicInst.h" - -#include "dxc/Support/Global.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/IR/Constant.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/Casting.h" - -#include - -using namespace llvm; -using namespace hlsl; - -// For parameter need to legalize, create alloca to replace all uses of it, and -// copy between the alloca and the parameter. - -namespace { - -class HLLegalizeParameter : public ModulePass { -public: - static char ID; - explicit HLLegalizeParameter() : ModulePass(ID) {} - bool runOnModule(Module &M) override; - -private: - void patchWriteOnInParam(Function &F, Argument &Arg, const DataLayout &DL); - void patchReadOnOutParam(Function &F, Argument &Arg, const DataLayout &DL); -}; - -AllocaInst *createAllocaForPatch(Function &F, Type *Ty) { - IRBuilder<> Builder(F.getEntryBlock().getFirstInsertionPt()); - return Builder.CreateAlloca(Ty); -} - -void copyIn(AllocaInst *temp, Value *arg, CallInst *CI, unsigned size) { - if (size == 0) - return; - // Copy arg to temp before CI. - IRBuilder<> Builder(CI); - Builder.CreateMemCpy(temp, arg, size, 1); -} - -void copyOut(AllocaInst *temp, Value *arg, CallInst *CI, unsigned size) { - if (size == 0) - return; - // Copy temp to arg after CI. - IRBuilder<> Builder(CI->getNextNode()); - Builder.CreateMemCpy(arg, temp, size, 1); -} - -bool isPointerNeedToLower(Value *V, Type *HandleTy) { - // CBuffer, Buffer, Texture.... - // Anything related to dxil op. - // hl.subscript. - // Got to root of GEP. - while (GEPOperator *GEP = dyn_cast(V)) { - V = GEP->getPointerOperand(); - } - CallInst *CI = dyn_cast(V); - if (!CI) { - // If array of vector, we need a copy to handle vector to array in - // LowerTypePasses. - Type *Ty = V->getType(); - if (Ty->isPointerTy()) - Ty = Ty->getPointerElementType(); - if (!Ty->isArrayTy()) - return false; - while (Ty->isArrayTy()) { - Ty = Ty->getArrayElementType(); - } - return Ty->isVectorTy(); - } - HLOpcodeGroup group = GetHLOpcodeGroup(CI->getCalledFunction()); - if (group != HLOpcodeGroup::HLSubscript) - return false; - Value *Ptr = CI->getArgOperand(HLOperandIndex::kSubscriptObjectOpIdx); - - // Ptr from resource handle. - if (Ptr->getType() == HandleTy) - return true; - unsigned Opcode = GetHLOpcode(CI); - // Ptr from cbuffer. - if (Opcode == (unsigned)HLSubscriptOpcode::CBufferSubscript) - return true; - - return isPointerNeedToLower(Ptr, HandleTy); -} - -bool mayAliasWithGlobal(Value *V, CallInst *CallSite, - std::vector &staticGVs) { - // The unsafe case need copy-in copy-out will be global variable alias with - // parameter. Then global variable is updated in the function, the parameter - // will be updated silently. - - // Currently add copy for all non-const static global in - // CGMSHLSLRuntime::EmitHLSLOutParamConversionInit. - // So here just return false and do nothing. - // For case like - // struct T { - // float4 a[10]; - //}; - // static T g; - // void foo(inout T t) { - // // modify g - //} - // void bar() { - // T t = g; - // // Not copy because t is local. - // // But optimizations will change t to g later. - // foo(t); - //} - // Optimizations which remove the copy should not replace foo(t) into foo(g) - // when g could be modified. - // TODO: remove copy for global in - // CGMSHLSLRuntime::EmitHLSLOutParamConversionInit, do analysis to check alias - // only generate copy when there's alias. - return false; -} - -struct CopyData { - CallInst *CallSite; - Value *Arg; - bool bCopyIn; - bool bCopyOut; -}; - -void ParameterCopyInCopyOut(hlsl::HLModule &HLM) { - Module &M = *HLM.GetModule(); - Type *HandleTy = HLM.GetOP()->GetHandleType(); - const DataLayout &DL = M.getDataLayout(); - - std::vector staticGVs; - for (GlobalVariable &GV : M.globals()) { - if (dxilutil::IsStaticGlobal(&GV) && !GV.isConstant()) { - staticGVs.emplace_back(&GV); - } - } - - SmallVector WorkList; - for (Function &F : M) { - if (F.user_empty()) - continue; - DxilFunctionAnnotation *Annot = HLM.GetFunctionAnnotation(&F); - // Skip functions don't have annotation, include llvm intrinsic and HLOp - // functions. - if (!Annot) - continue; - - bool bNoInline = - F.hasFnAttribute(llvm::Attribute::NoInline) || F.isDeclaration(); - - for (User *U : F.users()) { - CallInst *CI = dyn_cast(U); - if (!CI) - continue; - for (unsigned i = 0; i < CI->getNumArgOperands(); i++) { - Value *arg = CI->getArgOperand(i); - - if (!arg->getType()->isPointerTy()) - continue; - - DxilParameterAnnotation &ParamAnnot = Annot->GetParameterAnnotation(i); - bool bCopyIn = false; - bool bCopyOut = false; - switch (ParamAnnot.GetParamInputQual()) { - default: - break; - case DxilParamInputQual::In: { - bCopyIn = true; - } break; - case DxilParamInputQual::Out: { - bCopyOut = true; - } break; - case DxilParamInputQual::Inout: { - bCopyIn = true; - bCopyOut = true; - } break; - } - - if (!bCopyIn && !bCopyOut) - continue; - - // When use ptr from cbuffer/buffer, need copy to avoid lower on user - // function. - bool bNeedCopy = mayAliasWithGlobal(arg, CI, staticGVs); - if (bNoInline) - bNeedCopy |= isPointerNeedToLower(arg, HandleTy); - - if (!bNeedCopy) - continue; - - CopyData data = {CI, arg, bCopyIn, bCopyOut}; - WorkList.emplace_back(data); - } - } - } - - for (CopyData &data : WorkList) { - CallInst *CI = data.CallSite; - Value *arg = data.Arg; - Type *Ty = arg->getType()->getPointerElementType(); - Type *EltTy = dxilutil::GetArrayEltTy(Ty); - // Skip on object type and resource type. - if (dxilutil::IsHLSLObjectType(EltTy) || - dxilutil::IsHLSLResourceType(EltTy)) - continue; - unsigned size = DL.getTypeAllocSize(Ty); - AllocaInst *temp = createAllocaForPatch(*CI->getParent()->getParent(), Ty); - // TODO: Adding lifetime intrinsics isn't easy here, have to analyze uses. - if (data.bCopyIn) - copyIn(temp, arg, CI, size); - if (data.bCopyOut) - copyOut(temp, arg, CI, size); - CI->replaceUsesOfWith(arg, temp); - } -} - -} // namespace - -bool HLLegalizeParameter::runOnModule(Module &M) { - HLModule &HLM = M.GetOrCreateHLModule(); - - auto &typeSys = HLM.GetTypeSystem(); - const DataLayout &DL = M.getDataLayout(); - - for (Function &F : M) { - if (F.isDeclaration()) - continue; - DxilFunctionAnnotation *Annot = HLM.GetFunctionAnnotation(&F); - if (!Annot) - continue; - - for (Argument &Arg : F.args()) { - if (!Arg.getType()->isPointerTy()) - continue; - Type *EltTy = dxilutil::GetArrayEltTy(Arg.getType()); - if (dxilutil::IsHLSLObjectType(EltTy) || - dxilutil::IsHLSLResourceType(EltTy)) - continue; - - DxilParameterAnnotation &ParamAnnot = - Annot->GetParameterAnnotation(Arg.getArgNo()); - switch (ParamAnnot.GetParamInputQual()) { - default: - break; - case DxilParamInputQual::In: { - hlutil::PointerStatus PS(&Arg, 0, /*bLdStOnly*/ true); - PS.analyze(typeSys, /*bStructElt*/ false); - if (PS.HasStored()) { - patchWriteOnInParam(F, Arg, DL); - } - } break; - case DxilParamInputQual::Out: { - hlutil::PointerStatus PS(&Arg, 0, /*bLdStOnly*/ true); - PS.analyze(typeSys, /*bStructElt*/ false); - if (PS.HasLoaded()) { - patchReadOnOutParam(F, Arg, DL); - } - } - } - } - } - - // Copy-in copy-out for ptr arg when need. - ParameterCopyInCopyOut(HLM); - - return true; -} - -void HLLegalizeParameter::patchWriteOnInParam(Function &F, Argument &Arg, - const DataLayout &DL) { - // TODO: Adding lifetime intrinsics isn't easy here, have to analyze uses. - Type *Ty = Arg.getType()->getPointerElementType(); - AllocaInst *temp = createAllocaForPatch(F, Ty); - Arg.replaceAllUsesWith(temp); - IRBuilder<> Builder(temp->getNextNode()); - unsigned size = DL.getTypeAllocSize(Ty); - // copy arg to temp at beginning of function. - Builder.CreateMemCpy(temp, &Arg, size, 1); -} - -void HLLegalizeParameter::patchReadOnOutParam(Function &F, Argument &Arg, - const DataLayout &DL) { - // TODO: Adding lifetime intrinsics isn't easy here, have to analyze uses. - Type *Ty = Arg.getType()->getPointerElementType(); - AllocaInst *temp = createAllocaForPatch(F, Ty); - Arg.replaceAllUsesWith(temp); - - unsigned size = DL.getTypeAllocSize(Ty); - for (auto &BB : F.getBasicBlockList()) { - // copy temp to arg before every return. - if (ReturnInst *RI = dyn_cast(BB.getTerminator())) { - IRBuilder<> RetBuilder(RI); - RetBuilder.CreateMemCpy(&Arg, temp, size, 1); - } - } -} - -char HLLegalizeParameter::ID = 0; -ModulePass *llvm::createHLLegalizeParameter() { - return new HLLegalizeParameter(); -} - -INITIALIZE_PASS(HLLegalizeParameter, "hl-legalize-parameter", - "Legalize parameter", false, false) diff --git a/lib/Transforms/IPO/PassManagerBuilder.cpp b/lib/Transforms/IPO/PassManagerBuilder.cpp index a863ca20af..e27aa5c3bc 100644 --- a/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -345,8 +345,6 @@ void PassManagerBuilder::populateModulePassManager( if (HLSLEnableDebugNops) MPM.add(createDxilInsertPreservesPass(HLSLAllowPreserveValues)); // HLSL Change - insert preserve instructions if (Inliner) { - MPM.add(createHLLegalizeParameter()); // HLSL Change - legalize parameters - // before inline. MPM.add(Inliner); Inliner = nullptr; } @@ -406,7 +404,6 @@ void PassManagerBuilder::populateModulePassManager( MPM.add(createDxilRewriteOutputArgDebugInfoPass()); // Fix output argument types. - MPM.add(createHLLegalizeParameter()); // legalize parameters before inline. if (HLSLEarlyInlining && Inliner) { MPM.add(Inliner); Inliner = nullptr; diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index eb2572427e..ff09ddf390 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -2151,7 +2151,6 @@ def add_pass(name, type_name, doc, opts): add_pass('hlsl-hlemit', 'HLEmitMetadata', 'HLSL High-Level Metadata Emit.', []) add_pass("hl-expand-store-intrinsics", "HLExpandStoreIntrinsics", "Expand HLSL store intrinsics", []) - add_pass("hl-legalize-parameter", "HLLegalizeParameter", "Legalize parameter", []) add_pass('scalarrepl-param-hlsl', 'SROA_Parameter_HLSL', 'Scalar Replacement of Aggregates HLSL (parameters)', []) add_pass('static-global-to-alloca', 'LowerStaticGlobalIntoAlloca', 'Lower static global into Alloca', []) add_pass('hlmatrixlower', 'HLMatrixLowerPass', 'HLSL High-Level Matrix Lower', []) From 770bf5c4a2bcc86d43cafdd2c2341c58b0526f04 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 16 Mar 2023 16:22:43 -0500 Subject: [PATCH 31/98] One more non-reference type --- tools/clang/lib/Sema/SemaHLSL.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 6ee145b2ac..2f6f13d29e 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -6869,6 +6869,7 @@ unsigned HLSLExternalSource::GetNumConvertCheckElts(QualType leftType, } QualType HLSLExternalSource::GetNthElementType(QualType type, unsigned index) { + type = type.getNonReferenceType(); if (type.isNull()) { return type; } From b04ab014a3e04badfffe5041ded48faf300dd3c9 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 17 Mar 2023 10:27:36 -0500 Subject: [PATCH 32/98] WIP --- tools/clang/lib/CodeGen/CGExpr.cpp | 1 + tools/clang/lib/Sema/HLSLOutParamBuilder.h | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index b1f76f983c..cdc9c66f39 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -2936,6 +2936,7 @@ LValue CodeGenFunction::EmitHLSLOutParamExpr(const HLSLOutParamExpr *E) { if (E->canElide()) return EmitLValue(E->getBase()); llvm::Type *Ty = ConvertType(E->getType()); + // TODO: Use CreateAggTemp llvm::AllocaInst *OutTemp = CreateTempAlloca(Ty, "hlsl.out"); if (E->isInOut()) { RValue InVal = EmitAnyExprToTemp(E->getBase()); diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index 14e2c698ef..c2c8b4123d 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -53,8 +53,9 @@ class HLSLOutParamBuilder { QualType Ty = P->getType().getNonLValueExprType(Ctx); - // If the types mismatch we _may_ have some casting to perform. - if (Ty != Base->getType()) { + // If the unqualified types mismatch we may have some casting. Since this + // results in a copy we can ignore qualifiers. + if (Ty.getUnqualifiedType() != Base->getType().getUnqualifiedType()) { ExprResult Res = Sema.PerformImplicitConversion(Base, Ty, Sema::AA_Passing); if (Res.isInvalid()) From 941f4826c1c06c72f4e77738f23c8b5b92413ac7 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 17 Mar 2023 11:15:46 -0500 Subject: [PATCH 33/98] Generate input argument temporaries --- tools/clang/lib/CodeGen/CGCall.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index 04caf56da1..9a1f82d6c4 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -3086,10 +3086,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, LValue L = EmitLValue(cast(E)->getSubExpr()); assert(L.isSimple()); if (L.getAlignment() >= getContext().getTypeAlignInChars(type)) { - // HLSL Change Begin - don't copy input arg. - // Copy for out param is done at CGMSHLSLRuntime::EmitHLSLOutParamConversion*. - args.add(L.asAggregateRValue(), type); // /*NeedsCopy*/true); - // HLSL Change End + args.add(L.asAggregateRValue(), type, /*NeedsCopy*/true); } else { // We can't represent a misaligned lvalue in the CallArgList, so copy // to an aligned temporary now. @@ -3101,16 +3098,6 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, return; } - // HLSL Change Begins. - // For DeclRefExpr of aggregate type, don't create temp. - if (HasAggregateEvalKind && LangOptions().HLSL && - isa(E)) { - LValue LV = EmitDeclRefLValue(cast(E)); - RValue RV = RValue::getAggregate(LV.getAddress()); - args.add(RV, type); - return; - } - // HLSL Change Ends. args.add(EmitAnyExprToTemp(E), type); } From 64df9ede4ebd1aaa1bfe862f4ea1de823815cf03 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 17 Mar 2023 12:30:21 -0500 Subject: [PATCH 34/98] Add `ref` qualifier for hct intrinsics --- utils/hct/gen_intrin_main.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/hct/gen_intrin_main.txt b/utils/hct/gen_intrin_main.txt index 26a6cab4f0..01ea609059 100644 --- a/utils/hct/gen_intrin_main.txt +++ b/utils/hct/gen_intrin_main.txt @@ -356,7 +356,7 @@ p32u8 [[rn]] pack_clamp_u8(in sint16or32_only<4> v); void [[]] SetMeshOutputCounts(in uint numVertices, in uint numPrimitives); // Amplification shader intrinsics: -void [[]] DispatchMesh(in uint threadGroupCountX, in uint threadGroupCountY, in uint threadGroupCountZ, in udt meshPayload); +void [[]] DispatchMesh(in uint threadGroupCountX, in uint threadGroupCountY, in uint threadGroupCountZ, ref udt meshPayload); // Return true if the current lane is a helper lane bool [[ro]] IsHelperLane(); From ab7408a2ee4ddc22635490692800e87a0c961e2b Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 17 Mar 2023 13:42:31 -0500 Subject: [PATCH 35/98] Delete hl-legalize test --- .../hl/hl_legalize_param/out_only_param.ll | 119 ------------------ 1 file changed, 119 deletions(-) delete mode 100644 tools/clang/test/HLSLFileCheck/passes/hl/hl_legalize_param/out_only_param.ll diff --git a/tools/clang/test/HLSLFileCheck/passes/hl/hl_legalize_param/out_only_param.ll b/tools/clang/test/HLSLFileCheck/passes/hl/hl_legalize_param/out_only_param.ll deleted file mode 100644 index 3e7d0a6360..0000000000 --- a/tools/clang/test/HLSLFileCheck/passes/hl/hl_legalize_param/out_only_param.ll +++ /dev/null @@ -1,119 +0,0 @@ -; RUN: %opt %s -hl-legalize-parameter -S | FileCheck %s - -; Make sure no memcpy generated. -; CHECK-NOT:memcpy - -;struct ST { -; float4 a; -;}; -; -;ST CreateST(float a) { -; ST st; -; st.a = a; -; return st; -;} -; -;float a; -;ST GetST() { return CreateST(a); } -; -;float4 main() : SV_Target { -; -; return GetST().a; -;} - -target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" -target triple = "dxil-ms-dx" - -%"$Globals" = type { float } -%struct.ST = type { <4 x float> } -%dx.types.Handle = type { i8* } - -@"\01?a@@3MB" = external constant float, align 4 -@"$Globals" = external constant %"$Globals" - -; Function Attrs: nounwind -define <4 x float> @main() #0 { -entry: - %tmp = alloca %struct.ST, align 4 - call void @"\01?GetST@@YA?AUST@@XZ"(%struct.ST* sret %tmp) - %a = getelementptr inbounds %struct.ST, %struct.ST* %tmp, i32 0, i32 0 - %0 = load <4 x float>, <4 x float>* %a, align 4, !tbaa !27 - ret <4 x float> %0 -} - -; Function Attrs: alwaysinline nounwind -define internal void @"\01?GetST@@YA?AUST@@XZ"(%struct.ST* noalias sret %agg.result) #1 { -entry: - %0 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %\22$Globals\22*, i32)"(i32 0, %"$Globals"* @"$Globals", i32 0) - %1 = call %"$Globals"* @"dx.hl.subscript.cb.%\22$Globals\22* (i32, %dx.types.Handle, i32)"(i32 6, %dx.types.Handle %0, i32 0) - %2 = getelementptr inbounds %"$Globals", %"$Globals"* %1, i32 0, i32 0 - %3 = load float, float* %2, align 4, !tbaa !30 - call void @"\01?CreateST@@YA?AUST@@M@Z"(%struct.ST* sret %agg.result, float %3) - ret void -} - -; Function Attrs: alwaysinline nounwind -define internal void @"\01?CreateST@@YA?AUST@@M@Z"(%struct.ST* noalias sret %agg.result, float %a) #1 { -entry: - %a.addr = alloca float, align 4, !dx.temp !13 - store float %a, float* %a.addr, align 4, !tbaa !30 - %0 = load float, float* %a.addr, align 4, !tbaa !30 - %splat.splatinsert = insertelement <4 x float> undef, float %0, i32 0 - %splat.splat = shufflevector <4 x float> %splat.splatinsert, <4 x float> undef, <4 x i32> zeroinitializer - %a1 = getelementptr inbounds %struct.ST, %struct.ST* %agg.result, i32 0, i32 0 - store <4 x float> %splat.splat, <4 x float>* %a1, align 4, !tbaa !27 - ret void -} - -; Function Attrs: nounwind readnone -declare %"$Globals"* @"dx.hl.subscript.cb.%\22$Globals\22* (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #2 - -; Function Attrs: nounwind readnone -declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %\22$Globals\22*, i32)"(i32, %"$Globals"*, i32) #2 - -attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="0" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { alwaysinline nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="0" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #2 = { nounwind readnone } - -!pauseresume = !{!0} -!llvm.ident = !{!1} -!dx.version = !{!2} -!dx.valver = !{!3} -!dx.shaderModel = !{!4} -!dx.typeAnnotations = !{!5, !9} -!dx.entryPoints = !{!20} -!dx.fnprops = !{!24} -!dx.options = !{!25, !26} - -!0 = !{!"hlsl-hlemit", !"hlsl-hlensure"} -!1 = !{!"clang version 3.7 (tags/RELEASE_370/final)"} -!2 = !{i32 1, i32 0} -!3 = !{i32 1, i32 6} -!4 = !{!"ps", i32 6, i32 0} -!5 = !{i32 0, %struct.ST undef, !6, %"$Globals" undef, !8} -!6 = !{i32 16, !7} -!7 = !{i32 6, !"a", i32 3, i32 0, i32 7, i32 9} -!8 = !{i32 4, !7} -!9 = !{i32 1, <4 x float> ()* @main, !10, void (%struct.ST*)* @"\01?GetST@@YA?AUST@@XZ", !14, void (%struct.ST*, float)* @"\01?CreateST@@YA?AUST@@M@Z", !17} -!10 = !{!11} -!11 = !{i32 1, !12, !13} -!12 = !{i32 4, !"SV_Target", i32 7, i32 9} -!13 = !{} -!14 = !{!15, !16} -!15 = !{i32 0, !13, !13} -!16 = !{i32 1, !13, !13} -!17 = !{!15, !16, !18} -!18 = !{i32 0, !19, !13} -!19 = !{i32 7, i32 9} -!20 = !{<4 x float> ()* @main, !"main", null, !21, null} -!21 = !{null, null, !22, null} -!22 = !{!23} -!23 = !{i32 0, %"$Globals"* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 4, null} -!24 = !{<4 x float> ()* @main, i32 0, i1 false} -!25 = !{i32 144} -!26 = !{i32 -1} -!27 = !{!28, !28, i64 0} -!28 = !{!"omnipotent char", !29, i64 0} -!29 = !{!"Simple C/C++ TBAA"} -!30 = !{!31, !31, i64 0} -!31 = !{!"float", !28, i64 0} From c5548a02436709b8b05a53adce71bbc7f6dfa4c0 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 17 Mar 2023 13:42:46 -0500 Subject: [PATCH 36/98] Handle matrix load and store for outparamexpr --- tools/clang/lib/CodeGen/CGCall.cpp | 7 ++++++- tools/clang/lib/CodeGen/CGExpr.cpp | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index 9a1f82d6c4..8bf6ec12db 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -2597,7 +2597,12 @@ static void emitWriteback(CodeGenFunction &CGF, if (writeback.CastExpr) TmpVal = CGF.EmitAnyExprToTemp(writeback.CastExpr); else { - llvm::Value *value = CGF.Builder.CreateLoad(writeback.Temporary); + llvm::Value *value; + if (hlsl::IsHLSLMatType(srcLV.getType())) + value = CGF.CGM.getHLSLRuntime().EmitHLSLMatrixLoad( + CGF, writeback.Temporary, srcLV.getType()); + else + value = CGF.Builder.CreateLoad(writeback.Temporary); TmpVal = RValue::get(value); } if (TmpVal.isScalar()) diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index cdc9c66f39..a684353d28 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -2938,13 +2938,20 @@ LValue CodeGenFunction::EmitHLSLOutParamExpr(const HLSLOutParamExpr *E) { llvm::Type *Ty = ConvertType(E->getType()); // TODO: Use CreateAggTemp llvm::AllocaInst *OutTemp = CreateTempAlloca(Ty, "hlsl.out"); + if (E->isInOut()) { RValue InVal = EmitAnyExprToTemp(E->getBase()); - llvm::Value *V = - InVal.isScalar() - ? InVal.getScalarVal() - : Builder.CreateLoad(InVal.getAggregateAddr(), "hlsl.in"); - (void)Builder.CreateStore(V, OutTemp); + if (hlsl::IsHLSLMatType(E->getType())) { + // Use matrix store to keep major info. + CGM.getHLSLRuntime().EmitHLSLMatrixStore(*this, InVal.getScalarVal(), + OutTemp, E->getType()); + } else { + llvm::Value *V = + InVal.isScalar() + ? InVal.getScalarVal() + : Builder.CreateLoad(InVal.getAggregateAddr(), "hlsl.in"); + (void)Builder.CreateStore(V, OutTemp); + } } LValue Result = MakeAddrLValue(OutTemp, E->getType()); if (auto *OpV = E->getOpaqueValue()) From f0aabc25ab7dbf6c5fd04b3b4a5f1e61e8bf5d6e Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 17 Mar 2023 15:29:47 -0500 Subject: [PATCH 37/98] Another LValueToRValue cast cleanup --- tools/clang/lib/Sema/SemaCast.cpp | 35 +++++++++++++++++----------- tools/clang/lib/Sema/SemaExprCXX.cpp | 2 +- tools/clang/lib/Sema/SemaHLSL.cpp | 14 +++++------ 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/tools/clang/lib/Sema/SemaCast.cpp b/tools/clang/lib/Sema/SemaCast.cpp index 09264b61e2..695455d501 100644 --- a/tools/clang/lib/Sema/SemaCast.cpp +++ b/tools/clang/lib/Sema/SemaCast.cpp @@ -2066,6 +2066,12 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // HLSL Change Begin void CastOperation::CheckHLSLCStyleCast(bool FunctionalStyle, bool ListInitialization) { + if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent() || + SrcExpr.get()->isValueDependent()) { + assert(Kind == CK_Dependent); + return; + } + QualType SrcType = SrcExpr.get()->getType(); if (SrcType.getCanonicalType() == DestType.getCanonicalType()) { ValueKind = VK_LValue; @@ -2088,6 +2094,21 @@ void CastOperation::CheckHLSLCStyleCast(bool FunctionalStyle, return; } } + + // HLSL Change Starts + // Check for HLSL vector/matrix/array/struct shrinking. + if (ValueKind == VK_RValue && + !FunctionalStyle && + !isPlaceholder(BuiltinType::Overload) && + SrcExpr.get()->isLValue() && + // Cannot use casts on basic type l-values + !SrcType.getCanonicalType()->isBuiltinType() && + hlsl::IsConversionToLessOrEqualElements(&Self, SrcExpr, DestType, true)) { + ValueKind = VK_LValue; + DestType = Self.getASTContext().getLValueReferenceType(DestType); + } + // HLSL Change Ends + CheckCXXCStyleCast(FunctionalStyle, ListInitialization); } // HLSL Change End @@ -2135,20 +2156,6 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, return; } - // HLSL Change Starts - // Check for HLSL vector/matrix/array/struct shrinking. - if (ValueKind == VK_RValue && - !FunctionalStyle && - !isPlaceholder(BuiltinType::Overload) && - Self.getLangOpts().HLSL && - SrcExpr.get()->isLValue() && - // Cannot use casts on basic type l-values - !SrcExpr.get()->getType().getCanonicalType()->isBuiltinType() && - hlsl::IsConversionToLessOrEqualElements(&Self, SrcExpr, DestType, true)) { - ValueKind = VK_LValue; - } - // HLSL Change Ends - if (ValueKind == VK_RValue && !DestType->isRecordType() && !isPlaceholder(BuiltinType::Overload)) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get()); diff --git a/tools/clang/lib/Sema/SemaExprCXX.cpp b/tools/clang/lib/Sema/SemaExprCXX.cpp index 16176950cd..c93925ae29 100644 --- a/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -3459,7 +3459,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return ExprError(); From = FromRes.get(); // If this isn't going to a reference we also need an LValueToRValue cast - if (!ToType->isReferenceType()) { + if (!CStyle && !ToType->isReferenceType()) { ExprResult FromRes = DefaultLvalueConversion(From); if (FromRes.isInvalid()) return ExprError(); diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 2f6f13d29e..716f81c572 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -8911,10 +8911,7 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, // Set up a no-op conversion, other than lvalue to rvalue - HLSL does not // support references. standard->setAsIdentityConversion(); - if (needsLValueToRValue) { - standard->First = ICK_Lvalue_To_Rvalue; - } - + standard->First = clang::ICK_Identity; standard->setFromType(source); standard->setAllToTypes(target); } @@ -8960,8 +8957,12 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, if ((SourceInfo.EltKind == AR_OBJECT_CONSTANT_BUFFER || SourceInfo.EltKind == AR_OBJECT_TEXTURE_BUFFER) && TargetInfo.ShapeKind == AR_TOBJ_COMPOUND) { - if (standard) + if (standard) { standard->Second = ICK_Flat_Conversion; + if (needsLValueToRValue) { + standard->First = ICK_Lvalue_To_Rvalue; + } + } return hlsl::GetHLSLResourceResultType(source) == target; } @@ -9090,7 +9091,7 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, if (needsLValueToRValue) { // We don't need LValueToRValue cast before casting a derived object // to its base. - if (Second == ICK_HLSL_Derived_To_Base) { + if (Second == ICK_HLSL_Derived_To_Base || Second == ICK_Flat_Conversion) { standard->First = ICK_Identity; } else { standard->First = ICK_Lvalue_To_Rvalue; @@ -9103,7 +9104,6 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, DXASSERT(false, "We shouldn't be producing these implicit conversion kinds"); break; - case ICK_Flat_Conversion: case ICK_HLSLVector_Splat: standard->First = ICK_Lvalue_To_Rvalue; break; From ecf3227c78ba34e91270b7cc76e6c01b222b3bcc Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 20 Mar 2023 10:31:20 -0500 Subject: [PATCH 38/98] Don't elide copies of non-local storage --- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index c2c8b4123d..0f9b9b7324 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -22,7 +22,7 @@ namespace clang { class HLSLOutParamBuilder { - llvm::DenseSet SeenVars; + llvm::DenseSet SeenVars; // not copyable HLSLOutParamBuilder(const HLSLOutParamBuilder &) = delete; @@ -30,7 +30,7 @@ class HLSLOutParamBuilder { class DeclFinder : public StmtVisitor { public: - ValueDecl *Decl = nullptr; + VarDecl *Decl = nullptr; bool MultipleFound = false; DeclFinder() = default; @@ -40,7 +40,7 @@ class HLSLOutParamBuilder { return; if (Decl) MultipleFound = true; - Decl = cast(DRE->getFoundDecl()); + Decl = dyn_cast(DRE->getFoundDecl()); return; } }; @@ -82,7 +82,7 @@ class HLSLOutParamBuilder { // seen the decl before, generate a HLSLOutParamExpr that can't be elided. if (DF.MultipleFound || DF.Decl == nullptr || DF.Decl->getType().getQualifiers().hasAddressSpace() || - SeenVars.count(DF.Decl) > 0) + SeenVars.count(DF.Decl) > 0 || !DF.Decl->hasLocalStorage()) return ExprResult( HLSLOutParamExpr::Create(Ctx, Ty, Base, P->hasAttr())); // Add the decl to the seen list, and generate a HLSLOutParamExpr that can From b1dc1bd3b05fcafb6698da24cbbd1ca5f6c38bb9 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 20 Mar 2023 10:31:46 -0500 Subject: [PATCH 39/98] Remove an incorrect assert and cleanup lifetime users --- lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp index ae726fbcb6..63c7c4a192 100644 --- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp +++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp @@ -143,6 +143,8 @@ static unsigned getNestedLevelInStruct(const Type *ty) { return lvl; } +static void removeLifetimeUsers(Value *V); + // After SROA'ing a given value into a series of elements, // creates the debug info for the storage of the individual elements. static void addDebugInfoForElements(Value *ParentVal, Type *BrokenUpTy, @@ -1894,6 +1896,7 @@ bool SROAGlobalAndAllocas(HLModule &HLM, bool bHasDbgInfo) { } addDebugInfoForElements(AI, BrokenUpTy, NumInstances, Elts, DL, &DIB); + removeLifetimeUsers(AI); // Push Elts into workList. for (unsigned EltIdx = 0; EltIdx < Elts.size(); ++EltIdx) { @@ -2348,9 +2351,8 @@ void SROA_Helper::RewriteForStore(StoreInst *SI) { } } } - } else { - llvm_unreachable("other type don't need rewrite"); - } + } // Note: other data types we can just eliminate the store, so we don't need + // to rewrite anything here. // Remove the use so that the caller can keep iterating over its other users SI->setOperand(SI->getPointerOperandIndex(), From cd59b3618f9840abda576226d1a409e04d49b315 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 20 Mar 2023 11:03:31 -0500 Subject: [PATCH 40/98] Force implicit types used as paramters to be complete --- tools/clang/lib/Sema/SemaDecl.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tools/clang/lib/Sema/SemaDecl.cpp b/tools/clang/lib/Sema/SemaDecl.cpp index 1d287503a6..446395f390 100644 --- a/tools/clang/lib/Sema/SemaDecl.cpp +++ b/tools/clang/lib/Sema/SemaDecl.cpp @@ -8399,6 +8399,31 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Diag(NewFD->getLocation(), diag::warn_return_value_udt) << NewFD << R; } } + + // HLSL Change begin + // This is a hack... it forces that implicit types used as parameters are + // always completed. This is needed because some diagnostics that should be + // emitted in Sema (probably here-ish), are instead implemented in CodeGen + // (see: CGHLSLMS.cpp). This requires that we have a valid enough AST to + // CodeGen even to just get correct diagnostics emitted. See the test: + // + // test/HLSLFileCheck/shader_targets/raytracing/builtin-ray-types-anyhit.hlsl + if (getLangOpts().HLSL) { + for (auto Param: NewFD->params()) { + QualType PT = Param->getType().getNonReferenceType(); + if (const RecordType *RT = PT->getAs()) { + RecordDecl *RD = RT->getDecl(); + // The diagnostic here doesn't really matter because it should never be + // emitted. + if (RD->isImplicit() && + RequireCompleteType(Param->getLocStart(), PT, + diag::err_call_incomplete_argument)) + llvm_unreachable("Implicit types should never fail to complete."); + NewFD->setInvalidDecl(); + } + } + } + // HLSL Change end return Redeclaration; } From 0713424eafddb354994b4f92002497e9c9ad69ce Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 20 Mar 2023 11:03:48 -0500 Subject: [PATCH 41/98] Simplify looking through reference type --- tools/clang/lib/CodeGen/CGHLSLMS.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index dd90cb6a5d..9914b69905 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -1228,9 +1228,7 @@ unsigned CGMSHLSLRuntime::AddTypeAnnotation(QualType Ty, if (Ty.isNull()) return 0; - QualType paramTy = Ty.getCanonicalType(); - if (const ReferenceType *RefType = dyn_cast(paramTy)) - paramTy = RefType->getPointeeType(); + QualType paramTy = Ty.getNonReferenceType().getCanonicalType(); // Get size. llvm::Type *Type = CGM.getTypes().ConvertType(paramTy); From 16dc5389e5059557e067741bcb05dd787d9ef65a Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 20 Mar 2023 13:48:38 -0500 Subject: [PATCH 42/98] Fix braces :facepalm: --- tools/clang/lib/Sema/SemaDecl.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/Sema/SemaDecl.cpp b/tools/clang/lib/Sema/SemaDecl.cpp index 446395f390..af35865ae9 100644 --- a/tools/clang/lib/Sema/SemaDecl.cpp +++ b/tools/clang/lib/Sema/SemaDecl.cpp @@ -8409,17 +8409,20 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // // test/HLSLFileCheck/shader_targets/raytracing/builtin-ray-types-anyhit.hlsl if (getLangOpts().HLSL) { - for (auto Param: NewFD->params()) { + for (auto Param : NewFD->params()) { QualType PT = Param->getType().getNonReferenceType(); + if (!PT->isRecordType()) + continue; if (const RecordType *RT = PT->getAs()) { RecordDecl *RD = RT->getDecl(); // The diagnostic here doesn't really matter because it should never be // emitted. if (RD->isImplicit() && RequireCompleteType(Param->getLocStart(), PT, - diag::err_call_incomplete_argument)) + diag::err_call_incomplete_argument)) { llvm_unreachable("Implicit types should never fail to complete."); NewFD->setInvalidDecl(); + } } } } From 84fc43b05abfee0a547425b1b68a0a3476839c9f Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 20 Mar 2023 13:48:58 -0500 Subject: [PATCH 43/98] Allow eliding copies for static globals --- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index 0f9b9b7324..c89f8f29fc 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -82,7 +82,7 @@ class HLSLOutParamBuilder { // seen the decl before, generate a HLSLOutParamExpr that can't be elided. if (DF.MultipleFound || DF.Decl == nullptr || DF.Decl->getType().getQualifiers().hasAddressSpace() || - SeenVars.count(DF.Decl) > 0 || !DF.Decl->hasLocalStorage()) + SeenVars.count(DF.Decl) > 0 || DF.Decl->hasExternalStorage()) return ExprResult( HLSLOutParamExpr::Create(Ctx, Ty, Base, P->hasAttr())); // Add the decl to the seen list, and generate a HLSLOutParamExpr that can From 63a4aaf5298869b7e9998706bfb49487f5d511fa Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 20 Mar 2023 18:27:35 -0500 Subject: [PATCH 44/98] Don't rewrite non-constant globals --- lib/Transforms/Scalar/LowerTypePasses.cpp | 8 +++-- .../Scalar/ScalarReplAggregatesHLSL.cpp | 30 ++++++++++--------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/Transforms/Scalar/LowerTypePasses.cpp b/lib/Transforms/Scalar/LowerTypePasses.cpp index 2e57ccfa28..eb4ca1d9d8 100644 --- a/lib/Transforms/Scalar/LowerTypePasses.cpp +++ b/lib/Transforms/Scalar/LowerTypePasses.cpp @@ -307,9 +307,13 @@ void DynamicIndexingVectorToArray::ReplaceStaticIndexingOnVector(Value *V) { bool DynamicIndexingVectorToArray::needToLower(Value *V) { Type *Ty = V->getType()->getPointerElementType(); if (dyn_cast(Ty)) { - if (isa(V) || ReplaceAllVectors) { + if (ReplaceAllVectors) return true; - } + + auto *GV = dyn_cast(V); + if (GV && (!dxilutil::IsStaticGlobal(GV) || GV->isConstant())) + return true; + // Don't lower local vector which only static indexing. if (HasVectorDynamicIndexing(V)) { return true; diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp index 63c7c4a192..5418af2660 100644 --- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp +++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp @@ -1955,12 +1955,15 @@ bool SROAGlobalAndAllocas(HLModule &HLM, bool bHasDbgInfo) { std::vector Elts; bool SROAed = false; - if (GlobalVariable *NewEltGV = dyn_cast_or_null( - TranslatePtrIfUsedByLoweredFn(GV, typeSys))) { - GVDbgOffset dbgOffset = GVDbgOffsetMap[GV]; - // Don't need to update when skip SROA on base GV. - if (NewEltGV == dbgOffset.base) - continue; + // In Library shaders only promote global constants. + if (!HLM.GetShaderModel()->IsLib() || + (!dxilutil::IsStaticGlobal(GV) || GV->isConstant())) { + if (GlobalVariable *NewEltGV = dyn_cast_or_null( + TranslatePtrIfUsedByLoweredFn(GV, typeSys))) { + GVDbgOffset dbgOffset = GVDbgOffsetMap[GV]; + // Don't need to update when skip SROA on base GV. + if (NewEltGV == dbgOffset.base) + continue; if (GV != NewEltGV) { GVDbgOffsetMap[NewEltGV] = dbgOffset; @@ -1972,15 +1975,14 @@ bool SROAGlobalAndAllocas(HLModule &HLM, bool bHasDbgInfo) { GV->eraseFromParent(); staticGVs.remove(GV); } - GV = NewEltGV; + } else { + // SROA_Parameter_HLSL has no access to a domtree, if one is needed, + // it'll be generated + SROAed = SROA_Helper::DoScalarReplacement( + GV, Elts, Builder, bFlatVector, + // TODO: set precise. + /*hasPrecise*/ false, typeSys, DL, DeadInsts, /*DT*/ nullptr); } - } else { - // SROA_Parameter_HLSL has no access to a domtree, if one is needed, - // it'll be generated - SROAed = SROA_Helper::DoScalarReplacement( - GV, Elts, Builder, bFlatVector, - // TODO: set precise. - /*hasPrecise*/ false, typeSys, DL, DeadInsts, /*DT*/ nullptr); } if (SROAed) { From 142b57bb0050a61e893d36e2649796ff0a8d4ea7 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 21 Mar 2023 09:20:40 -0500 Subject: [PATCH 45/98] HLSLVector truncation produces rvalue --- tools/clang/lib/Sema/SemaHLSL.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 716f81c572..21d03037f0 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -8903,7 +8903,6 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, sourceExpr->isLValue() && !target->isLValueReferenceType() && sourceExpr->getStmtClass() != Expr::StringLiteralClass; - bool targetRef = target->isReferenceType(); bool TargetIsAnonymous = false; // Initialize the output standard sequence if available. @@ -9105,6 +9104,7 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, "We shouldn't be producing these implicit conversion kinds"); break; case ICK_HLSLVector_Splat: + case ICK_HLSLVector_Truncation: standard->First = ICK_Lvalue_To_Rvalue; break; default: @@ -9148,13 +9148,6 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, standard->Second = Second; standard->ComponentConversion = ComponentConversion; - - // For conversion which change to RValue but targeting reference type - // Hold the conversion to codeGen - if (targetRef && standard->First == ICK_Lvalue_To_Rvalue) { - standard->First = ICK_Identity; - standard->Second = ICK_Identity; - } } AssignOpt(Remarks, remarks); From 34bacb5c56e2d2cd075c71bfeeb01924254fb174 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 22 Mar 2023 16:19:41 -0500 Subject: [PATCH 46/98] Remove error about truncating matrix lvalue --- tools/clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 -- tools/clang/lib/Sema/Sema.cpp | 7 ------- 2 files changed, 9 deletions(-) diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index f7a38257fa..6461ea4998 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7555,8 +7555,6 @@ def err_hlsl_unsupported_incomplete_array: Error< "array dimensions of struct/class members must be explicit">; def err_hlsl_unsupported_bool_lvalue_op : Error< "operator cannot be used with a bool lvalue">; -def err_hlsl_unsupported_lvalue_cast_op : Error< - "cannot truncate lvalue vector/matrix">; def err_hlsl_unsupported_buffer_packoffset : Error< "packoffset is only allowed within a constant buffer, not on the constant buffer declaration">; def err_hlsl_unsupported_buffer_slot_target_specific : Error< diff --git a/tools/clang/lib/Sema/Sema.cpp b/tools/clang/lib/Sema/Sema.cpp index ab2d023dbb..4af5e994b7 100644 --- a/tools/clang/lib/Sema/Sema.cpp +++ b/tools/clang/lib/Sema/Sema.cpp @@ -360,13 +360,6 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue"); #endif - if (VK == VK_LValue) { - if (Kind == CastKind::CK_HLSLVectorTruncationCast || - Kind == CastKind::CK_HLSLMatrixTruncationCast) { - Diag(E->getLocStart(), diag::err_hlsl_unsupported_lvalue_cast_op); - } - } - // Check whether we're implicitly casting from a nullable type to a nonnull // type. if (auto exprNullability = E->getType()->getNullability(Context)) { From 9c055b9ba7e44c7bee752a4029c36a19bb3e32f5 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 23 Mar 2023 16:35:15 -0500 Subject: [PATCH 47/98] Generate HLSLOutExpr _or_ copy-initialize not both --- tools/clang/lib/Sema/SemaExpr.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/clang/lib/Sema/SemaExpr.cpp b/tools/clang/lib/Sema/SemaExpr.cpp index 87e0004a87..7fc8805bb9 100644 --- a/tools/clang/lib/Sema/SemaExpr.cpp +++ b/tools/clang/lib/Sema/SemaExpr.cpp @@ -4673,15 +4673,15 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, Arg = HLSLArrayTemporaryExpr::Create(getASTContext(), Arg); // HLSL Change end - ExprResult ArgE = PerformCopyInitialization( - Entity, SourceLocation(), Arg, IsListInitialization, AllowExplicit); - if (ArgE.isInvalid()) - return true; - - Arg = ArgE.getAs(); // HLSL Change Begin - Optimize out parameters. if (Param->isModifierOut()) { - ArgE = HLSLBuilder.Create(*this, Param, Arg); + ExprResult ArgE = HLSLBuilder.Create(*this, Param, Arg); + if (ArgE.isInvalid()) + return true; // TODO: Emit an error! + Arg = ArgE.getAs(); + } else { + ExprResult ArgE = PerformCopyInitialization( + Entity, SourceLocation(), Arg, IsListInitialization, AllowExplicit); if (ArgE.isInvalid()) return true; Arg = ArgE.getAs(); From 3fdcff8f972f1e97885e912dfe7683f9997c87d7 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 23 Mar 2023 16:35:44 -0500 Subject: [PATCH 48/98] If we need LValue to RValue, we should always need it... --- tools/clang/lib/Sema/SemaHLSL.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 21d03037f0..9201b2094f 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -9088,13 +9088,7 @@ bool HLSLExternalSource::CanConvert(SourceLocation loc, Expr *sourceExpr, if (standard) { if (sourceExpr->isLValue()) { if (needsLValueToRValue) { - // We don't need LValueToRValue cast before casting a derived object - // to its base. - if (Second == ICK_HLSL_Derived_To_Base || Second == ICK_Flat_Conversion) { - standard->First = ICK_Identity; - } else { - standard->First = ICK_Lvalue_To_Rvalue; - } + standard->First = ICK_Lvalue_To_Rvalue; } else { switch (Second) { case ICK_NoReturn_Adjustment: From fdcc9d7e0db2822fac5ec2b817a65e4a7825c3e5 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 23 Mar 2023 16:36:59 -0500 Subject: [PATCH 49/98] No extra lvalue to rvalue The implicit conversion sequence will have an LValueToRValue conversion if we need it --- tools/clang/lib/Sema/SemaExprCXX.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tools/clang/lib/Sema/SemaExprCXX.cpp b/tools/clang/lib/Sema/SemaExprCXX.cpp index c93925ae29..4104b7b523 100644 --- a/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -3458,13 +3458,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (FromRes.isInvalid()) return ExprError(); From = FromRes.get(); - // If this isn't going to a reference we also need an LValueToRValue cast - if (!CStyle && !ToType->isReferenceType()) { - ExprResult FromRes = DefaultLvalueConversion(From); - if (FromRes.isInvalid()) - return ExprError(); - From = FromRes.get(); - } break; } // HLSL Change Ends From 7ea65861dce55f093994a0f20f8601573a147525 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 23 Mar 2023 16:52:30 -0500 Subject: [PATCH 50/98] Deleting test that verifies a behavior I removed --- .../HLSLFileCheck/hlsl/types/cast/cast7.hlsl | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 tools/clang/test/HLSLFileCheck/hlsl/types/cast/cast7.hlsl diff --git a/tools/clang/test/HLSLFileCheck/hlsl/types/cast/cast7.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/types/cast/cast7.hlsl deleted file mode 100644 index bb7eeca662..0000000000 --- a/tools/clang/test/HLSLFileCheck/hlsl/types/cast/cast7.hlsl +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: %dxc -E main -T ps_6_0 %s -fcgl | FileCheck %s - -// Make sure no bitcast to %struct.A*. -// CHECK-NOT: to %struct.A* - -struct A { - float a; -}; - -struct B : A { - float b; -}; - -A ga; -float2 ib; - -float main() : SV_Target -{ - B b = {ib}; - (A)b = ga; - return ((A)b).a + b.b; -} From f76c1f6fbc2ee248abe0b752dd09a4b586dbd825 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 23 Mar 2023 20:19:31 -0500 Subject: [PATCH 51/98] Properly look through typedef without stripping attributes --- tools/clang/lib/CodeGen/CGHLSLMS.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 9914b69905..0269816044 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -1904,8 +1904,8 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) { AddValToPropertyMap(ArgIt, fieldTy); // if parameter type is a typedef, try to desugar it first. - if (isa(fieldTy.getTypePtr())) - fieldTy = fieldTy.getDesugaredType(FD->getASTContext()); + if (auto T = fieldTy->getAs()) + fieldTy = T->desugar(); ConstructFieldAttributedAnnotation(paramAnnotation, fieldTy, bDefaultRowMajor); if (parmDecl->hasAttr()) From 53f36f37b791571624c4aef5959057426d4874f8 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 23 Mar 2023 20:19:58 -0500 Subject: [PATCH 52/98] Function arguments get converted for memory --- tools/clang/lib/CodeGen/CGExpr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index a684353d28..920099213a 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -2935,7 +2935,7 @@ CodeGenFunction::EmitExtMatrixElementExpr(const ExtMatrixElementExpr *E) { LValue CodeGenFunction::EmitHLSLOutParamExpr(const HLSLOutParamExpr *E) { if (E->canElide()) return EmitLValue(E->getBase()); - llvm::Type *Ty = ConvertType(E->getType()); + llvm::Type *Ty = ConvertTypeForMem(E->getType()); // TODO: Use CreateAggTemp llvm::AllocaInst *OutTemp = CreateTempAlloca(Ty, "hlsl.out"); @@ -2950,6 +2950,8 @@ LValue CodeGenFunction::EmitHLSLOutParamExpr(const HLSLOutParamExpr *E) { InVal.isScalar() ? InVal.getScalarVal() : Builder.CreateLoad(InVal.getAggregateAddr(), "hlsl.in"); + if (V->getType()->getScalarType()->isIntegerTy(1)) + V = Builder.CreateZExt(V, Ty, "frombool"); (void)Builder.CreateStore(V, OutTemp); } } From b71d815216afdebb1dc2fbf436d2712560883b88 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 23 Mar 2023 20:41:59 -0500 Subject: [PATCH 53/98] Updating test --- .../hlsl/types/vector/VectorIndexingAsArgument.hlsl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl index 5cbaf6ce90..92affbf1b5 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl @@ -8,10 +8,12 @@ // CHECK:%[[A4:.*]] = alloca i32 // CHECK:%[[A5:.*]] = alloca i32 // CHECK:%[[A6:.*]] = alloca i32 +// CHECK:%[[A7:.*]] = alloca i32 +// CHECK:%[[A8:.*]] = alloca i32 -// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A0]], i32* nonnull dereferenceable(4) %[[A5]], i32* nonnull dereferenceable(4) %[[A6]]) -// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A4]], i32* nonnull dereferenceable(4) %[[A3]], i32* nonnull dereferenceable(4) %[[A6]]) -// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A2]], i32* nonnull dereferenceable(4) %[[A1]], i32* nonnull dereferenceable(4) %[[A6]]) +// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A2]], i32* nonnull dereferenceable(4) %[[A1]], i32* nonnull dereferenceable(4) %[[A0]]) +// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A5]], i32* nonnull dereferenceable(4) %[[A4]], i32* nonnull dereferenceable(4) %[[A3]]) +// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A8]], i32* nonnull dereferenceable(4) %[[A7]], i32* nonnull dereferenceable(4) %[[A6]]) struct DimStruct { uint2 Dims; From 302de4107948444f93a2254677a67809fc8e18dc Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 23 Mar 2023 20:51:34 -0500 Subject: [PATCH 54/98] Diagnose vector/matrix cast lvalue truncation to scalar --- tools/clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ tools/clang/lib/Sema/HLSLOutParamBuilder.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6461ea4998..f7a38257fa 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7555,6 +7555,8 @@ def err_hlsl_unsupported_incomplete_array: Error< "array dimensions of struct/class members must be explicit">; def err_hlsl_unsupported_bool_lvalue_op : Error< "operator cannot be used with a bool lvalue">; +def err_hlsl_unsupported_lvalue_cast_op : Error< + "cannot truncate lvalue vector/matrix">; def err_hlsl_unsupported_buffer_packoffset : Error< "packoffset is only allowed within a constant buffer, not on the constant buffer declaration">; def err_hlsl_unsupported_buffer_slot_target_specific : Error< diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index c89f8f29fc..8d3c80d08d 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -53,6 +53,11 @@ class HLSLOutParamBuilder { QualType Ty = P->getType().getNonLValueExprType(Ctx); + if(hlsl::IsHLSLVecMatType(Base->getType()) && Ty->isScalarType()) { + Sema.Diag(Base->getLocStart(), diag::err_hlsl_unsupported_lvalue_cast_op); + return ExprError(); + } + // If the unqualified types mismatch we may have some casting. Since this // results in a copy we can ignore qualifiers. if (Ty.getUnqualifiedType() != Base->getType().getUnqualifiedType()) { From af2758592a8d52e4dd8cf765f5f022be3d67db74 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 23 Mar 2023 20:51:45 -0500 Subject: [PATCH 55/98] Fix DXR payload diagnostics --- tools/clang/lib/Sema/SemaDXR.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/lib/Sema/SemaDXR.cpp b/tools/clang/lib/Sema/SemaDXR.cpp index bde418c647..42ff450ad5 100644 --- a/tools/clang/lib/Sema/SemaDXR.cpp +++ b/tools/clang/lib/Sema/SemaDXR.cpp @@ -320,7 +320,7 @@ GetAllReadsReachedFromEntry(CFG &ShaderCFG, ArrayRef PayloadReads) { // Returns the record type of a payload declaration. CXXRecordDecl *GetPayloadType(const VarDecl *Payload) { - auto PayloadType = Payload->getType(); + QualType PayloadType = Payload->getType().getNonReferenceType(); if (PayloadType->isStructureOrClassType()) { return PayloadType->getAsCXXRecordDecl(); } From b7832126d9135ce42c2d73a112b563ddcb04e747 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 27 Mar 2023 10:38:38 -0500 Subject: [PATCH 56/98] Handle flat conversion early Handling flat conversion early prevents array decay in cases where flat conversions are valid. --- tools/clang/lib/Sema/SemaCast.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/clang/lib/Sema/SemaCast.cpp b/tools/clang/lib/Sema/SemaCast.cpp index 695455d501..6a3c6d2673 100644 --- a/tools/clang/lib/Sema/SemaCast.cpp +++ b/tools/clang/lib/Sema/SemaCast.cpp @@ -2094,8 +2094,10 @@ void CastOperation::CheckHLSLCStyleCast(bool FunctionalStyle, return; } } + + bool PossibleFlatConv = + hlsl::IsConversionToLessOrEqualElements(&Self, SrcExpr, DestType, true); - // HLSL Change Starts // Check for HLSL vector/matrix/array/struct shrinking. if (ValueKind == VK_RValue && !FunctionalStyle && @@ -2103,11 +2105,17 @@ void CastOperation::CheckHLSLCStyleCast(bool FunctionalStyle, SrcExpr.get()->isLValue() && // Cannot use casts on basic type l-values !SrcType.getCanonicalType()->isBuiltinType() && - hlsl::IsConversionToLessOrEqualElements(&Self, SrcExpr, DestType, true)) { + PossibleFlatConv) { ValueKind = VK_LValue; DestType = Self.getASTContext().getLValueReferenceType(DestType); } - // HLSL Change Ends + + // If the source is an Array and this is a possible flat conversion we should + // handle it to prevent array to pointer decay. + if (SrcType->isArrayType() && PossibleFlatConv) { + Kind = clang::CK_FlatConversion; + return; + } CheckCXXCStyleCast(FunctionalStyle, ListInitialization); } From a253b4d689038a306e87583ffff7610c4ce7b46a Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 27 Mar 2023 16:11:25 -0500 Subject: [PATCH 57/98] look through reference type --- tools/clang/lib/Sema/SemaDXR.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/clang/lib/Sema/SemaDXR.cpp b/tools/clang/lib/Sema/SemaDXR.cpp index 42ff450ad5..14a5bee566 100644 --- a/tools/clang/lib/Sema/SemaDXR.cpp +++ b/tools/clang/lib/Sema/SemaDXR.cpp @@ -1075,7 +1075,8 @@ bool DiagnosePayloadParameter(Sema &S, ParmVarDecl *Payload, FunctionDecl *FD, return false; } - CXXRecordDecl *Decl = Payload->getType()->getAsCXXRecordDecl(); + CXXRecordDecl *Decl = + Payload->getType().getNonReferenceType()->getAsCXXRecordDecl(); if (!Decl || Decl->isImplicit()) { // error: not a user defined type decl return false; From ad2caf3772533e9dd2a3576a69abbb3a8b5325dc Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 28 Mar 2023 14:34:03 -0500 Subject: [PATCH 58/98] Generate lifetime markers for parameter temporaries --- tools/clang/lib/CodeGen/CGCall.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index 8bf6ec12db..769340ea6c 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -2610,6 +2610,10 @@ static void emitWriteback(CodeGenFunction &CGF, else CGF.EmitAggregateCopy(srcLV.getAddress(), TmpVal.getAggregateAddr(), srcLV.getType()); + uint64_t Sz = CGF.CGM.getDataLayout().getTypeAllocSize( + CGF.ConvertTypeForMem(srcLV.getType())); + CGF.EmitLifetimeEnd(llvm::ConstantInt::get(CGF.Int64Ty, Sz), + writeback.Temporary); return; } @@ -3024,9 +3028,13 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, // Add writeback for HLSLOutParamExpr. if (const HLSLOutParamExpr *OE = dyn_cast(E)) { LValue LV = EmitLValue(E); - if (!OE->canElide()) + if (!OE->canElide()) { + uint64_t Sz = + CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(LV.getType())); + EmitLifetimeStart(Sz, LV.getAddress()); args.addWriteback(EmitLValue(OE->getSrcLV()), LV.getAddress(), nullptr, OE->getWriteback()); + } return args.add(RValue::get(LV.getAddress()), type); } // HLSL Change Ends. From f31d60800c2f6212b4eaddc513e4e3300bcc7bc4 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 30 Mar 2023 14:09:36 -0500 Subject: [PATCH 59/98] Fixing tests where ordering changed --- .../Scenarios/unbounded-resource-arrays.hlsl | 64 +++++++++---------- .../raytracing/raytracing_callable.hlsl | 10 +-- ...raytracing_intersection_geometryIndex.hlsl | 6 +- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/objects/Scenarios/unbounded-resource-arrays.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/objects/Scenarios/unbounded-resource-arrays.hlsl index 847d1f178e..7034504b2b 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/objects/Scenarios/unbounded-resource-arrays.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/objects/Scenarios/unbounded-resource-arrays.hlsl @@ -53,8 +53,8 @@ SamplerComparisonState SampCmp SUB(15) : register(t0, space15); // ConstantBuffer and TextureBuffer get created first -// CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 64, i1 false) -// CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 61, i1 false) +// CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 64, i1 false) +// CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 61, i1 false) ConstantBuffer CBuf SUB(16) : register(b0, space16); // 1*(3+16)*3 + 1*3 + 1 = 61 TextureBuffer TBuf SUB(17) : register(t0, space17); // 1*(3+17)*3 + 1*3 + 1 = 64 @@ -73,34 +73,34 @@ FeedbackTexture2DArray FBTex2DArr SUB(27) : register(u float4 main(int4 a : A, float4 f : F) : SV_Target { - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 13, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 16, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 19, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 22, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 25, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 13, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 16, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 19, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 22, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 25, i1 false) float4 res = Tex1D IDX(0).Load(a.x) // 1*(3+0)*3 + 1*3 + 1 = 13 * Tex1DArr IDX(1).Load(a.xyz) // 1*(3+1)*3 + 1*3 + 1 = 16 * Tex2D IDX(2).Load(a.xyz) // 1*(3+2)*3 + 1*3 + 1 = 19 * Tex2DArr IDX(3).Load(a.xyzw) // 1*(3+3)*3 + 1*3 + 1 = 22 * Tex3D IDX(4).Load(a.xyzw) // 1*(3+4)*3 + 1*3 + 1 = 25 - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 28, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 31, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 34, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 37, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 40, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 28, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 31, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 34, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 37, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 40, i1 false) * RWTex1D IDX(5).Load(a.x) // 1*(3+5)*3 + 1*3 + 1 = 28 * RWTex1DArr IDX(6).Load(a.xy) // 1*(3+6)*3 + 1*3 + 1 = 31 * RWTex2D IDX(7).Load(a.xy) // 1*(3+7)*3 + 1*3 + 1 = 34 * RWTex2DArr IDX(8).Load(a.xyz) // 1*(3+8)*3 + 1*3 + 1 = 37 * RWTex3D IDX(9).Load(a.xyz) // 1*(3+9)*3 + 1*3 + 1 = 40 - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 43, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 46, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 49, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 55, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 52, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 58, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 43, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 46, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 49, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 55, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 52, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 58, i1 false) * Tex2DMS IDX(10).Load(a.xy, a.w) // 1*(3+10)*3 + 1*3 + 1 = 43 * Tex2DMSArr IDX(11).Load(a.xyz, a.w) // 1*(3+11)*3 + 1*3 + 1 = 46 * TexCube IDX(12).Sample(Samp IDX(14), f.xyz) // 1*(3+12)*3 + 1*3 + 1 = 49; 1*(3+14)*3 + 1*3 + 1 = 55 @@ -110,29 +110,29 @@ float4 main(int4 a : A, float4 f : F) : SV_Target { * CBuf IDX(16).f * TBuf IDX(17).f - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 67, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 70, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 73, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 67, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 70, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 73, i1 false) * Buf IDX(18).Load(a.x) // 1*(3+18)*3 + 1*3 + 1 = 67 * SBuf IDX(19).Load(a.x) // 1*(3+19)*3 + 1*3 + 1 = 70 * BABuf IDX(20).Load(a.x) // 1*(3+20)*3 + 1*3 + 1 = 73 - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 76, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 79, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 82, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 85, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 76, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 79, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 82, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 85, i1 false) * RWBuf IDX(21).Load(a.x) // 1*(3+21)*3 + 1*3 + 1 = 76 * RWSBuf IDX(22).Load(a.x) // 1*(3+22)*3 + 1*3 + 1 = 79 * RWBABuf IDX(23).Load(a.x)// 1*(3+23)*3 + 1*3 + 1 = 82 * CSBuf IDX(24).Consume(); // 1*(3+24)*3 + 1*3 + 1 = 85 - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 88, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 91, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 19, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 55, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 94, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 22, i1 false) - // CHECK: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 55, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 88, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 91, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 19, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 55, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 94, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 22, i1 false) + // CHECK-DAG: call %dx.types.Handle @dx.op.createHandle{{.*}}i32 55, i1 false) ASBuf IDX(25).Append(3.0); // 1*(3+25)*3 + 1*3 + 1 = 88 FBTex2D IDX(26).WriteSamplerFeedback(Tex2D IDX(2), Samp IDX(14), f.xy); // 1*(3+26)*3 + 1*3 + 1 = 91; 1*(3+2)*3 + 1*3 + 1 = 19; 1*(3+14)*3 + 1*3 + 1 = 55 FBTex2DArr IDX(27).WriteSamplerFeedback(Tex2DArr IDX(3), Samp IDX(14), f.xyz); // 1*(3+27)*3 + 1*3 + 1 = 94; 1*(3+3)*3 + 1*3 + 1 = 22; 1*(3+14)*3 + 1*3 + 1 = 55 diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_callable.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_callable.hlsl index 298dc20c12..1f4b859ec5 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_callable.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_callable.hlsl @@ -6,11 +6,11 @@ // CHECK:@"\01?T{{[@$?.A-Za-z0-9_]+}}" = external constant %"class.Texture2D >", align 4 // CHECK:@"\01?S{{[@$?.A-Za-z0-9_]+}}" = external constant %struct.SamplerState, align 4 -// CHECK: define void [[callable1:@"\\01\?callable1@[^\"]+"]](%struct.MyParam* noalias nocapture %param) #0 { -// CHECK: %[[i_0:[0-9]+]] = load %struct.SamplerState, %struct.SamplerState* @"\01?S{{[@$?.A-Za-z0-9_]+}}", align 4 -// CHECK: %[[i_1:[0-9]+]] = load %"class.Texture2D >", %"class.Texture2D >"* @"\01?T{{[@$?.A-Za-z0-9_]+}}", align 4 -// CHECK: %[[i_3:[0-9]+]] = call %dx.types.Handle @"dx.op.createHandleForLib.class.Texture2D >"(i32 160, %"class.Texture2D >" %[[i_1]]) -// CHECK: %[[i_4:[0-9]+]] = call %dx.types.Handle @dx.op.createHandleForLib.struct.SamplerState(i32 160, %struct.SamplerState %[[i_0]]) +// CHECK: define void [[callable1:@"\\01\?callable1@[^\"]+"]]( +// CHECK-DAG: %[[i_0:[0-9]+]] = load %struct.SamplerState, %struct.SamplerState* @"\01?S{{[@$?.A-Za-z0-9_]+}}", align 4 +// CHECK-DAG: %[[i_1:[0-9]+]] = load %"class.Texture2D >", %"class.Texture2D >"* @"\01?T{{[@$?.A-Za-z0-9_]+}}", align 4 +// CHECK-DAG: %[[i_3:[0-9]+]] = call %dx.types.Handle @"dx.op.createHandleForLib.class.Texture2D >"(i32 160, %"class.Texture2D >" %[[i_1]]) +// CHECK-DAG: %[[i_4:[0-9]+]] = call %dx.types.Handle @dx.op.createHandleForLib.struct.SamplerState(i32 160, %struct.SamplerState %[[i_0]]) // CHECK: %[[i_7:[0-9]+]] = call %dx.types.ResRet.f32 @dx.op.sampleLevel.f32(i32 62, %dx.types.Handle %[[i_3]], %dx.types.Handle %[[i_4]], float %[[i_5:[0-9]+]], float %[[i_6:[0-9]+]], float undef, float undef, i32 0, i32 0, i32 undef, float 0.000000e+00) // CHECK: ret void diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_intersection_geometryIndex.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_intersection_geometryIndex.hlsl index 12df1ecbcf..d29a09cc9b 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_intersection_geometryIndex.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_intersection_geometryIndex.hlsl @@ -1,9 +1,9 @@ // RUN: %dxc -T lib_6_5 -auto-binding-space 11 %s | FileCheck %s // CHECK: define void [[intersection1:@"\\01\?intersection1@[^\"]+"]]() #0 { -// CHECK: [[rayTCurrent:%[^ ]+]] = call float @dx.op.rayTCurrent.f32(i32 154) -// CHECK: [[GeometryIndex:%[^ ]+]] = call i32 @dx.op.geometryIndex.i32(i32 213) -// CHECK: icmp eq i32 [[GeometryIndex]], 0 +// CHECK-DAG: [[rayTCurrent:%[^ ]+]] = call float @dx.op.rayTCurrent.f32(i32 154) +// CHECK-DAG: [[GeometryIndex:%[^ ]+]] = call i32 @dx.op.geometryIndex.i32(i32 213) +// CHECK-DAG: icmp eq i32 [[GeometryIndex]], 0 // CHECK: call i1 @dx.op.reportHit.struct.MyAttributes(i32 158, float [[rayTCurrent]], i32 0, %struct.MyAttributes* nonnull {{.*}}) // CHECK: ret void From 8b88531356f14511da63f9b023659244dc1a411c Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 30 Mar 2023 14:10:01 -0500 Subject: [PATCH 60/98] Fixing tests where dereferencable signatures updated --- .../shader_targets/raytracing/raytracing_anyhit.hlsl | 2 +- .../raytracing/raytracing_anyhit_geometryIndex.hlsl | 2 +- .../shader_targets/raytracing/raytracing_closesthit.hlsl | 2 +- .../raytracing/raytracing_closesthit_geometryIndex.hlsl | 2 +- .../shader_targets/raytracing/raytracing_miss.hlsl | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_anyhit.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_anyhit.hlsl index 52189aefb2..0236f31fb4 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_anyhit.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_anyhit.hlsl @@ -1,6 +1,6 @@ // RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s -// CHECK: define void [[anyhit1:@"\\01\?anyhit1@[^\"]+"]](%struct.MyPayload* noalias nocapture %payload, %struct.MyAttributes* nocapture readonly %attr) #0 { +// CHECK: define void [[anyhit1:@"\\01\?anyhit1@[^\"]+"]]( // CHECK: call float @dx.op.objectRayOrigin.f32(i32 149, i8 2) // CHECK: call float @dx.op.objectRayDirection.f32(i32 150, i8 2) // CHECK: call float @dx.op.rayTCurrent.f32(i32 154) diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_anyhit_geometryIndex.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_anyhit_geometryIndex.hlsl index 2cb2ab4920..129009fb41 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_anyhit_geometryIndex.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_anyhit_geometryIndex.hlsl @@ -1,6 +1,6 @@ // RUN: %dxc -T lib_6_5 -auto-binding-space 11 %s | FileCheck %s -// CHECK: define void [[anyhit1:@"\\01\?anyhit1@[^\"]+"]](%struct.MyPayload* noalias nocapture %payload, %struct.MyAttributes* nocapture readonly %attr) #0 { +// CHECK: define void [[anyhit1:@"\\01\?anyhit1@[^\"]+"]]( // CHECK: call float @dx.op.objectRayOrigin.f32(i32 149, i8 2) // CHECK: call float @dx.op.objectRayDirection.f32(i32 150, i8 2) // CHECK: call float @dx.op.rayTCurrent.f32(i32 154) diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_closesthit.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_closesthit.hlsl index 32dac74e2d..43a893b567 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_closesthit.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_closesthit.hlsl @@ -1,6 +1,6 @@ // RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s -// CHECK: define void [[closesthit1:@"\\01\?closesthit1@[^\"]+"]](%struct.MyPayload* noalias nocapture %payload, %struct.BuiltInTriangleIntersectionAttributes* nocapture readonly %attr) #0 { +// CHECK: define void [[closesthit1:@"\\01\?closesthit1@[^\"]+"]]( // CHECK: call void @dx.op.callShader.struct.MyParam(i32 159, i32 {{.*}}, %struct.MyParam* nonnull {{.*}}) // CHECK: %[[color:[^ ]+]] = getelementptr inbounds %struct.MyPayload, %struct.MyPayload* %payload, i32 0, i32 0 // CHECK: store <4 x float> {{.*}}, <4 x float>* %[[color]], align 4 diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_closesthit_geometryIndex.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_closesthit_geometryIndex.hlsl index d5a46610ed..f2dcd0a144 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_closesthit_geometryIndex.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_closesthit_geometryIndex.hlsl @@ -1,6 +1,6 @@ // RUN: %dxc -T lib_6_5 -auto-binding-space 11 %s | FileCheck %s -// CHECK: define void [[closesthit1:@"\\01\?closesthit1@[^\"]+"]](%struct.MyPayload* noalias nocapture %payload, %struct.BuiltInTriangleIntersectionAttributes* nocapture readonly %attr) #0 { +// CHECK: define void [[closesthit1:@"\\01\?closesthit1@[^\"]+"]]( // CHECK: [[GeometryIndex:%[^ ]+]] = call i32 @dx.op.geometryIndex.i32(i32 213) // CHECK: icmp eq i32 [[GeometryIndex]], 0 // CHECK: call void @dx.op.callShader.struct.MyParam(i32 159, i32 {{.*}}, %struct.MyParam* nonnull {{.*}}) diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_miss.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_miss.hlsl index f1f3f81867..f6bbf6d3f8 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_miss.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/raytracing/raytracing_miss.hlsl @@ -1,6 +1,6 @@ // RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s -// CHECK: define void [[miss1:@"\\01\?miss1@[^\"]+"]](%struct.MyPayload* noalias nocapture %payload) #0 { +// CHECK: define void [[miss1:@"\\01\?miss1@[^\"]+"]]( // CHECK: %[[result:[^ ]+]] = getelementptr inbounds %struct.MyPayload, %struct.MyPayload* %payload, i32 0, i32 0 // CHECK: store <4 x float> , <4 x float>* %[[result]], align 4 // CHECK: ret void From 9c6f6a2bb58a0b062568b08a45538061fa92283f Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 3 Apr 2023 10:36:43 -0500 Subject: [PATCH 61/98] Updating tests where instruction order shifted --- .../arguments/copyin-copyout-struct.hlsl | 22 +++++++++++-------- .../arguments/global_constant_const.hlsl | 11 ++++++---- .../hlsl/resource_binding/res_in_cb2.hlsl | 6 ++--- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl index 3397651105..669e4d54bd 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl @@ -18,15 +18,19 @@ void fn() { CalledFunction(P.X, P); } -// CHECK: [[TmpP:%[0-9A-Z]+]] = alloca %struct.Pup +// CHECK: define internal void @"\01?fn@ +// CHECK-DAG: [[P:%[0-9A-Z]+]] = alloca %struct.Pup +// CHECK-DAG: [[X:%[0-9A-Z]+]] = alloca float, align 4 +// CHECK-DAG: [[TmpX:%[0-9a-z.]+]] = alloca float -// CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 -// CHECK: [[P:%[0-9A-Z]+]] = alloca %struct.Pup, align 4 -// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], %struct.Pup* [[P]]) +// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], %struct.Pup* dereferenceable(4) [[P]]) -// CHECK: [[TmpPPtr:%[0-9A-Z]+]] = bitcast %struct.Pup* [[TmpP]] to i8* -// CHECK: [[PPtr:%[0-9A-Z]+]] = bitcast %struct.Pup* [[P]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TmpPPtr]], i8* [[PPtr]], i64 4, i32 1, i1 false) +// CHECK: [[PXPtr:%[0-9A-Z]+]] = getelementptr inbounds %struct.Pup, %struct.Pup* [[P]], i32 0, i32 0 +// CHECK: [[PXVal:%[0-9A-Z]+]] = load float, float* [[PXPtr]], align 4 +// CHECK: store float [[PXVal]], float* [[TmpX]] -// CHECK: [[PDotX:%[0-9A-Z]+]] = getelementptr inbounds %struct.Pup, %struct.Pup* [[P]], i32 0, i32 0 -// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[PDotX]], %struct.Pup* [[TmpP]]) +// CHECK-DAG: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[TmpX]], %struct.Pup* dereferenceable(4) [[P]]) +// CHECK-DAG: [[PXPtr2:%[0-9A-Z]+]] = getelementptr inbounds %struct.Pup, %struct.Pup* [[P]], i32 0, i32 0 + +// CHECK: [[TmpVal:%[0-9A-Z]+]] = load float, float* [[TmpX]] +// CHECK: store float [[TmpVal]], float* [[PXPtr2]], align 4 diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/global_constant_const.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/global_constant_const.hlsl index f9cfeb34a7..e3226673ca 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/global_constant_const.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/global_constant_const.hlsl @@ -22,12 +22,15 @@ float4 main() : SV_Target { // bar should be called with a copy of st.a. // CHECK: define <4 x float> @main() -// CHECK: [[a:%[0-9A-Z]+]] = getelementptr inbounds %"$Globals", %"$Globals"* {{%[0-9A-Z]+}}, i32 0, i32 0, i32 0 -// CHECK: call <4 x float> @"\01?bar{{[@$?.A-Za-z0-9_]+}}"([32 x <4 x float>]* [[a]]) +// CHECK-DAG: [[tmp:%[0-9A-Za-z.]+]] = alloca [32 x <4 x float>], align 4 +// CHECK-DAG: [[global:%[0-9]+]] = getelementptr inbounds %"$Globals", %"$Globals"* %2, i32 0, i32 0, i32 0 +// CHECK-DAG: [[dstPtr:%[0-9]+]] = bitcast [32 x <4 x float>]* [[tmp]] to i8* +// CHECK-DAG: [[srcPtr:%[0-9]+]] = bitcast [32 x <4 x float>]* [[global]] to i8* +// CHECK-DAG: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[dstPtr]], i8* [[srcPtr]], i64 512, i32 1, i1 false) +// CHECK: call <4 x float> @"\01?bar{{[@$?.A-Za-z0-9_]+}}"([32 x <4 x float>]* [[tmp]]) -// Bug: Because a isn't marked noalias, we are generating copies for it. // CHECK: define internal <4 x float> @"\01?bar{{[@$?.A-Za-z0-9_]+}}"([32 x <4 x float>]* [[a:%[0-9a]+]]) #1 { -// CHECK: [[Tmpa:%[0-9A-Z]+]] = alloca [32 x <4 x float>] +// CHECK: [[Tmpa:%[0-9A-Za-z.]+]] = alloca [32 x <4 x float>] // CHECK: [[TmpaPtr:%[0-9A-Z]+]] = bitcast [32 x <4 x float>]* [[Tmpa]] to i8* // CHECK: [[aPtr:%[0-9A-Z]+]] = bitcast [32 x <4 x float>]* [[a]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TmpaPtr]], i8* [[aPtr]], i64 512, i32 1, i1 false) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/resource_binding/res_in_cb2.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/resource_binding/res_in_cb2.hlsl index 14c04cb2a8..941927c4ca 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/resource_binding/res_in_cb2.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/resource_binding/res_in_cb2.hlsl @@ -2,8 +2,8 @@ // Make sure array of struct with resource works. -//CHECK: x.1.s sampler NA NA S0 s4 1 -//CHECK: x.0.s sampler NA NA S1 s3 1 +//CHECK: x.0.s sampler NA NA S0 s3 1 +//CHECK: x.1.s sampler NA NA S1 s4 1 //CHECK: x.1.x texture f32 2d T0 t5 1 //CHECK: x.0.y texture f32 2d T1 t4 1 //CHECK: m texture f32 2d T2 t9 1 @@ -23,4 +23,4 @@ cbuffer A { float4 main(float2 uv:UV, uint i:I) : SV_Target { return x[1].x.Sample(x[1].s,uv) + x[0].y.Sample(x[0].s, uv) + m.Sample(x[0].s, uv); -} \ No newline at end of file +} From 7067650f188a60ae3df49a203157e3b2c84c2630 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 3 Apr 2023 13:33:14 -0500 Subject: [PATCH 62/98] Fixes eliding copies for aggregates This is two important and intertwined fixes. 1) When determining if we can elide a copy we need to traverse statement children to find the Decl. 2) During codegen we were generating duplicate copies for aggregates, we should not need that. I've also left a todo in the HLSLOutParamBuilder code which impacts correctness of eliding copies. --- tools/clang/lib/CodeGen/CGExpr.cpp | 30 +++++++++++-------- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 9 ++++++ .../arguments/copyin-copyout-struct.hlsl | 15 +++++----- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp index 920099213a..edbf196e0c 100644 --- a/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/tools/clang/lib/CodeGen/CGExpr.cpp @@ -2937,24 +2937,28 @@ LValue CodeGenFunction::EmitHLSLOutParamExpr(const HLSLOutParamExpr *E) { return EmitLValue(E->getBase()); llvm::Type *Ty = ConvertTypeForMem(E->getType()); // TODO: Use CreateAggTemp - llvm::AllocaInst *OutTemp = CreateTempAlloca(Ty, "hlsl.out"); + llvm::Value *OutTemp; if (E->isInOut()) { RValue InVal = EmitAnyExprToTemp(E->getBase()); - if (hlsl::IsHLSLMatType(E->getType())) { - // Use matrix store to keep major info. - CGM.getHLSLRuntime().EmitHLSLMatrixStore(*this, InVal.getScalarVal(), - OutTemp, E->getType()); + if (!InVal.isScalar()) { + OutTemp = InVal.getAggregateAddr(); } else { - llvm::Value *V = - InVal.isScalar() - ? InVal.getScalarVal() - : Builder.CreateLoad(InVal.getAggregateAddr(), "hlsl.in"); - if (V->getType()->getScalarType()->isIntegerTy(1)) - V = Builder.CreateZExt(V, Ty, "frombool"); - (void)Builder.CreateStore(V, OutTemp); + OutTemp = CreateTempAlloca(Ty, "hlsl.out"); + if (hlsl::IsHLSLMatType(E->getType())) { + // Use matrix store to keep major info. + CGM.getHLSLRuntime().EmitHLSLMatrixStore(*this, InVal.getScalarVal(), + OutTemp, E->getType()); + } + else { + llvm::Value *V = InVal.getScalarVal(); + if (V->getType()->getScalarType()->isIntegerTy(1)) + V = Builder.CreateZExt(V, Ty, "frombool"); + (void)Builder.CreateStore(V, OutTemp); + } } - } + } else + OutTemp = CreateTempAlloca(Ty, "hlsl.out"); LValue Result = MakeAddrLValue(OutTemp, E->getType()); if (auto *OpV = E->getOpaqueValue()) OpaqueValueMappingData::bind(*this, OpV, Result); diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index 8d3c80d08d..9638a6b517 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -31,10 +31,19 @@ class HLSLOutParamBuilder { class DeclFinder : public StmtVisitor { public: VarDecl *Decl = nullptr; + + // TODO: For correctness, when multiple decls are found all decls should be + // added to the Seen list. bool MultipleFound = false; DeclFinder() = default; + void VisitStmt(Stmt *S) { + for (Stmt *Child : S->children()) + if (Child) + Visit(Child); + } + void VisitDeclRefExpr(DeclRefExpr *DRE) { if (MultipleFound) return; diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl index 669e4d54bd..94c3ae70c9 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl @@ -21,16 +21,15 @@ void fn() { // CHECK: define internal void @"\01?fn@ // CHECK-DAG: [[P:%[0-9A-Z]+]] = alloca %struct.Pup // CHECK-DAG: [[X:%[0-9A-Z]+]] = alloca float, align 4 -// CHECK-DAG: [[TmpX:%[0-9a-z.]+]] = alloca float +// CHECK-DAG: [[TmpP:%[0-9a-z.]+]] = alloca %struct.Pup // CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], %struct.Pup* dereferenceable(4) [[P]]) +// CHECK-DAG: [[TmpPPtr:%[0-9]+]] = bitcast %struct.Pup* [[TmpP]] to i8* +// CHECK-DAG: [[PPtr:%[0-9]+]] = bitcast %struct.Pup* [[P]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TmpPPtr]], i8* [[PPtr]], i64 4, i32 1, i1 false) // CHECK: [[PXPtr:%[0-9A-Z]+]] = getelementptr inbounds %struct.Pup, %struct.Pup* [[P]], i32 0, i32 0 -// CHECK: [[PXVal:%[0-9A-Z]+]] = load float, float* [[PXPtr]], align 4 -// CHECK: store float [[PXVal]], float* [[TmpX]] -// CHECK-DAG: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[TmpX]], %struct.Pup* dereferenceable(4) [[P]]) -// CHECK-DAG: [[PXPtr2:%[0-9A-Z]+]] = getelementptr inbounds %struct.Pup, %struct.Pup* [[P]], i32 0, i32 0 - -// CHECK: [[TmpVal:%[0-9A-Z]+]] = load float, float* [[TmpX]] -// CHECK: store float [[TmpVal]], float* [[PXPtr2]], align 4 +// CHECK-DAG: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[PXPtr]], %struct.Pup* dereferenceable(4) [[TmpP]]) +// CHECK: [[TmpPVal:%[0-9]+]] = load %struct.Pup, %struct.Pup* [[TmpP]] +// CHECK: store %struct.Pup [[TmpPVal]], %struct.Pup* [[P]], align 4 From 4fe1edda5bf172fcf34e60a388f51712d1edbf4a Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 3 Apr 2023 15:53:52 -0500 Subject: [PATCH 63/98] Fix vector argument generation --- tools/clang/lib/CodeGen/CGCall.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index 769340ea6c..a490e187da 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -3028,14 +3028,24 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, // Add writeback for HLSLOutParamExpr. if (const HLSLOutParamExpr *OE = dyn_cast(E)) { LValue LV = EmitLValue(E); + llvm::Value *Addr, *BaseAddr; + if (LV.isExtVectorElt()) { + llvm::Constant *VecElts = LV.getExtVectorElts(); + BaseAddr = LV.getExtVectorAddr(); + Addr = Builder.CreateGEP( + BaseAddr, + {Builder.getInt32(0), VecElts->getAggregateElement((unsigned)0)}); + } else // LV.getAddress() will assert if this is not a simple LValue. + Addr = BaseAddr = LV.getAddress(); + if (!OE->canElide()) { - uint64_t Sz = - CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(LV.getType())); - EmitLifetimeStart(Sz, LV.getAddress()); - args.addWriteback(EmitLValue(OE->getSrcLV()), LV.getAddress(), nullptr, + uint64_t Sz = CGM.getDataLayout().getTypeAllocSize( + ConvertTypeForMem(LV.getType())); + EmitLifetimeStart(Sz, BaseAddr); + args.addWriteback(EmitLValue(OE->getSrcLV()), Addr, nullptr, OE->getWriteback()); } - return args.add(RValue::get(LV.getAddress()), type); + return args.add(RValue::get(Addr), type); } // HLSL Change Ends. assert(E->getObjectKind() == OK_Ordinary); From 0c923a9586fb3f783469311c0d5b6ab7cf439f0d Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 5 Apr 2023 09:43:18 -0500 Subject: [PATCH 64/98] Don't elide non-local storage --- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index 9638a6b517..52e7a2e2fe 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -96,7 +96,7 @@ class HLSLOutParamBuilder { // seen the decl before, generate a HLSLOutParamExpr that can't be elided. if (DF.MultipleFound || DF.Decl == nullptr || DF.Decl->getType().getQualifiers().hasAddressSpace() || - SeenVars.count(DF.Decl) > 0 || DF.Decl->hasExternalStorage()) + SeenVars.count(DF.Decl) > 0 || !DF.Decl->hasLocalStorage()) return ExprResult( HLSLOutParamExpr::Create(Ctx, Ty, Base, P->hasAttr())); // Add the decl to the seen list, and generate a HLSLOutParamExpr that can From 5dd8a84e29530413664dfecbc1baf9e4e8d4e3e6 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 5 Apr 2023 10:34:08 -0500 Subject: [PATCH 65/98] Don't just assume that GEPs can only be used by specific instructions --- lib/Transforms/Scalar/LowerTypePasses.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Transforms/Scalar/LowerTypePasses.cpp b/lib/Transforms/Scalar/LowerTypePasses.cpp index eb4ca1d9d8..2750c80222 100644 --- a/lib/Transforms/Scalar/LowerTypePasses.cpp +++ b/lib/Transforms/Scalar/LowerTypePasses.cpp @@ -274,7 +274,7 @@ void DynamicIndexingVectorToArray::ReplaceStaticIndexingOnVector(Value *V) { ldVal = Builder.CreateLoad(V); ldVal = Builder.CreateInsertElement(ldVal, Elt, constIdx); Builder.CreateStore(ldVal, V); - } else { + } else if (StoreInst *stInst = dyn_cast(GEPUser)) { // Change // st val, a->x // into @@ -282,7 +282,6 @@ void DynamicIndexingVectorToArray::ReplaceStaticIndexingOnVector(Value *V) { // tmp.x = val // st tmp, a // Must be store inst here. - StoreInst *stInst = cast(GEPUser); Value *val = stInst->getValueOperand(); Value *ldVal = Builder.CreateLoad(V); ldVal = Builder.CreateInsertElement(ldVal, val, constIdx); @@ -290,7 +289,8 @@ void DynamicIndexingVectorToArray::ReplaceStaticIndexingOnVector(Value *V) { stInst->eraseFromParent(); } } - GEP->eraseFromParent(); + if (GEP->user_empty()) + GEP->eraseFromParent(); } else if (GEP->getNumIndices() == 1) { Value *Idx = *GEP->idx_begin(); if (ConstantInt *C = dyn_cast(Idx)) { From df068bd3075571502cdff92660b467e889856c24 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 5 Apr 2023 10:35:22 -0500 Subject: [PATCH 66/98] Rework writeback generation This makes it more likely to generate memcpy instead of load/store sequences. Generally I think load/store sequences are cleaner and more optimizable but our IR passes are fragile to the load/store sequences that get exploded by SROA. --- tools/clang/lib/CodeGen/CGCall.cpp | 37 +++++++++++++++++------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index a490e187da..cc660e7db6 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -2591,25 +2591,30 @@ static bool isProvablyNonNull(llvm::Value *addr) { static void emitWriteback(CodeGenFunction &CGF, const CallArgList::Writeback &writeback) { const LValue &srcLV = writeback.Source; - + if (CGF.getLangOpts().HLSL) { - RValue TmpVal; - if (writeback.CastExpr) - TmpVal = CGF.EmitAnyExprToTemp(writeback.CastExpr); - else { - llvm::Value *value; - if (hlsl::IsHLSLMatType(srcLV.getType())) - value = CGF.CGM.getHLSLRuntime().EmitHLSLMatrixLoad( - CGF, writeback.Temporary, srcLV.getType()); + if (writeback.CastExpr) { + RValue TmpVal = CGF.EmitAnyExprToTemp(writeback.CastExpr); + if (TmpVal.isScalar()) + CGF.EmitStoreThroughLValue(TmpVal, srcLV); else - value = CGF.Builder.CreateLoad(writeback.Temporary); - TmpVal = RValue::get(value); + CGF.EmitAggregateCopy(srcLV.getAddress(), TmpVal.getAggregateAddr(), + srcLV.getType()); + } else { + if (srcLV.isSimple()) + CGF.EmitAggregateCopy(srcLV.getAddress(), writeback.Temporary, + srcLV.getType()); + else { + llvm::Value *value; + if (hlsl::IsHLSLMatType(srcLV.getType())) + value = CGF.CGM.getHLSLRuntime().EmitHLSLMatrixLoad( + CGF, writeback.Temporary, srcLV.getType()); + else + value = CGF.Builder.CreateLoad(writeback.Temporary); + RValue TmpVal = RValue::get(value); + CGF.EmitStoreThroughLValue(TmpVal, srcLV); + } } - if (TmpVal.isScalar()) - CGF.EmitStoreThroughLValue(TmpVal, srcLV); - else - CGF.EmitAggregateCopy(srcLV.getAddress(), TmpVal.getAggregateAddr(), - srcLV.getType()); uint64_t Sz = CGF.CGM.getDataLayout().getTypeAllocSize( CGF.ConvertTypeForMem(srcLV.getType())); CGF.EmitLifetimeEnd(llvm::ConstantInt::get(CGF.Int64Ty, Sz), From 238b35225b71b405a62af04951294d69b1410571 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 5 Apr 2023 14:03:13 -0500 Subject: [PATCH 67/98] don't elide vectors :( --- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index 52e7a2e2fe..7c8b2c0ab6 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -94,8 +94,14 @@ class HLSLOutParamBuilder { // If the analysis returned multiple possible decls, or no decl, or we've // seen the decl before, generate a HLSLOutParamExpr that can't be elided. + // Note: The DXIL IR passes are fragile to a bunch of cases when vectors are + // retained as parameter types to user-defined function calls. To work + // around that we always emit copies for vector arguments. This is not a + // regression because the HLParameterLegalization pass used to do the same + // thing. if (DF.MultipleFound || DF.Decl == nullptr || DF.Decl->getType().getQualifiers().hasAddressSpace() || + hlsl::IsHLSLVecType(Ty) || // This is a hack, see note above. SeenVars.count(DF.Decl) > 0 || !DF.Decl->hasLocalStorage()) return ExprResult( HLSLOutParamExpr::Create(Ctx, Ty, Base, P->hasAttr())); From af3c6f58ea75cd6d2073e6b8816bdad7571b7823 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 6 Apr 2023 12:40:52 -0500 Subject: [PATCH 68/98] Deleting test verifying incorrect behavior --- .../library/lib_skip_copy_in.hlsl | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 tools/clang/test/HLSLFileCheck/shader_targets/library/lib_skip_copy_in.hlsl diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/library/lib_skip_copy_in.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/library/lib_skip_copy_in.hlsl deleted file mode 100644 index 416a35ca73..0000000000 --- a/tools/clang/test/HLSLFileCheck/shader_targets/library/lib_skip_copy_in.hlsl +++ /dev/null @@ -1,34 +0,0 @@ -// RUN: %dxc -T lib_6_3 -DTYPE=float -Od %s | FileCheck %s -check-prefixes=CHECK -// RUN: %dxc -T lib_6_3 -DTYPE=float2x2 -Od %s | FileCheck %s -check-prefixes=CHECK -// RUN: %dxc -T lib_6_3 -DTYPE=float2x2 -Od -Zpr %s | FileCheck %s -check-prefixes=CHECK -// RUN: %dxc -T lib_6_3 -DTYPE=float2x2 -DTYPEMOD=row_major -Od -Zpr %s | FileCheck %s -check-prefixes=CHECK -// These need to copy: -// RUN: %dxc -T lib_6_3 -DTYPE=float2x2 -DTYPEMOD=row_major -Od %s | FileCheck %s -check-prefixes=CHECK,COPY -// RUN: %dxc -T lib_6_3 -DTYPE=float2x2 -DTYPEMOD=column_major -Od -Zpr %s | FileCheck %s -check-prefixes=CHECK,COPY - -// Make sure array is not copied unless matrix orientation changed -// CHECK: alloca -// COPY: alloca -// CHECK-NOT: alloca -// CHECK: ret - -#ifndef TYPEMOD -#define TYPEMOD -#endif - -TYPE lookup(in TYPE arr[16], int index) { - return arr[index]; -} - -int idx; - -[shader("vertex")] -TYPE main() : OUT { - TYPEMOD TYPE arr[16]; - for (int i = 0; i < 16; i++) { - arr[i] = (TYPE)i; - } - return lookup(arr, idx); -} - - From 62464a0cea877e427c10d7ac9ec1a5166bc2c502 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 17 Apr 2023 14:56:51 -0500 Subject: [PATCH 69/98] Fix test --- .../HLSLFileCheck/shader_targets/library/lib_no_alias.hlsl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/library/lib_no_alias.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/library/lib_no_alias.hlsl index 04acbee74d..d3e046706c 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/library/lib_no_alias.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/library/lib_no_alias.hlsl @@ -1,7 +1,11 @@ // RUN: %dxc -T lib_6_3 -auto-binding-space 11 -default-linkage external %s | FileCheck %s // Make sure out param has no-alias. -// CHECK: float @"\01?test{{[@$?.A-Za-z0-9_]+}}"(float %a, %struct.T* noalias nocapture %t, %class.matrix.float.2.2* noalias nocapture dereferenceable(16) %m, float %b) +// CHECK: float @"\01?test{{[@$?.A-Za-z0-9_]+}}"( +// CHECK-SAME: float %a, +// CHECK-SAME: %struct.T* noalias nocapture dereferenceable(8) %t, +// CHECK-SAME: %class.matrix.float.2.2* noalias nocapture dereferenceable(16) %m, +// CHECK-SAME float %b struct T { float a; From 376ddce36204155c0ece238d1dd10d534baad80e Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 18 Apr 2023 13:00:49 -0500 Subject: [PATCH 70/98] Support flat-conversion of l-values in out parameters --- tools/clang/lib/Sema/HLSLOutParamBuilder.h | 63 +++++++++++++------ .../inout_struct_mismatch-strictudt.hlsl | 10 +-- .../library/inout_struct_mismatch.hlsl | 10 +-- 3 files changed, 49 insertions(+), 34 deletions(-) diff --git a/tools/clang/lib/Sema/HLSLOutParamBuilder.h b/tools/clang/lib/Sema/HLSLOutParamBuilder.h index 7c8b2c0ab6..fd75506df3 100644 --- a/tools/clang/lib/Sema/HLSLOutParamBuilder.h +++ b/tools/clang/lib/Sema/HLSLOutParamBuilder.h @@ -17,6 +17,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/StmtVisitor.h" #include "clang/Sema/Sema.h" +#include "clang/Sema/SemaHLSL.h" #include "llvm/ADT/DenseSet.h" namespace clang { @@ -54,6 +55,30 @@ class HLSLOutParamBuilder { } }; + ExprResult CreateCasted(Sema &Sema, ParmVarDecl *P, Expr *Base, QualType Ty) { + ASTContext &Ctx = Sema.getASTContext(); + ExprResult Res = + Sema.PerformImplicitConversion(Base, Ty, Sema::AA_Passing); + if (Res.isInvalid()) + return ExprError(); + // After the cast, drop the reference type when creating the exprs. + Ty = Ty.getNonLValueExprType(Ctx); + HLSLOutParamExpr *OutExpr = + HLSLOutParamExpr::Create(Ctx, Ty, Res.get(), + P->hasAttr()); + auto *OpV = new (Ctx) OpaqueValueExpr(P->getLocStart(), Ty, VK_LValue, + OK_Ordinary, OutExpr); + Res = Sema.PerformImplicitConversion(OpV, Base->getType(), + Sema::AA_Passing); + if (Res.isInvalid()) + return ExprError(); + OutExpr->setWriteback(Res.get()); + OutExpr->setSrcLV(Base); + OutExpr->setOpaqueValue(OpV); + OpV->setSourceIsParent(); + return ExprResult(OutExpr); + } + public: HLSLOutParamBuilder() = default; @@ -67,27 +92,14 @@ class HLSLOutParamBuilder { return ExprError(); } + bool PossibleFlatConv = + hlsl::IsConversionToLessOrEqualElements(&Sema, Base, Ty, true); + bool RequiresConversion = Ty.getUnqualifiedType() != Base->getType().getUnqualifiedType(); + // If the unqualified types mismatch we may have some casting. Since this // results in a copy we can ignore qualifiers. - if (Ty.getUnqualifiedType() != Base->getType().getUnqualifiedType()) { - ExprResult Res = - Sema.PerformImplicitConversion(Base, Ty, Sema::AA_Passing); - if (Res.isInvalid()) - return ExprError(); - HLSLOutParamExpr *OutExpr = HLSLOutParamExpr::Create( - Ctx, Ty, Res.get(), P->hasAttr()); - auto *OpV = new (Ctx) OpaqueValueExpr(P->getLocStart(), Ty, VK_LValue, - OK_Ordinary, OutExpr); - Res = Sema.PerformImplicitConversion(OpV, Base->getType(), - Sema::AA_Passing); - if (Res.isInvalid()) - return ExprError(); - OutExpr->setWriteback(Res.get()); - OutExpr->setSrcLV(Base); - OutExpr->setOpaqueValue(OpV); - OpV->setSourceIsParent(); - return ExprResult(OutExpr); - } + if (!PossibleFlatConv && RequiresConversion) + return CreateCasted(Sema, P, Base, Ty); DeclFinder DF; DF.Visit(Base); @@ -102,9 +114,20 @@ class HLSLOutParamBuilder { if (DF.MultipleFound || DF.Decl == nullptr || DF.Decl->getType().getQualifiers().hasAddressSpace() || hlsl::IsHLSLVecType(Ty) || // This is a hack, see note above. - SeenVars.count(DF.Decl) > 0 || !DF.Decl->hasLocalStorage()) + SeenVars.count(DF.Decl) > 0 || !DF.Decl->hasLocalStorage()) { + if (RequiresConversion) + return CreateCasted(Sema, P, Base, P->getType()); return ExprResult( HLSLOutParamExpr::Create(Ctx, Ty, Base, P->hasAttr())); + } + + if (RequiresConversion) { + ExprResult Res = + Sema.PerformImplicitConversion(Base, P->getType(), Sema::AA_Passing); + if (Res.isInvalid()) + return ExprError(); + Base = Res.get(); + } // Add the decl to the seen list, and generate a HLSLOutParamExpr that can // be elided. SeenVars.insert(DF.Decl); diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/library/inout_struct_mismatch-strictudt.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/library/inout_struct_mismatch-strictudt.hlsl index b52cd207aa..a4fd446881 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/library/inout_struct_mismatch-strictudt.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/library/inout_struct_mismatch-strictudt.hlsl @@ -2,13 +2,9 @@ // CHECK: define <4 x float> // CHECK-SAME: main -// CHECK-NOT: bitcast -// CHECK-NOT: CallStruct -// CHECK: ParamStruct -// CHECK: call void @llvm.lifetime.start -// CHECK-NOT: bitcast -// CHECK-NOT: CallStruct -// CHECK-LABEL: ret <4 x float> +// CHECK: [[local:%(local)|([0-9]+)]] = alloca %struct.CallStruct +// CHECK: [[param:%[0-9]+]] = bitcast %struct.CallStruct* [[local]] to %struct.ParamStruct* +// CHEKC: call void @"\01?modify_ext{{.*}}(%struct.ParamStruct* dereferenceable(8) [[param]]) struct ParamStruct { int i; diff --git a/tools/clang/test/HLSLFileCheck/shader_targets/library/inout_struct_mismatch.hlsl b/tools/clang/test/HLSLFileCheck/shader_targets/library/inout_struct_mismatch.hlsl index 0dec1c0e35..4c02d04189 100644 --- a/tools/clang/test/HLSLFileCheck/shader_targets/library/inout_struct_mismatch.hlsl +++ b/tools/clang/test/HLSLFileCheck/shader_targets/library/inout_struct_mismatch.hlsl @@ -2,13 +2,9 @@ // CHECK: define <4 x float> // CHECK-SAME: main -// CHECK-NOT: bitcast -// CHECK-NOT: CallStruct -// CHECK: ParamStruct -// CHECK: call void @llvm.lifetime.start -// CHECK-NOT: bitcast -// CHECK-NOT: CallStruct -// CHECK-LABEL: ret <4 x float> +// CHECK: [[local:%(local)|([0-9]+)]] = alloca %struct.CallStruct +// CHECK: [[param:%[0-9]+]] = bitcast %struct.CallStruct* [[local]] to %struct.ParamStruct* +// CHEKC: call void @"\01?modify_ext{{.*}}(%struct.ParamStruct* dereferenceable(8) [[param]]) struct ParamStruct { int i; From 279b2a6f12c94c00984d7eae8e7c33f5c805ec5f Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 19 Apr 2023 09:49:32 -0500 Subject: [PATCH 71/98] Update test based on new codegen --- .../lib_2d_array_call_export_subarray.hlsl | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/lib_2d_array_call_export_subarray.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/lib_2d_array_call_export_subarray.hlsl index e7cda73918..a60fbf670c 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/lib_2d_array_call_export_subarray.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/lib_2d_array_call_export_subarray.hlsl @@ -3,28 +3,40 @@ // Ensure 2d array is broken down into 2 1d arrays, properly initialized, // modified, and passed to function calls -// CHECK-DAG: %[[h0:.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf0 -// CHECK-DAG: %[[h1:.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf1 -// CHECK-DAG: %[[h2:.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf2 -// CHECK-DAG: %[[h3:.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf3 -// CHECK: %[[a1:.+]] = alloca [2 x %dx.types.Handle] -// CHECK: %[[a0:.+]] = alloca [2 x %dx.types.Handle] -// CHECK-DAG: %[[gep0:.+]] = getelementptr [2 x %dx.types.Handle], [2 x %dx.types.Handle]* %[[a0]], i32 0, i32 0 -// CHECK-DAG: %[[gep1:.+]] = getelementptr [2 x %dx.types.Handle], [2 x %dx.types.Handle]* %[[a0]], i32 0, i32 1 -// CHECK-DAG: %[[gep2:.+]] = getelementptr [2 x %dx.types.Handle], [2 x %dx.types.Handle]* %[[a1]], i32 0, i32 0 -// CHECK-DAG: %[[gep3:.+]] = getelementptr [2 x %dx.types.Handle], [2 x %dx.types.Handle]* %[[a1]], i32 0, i32 1 -// CHECK: store %dx.types.Handle %[[h0]], %dx.types.Handle* %[[gep0]] -// CHECK: store %dx.types.Handle %[[h1]], %dx.types.Handle* %[[gep1]] -// CHECK: store %dx.types.Handle %[[h2]], %dx.types.Handle* %[[gep2]] -// CHECK: store %dx.types.Handle %[[h3]], %dx.types.Handle* %[[gep3]] -// CHECK: call void @{{.*}}useArray{{.*}}([2 x %dx.types.Handle]* nonnull %[[a0]]) -// CHECK: call void @{{.*}}useArray{{.*}}([2 x %dx.types.Handle]* nonnull %[[a1]]) -// CHECK: %[[h10:.+]] = load %dx.types.Handle, %dx.types.Handle* %[[gep2]] -// CHECK: store %dx.types.Handle %[[h10]], %dx.types.Handle* %[[gep1]] -// CHECK: call void @{{.*}}useArray{{.*}}([2 x %dx.types.Handle]* nonnull %[[a0]]) -// CHECK: %[[h01:.+]] = load %dx.types.Handle, %dx.types.Handle* %[[gep1]] -// CHECK: store %dx.types.Handle %[[h01]], %dx.types.Handle* %[[gep2]] -// CHECK: call void @{{.*}}useArray{{.*}}([2 x %dx.types.Handle]* nonnull %[[a1]]) +// CHECK-DAG: [[h0:%.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf0 +// CHECK-DAG: [[h1:%.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf1 +// CHECK-DAG: [[h2:%.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf2 +// CHECK-DAG: [[h3:%.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf3 +// CHECK: [[tmp:%.+]] = alloca [2 x %dx.types.Handle] +// CHECK-DAG: [[gep0:%.+]] = getelementptr inbounds [2 x %dx.types.Handle], [2 x %dx.types.Handle]* [[tmp]], i32 0, i32 0 +// CHECK-DAG: [[gep1:%.+]] = getelementptr inbounds [2 x %dx.types.Handle], [2 x %dx.types.Handle]* [[tmp]], i32 0, i32 1 + +// CHECK-DAG: store %dx.types.Handle [[h0]], %dx.types.Handle* [[gep0]] +// CHECK-DAG: store %dx.types.Handle [[h1]], %dx.types.Handle* [[gep1]] + +// CHECK: call void @{{.*}}useArray{{.*}}([2 x %dx.types.Handle]* nonnull [[tmp]]) + +// CHECK-DAG: store %dx.types.Handle [[h2]], %dx.types.Handle* [[gep0]] +// CHECK-DAG: store %dx.types.Handle [[h3]], %dx.types.Handle* [[gep1]] + +// CHECK: call void @{{.*}}useArray{{.*}}([2 x %dx.types.Handle]* nonnull [[tmp]]) + + +// CHECK-DAG: [[cmp:%.*]] = icmp eq i32 {{%.*}}, 1 +// CHECK-DAG: [[h4:%.*]] = select i1 [[cmp]], %dx.types.Handle [[h2]], %dx.types.Handle [[h1]] +// CHECK-DAG: store %dx.types.Handle [[h0]], %dx.types.Handle* [[gep0]] +// CHECK-DAG: store %dx.types.Handle [[h4]], %dx.types.Handle* [[gep1]] + +// CHECK: call void @{{.*}}useArray{{.*}}([2 x %dx.types.Handle]* nonnull [[tmp]]) + + +// CHECK-DAG: [[cmp2:%.*]] = icmp eq i32 {{%.*}}, 2 +// CHECK-DAG: [[h5:%.*]] = select i1 [[cmp2]], %dx.types.Handle [[h4]], %dx.types.Handle [[h2]] +// CHECK-DAG: store %dx.types.Handle [[h5]], %dx.types.Handle* [[gep0]] +// CHECK-DAG: store %dx.types.Handle [[h3]], %dx.types.Handle* [[gep1]] + + +// CHECK: call void @{{.*}}useArray{{.*}}([2 x %dx.types.Handle]* nonnull [[tmp]]) void useArray(RWStructuredBuffer buffers[2]); From 3cbabea623b27ae014cbfb90078f9ce994e63471 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 19 Apr 2023 11:09:40 -0500 Subject: [PATCH 72/98] Rewrite test --- .../unroll/lib_2d_array_call_export.hlsl | 74 +++++++++++++------ 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/lib_2d_array_call_export.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/lib_2d_array_call_export.hlsl index 96cced8ca7..ad097296e3 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/lib_2d_array_call_export.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/lib_2d_array_call_export.hlsl @@ -7,28 +7,60 @@ // arrays, then all that code, being dead, getting deleted, leaving just the // passing of uninitialized arrays to the function calls. -// CHECK-DAG: %[[h0:.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf0 -// CHECK-DAG: %[[h1:.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf1 -// CHECK-DAG: %[[h2:.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf2 -// CHECK-DAG: %[[h3:.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf3 -// CHECK: %[[buffers:.+]] = alloca [2 x [2 x %dx.types.Handle]] -// CHECK-DAG: %[[gep0:.+]] = getelementptr inbounds [2 x [2 x %dx.types.Handle]], [2 x [2 x %dx.types.Handle]]* %[[buffers]], i32 0, i32 0, i32 0 -// CHECK: store %dx.types.Handle %[[h0]], %dx.types.Handle* %[[gep0]], align 8 -// CHECK-DAG: %[[gep1:.+]] = getelementptr inbounds [2 x [2 x %dx.types.Handle]], [2 x [2 x %dx.types.Handle]]* %[[buffers]], i32 0, i32 0, i32 1 -// CHECK: store %dx.types.Handle %[[h1]], %dx.types.Handle* %[[gep1]], align 8 -// CHECK-DAG: %[[gep2:.+]] = getelementptr inbounds [2 x [2 x %dx.types.Handle]], [2 x [2 x %dx.types.Handle]]* %[[buffers]], i32 0, i32 1, i32 0 -// CHECK: store %dx.types.Handle %[[h2]], %dx.types.Handle* %[[gep2]], align 8 -// CHECK-DAG: %[[gep3:.+]] = getelementptr inbounds [2 x [2 x %dx.types.Handle]], [2 x [2 x %dx.types.Handle]]* %[[buffers]], i32 0, i32 1, i32 1 -// CHECK: store %dx.types.Handle %[[h3]], %dx.types.Handle* %[[gep3]], align 8 -// CHECK: call void @{{.*}}useArray{{.*}}([2 x [2 x %dx.types.Handle]]* nonnull %[[buffers]]) -// CHECK: call void @{{.*}}useArray{{.*}}([2 x [2 x %dx.types.Handle]]* nonnull %[[buffers]]) -// CHECK: %[[h10:.+]] = load %dx.types.Handle, %dx.types.Handle* %[[gep2]], align 8 -// CHECK: store %dx.types.Handle %[[h10]], %dx.types.Handle* %[[gep1]], align 8 -// CHECK: call void @{{.*}}useArray{{.*}}([2 x [2 x %dx.types.Handle]]* nonnull %[[buffers]]) -// CHECK: %[[h01:.+]] = load %dx.types.Handle, %dx.types.Handle* %[[gep1]], align 8 -// CHECK: store %dx.types.Handle %[[h01]], %dx.types.Handle* %[[gep2]], align 8 -// CHECK: call void @{{.*}}useArray{{.*}}([2 x [2 x %dx.types.Handle]]* nonnull %[[buffers]]) +// Because the array could be modified in the call, it needs to be +// re-initialized before each call. The tests below verify the initialization of +// the array between each call. +// CHECK-DAG: [[h0:%.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf0 +// CHECK-DAG: [[h1:%.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf1 +// CHECK-DAG: [[h2:%.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf2 +// CHECK-DAG: [[h3:%.+]] = load %dx.types.Handle, %dx.types.Handle* @{{.*}}buf3 +// CHECK: [[tmp:%.+]] = alloca [2 x [2 x %dx.types.Handle]] + +// CHECK-DAG: [[gep0:%.+]] = getelementptr inbounds [2 x [2 x %dx.types.Handle]], [2 x [2 x %dx.types.Handle]]* [[tmp]], i32 0, i32 0, i32 0 +// CHECK-DAG: [[gep1:%.+]] = getelementptr inbounds [2 x [2 x %dx.types.Handle]], [2 x [2 x %dx.types.Handle]]* [[tmp]], i32 0, i32 0, i32 1 +// CHECK-DAG: [[gep2:%.+]] = getelementptr inbounds [2 x [2 x %dx.types.Handle]], [2 x [2 x %dx.types.Handle]]* [[tmp]], i32 0, i32 1, i32 0 +// CHECK-DAG: [[gep3:%.+]] = getelementptr inbounds [2 x [2 x %dx.types.Handle]], [2 x [2 x %dx.types.Handle]]* [[tmp]], i32 0, i32 1, i32 1 + +// Store: {0, 1, 2, 3} +// CHECK-DAG: store %dx.types.Handle [[h0]], %dx.types.Handle* [[gep0]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h1]], %dx.types.Handle* [[gep1]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h2]], %dx.types.Handle* [[gep2]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h3]], %dx.types.Handle* [[gep3]], align 8 + +// CHECK: call void @{{.*}}useArray{{.*}}([2 x [2 x %dx.types.Handle]]* nonnull [[tmp]]) + +// Store: {0, 1, 2, 3} +// CHECK-DAG: store %dx.types.Handle [[h0]], %dx.types.Handle* [[gep0]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h1]], %dx.types.Handle* [[gep1]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h2]], %dx.types.Handle* [[gep2]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h3]], %dx.types.Handle* [[gep3]], align 8 + +// CHECK: call void @{{.*}}useArray{{.*}}([2 x [2 x %dx.types.Handle]]* nonnull [[tmp]]) + +// Store: {0, (1 | 2), 2, 3} + +// CHECK-DAG: [[cmp:%.*]] = icmp eq i32 {{%.*}}, 1 +// CHECK-DAG: [[h4:%.*]] = select i1 [[cmp]], %dx.types.Handle [[h2]], %dx.types.Handle [[h1]] + +// CHECK-DAG: store %dx.types.Handle [[h0]], %dx.types.Handle* [[gep0]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h4]], %dx.types.Handle* [[gep1]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h2]], %dx.types.Handle* [[gep2]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h3]], %dx.types.Handle* [[gep3]], align 8 + +// CHECK: call void @{{.*}}useArray{{.*}}([2 x [2 x %dx.types.Handle]]* nonnull [[tmp]]) + +// Store: {0, (1 | 2), ((1 | 2) | 2), 3} + +// CHECK-DAG: [[cmp2:%.*]] = icmp eq i32 {{%.*}}, 2 +// CHECK-DAG: [[h5:%.*]] = select i1 [[cmp2]], %dx.types.Handle [[h4]], %dx.types.Handle [[h2]] + +// CHECK-DAG: store %dx.types.Handle [[h0]], %dx.types.Handle* [[gep0]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h4]], %dx.types.Handle* [[gep1]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h5]], %dx.types.Handle* [[gep2]], align 8 +// CHECK-DAG: store %dx.types.Handle [[h3]], %dx.types.Handle* [[gep3]], align 8 + +// CHECK: call void @{{.*}}useArray{{.*}}([2 x [2 x %dx.types.Handle]]* nonnull [[tmp]]) void useArray(RWStructuredBuffer buffers[2][2]); RWStructuredBuffer buf0; From d8d0b1a9a8fca11b1757be9b5175c58043f3297b Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 21 Apr 2023 09:42:49 -0500 Subject: [PATCH 73/98] Update test case --- .../functions/arguments/copyin-copyout.hlsl | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl index f38302b13c..17f5b0472d 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl @@ -16,56 +16,67 @@ void fn() { } // CHECK: define internal void @"\01?fn{{[@$?.A-Za-z0-9_]+}}"() +// CHECK: [[Tmp1:%[0-9a-z.]+]] = alloca float +// CHECK: [[Tmp2:%[0-9a-z.]+]] = alloca float // CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 // CHECK: [[Y:%[0-9A-Z]+]] = alloca float, align 4 // CHECK: [[Z:%[0-9A-Z]+]] = alloca float, align 4 -// CHECK: [[Tmp1:%[0-9a-z.]+]] = alloca float -// CHECK: [[Tmp2:%[0-9a-z.]+]] = alloca float // First call has no copy-in/copy out parameters since all parameters are unique. -// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Z]]) +// CHECK: call void @"\01?CalledFunction +// CHECK-SAME: (float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Z]]) // Second call, copies X for parameter 2. // CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 -// CHECK: store float [[TmpX]], float* [[Tmp1]] +// CHECK: store float [[TmpX]], float* [[Tmp2]] -// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp1]], float* dereferenceable(4) [[Z]]) +// CHECK: call void @"\01?CalledFunction +// CHECK-SAME: (float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp2]], float* dereferenceable(4) [[Z]]) // Second call, saves parameter 2 to X after the call. -// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp1]] +// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp2]] // CHECK: store float [[TmpX]], float* [[X]] // The third call copies X for the third parameter. // CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 -// CHECK: store float [[TmpX]], float* [[Tmp2]] +// CHECK: store float [[TmpX]], float* [[Tmp1]] -// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Tmp2]]) +// CHECK: call void @"\01?CalledFunction +// CHECK-SAME: (float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Tmp1]]) // The third call stores parameter 3 to X after the call. -// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp2]] +// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp1]] // CHECK: store float [[TmpX]], float* [[X]] +// CHECK: ret + void fn2() { float X = 0.0; CalledFunction(X, X, X); } -// CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 +// CHECK: define internal void @"\01?fn2 + // CHECK: [[Tmp1:%[0-9a-z.]+]] = alloca float // CHECK: [[Tmp2:%[0-9a-z.]+]] = alloca float +// CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 // X gets copied in for both parameters two and three. // CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 -// CHECK: store float [[TmpX]], float* [[Tmp1]] -// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 // CHECK: store float [[TmpX]], float* [[Tmp2]] +// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 +// CHECK: store float [[TmpX]], float* [[Tmp1]] -// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp2]], float* dereferenceable(4) [[Tmp1]]) +// CHECK: call void @"\01?CalledFunction +// CHECK-SAME: (float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp2]], float* dereferenceable(4) [[Tmp1]]) // X gets restored from parameter 2 _then_ parameter 3, so the last paramter is // the final value of X. -// CHECK: [[X2:%[0-9A-Z]+]] = load float, float* [[Tmp1]] -// CHECK: store float [[X2]], float* [[X]] + // CHECK: [[X1:%[0-9A-Z]+]] = load float, float* [[Tmp2]] // CHECK: store float [[X1]], float* [[X]], align 4 -// line:31 col:3 + +// CHECK: [[X2:%[0-9A-Z]+]] = load float, float* [[Tmp1]] +// CHECK: store float [[X2]], float* [[X]] + +// CHECK: ret From e21e46c6333acb48250d4c78bb29ca6f5fb2b3e7 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 21 Apr 2023 11:34:21 -0500 Subject: [PATCH 74/98] Reverse writeback order Under the MSVC ABI arguments are emitted right to left, but writebacks need to be emitted left to right for HLSL. This is probably a case that we need to look into more. --- tools/clang/lib/CodeGen/CGCall.cpp | 6 +++++ tools/clang/lib/CodeGen/CGCall.h | 7 +++++ .../functions/arguments/copyin-copyout.hlsl | 27 ++++++++++--------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index cc660e7db6..e6be5776b4 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -2931,6 +2931,12 @@ void CodeGenFunction::EmitCallArgs(CallArgList &Args, // Un-reverse the arguments we just evaluated so they match up with the LLVM // IR function. std::reverse(Args.begin() + CallArgsStart, Args.end()); + + // HLSL Change Begin + // We also need to un-reverse the writebacks so that they are emitted left + // to right since the args were emitted right to left. + Args.reverseWritebacks(); + // HLSL Change End return; } diff --git a/tools/clang/lib/CodeGen/CGCall.h b/tools/clang/lib/CodeGen/CGCall.h index 9aa1f2d790..34fd8db61d 100644 --- a/tools/clang/lib/CodeGen/CGCall.h +++ b/tools/clang/lib/CodeGen/CGCall.h @@ -129,6 +129,13 @@ namespace CodeGen { /// memory. bool isUsingInAlloca() const { return StackBase; } + // HLSL Change Begin + // Support reversing writebacks for MSVC ABI. + void reverseWritebacks() { + std::reverse(Writebacks.begin(), Writebacks.end()); + } + // HLSL Change End + private: SmallVector Writebacks; diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl index 17f5b0472d..411ff21321 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout.hlsl @@ -16,11 +16,11 @@ void fn() { } // CHECK: define internal void @"\01?fn{{[@$?.A-Za-z0-9_]+}}"() -// CHECK: [[Tmp1:%[0-9a-z.]+]] = alloca float -// CHECK: [[Tmp2:%[0-9a-z.]+]] = alloca float // CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 // CHECK: [[Y:%[0-9A-Z]+]] = alloca float, align 4 // CHECK: [[Z:%[0-9A-Z]+]] = alloca float, align 4 +// CHECK: [[Tmp1:%[0-9a-z.]+]] = alloca float +// CHECK: [[Tmp2:%[0-9a-z.]+]] = alloca float // First call has no copy-in/copy out parameters since all parameters are unique. // CHECK: call void @"\01?CalledFunction @@ -28,24 +28,24 @@ void fn() { // Second call, copies X for parameter 2. // CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 -// CHECK: store float [[TmpX]], float* [[Tmp2]] +// CHECK: store float [[TmpX]], float* [[Tmp1]] // CHECK: call void @"\01?CalledFunction -// CHECK-SAME: (float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp2]], float* dereferenceable(4) [[Z]]) +// CHECK-SAME: (float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp1]], float* dereferenceable(4) [[Z]]) // Second call, saves parameter 2 to X after the call. -// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp2]] +// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp1]] // CHECK: store float [[TmpX]], float* [[X]] // The third call copies X for the third parameter. // CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 -// CHECK: store float [[TmpX]], float* [[Tmp1]] +// CHECK: store float [[TmpX]], float* [[Tmp2]] // CHECK: call void @"\01?CalledFunction -// CHECK-SAME: (float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Tmp1]]) +// CHECK-SAME: (float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Y]], float* dereferenceable(4) [[Tmp2]]) // The third call stores parameter 3 to X after the call. -// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp1]] +// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[Tmp2]] // CHECK: store float [[TmpX]], float* [[X]] // CHECK: ret @@ -57,15 +57,16 @@ void fn2() { // CHECK: define internal void @"\01?fn2 +// CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 // CHECK: [[Tmp1:%[0-9a-z.]+]] = alloca float // CHECK: [[Tmp2:%[0-9a-z.]+]] = alloca float -// CHECK: [[X:%[0-9A-Z]+]] = alloca float, align 4 -// X gets copied in for both parameters two and three. -// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 -// CHECK: store float [[TmpX]], float* [[Tmp2]] +// X gets copied in for both parameters two and three. The MSVC ABI dictates +// right to left construction of arguments. // CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 // CHECK: store float [[TmpX]], float* [[Tmp1]] +// CHECK: [[TmpX:%[0-9A-Z]+]] = load float, float* [[X]], align 4 +// CHECK: store float [[TmpX]], float* [[Tmp2]] // CHECK: call void @"\01?CalledFunction // CHECK-SAME: (float* dereferenceable(4) [[X]], float* dereferenceable(4) [[Tmp2]], float* dereferenceable(4) [[Tmp1]]) @@ -74,7 +75,7 @@ void fn2() { // the final value of X. // CHECK: [[X1:%[0-9A-Z]+]] = load float, float* [[Tmp2]] -// CHECK: store float [[X1]], float* [[X]], align 4 +// CHECK: store float [[X1]], float* [[X]] // CHECK: [[X2:%[0-9A-Z]+]] = load float, float* [[Tmp1]] // CHECK: store float [[X2]], float* [[X]] From d4d0048406e068a457a0ca0c4b8c73ac561fc56a Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 21 Apr 2023 13:37:33 -0500 Subject: [PATCH 75/98] Update test regex --- .../hlsl/functions/arguments/gep_arg_nocopy.hlsl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/gep_arg_nocopy.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/gep_arg_nocopy.hlsl index 7135da876f..94161a8d68 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/gep_arg_nocopy.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/gep_arg_nocopy.hlsl @@ -22,17 +22,16 @@ float4 main() : SV_Target { // bar should be called with a copy of st.a. // CHECK: define <4 x float> @main() -// CHECK: [[a:%[0-9A-Z]+]] = getelementptr inbounds %"$Globals", %"$Globals"* {{%[0-9A-Z]+}}, i32 0, i32 0, i32 0 -// CHECK: [[Tmpa:%[0-9A-Z]+]] = alloca [32 x <4 x float>] -// CHECK: [[TmpaPtr:%[0-9A-Z]+]] = bitcast [32 x <4 x float>]* [[Tmpa]] to i8* -// CHECK: [[aPtr:%[0-9A-Z]+]] = bitcast [32 x <4 x float>]* [[a]] to i8* +// CHECK: [[a:%.+]] = getelementptr inbounds %"$Globals", %"$Globals"* {{%[0-9A-Z]+}}, i32 0, i32 0, i32 0 +// CHECK: [[Tmpa:%.+]] = alloca [32 x <4 x float>] +// CHECK: [[TmpaPtr:%.+]] = bitcast [32 x <4 x float>]* [[Tmpa]] to i8* +// CHECK: [[aPtr:%.+]] = bitcast [32 x <4 x float>]* [[a]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TmpaPtr]], i8* [[aPtr]], i64 512, i32 1, i1 false) // CHECK: call <4 x float> @"\01?bar{{[@$?.A-Za-z0-9_]+}}"([32 x <4 x float>]* [[Tmpa]]) -// Bug: Because a isn't marked noalias, we are generating copies for it. // CHECK: define internal <4 x float> @"\01?bar{{[@$?.A-Za-z0-9_]+}}"([32 x <4 x float>]* [[a:%[0-9a]+]]) #1 { -// CHECK: [[Tmpa:%[0-9A-Z]+]] = alloca [32 x <4 x float>] -// CHECK: [[TmpaPtr:%[0-9A-Z]+]] = bitcast [32 x <4 x float>]* [[Tmpa]] to i8* -// CHECK: [[aPtr:%[0-9A-Z]+]] = bitcast [32 x <4 x float>]* [[a]] to i8* +// CHECK: [[Tmpa:%.+]] = alloca [32 x <4 x float>] +// CHECK: [[TmpaPtr:%.+]] = bitcast [32 x <4 x float>]* [[Tmpa]] to i8* +// CHECK: [[aPtr:%.+]] = bitcast [32 x <4 x float>]* [[a]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TmpaPtr]], i8* [[aPtr]], i64 512, i32 1, i1 false) // CHECK: call <4 x float> @"\01?foo{{[@$?.A-Za-z0-9_]+}}"([32 x <4 x float>]* [[Tmpa]], i32 {{%[0-9A-Z]+}}) From a7bd5c7ef53de788341bcb56b5513583e7b38408 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 21 Apr 2023 14:05:03 -0500 Subject: [PATCH 76/98] rewrite vector truncation warning --- tools/clang/lib/Sema/SemaExprCXX.cpp | 4 +- tools/clang/test/HLSL/inout_trunc.hlsl | 58 +++++++++++++++ .../hlsl/functions/arguments/inout_trunc.hlsl | 72 ------------------- tools/clang/unittests/HLSL/VerifierTest.cpp | 5 ++ 4 files changed, 66 insertions(+), 73 deletions(-) create mode 100644 tools/clang/test/HLSL/inout_trunc.hlsl delete mode 100644 tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/inout_trunc.hlsl diff --git a/tools/clang/lib/Sema/SemaExprCXX.cpp b/tools/clang/lib/Sema/SemaExprCXX.cpp index 4104b7b523..fb314668cf 100644 --- a/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -3447,11 +3447,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } // HLSL Change Starts + case ICK_HLSLVector_Truncation: + Diag(From->getLocStart(), diag::warn_hlsl_implicit_vector_truncation); + LLVM_FALLTHROUGH; case ICK_Flat_Conversion: case ICK_HLSL_Derived_To_Base: case ICK_HLSLVector_Splat: case ICK_HLSLVector_Scalar: - case ICK_HLSLVector_Truncation: case ICK_HLSLVector_Conversion: { ExprResult FromRes = hlsl::PerformHLSLConversion(this, From, ToType, SCS, CCK); diff --git a/tools/clang/test/HLSL/inout_trunc.hlsl b/tools/clang/test/HLSL/inout_trunc.hlsl new file mode 100644 index 0000000000..45e6a981e7 --- /dev/null +++ b/tools/clang/test/HLSL/inout_trunc.hlsl @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -ffreestanding -verify %s + +// Test that no crashes result when a scalar is provided to an outvar +// and that the new warning is produced. + +// CHK_NOCRASH: NocrashMain + +float val1; +float val2; +float val3; + +float2 vec2; +float3 vec3; +float4 vec4; + +void TakeItOut(out float2 it) { + it = val1; +} + +void TakeItIn(inout float3 it) { + it = val2; +} + +void TakeItIn2(inout float4 it) { + it += val3; +} + +void TakeEmOut(out float2 em) { + em = vec2; +} + +void TakeEmIn(inout float3 em) { + em = vec3; +} + +void TakeEmIn2(inout float4 em) { + em += vec4; +} + + +float2 RunTest(float it, float em) +{ + float c = it; + TakeItOut(it); // expected-warning{{implicit truncation of vector type}} + TakeItIn(it); // expected-warning{{implicit truncation of vector type}} + TakeItIn2(it); // expected-warning{{implicit truncation of vector type}} + + TakeEmOut(em); // expected-warning{{implicit truncation of vector type}} + TakeEmIn(em); // expected-warning{{implicit truncation of vector type}} + TakeEmIn2(em); // expected-warning{{implicit truncation of vector type}} + return float2(it, em); +} + +float2 main(float it: A, float em: B) : SV_Target +{ + return RunTest(it, em); +} + diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/inout_trunc.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/inout_trunc.hlsl deleted file mode 100644 index 261dd30b29..0000000000 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/inout_trunc.hlsl +++ /dev/null @@ -1,72 +0,0 @@ -// RUN: %dxc -E NocrashMain -T ps_6_0 %s | FileCheck %s -check-prefix=CHK_NOCRASH -// RUN: %dxc -E WarnMain -T ps_6_0 %s | FileCheck %s -check-prefix=CHK_WARN - -// Test that no crashes result when a scalar is provided to an outvar -// and that the new warning is produced. - -// CHK_WARN: warning: implicit truncation of vector type -// CHK_WARN: warning: implicit truncation of vector type -// CHK_WARN: warning: implicit truncation of vector type -// CHK_WARN: warning: implicit truncation of vector type -// CHK_WARN: warning: implicit truncation of vector type -// CHK_WARN: warning: implicit truncation of vector type -// CHK_WARN-NOT: warning: implicit truncation of vector type -// CHK_NOCRASH: NocrashMain - -float val1; -float val2; -float val3; - -float2 vec2; -float3 vec3; -float4 vec4; - -void TakeItOut(out float2 it) { - it = val1; -} - -void TakeItIn(inout float3 it) { - it = val2; -} - -void TakeItIn2(inout float4 it) { - it += val3; -} - -void TakeEmOut(out float2 em) { - em = vec2; -} - -void TakeEmIn(inout float3 em) { - em = vec3; -} - -void TakeEmIn2(inout float4 em) { - em += vec4; -} - - -float2 RunTest(float it, float em) -{ - float c = it; - TakeItOut(it); - TakeItIn(it); - TakeItIn2(it); - - TakeEmOut(em); - TakeEmIn(em); - TakeEmIn2(em); - return float2(it, em); -} - -float2 NocrashMain(float it: A, float em: B) : SV_Target -{ - return RunTest(it, em); -} - -// Missing out semantic to force filecheck to read stderr and see the warnings. -float2 WarnMain(float it: A, float em: B) -{ - return RunTest(it, em); -} - diff --git a/tools/clang/unittests/HLSL/VerifierTest.cpp b/tools/clang/unittests/HLSL/VerifierTest.cpp index 4eae18cce7..b0cd365fbf 100644 --- a/tools/clang/unittests/HLSL/VerifierTest.cpp +++ b/tools/clang/unittests/HLSL/VerifierTest.cpp @@ -55,6 +55,7 @@ class VerifierTest TEST_CLASS_DERIVATION { TEST_METHOD(RunFunctions) TEST_METHOD(RunIncompleteType) TEST_METHOD(RunIndexingOperator) + TEST_METHOD(RunInOutTrunc) TEST_METHOD(RunIntrinsicExamples) TEST_METHOD(RunInvalidDeclTemplateArg) TEST_METHOD(RunMatrixAssignments) @@ -262,6 +263,10 @@ TEST_F(VerifierTest, RunIndexingOperator) { CheckVerifiesHLSL(L"indexing-operator.hlsl"); } +TEST_F(VerifierTest, RunInOutTrunc) { + CheckVerifiesHLSL(L"inout_trunc.hlsl"); +} + TEST_F(VerifierTest, RunIntrinsicExamples) { CheckVerifiesHLSL(L"intrinsic-examples.hlsl"); } From 627a54dcba06dd48732800fea2975492bd581d0b Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 21 Apr 2023 14:20:58 -0500 Subject: [PATCH 77/98] Rewrite truncation diagnostics part 2... --- tools/clang/lib/Sema/SemaExprCXX.cpp | 3 ++- tools/clang/lib/Sema/SemaHLSL.cpp | 4 ---- .../binary => HLSL}/vector-matrix-binops.hlsl | 24 ++++--------------- tools/clang/unittests/HLSL/VerifierTest.cpp | 5 ++++ 4 files changed, 12 insertions(+), 24 deletions(-) rename tools/clang/test/{HLSLFileCheck/hlsl/operators/binary => HLSL}/vector-matrix-binops.hlsl (54%) diff --git a/tools/clang/lib/Sema/SemaExprCXX.cpp b/tools/clang/lib/Sema/SemaExprCXX.cpp index fb314668cf..10c19470ed 100644 --- a/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -3448,7 +3448,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // HLSL Change Starts case ICK_HLSLVector_Truncation: - Diag(From->getLocStart(), diag::warn_hlsl_implicit_vector_truncation); + if(CCK == CCK_ImplicitConversion) + Diag(From->getLocStart(), diag::warn_hlsl_implicit_vector_truncation); LLVM_FALLTHROUGH; case ICK_Flat_Conversion: case ICK_HLSL_Derived_To_Base: diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 9201b2094f..7953b83f3e 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -10407,10 +10407,6 @@ bool HLSLExternalSource::ValidateCast(SourceLocation OpLoc, Expr *sourceExpr, m_sema->Diag(OpLoc, diag::warn_hlsl_narrowing) << source << target; } } - - if ((remarks & TYPE_CONVERSION_ELT_TRUNCATION) != 0) { - m_sema->Diag(OpLoc, diag::warn_hlsl_implicit_vector_truncation); - } } } diff --git a/tools/clang/test/HLSLFileCheck/hlsl/operators/binary/vector-matrix-binops.hlsl b/tools/clang/test/HLSL/vector-matrix-binops.hlsl similarity index 54% rename from tools/clang/test/HLSLFileCheck/hlsl/operators/binary/vector-matrix-binops.hlsl rename to tools/clang/test/HLSL/vector-matrix-binops.hlsl index fdf3ad6ef3..b4d2850490 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/operators/binary/vector-matrix-binops.hlsl +++ b/tools/clang/test/HLSL/vector-matrix-binops.hlsl @@ -1,18 +1,4 @@ -// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s - -// CHECK: vector-matrix-binops.hlsl:29:26: warning: implicit truncation of vector type -// CHECK: vector-matrix-binops.hlsl:30:21: warning: implicit truncation of vector type -// CHECK: vector-matrix-binops.hlsl:30:14: warning: implicit truncation of vector type -// CHECK: vector-matrix-binops.hlsl:35:23: warning: implicit truncation of vector type -// CHECK: vector-matrix-binops.hlsl:36:29: warning: implicit truncation of vector type -// CHECK: vector-matrix-binops.hlsl:37:23: warning: implicit truncation of vector type -// CHECK: vector-matrix-binops.hlsl:37:16: warning: implicit truncation of vector type -// CHECK: vector-matrix-binops.hlsl:42:26: error: cannot convert from 'float4x4' to 'float4' -// CHECK: vector-matrix-binops.hlsl:43:29: error: cannot convert from 'float4' to 'float4x4' -// CHECK: vector-matrix-binops.hlsl:44:26: warning: implicit truncation of vector type -// CHECK: vector-matrix-binops.hlsl:45:21: warning: implicit truncation of vector type -// CHECK: vector-matrix-binops.hlsl:58:29: error: cannot convert from 'float3x2' to 'float2x3' -// CHECK: vector-matrix-binops.hlsl:59:29: error: cannot convert from 'float2x3' to 'float1x4' +// RUN: %clang_cc1 -fsyntax-only -ffreestanding -verify % void main() { @@ -26,8 +12,8 @@ void main() { // vector truncation { - float2 res1 = v2 * v4; // expected-warning {{implicit truncation of vector type}} - float2 res2 = v4 - v3; // expected-warning {{implicit truncation of vector type}} + float2 res1 = v2 * v4; // expected-warning {{implicit truncation of vector type}} expected-warning {{implicit truncation of vector type}} + float2 res2 = v4 - v3; // expected-warning {{implicit truncation of vector type}} expected-warning {{implicit truncation of vector type}} } // matrix truncation @@ -55,7 +41,7 @@ void main() { // matrix mismatched dimensions { float2x3 m23 = float2x3(1, 2, 3, 4, 5, 6); - float3x2 res1 = m23 - m32; // expected-error {{error: cannot convert from 'float3x2' to 'float2x3'}} + float3x2 res1 = m23 - m32; // expected-error {{cannot convert from 'float3x2' to 'float2x3'}} float1x4 res2 = m14 / m23; // expected-error {{cannot convert from 'float2x3' to 'float1x4'}} } -} \ No newline at end of file +} diff --git a/tools/clang/unittests/HLSL/VerifierTest.cpp b/tools/clang/unittests/HLSL/VerifierTest.cpp index b0cd365fbf..c0721ab950 100644 --- a/tools/clang/unittests/HLSL/VerifierTest.cpp +++ b/tools/clang/unittests/HLSL/VerifierTest.cpp @@ -113,6 +113,7 @@ class VerifierTest TEST_CLASS_DERIVATION { TEST_METHOD(RunBitFieldAnnotations) TEST_METHOD(RunUDTByteAddressBufferLoad) TEST_METHOD(RunObjectTemplateDiagDeferred) + TEST_METHOD(RunVectorMatrixBinOp) void CheckVerifies(const wchar_t *path) { WEX::TestExecution::SetVerifyOutput verifySettings( WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures); @@ -468,3 +469,7 @@ TEST_F(VerifierTest, RunUDTByteAddressBufferLoad) { TEST_F(VerifierTest, RunObjectTemplateDiagDeferred) { CheckVerifiesHLSL(L"object-template-diag-deferred.hlsl"); } + +TEST_F(VerifierTest, RunVectorMatrixBinOp) { + CheckVerifiesHLSL(L"vector-matrix-binops.hlsl"); +} From 02391979f41f419d136a5e9ff87d1eb9704cf149 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 21 Apr 2023 14:33:01 -0500 Subject: [PATCH 78/98] rewrite test --- .../functions/arguments/copyin-copyout-struct.hlsl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl index 94c3ae70c9..1d8d8bbba1 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/functions/arguments/copyin-copyout-struct.hlsl @@ -30,6 +30,10 @@ void fn() { // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TmpPPtr]], i8* [[PPtr]], i64 4, i32 1, i1 false) // CHECK: [[PXPtr:%[0-9A-Z]+]] = getelementptr inbounds %struct.Pup, %struct.Pup* [[P]], i32 0, i32 0 -// CHECK-DAG: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}"(float* dereferenceable(4) [[PXPtr]], %struct.Pup* dereferenceable(4) [[TmpP]]) -// CHECK: [[TmpPVal:%[0-9]+]] = load %struct.Pup, %struct.Pup* [[TmpP]] -// CHECK: store %struct.Pup [[TmpPVal]], %struct.Pup* [[P]], align 4 +// CHECK: call void @"\01?CalledFunction{{[@$?.A-Za-z0-9_]+}}" +// CHECK-SAME: (float* dereferenceable(4) [[PXPtr]], %struct.Pup* dereferenceable(4) [[TmpP]]) + +// CHECK-DAG: [[PPtr:%[0-9]+]] = bitcast %struct.Pup* [[P]] to i8* +// CHECK-DAG: [[TmpPPtr:%[0-9]+]] = bitcast %struct.Pup* [[TmpP]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[PPtr]], i8* [[TmpPPtr]], i64 4, i32 1, i1 false) + From 9069939e81a67bcaae2782832d7d16d965c19973 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 21 Apr 2023 16:04:18 -0500 Subject: [PATCH 79/98] Update diagnosic locations --- .../hlsl/diagnostics/errors/local_resource2.hlsl | 4 ++-- .../hlsl/diagnostics/errors/local_resource3.hlsl | 4 ++-- .../hlsl/diagnostics/errors/local_resource6_dbg.hlsl | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource2.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource2.hlsl index 4dcd19447c..d2c534dbf0 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource2.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource2.hlsl @@ -1,8 +1,8 @@ // RUN: %dxc -Zi -E main -Od -T ps_6_0 %s | FileCheck %s -check-prefix=CHK_DB // RUN: %dxc -E main -Od -T ps_6_0 %s | FileCheck %s -check-prefix=CHK_NODB -// CHK_DB: 9:10: error: local resource not guaranteed to map to unique global resource. -// CHK_NODB: 9:10: error: local resource not guaranteed to map to unique global resource. +// CHK_DB: 16:10: error: local resource not guaranteed to map to unique global resource. +// CHK_NODB: 16:10: error: local resource not guaranteed to map to unique global resource. float4 Tex2D(Texture2D t, SamplerState s, float2 c) { diff --git a/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource3.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource3.hlsl index 1e61dcbae5..cd75b934a4 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource3.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource3.hlsl @@ -1,8 +1,8 @@ // RUN: %dxc -Zi -E main -Od -T ps_6_0 %s | FileCheck %s -check-prefix=CHK_DB // RUN: %dxc -E main -Od -T ps_6_0 %s | FileCheck %s -check-prefix=CHK_NODB -// CHK_DB: 9:10: error: local resource not guaranteed to map to unique global resource. -// CHK_NODB: 9:10: error: local resource not guaranteed to map to unique global resource. +// CHK_DB: 26:10: error: local resource not guaranteed to map to unique global resource. +// CHK_NODB: 26:10: error: local resource not guaranteed to map to unique global resource. float4 Tex2D(Texture2D t, SamplerState s, float2 c) { diff --git a/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource6_dbg.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource6_dbg.hlsl index bd7e513ceb..5772ca0c2b 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource6_dbg.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/diagnostics/errors/local_resource6_dbg.hlsl @@ -1,8 +1,8 @@ // RUN: %dxc -Zi -E main -Od -T ps_6_0 %s | FileCheck %s -check-prefix=CHK_DB // RUN: %dxc -E main -Od -T ps_6_0 %s | FileCheck %s -check-prefix=CHK_NODB -// CHK_DB: 9:10: error: local resource not guaranteed to map to unique global resource. -// CHK_NODB: 9:10: error: local resource not guaranteed to map to unique global resource. +// CHK_DB: 23:10: error: local resource not guaranteed to map to unique global resource. +// CHK_NODB: 23:10: error: local resource not guaranteed to map to unique global resource. float4 Tex2D(Texture2D t, SamplerState s, float2 c) { From b2110b1102b97c21c2146323ae74a6e1bf8aa2a7 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 25 Apr 2023 15:43:37 -0500 Subject: [PATCH 80/98] Updating AST matching --- .../HLSLFileCheck/hlsl/classes/class_method_overload.hlsl | 5 ++--- .../HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/classes/class_method_overload.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/classes/class_method_overload.hlsl index d89d8edd69..35914ba87c 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/classes/class_method_overload.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/classes/class_method_overload.hlsl @@ -1,11 +1,10 @@ // RUN: %dxc -T vs_6_0 -E main %s -ast-dump | FileCheck %s -// CHECK: FunctionDecl {{.*}} used CallMethod 'uint (__restrict MyClass)' +// CHECK: FunctionDecl {{.*}} used CallMethod 'uint (MyClass &__restrict)' // CHECK: CXXMemberCallExpr // CHECK-NEXT: MemberExpr {{.*}} .Method -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'MyClass' lvalue // CHECK-NEXT: DeclRefExpr -// CHECK-SAME: '__restrict MyClass' lvalue ParmVar 0x{{[0-9a-zA-Z]+}} 'c' '__restrict MyClass' +// CHECK-SAME: 'MyClass' lvalue ParmVar 0x{{[0-9a-zA-Z]+}} 'c' 'MyClass &__restrict' class MyClass { uint Method(uint2 u2) { return u2.y * 2; } diff --git a/tools/clang/test/HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl index 1b16084270..3da7749f84 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/classes/derived-to-base-casting.hlsl @@ -79,5 +79,4 @@ void DerivedToBaseGS() { // CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'da1' 'DerivedAgain' // CHECK-NEXT: ImplicitCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' // CHECK-NEXT: CStyleCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' lvalue -// CHECK-NEXT: ImplicitCastExpr {{0x[0-9a-fA-F]+}} 'DerivedAgain' // CHECK-NEXT: DeclRefExpr {{0x[0-9a-fA-F]+}} '__attribute__((address_space(3))) DerivedAgain' lvalue Var {{0x[0-9a-fA-F]+}} 'daGS' '__attribute__((address_space(3))) DerivedAgain' From 112064086593698ea9ef023f3a70b9f7109e9af9 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 25 Apr 2023 15:58:20 -0500 Subject: [PATCH 81/98] don't generate lifetime markers for writeback if disabled --- tools/clang/lib/CodeGen/CGCall.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/clang/lib/CodeGen/CGCall.cpp b/tools/clang/lib/CodeGen/CGCall.cpp index e6be5776b4..8a6725e05a 100644 --- a/tools/clang/lib/CodeGen/CGCall.cpp +++ b/tools/clang/lib/CodeGen/CGCall.cpp @@ -2615,10 +2615,12 @@ static void emitWriteback(CodeGenFunction &CGF, CGF.EmitStoreThroughLValue(TmpVal, srcLV); } } - uint64_t Sz = CGF.CGM.getDataLayout().getTypeAllocSize( - CGF.ConvertTypeForMem(srcLV.getType())); - CGF.EmitLifetimeEnd(llvm::ConstantInt::get(CGF.Int64Ty, Sz), - writeback.Temporary); + if (CGF.CGM.getCodeGenOpts().HLSLEnableLifetimeMarkers) { + uint64_t Sz = CGF.CGM.getDataLayout().getTypeAllocSize( + CGF.ConvertTypeForMem(srcLV.getType())); + CGF.EmitLifetimeEnd(llvm::ConstantInt::get(CGF.Int64Ty, Sz), + writeback.Temporary); + } return; } From 6d7b78412d6390716f63c6f83a5ba22630f4044a Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 26 Apr 2023 12:08:39 -0500 Subject: [PATCH 82/98] rewrite test checks --- .../hlsl/classes/this_cast_to_base_class.hlsl | 111 ++++++++++-------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/classes/this_cast_to_base_class.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/classes/this_cast_to_base_class.hlsl index ce91e35179..9de3ea34f6 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/classes/this_cast_to_base_class.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/classes/this_cast_to_base_class.hlsl @@ -1,52 +1,71 @@ // RUN: %dxc -T lib_6_6 -HV 2021 -disable-lifetime-markers -fcgl %s | FileCheck %s -// CHECK-LABEL: define linkonce_odr void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(%class.Child* %this) -// CHECK: %[[OutArg:.+]] = alloca %class.Parent -// CHECK: %[[OutThisPtr:.+]] = getelementptr inbounds %class.Child, %class.Child* %this, i32 0, i32 0 -// CHECK: call void @"\01?lib_func2{{[@$?.A-Za-z0-9_]+}}"(%class.Parent* %[[OutArg]]) -// Make sure copy-out. -// CHECK: %[[OutThisCpyPtr:.+]] = bitcast %class.Parent* %[[OutThisPtr]] to i8* -// CHECK: %[[OutArgCpyPtr:.+]] = bitcast %class.Parent* %[[OutArg]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[OutThisCpyPtr]], i8* %[[OutArgCpyPtr]], i64 8, i32 1, i1 false) - -// CHECK-LABEL: define linkonce_odr void @"\01?bar{{[@$?.A-Za-z0-9_]+}}"(%class.Child* %this) -// CHECK: %[[InOutArg:.+]] = alloca %class.Parent -// CHECK: %[[InOutThisPtr:.+]] = getelementptr inbounds %class.Child, %class.Child* %this, i32 0, i32 0 - -// Make sure copy-in. -// CHECK: %[[InOutArgCpyPtr:.+]] = bitcast %class.Parent* %[[InOutArg]] to i8* -// CHECK: %[[InOutThisCpyPtr:.+]] = bitcast %class.Parent* %[[InOutThisPtr]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[InOutArgCpyPtr]], i8* %[[InOutThisCpyPtr]], i64 8, i32 1, i1 false) - -// The call. -// CHECK: call void @"\01?lib_func3{{[@$?.A-Za-z0-9_]+}}"(%class.Parent* %[[InOutArg]]) - -// Make sure copy-out. -// CHECK: %[[InOutThisCpyOutPtr:.+]] = bitcast %class.Parent* %[[InOutThisPtr]] to i8* -// CHECK: %[[InOutArgCpyOutPtr:.+]] = bitcast %class.Parent* %[[InOutArg]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[InOutThisCpyOutPtr]], i8* %[[InOutArgCpyOutPtr]], i64 8, i32 1, i1 false) - -// CHECK-LABEL: define linkonce_odr i32 @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(%class.Child* %this, i32 %a, i32 %b) +// `foo` calls `lib_func2` and copies out the temporary. Derived to base copies +// should probably always happen since HLSL doesn't have any real support for +// dynamic typing. + +// CHECK-LABEL: define linkonce_odr void @"\01?foo@ +// CHECK-SAME: (%class.Child* [[this:%.+]]) +// Create a temporary. +// CHECK: [[OutArg:%.+]] = alloca %class.Parent +// CHECK: [[OutThisPtr:%.+]] = bitcast %class.Child* [[this]] to %class.Parent* + +// Call lib_func2 with the temporary. +// CHECK: call void @"\01?lib_func2 +// CHECK-SAME: (%class.Parent* dereferenceable(8) [[OutArg]]) + +// Copy the temporary back to the `this` object. +// CHECK: [[OutThisCpyPtr:%.+]] = bitcast %class.Parent* [[OutThisPtr]] to i8* +// CHECK: [[OutArgCpyPtr:%.+]] = bitcast %class.Parent* [[OutArg]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[OutThisCpyPtr]], i8* [[OutArgCpyPtr]], i64 8, i32 1, i1 false) + +// `bar` calls `lib_func_3` with `this` as an `inout` parameter, so it needs to +// be initialized first, then copied back after the call. + +// CHECK-LABEL: define linkonce_odr void @"\01?bar@ +// CHEKC-SAME: (%class.Child* [[this:%.+]]) +// CHECK: [[InOutArg:%.+]] = alloca %class.Parent + +// Initialize the temporary from `this`. +// CHECK-DAG: [[ThisIPtr:%.+]] = getelementptr inbounds %class.Child, %class.Child* [[this]], i32 0, i32 0, i32 0 +// CHECK-DAG: [[ThisFPtr:%.+]] = getelementptr inbounds %class.Child, %class.Child* [[this]], i32 0, i32 0, i32 1 +// CHECK-DAG: [[ThisI:%.+]] = load i32, i32* [[ThisIPtr]] +// CHECK-DAG: [[ThisF:%.+]] = load float, float* [[ThisFPtr]] +// CHECK-DAG: [[TmpIPtr:%.+]] = getelementptr inbounds %class.Parent, %class.Parent* [[InOutArg]], i32 0, i32 0 +// CHECK-DAG: [[TmpFPtr:%.+]] = getelementptr inbounds %class.Parent, %class.Parent* [[InOutArg]], i32 0, i32 1 +// CHECK-DAG: store i32 [[ThisI]], i32* [[TmpIPtr]] +// CHECK-DAG: store float [[ThisF]], float* [[TmpFPtr]] + +// Call lib_func3 with the temporary. +// CHECK-DAG: call void @"\01?lib_func3@{{[@$?.A-Za-z0-9_]+}}"(%class.Parent* dereferenceable(8) [[InOutArg]]) + +// Copy back the temporary to `this`. There is a redundant bitcast here due to +// the aggregate copy trying to match the target type before the memcpy is +// generated. This could be removed in the future. + +// CHECK-DAG: [[ThisCastParent:%.+]] = bitcast %class.Child* [[this]] to %class.Parent* +// CHECK-DAG: [[ThisCastI8:%.+]] = bitcast %class.Parent* [[ThisCastParent]] to i8* +// CHECK-DAG: [[TmpCastI8:%.+]] = bitcast %class.Parent* [[InOutArg]] to i8* +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[ThisCastI8]], i8* [[TmpCastI8]], i64 8, i32 1, i1 false) + + +// CHECK-LABEL: define linkonce_odr i32 @"\01?foo@ +// CHECK-SAME: (%class.Child* [[this:%.+]], i32 [[a:%.+]], i32 [[b:%.+]]) // CHECK: %[[Arg:.+]] = alloca %class.Parent -// CHECK: %[[Tmp:.+]] = alloca %class.Parent, align 4 - -// Make sure this is copy to agg tmp. -// CHECK: %[[PtrI:.+]] = getelementptr inbounds %class.Child, %class.Child* %this, i32 0, i32 0, i32 0 -// CHECK: %[[PtrJ:.+]] = getelementptr inbounds %class.Child, %class.Child* %this, i32 0, i32 0, i32 1 -// CHECK: %[[I:.+]] = load i32, i32* %[[PtrI]] -// CHECK: %[[J:.+]] = load float, float* %[[PtrJ]] -// CHECK: %[[TmpPtrI:.+]] = getelementptr inbounds %class.Parent, %class.Parent* %[[Tmp]], i32 0, i32 0 -// CHECK: %[[TmpPtrJ:.+]] = getelementptr inbounds %class.Parent, %class.Parent* %[[Tmp]], i32 0, i32 1 -// CHECK: store i32 %[[I]], i32* %[[TmpPtrI]] -// CHECK: store float %[[J]], float* %[[TmpPtrJ]] - -// Make sure Tmp copy to Arg. -// CHECK: %[[ArgPtr:.+]] = bitcast %class.Parent* %[[Arg]] to i8* -// CHECK: %[[TmpPtr:.+]] = bitcast %class.Parent* %[[Tmp]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[ArgPtr]], i8* %[[TmpPtr]], i64 8, i32 1, i1 false) - -// Use Arg to call lib_func. -// CHECK: call i32 @"\01?lib_func{{[@$?.A-Za-z0-9_]+}}"(%class.Parent* %[[Arg]], i32 %{{.*}}, i32 %{{.*}}) + +// Initialize the temporary from `this`. +// CHECK-DAG: [[ThisIPtr:%.+]] = getelementptr inbounds %class.Child, %class.Child* [[this]], i32 0, i32 0, i32 0 +// CHECK-DAG: [[ThisFPtr:%.+]] = getelementptr inbounds %class.Child, %class.Child* [[this]], i32 0, i32 0, i32 1 +// CHECK-DAG: [[ThisI:%.+]] = load i32, i32* [[ThisIPtr]] +// CHECK-DAG: [[ThisF:%.+]] = load float, float* [[ThisFPtr]] +// CHECK-DAG: [[TmpIPtr:%.+]] = getelementptr inbounds %class.Parent, %class.Parent* [[InOutArg]], i32 0, i32 0 +// CHECK-DAG: [[TmpFPtr:%.+]] = getelementptr inbounds %class.Parent, %class.Parent* [[InOutArg]], i32 0, i32 1 +// CHECK-DAG: store i32 [[ThisI]], i32* [[TmpIPtr]] +// CHECK-DAG: store float [[ThisF]], float* [[TmpFPtr]] + +// Use the temporary to call lib_func. +// CHECK: call i32 @"\01?lib_func@ +// CHECK-SAME: (%class.Parent* %[[Arg]], i32 %{{.*}}, i32 %{{.*}}) class Parent { From 48c0af7f7ba3ce9f3e7b9ef150fae10a3ed88be2 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 2 May 2023 15:46:21 -0500 Subject: [PATCH 83/98] Initial SPIR-V support for HLSLOutParamExpr --- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 95 +++++++++++++++++--------- tools/clang/lib/SPIRV/SpirvEmitter.h | 17 +++++ 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 0e81543274..3cbb86c8b5 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -1194,6 +1194,12 @@ SpirvInstruction *SpirvEmitter::doExpr(const Expr *expr, } else if (const auto *tmplParamExpr = dyn_cast(expr)) { result = doExpr(tmplParamExpr->getReplacement()); + } else if (const auto *outParamExpr = dyn_cast(expr)) { + result = doHLSLOutParamExpr(outParamExpr); + } else if (const auto *arrayTmpExpr = dyn_cast(expr)) { + result = doHLSLArrayTemporaryExpr(arrayTmpExpr); + } else if (const auto *opaqueValExpr = dyn_cast(expr)) { + result = doOpaqueValueExpr(opaqueValExpr); } else { emitError("expression class '%0' unimplemented", expr->getExprLoc()) << expr->getStmtClassName() << expr->getSourceRange(); @@ -2830,6 +2836,7 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) { llvm::SmallVector vars; // Variables for function call llvm::SmallVector isTempVar; // Temporary variable or not llvm::SmallVector args; // Evaluated arguments + llvm::SmallVector, 4> writebacks; if (const auto *memberCall = dyn_cast(callExpr)) { const auto *memberFn = cast(memberCall->getCalleeDecl()); @@ -2916,6 +2923,9 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) { auto *argInst = doExpr(arg); + if (const auto *outParamExpr = dyn_cast(arg)) + writebacks.push_back(std::make_pair(argInst, outParamExpr)); + bool isArgGlobalVarWithResourceType = argInfo && argInfo->getStorageClass() != spv::StorageClass::Function && isResourceType(paramType); @@ -3005,38 +3015,15 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) { callExpr->getSourceRange()); // Go through all parameters and write those marked as out/inout - for (uint32_t i = 0; i < numParams; ++i) { - const auto *param = callee->getParamDecl(i); - const auto paramType = param->getType(); - // If it calls a non-static member function, the object itself is argument - // 0, and therefore all other argument positions are shifted by 1. - const uint32_t index = i + isNonStaticMemberCall; - // Using a resouce as a function parameter is never passed-by-copy. As a - // result, even if the function parameter is marked as 'out' or 'inout', - // there is no reason to copy back the results after the function call into - // the resource. - if (isTempVar[index] && canActAsOutParmVar(param) && - !isResourceType(paramType)) { - // Arguments for the overloaded operator includes the object itself. The - // actual argument starts from the second one. - const uint32_t argIndex = i + isOperatorOverloading; - - const auto *arg = callExpr->getArg(argIndex); - SpirvInstruction *value = - spvBuilder.createLoad(paramType, vars[index], arg->getLocStart()); - - // Now we want to assign 'value' to arg. But first, in rare cases when - // using 'out' or 'inout' where the parameter and argument have a type - // mismatch, we need to first cast 'value' to the type of 'arg' because - // the AST will not include a cast node. - if (!paramTypeMatchesArgType(paramType, arg->getType())) { - if (const auto *refType = paramType->getAs()) - value = castToType(value, refType->getPointeeType(), arg->getType(), - arg->getLocStart()); - } - - processAssignment(arg, value, false, args[index]); + for (auto wb : writebacks) { + SpirvInstruction *ArgResult = nullptr; + if (const auto wbExpr = wb.second->getWriteback()) { + ArgResult = doExpr(wbExpr); + } else { + ArgResult = spvBuilder.createLoad( + wb.second->getType(), wb.first, wb.second->getLocStart()); } + processAssignment(wb.second->getSrcLV(), ArgResult, false); } return retVal; @@ -14219,5 +14206,51 @@ SpirvEmitter::doUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *expr) { return sizeConst; } +SpirvInstruction * +SpirvEmitter::doHLSLOutParamExpr(const HLSLOutParamExpr *Expr) { + SpirvVariable *TmpVar = nullptr; + if (Expr->isInOut()) { + SpirvInstruction *InitVal = doExpr(Expr->getBase()); + if (!InitVal->isRValue()) + InitVal = + spvBuilder.createLoad(Expr->getType(), InitVal, Expr->getLocStart()); + + TmpVar = createTemporaryVar(Expr->getType(), "hlsl.inout", InitVal, + Expr->getLocStart()); + } else { + TmpVar = + spvBuilder.addFnVar(Expr->getType(), Expr->getLocStart(), "hlsl.out"); + } + + if (const auto *OpaqueVal = Expr->getOpaqueValue()) + bindOpaqueValue(TmpVar, OpaqueVal); + + return TmpVar; +} + +SpirvInstruction * +SpirvEmitter::doHLSLArrayTemporaryExpr(const HLSLArrayTemporaryExpr *expr) { + assert(false && "Todo"); + return nullptr; +} + +SpirvInstruction *SpirvEmitter::doOpaqueValueExpr(const OpaqueValueExpr *expr) { + return getLValueForOpaqueValue(expr); +} + +void SpirvEmitter::bindOpaqueValue(SpirvVariable *lvalue, + const OpaqueValueExpr *opaqueVal) { + assert(opaqueValueBindings.count(opaqueVal) == 0 && + "Opaque values cannot map to multiple lvalues."); + opaqueValueBindings.insert(std::make_pair(opaqueVal, lvalue)); +} + +SpirvVariable * +SpirvEmitter::getLValueForOpaqueValue(const OpaqueValueExpr *opaqueVal) { + assert(opaqueValueBindings.count(opaqueVal) == 1 && + "Looking for an unbound opaque value."); + return opaqueValueBindings.find(opaqueVal)->second; +} + } // end namespace spirv } // end namespace clang diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.h b/tools/clang/lib/SPIRV/SpirvEmitter.h index c3da45e92b..2502465488 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.h +++ b/tools/clang/lib/SPIRV/SpirvEmitter.h @@ -151,6 +151,18 @@ class SpirvEmitter : public ASTConsumer { SpirvInstruction *doUnaryOperator(const UnaryOperator *expr); SpirvInstruction * doUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *expr); + + SpirvInstruction *doHLSLOutParamExpr(const HLSLOutParamExpr *expr); + SpirvInstruction * + doHLSLArrayTemporaryExpr(const HLSLArrayTemporaryExpr *expr); + SpirvInstruction *doOpaqueValueExpr(const OpaqueValueExpr *expr); + + + /// Binds an lvalue to an opaque value expression. + void bindOpaqueValue(SpirvVariable *lvalue, const OpaqueValueExpr *opaqueVal); + + /// Gets the lvalue for an opaque value. + SpirvVariable *getLValueForOpaqueValue(const OpaqueValueExpr *opaqueVal); /// Overload with pre computed SpirvEvalInfo. /// @@ -1397,6 +1409,11 @@ class SpirvEmitter : public ASTConsumer { /// The of the OpString containing the main source file's path. SpirvString *mainSourceFile; + + /// Stores the mapping of OpaqueValueExprs to SpirvVariables. + /// + /// Note: 16 is an arbitrarily chosen value. + llvm::DenseMap opaqueValueBindings; }; void SpirvEmitter::doDeclStmt(const DeclStmt *declStmt) { From 9bd9e732aaa9432a5579656c1a3d4426966109e2 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 15 May 2023 10:26:06 -0500 Subject: [PATCH 84/98] Add support for Array temporaries in SPIR-V --- .../clang/include/clang/SPIRV/SpirvBuilder.h | 3 +++ .../include/clang/SPIRV/SpirvInstruction.h | 25 +++++++++++++++++++ .../clang/include/clang/SPIRV/SpirvVisitor.h | 1 + tools/clang/lib/SPIRV/EmitVisitor.cpp | 11 ++++++++ tools/clang/lib/SPIRV/EmitVisitor.h | 1 + tools/clang/lib/SPIRV/SpirvBuilder.cpp | 13 ++++++++++ tools/clang/lib/SPIRV/SpirvEmitter.cpp | 14 ++++------- tools/clang/lib/SPIRV/SpirvInstruction.cpp | 6 +++++ 8 files changed, 65 insertions(+), 9 deletions(-) diff --git a/tools/clang/include/clang/SPIRV/SpirvBuilder.h b/tools/clang/include/clang/SPIRV/SpirvBuilder.h index 4389e1664f..c9c7ac3321 100644 --- a/tools/clang/include/clang/SPIRV/SpirvBuilder.h +++ b/tools/clang/include/clang/SPIRV/SpirvBuilder.h @@ -186,6 +186,9 @@ class SpirvBuilder { SpirvCopyObject *createCopyObject(QualType resultType, SpirvInstruction *pointer, SourceLocation); + SpirvCopyMemory *createCopyMemory(QualType resultType, SpirvInstruction *src, + SpirvInstruction *dst, SourceLocation loc); + /// \brief Creates a store sequence storing the given value into the given /// address. Returns the instruction pointer for the store instruction. /// This function handles storing to bitfields. diff --git a/tools/clang/include/clang/SPIRV/SpirvInstruction.h b/tools/clang/include/clang/SPIRV/SpirvInstruction.h index 645198c756..9f0af77c7b 100644 --- a/tools/clang/include/clang/SPIRV/SpirvInstruction.h +++ b/tools/clang/include/clang/SPIRV/SpirvInstruction.h @@ -101,6 +101,7 @@ class SpirvInstruction { IK_CompositeExtract, // OpCompositeExtract IK_CompositeInsert, // OpCompositeInsert IK_CopyObject, // OpCopyObject + IK_CopyMemory, // OpCopyObject IK_DemoteToHelperInvocation, // OpDemoteToHelperInvocation IK_IsHelperInvocationEXT, // OpIsHelperInvocationEXT IK_ExtInst, // OpExtInst @@ -1731,6 +1732,30 @@ class SpirvCopyObject : public SpirvInstruction { SpirvInstruction *pointer; }; +/// \brief OpCopyMemory instruction +class SpirvCopyMemory : public SpirvInstruction { +public: + SpirvCopyMemory(QualType resultType, SourceLocation loc, + SpirvInstruction *src, SpirvInstruction *dst); + + DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvCopyMemory) + + // For LLVM-style RTTI + static bool classof(const SpirvInstruction *inst) { + return inst->getKind() == IK_CopyMemory; + } + + bool invokeVisitor(Visitor *v) override; + + SpirvInstruction *getSource() const { return source; } + + SpirvInstruction *getDestination() const { return destination; } + +private: + SpirvInstruction *source; + SpirvInstruction *destination; +}; + /// \brief OpSampledImage instruction /// Result Type must be the OpTypeSampledImage type whose Image Type operand is /// the type of Image. We store the QualType for the underlying image as result diff --git a/tools/clang/include/clang/SPIRV/SpirvVisitor.h b/tools/clang/include/clang/SPIRV/SpirvVisitor.h index 8fe0020ae9..f300461758 100644 --- a/tools/clang/include/clang/SPIRV/SpirvVisitor.h +++ b/tools/clang/include/clang/SPIRV/SpirvVisitor.h @@ -105,6 +105,7 @@ class Visitor { DEFINE_VISIT_METHOD(SpirvImageTexelPointer) DEFINE_VISIT_METHOD(SpirvLoad) DEFINE_VISIT_METHOD(SpirvCopyObject) + DEFINE_VISIT_METHOD(SpirvCopyMemory) DEFINE_VISIT_METHOD(SpirvSampledImage) DEFINE_VISIT_METHOD(SpirvSelect) DEFINE_VISIT_METHOD(SpirvSpecConstantBinaryOp) diff --git a/tools/clang/lib/SPIRV/EmitVisitor.cpp b/tools/clang/lib/SPIRV/EmitVisitor.cpp index ef2a3af41c..2596b626f8 100644 --- a/tools/clang/lib/SPIRV/EmitVisitor.cpp +++ b/tools/clang/lib/SPIRV/EmitVisitor.cpp @@ -1262,6 +1262,17 @@ bool EmitVisitor::visit(SpirvCopyObject *inst) { return true; } +bool EmitVisitor::visit(SpirvCopyMemory *inst) { + initInstruction(inst); + curInst.push_back( + getOrAssignResultId(inst->getDestination())); + curInst.push_back(getOrAssignResultId(inst->getSource())); + finalizeInstruction(&mainBinary); + emitDebugNameForInstruction(getOrAssignResultId(inst), + inst->getDebugName()); + return true; +} + bool EmitVisitor::visit(SpirvSampledImage *inst) { initInstruction(inst); curInst.push_back(inst->getResultTypeId()); diff --git a/tools/clang/lib/SPIRV/EmitVisitor.h b/tools/clang/lib/SPIRV/EmitVisitor.h index 8852ef2620..8dee13dc6b 100644 --- a/tools/clang/lib/SPIRV/EmitVisitor.h +++ b/tools/clang/lib/SPIRV/EmitVisitor.h @@ -264,6 +264,7 @@ class EmitVisitor : public Visitor { bool visit(SpirvImageTexelPointer *) override; bool visit(SpirvLoad *) override; bool visit(SpirvCopyObject *) override; + bool visit(SpirvCopyMemory *) override; bool visit(SpirvSampledImage *) override; bool visit(SpirvSelect *) override; bool visit(SpirvSpecConstantBinaryOp *) override; diff --git a/tools/clang/lib/SPIRV/SpirvBuilder.cpp b/tools/clang/lib/SPIRV/SpirvBuilder.cpp index 24f3bb718f..ef16a75b5d 100644 --- a/tools/clang/lib/SPIRV/SpirvBuilder.cpp +++ b/tools/clang/lib/SPIRV/SpirvBuilder.cpp @@ -237,6 +237,19 @@ SpirvInstruction *SpirvBuilder::createLoad(QualType resultType, pointer->getAstResultType()->isSignedIntegerOrEnumerationType(), loc); } +SpirvCopyMemory *SpirvBuilder::createCopyMemory(QualType resultType, + SpirvInstruction *src, + SpirvInstruction *dst, + SourceLocation loc) { + auto instruction = new (context) SpirvCopyMemory(resultType, loc, src, dst); + instruction->setStorageClass(dst->getStorageClass()); + instruction->setLayoutRule(dst->getLayoutRule()); + // The result of OpCopyMemory is always an rvalue. + instruction->setRValue(dst->isRValue()); + insertPoint->addInstruction(instruction); + return instruction; +} + SpirvCopyObject *SpirvBuilder::createCopyObject(QualType resultType, SpirvInstruction *pointer, SourceLocation loc) { diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 3cbb86c8b5..8a6db48dac 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -3410,14 +3410,7 @@ SpirvInstruction *SpirvEmitter::doCastExpr(const CastExpr *expr, subExpr->getExprLoc(), range); } case CastKind::CK_ArrayToPointerDecay: { - // Literal string to const string conversion falls under this category. - if (hlsl::IsStringLiteralType(subExprType) && hlsl::IsStringType(toType)) { return doExpr(subExpr, range); - } else { - emitError("implicit cast kind '%0' unimplemented", expr->getExprLoc()) - << expr->getCastKindName() << expr->getSourceRange(); - expr->dump(); - return 0; } } default: @@ -14230,8 +14223,11 @@ SpirvEmitter::doHLSLOutParamExpr(const HLSLOutParamExpr *Expr) { SpirvInstruction * SpirvEmitter::doHLSLArrayTemporaryExpr(const HLSLArrayTemporaryExpr *expr) { - assert(false && "Todo"); - return nullptr; + auto *InitVal = doExpr(expr->getBase()); + auto *TmpVar = spvBuilder.addFnVar(expr->getType(), expr->getLocStart(), "tmp.hlsl.array"); + (void)spvBuilder.createCopyMemory(TmpVar->getAstResultType(), InitVal, + TmpVar, expr->getLocStart()); + return TmpVar; } SpirvInstruction *SpirvEmitter::doOpaqueValueExpr(const OpaqueValueExpr *expr) { diff --git a/tools/clang/lib/SPIRV/SpirvInstruction.cpp b/tools/clang/lib/SPIRV/SpirvInstruction.cpp index b59b855654..4418f9298d 100644 --- a/tools/clang/lib/SPIRV/SpirvInstruction.cpp +++ b/tools/clang/lib/SPIRV/SpirvInstruction.cpp @@ -73,6 +73,7 @@ DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvImageSparseTexelsResident) DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvImageTexelPointer) DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvLoad) DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvCopyObject) +DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvCopyMemory) DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvSampledImage) DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvSelect) DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvSpecConstantBinaryOp) @@ -799,6 +800,11 @@ SpirvCopyObject::SpirvCopyObject(QualType resultType, SourceLocation loc, : SpirvInstruction(IK_CopyObject, spv::Op::OpCopyObject, resultType, loc), pointer(pointerInst) {} +SpirvCopyMemory::SpirvCopyMemory(QualType resultType, SourceLocation loc, + SpirvInstruction *src, SpirvInstruction *dst) + : SpirvInstruction(IK_CopyMemory, spv::Op::OpCopyMemory, resultType, loc), + source(src), destination(dst) {} + SpirvSampledImage::SpirvSampledImage(QualType resultType, SourceLocation loc, SpirvInstruction *imageInst, SpirvInstruction *samplerInst, From 83705aecd6094206699f9c80af65ebd771556e53 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 23 May 2023 12:52:42 -0500 Subject: [PATCH 85/98] Only generate array temporaries for sized arrays If we have an unsized array we can't generate a temporary for it. That makes unsized arrays as function parameters an odd special case that we should fix. --- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 18 +++++++++--------- tools/clang/lib/Sema/SemaExpr.cpp | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 8a6db48dac..3ad856c309 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -3410,8 +3410,7 @@ SpirvInstruction *SpirvEmitter::doCastExpr(const CastExpr *expr, subExpr->getExprLoc(), range); } case CastKind::CK_ArrayToPointerDecay: { - return doExpr(subExpr, range); - } + return doExpr(subExpr, range); } default: emitError("implicit cast kind '%0' unimplemented", expr->getExprLoc()) @@ -11616,8 +11615,8 @@ void SpirvEmitter::processCallShader(const CallExpr *callExpr) { // HLSL Func : // template // void CallShader(in int sbtIndex, inout CallData arg) - if (const auto *implCastExpr = dyn_cast(args[1])) { - if (const auto *arg = dyn_cast(implCastExpr->getSubExpr())) { + if (const auto *outParamExpr = dyn_cast(args[1])) { + if (const auto *arg = dyn_cast(outParamExpr->getBase())) { if (const auto *varDecl = dyn_cast(arg->getDecl())) { callDataType = varDecl->getType(); callDataArg = varDecl; @@ -11702,8 +11701,8 @@ void SpirvEmitter::processTraceRay(const CallExpr *callExpr) { // inout RayPayload p) // where RayDesc = {float3 origin, float tMin, float3 direction, float tMax} - if (const auto *implCastExpr = dyn_cast(args[7])) { - if (const auto *arg = dyn_cast(implCastExpr->getSubExpr())) { + if (const auto *outExpr = dyn_cast(args[7])) { + if (const auto *arg = dyn_cast(outExpr->getBase())) { if (const auto *varDecl = dyn_cast(arg->getDecl())) { rayPayloadType = varDecl->getType(); rayPayloadArg = varDecl; @@ -12889,7 +12888,7 @@ bool SpirvEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl, // Create temporary variables for holding function call arguments llvm::SmallVector params; for (const auto *param : decl->params()) { - const auto paramType = param->getType(); + const auto paramType = param->getType().getNonReferenceType(); std::string tempVarName = "param.var." + param->getNameAsString(); auto *tempVar = spvBuilder.addFnVar(paramType, param->getLocation(), tempVarName, @@ -12971,8 +12970,9 @@ bool SpirvEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl, // .Append() intrinsic method. No need to load the parameter since we // won't need to write back here. if (param->isUsed() && !spvContext.isGS()) - loadedParam = spvBuilder.createLoad(param->getType(), params[i], - param->getLocStart()); + loadedParam = + spvBuilder.createLoad(param->getType().getNonReferenceType(), + params[i], param->getLocStart()); if (!declIdMapper.createStageOutputVar(param, loadedParam, false)) return false; diff --git a/tools/clang/lib/Sema/SemaExpr.cpp b/tools/clang/lib/Sema/SemaExpr.cpp index 7fc8805bb9..663c3bc482 100644 --- a/tools/clang/lib/Sema/SemaExpr.cpp +++ b/tools/clang/lib/Sema/SemaExpr.cpp @@ -4667,9 +4667,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, Entity.setParameterCFAudited(); // HLSL Change begin - // If this is an array and not an oputput, generate an array temporary - // expression here rather than an RValue cast. - if (ProtoArgType->isArrayType() && !Param->isModifierOut()) + // If this is a constant sized array and not an oputput, generate an array + // temporary expression here rather than an RValue cast. + if (ProtoArgType->isConstantArrayType() && !Param->isModifierOut()) Arg = HLSLArrayTemporaryExpr::Create(getASTContext(), Arg); // HLSL Change end From c0197f7ac86a12af4bbc86b012bbdc2691bfaedb Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 25 May 2023 15:13:58 -0500 Subject: [PATCH 86/98] [SPIR-V] Look through references for stage variables --- tools/clang/lib/SPIRV/DeclResultIdMapper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index 0c1f2df5ef..754d518bd2 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -2429,6 +2429,10 @@ bool DeclResultIdMapper::createStageVars( QualType type, uint32_t arraySize, const llvm::StringRef namePrefix, llvm::Optional invocationId, SpirvInstruction **value, bool noWriteBack, SemanticInfo *inheritSemantic) { + + // Look through references for stage variables. + type = type.getNonReferenceType(); + assert(value); // invocationId should only be used for handling HS per-vertex output. if (invocationId.hasValue()) { From c0a889579ae4952fbf1232d31a02ee588e2e1723 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 25 May 2023 16:27:44 -0500 Subject: [PATCH 87/98] [SPIRV] Enable eliding of `out` parameters --- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 3ad856c309..9ed132fb24 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -8023,7 +8023,8 @@ const Expr *SpirvEmitter::collectArrayStructIndices( // `-ImplicitCastExpr 'const T' lvalue // `-ArraySubscriptExpr 'ConstantBuffer':'ConstantBuffer' lvalue if (auto *castExpr = dyn_cast(expr)) { - if (castExpr->getCastKind() == CK_FlatConversion) { + if (castExpr->getCastKind() == CK_FlatConversion || + castExpr->getCastKind() == CK_ArrayToPointerDecay) { const auto *subExpr = castExpr->getSubExpr(); const QualType subExprType = subExpr->getType(); if (isConstantTextureBuffer(subExprType)) { @@ -14201,6 +14202,8 @@ SpirvEmitter::doUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *expr) { SpirvInstruction * SpirvEmitter::doHLSLOutParamExpr(const HLSLOutParamExpr *Expr) { + if (Expr->canElide()) + return doExpr(Expr->getBase()); SpirvVariable *TmpVar = nullptr; if (Expr->isInOut()) { SpirvInstruction *InitVal = doExpr(Expr->getBase()); From caf498197fd1ff93dab50eccd6b3f31abb1d9110 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 26 May 2023 12:21:13 -0500 Subject: [PATCH 88/98] [SPIRV] Look through reference type --- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 9ed132fb24..9d94ddacfa 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -12585,6 +12585,7 @@ bool SpirvEmitter::emitEntryFunctionWrapperForRayTracing( bool SpirvEmitter::processMeshOrAmplificationShaderAttributes( const FunctionDecl *decl, uint32_t *outVerticesArraySize) { + // TODO: All the `emitError` calls here should be moved to AST-based analysis. if (auto *numThreadsAttr = decl->getAttr()) { uint32_t x, y, z; x = static_cast(numThreadsAttr->getX()); @@ -12624,7 +12625,7 @@ bool SpirvEmitter::processMeshOrAmplificationShaderAttributes( for (uint32_t i = 0; i < decl->getNumParams(); i++) { const auto param = decl->getParamDecl(i); - const auto paramType = param->getType(); + const auto paramType = param->getType().getNonReferenceType(); const auto paramLoc = param->getLocation(); if (param->hasAttr() || param->hasAttr() || From d0a99e09013a36e5443d8b850ac52b9e2268dfe1 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 30 May 2023 10:20:35 -0500 Subject: [PATCH 89/98] Look through reference types --- tools/clang/lib/SPIRV/DeclResultIdMapper.cpp | 2 +- tools/clang/lib/SPIRV/GlPerVertex.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index 754d518bd2..f19bfec4ab 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -720,7 +720,7 @@ SemanticInfo DeclResultIdMapper::getStageVarSemantic(const NamedDecl *decl) { bool DeclResultIdMapper::createStageOutputVar(const DeclaratorDecl *decl, SpirvInstruction *storedValue, bool forPCF) { - QualType type = getTypeOrFnRetType(decl); + QualType type = getTypeOrFnRetType(decl).getNonReferenceType(); uint32_t arraySize = 0; // Output stream types (PointStream, LineStream, TriangleStream) are diff --git a/tools/clang/lib/SPIRV/GlPerVertex.cpp b/tools/clang/lib/SPIRV/GlPerVertex.cpp index 09b09236b4..759a491caa 100644 --- a/tools/clang/lib/SPIRV/GlPerVertex.cpp +++ b/tools/clang/lib/SPIRV/GlPerVertex.cpp @@ -112,7 +112,7 @@ llvm::SmallVector GlPerVertex::getStageOutVars() const { bool GlPerVertex::recordGlPerVertexDeclFacts(const DeclaratorDecl *decl, bool asInput) { - const QualType type = getTypeOrFnRetType(decl); + const QualType type = getTypeOrFnRetType(decl).getNonReferenceType(); if (type->isVoidType()) return true; From 16f5b8f95a116d5a5df934c81a1ad1511f5e6a6a Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 14 Jun 2023 12:28:13 -0500 Subject: [PATCH 90/98] Update fixfuncall SPIR-V tests --- tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl | 3 ++- tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl b/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl index daad5393ee..69b7fb2bd3 100644 --- a/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl +++ b/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl @@ -10,15 +10,16 @@ float4 foo(inout float f0, inout int f1) // CHECK: [[s39:%\w+]] = OpVariable %_ptr_Function_int Function // CHECK: [[s36:%\w+]] = OpVariable %_ptr_Function_float Function // CHECK: [[s33:%\w+]] = OpAccessChain %_ptr_Uniform_float {{%\w+}} %int_0 -// CHECK: [[s34:%\w+]] = OpAccessChain %_ptr_Function_int {{%\w+}} %int_1 // CHECK: [[s37:%\w+]] = OpLoad %float [[s33]] // CHECK: OpStore [[s36]] [[s37]] +// CHECK: [[s34:%\w+]] = OpAccessChain %_ptr_Function_int {{%\w+}} %int_1 // CHECK: [[s40:%\w+]] = OpLoad %int [[s34]] // CHECK: OpStore [[s39]] [[s40]] // CHECK: {{%\w+}} = OpFunctionCall %v4float %foo [[s36]] [[s39]] // CHECK: [[s41:%\w+]] = OpLoad %int [[s39]] // CHECK: OpStore [[s34]] [[s41]] // CHECK: [[s38:%\w+]] = OpLoad %float [[s36]] +// CHECK: [[s33:%\w+]] = OpAccessChain %_ptr_Uniform_float {{%\w+}} %int_0 // CHECK: OpStore [[s33]] [[s38]] struct Stru { diff --git a/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl b/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl index f2250e67dd..3682039768 100644 --- a/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl +++ b/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl @@ -9,15 +9,16 @@ RWStructuredBuffer< float4 > output : register(u1); // CHECK: [[s39:%\w+]] = OpVariable %_ptr_Function_int Function // CHECK: [[s36:%\w+]] = OpVariable %_ptr_Function_float Function // CHECK: [[s33:%\w+]] = OpAccessChain %_ptr_StorageBuffer_float {{%\w+}} %int_0 -// CHECK: [[s34:%\w+]] = OpAccessChain %_ptr_Function_int %stru %int_1 // CHECK: [[s37:%\w+]] = OpLoad %float [[s33]] // CHECK: OpStore [[s36]] [[s37]] +// CHECK: [[s34:%\w+]] = OpAccessChain %_ptr_Function_int %stru %int_1 // CHECK: [[s40:%\w+]] = OpLoad %int [[s34]] // CHECK: OpStore [[s39]] [[s40]] // CHECK: {{%\w+}} = OpFunctionCall %void %func [[s36]] [[s39]] // CHECK: [[s41:%\w+]] = OpLoad %int [[s39]] // CHECK: OpStore [[s34]] [[s41]] // CHECK: [[s38:%\w+]] = OpLoad %float [[s36]] +// CHECK: [[s33:%\w+]] = OpAccessChain %_ptr_StorageBuffer_float {{%\w+}} %int_0 // CHECK: OpStore [[s33]] [[s38]] [noinline] From d5076fc537c50c14e5bad78ae1ce016d1fd3ef57 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 15 Jun 2023 20:29:09 -0500 Subject: [PATCH 91/98] [SPIR-V] Fix pointer array decay --- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index 9d94ddacfa..b9b4c1e92b 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -8023,14 +8023,16 @@ const Expr *SpirvEmitter::collectArrayStructIndices( // `-ImplicitCastExpr 'const T' lvalue // `-ArraySubscriptExpr 'ConstantBuffer':'ConstantBuffer' lvalue if (auto *castExpr = dyn_cast(expr)) { - if (castExpr->getCastKind() == CK_FlatConversion || - castExpr->getCastKind() == CK_ArrayToPointerDecay) { - const auto *subExpr = castExpr->getSubExpr(); + const auto *subExpr = castExpr->getSubExpr(); + if (castExpr->getCastKind() == CK_FlatConversion) { const QualType subExprType = subExpr->getType(); if (isConstantTextureBuffer(subExprType)) { return collectArrayStructIndices(subExpr, rawIndex, rawIndices, indices, isMSOutAttribute); } + } else if (castExpr->getCastKind() == CK_ArrayToPointerDecay) { + return collectArrayStructIndices(subExpr, rawIndex, rawIndices, + indices, isMSOutAttribute); } } } From c0437c5e2c28b4725c7c46735029e3e4ba309202 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 15 Jun 2023 20:29:19 -0500 Subject: [PATCH 92/98] Revert "Update fixfuncall SPIR-V tests" This reverts commit 93635eb3bbb005998f6627beea7dd44bb9cc3c23. --- tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl | 3 +-- tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl b/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl index 69b7fb2bd3..daad5393ee 100644 --- a/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl +++ b/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-compute.hlsl @@ -10,16 +10,15 @@ float4 foo(inout float f0, inout int f1) // CHECK: [[s39:%\w+]] = OpVariable %_ptr_Function_int Function // CHECK: [[s36:%\w+]] = OpVariable %_ptr_Function_float Function // CHECK: [[s33:%\w+]] = OpAccessChain %_ptr_Uniform_float {{%\w+}} %int_0 +// CHECK: [[s34:%\w+]] = OpAccessChain %_ptr_Function_int {{%\w+}} %int_1 // CHECK: [[s37:%\w+]] = OpLoad %float [[s33]] // CHECK: OpStore [[s36]] [[s37]] -// CHECK: [[s34:%\w+]] = OpAccessChain %_ptr_Function_int {{%\w+}} %int_1 // CHECK: [[s40:%\w+]] = OpLoad %int [[s34]] // CHECK: OpStore [[s39]] [[s40]] // CHECK: {{%\w+}} = OpFunctionCall %v4float %foo [[s36]] [[s39]] // CHECK: [[s41:%\w+]] = OpLoad %int [[s39]] // CHECK: OpStore [[s34]] [[s41]] // CHECK: [[s38:%\w+]] = OpLoad %float [[s36]] -// CHECK: [[s33:%\w+]] = OpAccessChain %_ptr_Uniform_float {{%\w+}} %int_0 // CHECK: OpStore [[s33]] [[s38]] struct Stru { diff --git a/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl b/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl index 3682039768..f2250e67dd 100644 --- a/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl +++ b/tools/clang/test/CodeGenSPIRV/fn.fixfuncall-linkage.hlsl @@ -9,16 +9,15 @@ RWStructuredBuffer< float4 > output : register(u1); // CHECK: [[s39:%\w+]] = OpVariable %_ptr_Function_int Function // CHECK: [[s36:%\w+]] = OpVariable %_ptr_Function_float Function // CHECK: [[s33:%\w+]] = OpAccessChain %_ptr_StorageBuffer_float {{%\w+}} %int_0 +// CHECK: [[s34:%\w+]] = OpAccessChain %_ptr_Function_int %stru %int_1 // CHECK: [[s37:%\w+]] = OpLoad %float [[s33]] // CHECK: OpStore [[s36]] [[s37]] -// CHECK: [[s34:%\w+]] = OpAccessChain %_ptr_Function_int %stru %int_1 // CHECK: [[s40:%\w+]] = OpLoad %int [[s34]] // CHECK: OpStore [[s39]] [[s40]] // CHECK: {{%\w+}} = OpFunctionCall %void %func [[s36]] [[s39]] // CHECK: [[s41:%\w+]] = OpLoad %int [[s39]] // CHECK: OpStore [[s34]] [[s41]] // CHECK: [[s38:%\w+]] = OpLoad %float [[s36]] -// CHECK: [[s33:%\w+]] = OpAccessChain %_ptr_StorageBuffer_float {{%\w+}} %int_0 // CHECK: OpStore [[s33]] [[s38]] [noinline] From 1483ab358c6958bb0a1408ab1a95184ba631ba86 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Thu, 15 Jun 2023 20:38:25 -0500 Subject: [PATCH 93/98] Need to get non-reference types --- tools/clang/lib/SPIRV/SpirvEmitter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index b9b4c1e92b..0bcd3f7ce6 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -7549,7 +7549,7 @@ SpirvInstruction *SpirvEmitter::tryToAssignToMSOutAttrsOrIndices( assignToMSOutIndices(varDecl, rhs, indices); } else { assert(isMSOutAttributeBlock); - QualType type = varDecl->getType(); + QualType type = varDecl->getType().getNonReferenceType(); assert(isa(type)); type = astContext.getAsConstantArrayType(type)->getElementType(); assert(type->isStructureType()); @@ -7613,7 +7613,8 @@ void SpirvEmitter::assignToMSOutIndices( vecComponent = indices.back(); } auto *var = declIdMapper.getStageVarInstruction(decl); - const auto *varTypeDecl = astContext.getAsConstantArrayType(decl->getType()); + QualType declType = decl->getType().getNonReferenceType(); + const auto *varTypeDecl = astContext.getAsConstantArrayType(declType); QualType varType = varTypeDecl->getElementType(); uint32_t numVertices = 1; if (!isVectorType(varType, nullptr, &numVertices)) { From 0c17f619f664ae630a65521ec4ff5836af56569a Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 5 Jul 2023 12:50:21 -0500 Subject: [PATCH 94/98] Fixing failing test case The old test verified incorrect debug info based on incorrect code generation. This test verifies correct debug info. ../tools/clang/test/HLSLFileCheck/dxil/debug/out_args.hlsl --- .../HLSLFileCheck/dxil/debug/out_args.hlsl | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/dxil/debug/out_args.hlsl b/tools/clang/test/HLSLFileCheck/dxil/debug/out_args.hlsl index 16c6257407..2e0fa4afa6 100644 --- a/tools/clang/test/HLSLFileCheck/dxil/debug/out_args.hlsl +++ b/tools/clang/test/HLSLFileCheck/dxil/debug/out_args.hlsl @@ -1,15 +1,30 @@ // RUN: %dxc -E main -T ps_6_0 %s -Zi -O0 | FileCheck %s // CHECK-NOT: DW_OP_deref -// CHECK-DAG: dbg.value(metadata float {{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"arg0" !DIExpression(DW_OP_bit_piece, 0, 32) -// CHECK-DAG: dbg.value(metadata float {{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"arg0" !DIExpression(DW_OP_bit_piece, 32, 32) -// CHECK-DAG: dbg.value(metadata float {{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"arg0" !DIExpression(DW_OP_bit_piece, 64, 32) -// CHECK-DAG: dbg.value(metadata float {{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"arg1" !DIExpression(DW_OP_bit_piece, 0, 32) -// CHECK-DAG: dbg.value(metadata float {{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"arg1" !DIExpression(DW_OP_bit_piece, 32, 32) -// CHECK-DAG: dbg.value(metadata float {{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"arg1" !DIExpression(DW_OP_bit_piece, 64, 32) -// CHECK-DAG: dbg.value(metadata float {{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"output" !DIExpression(DW_OP_bit_piece, 0, 32) -// CHECK-DAG: dbg.value(metadata float {{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"output" !DIExpression(DW_OP_bit_piece, 32, 32) -// CHECK-DAG: dbg.value(metadata float {{.+}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"output" !DIExpression(DW_OP_bit_piece, 64, 32) + +// arg0 gets initialized in foo to {1,2,3}. +// CHECK: call void @llvm.dbg.value(metadata <3 x float> , i64 0, metadata {{![0-9]+}}, metadata {{![0-9]+}}), !dbg {{![0-9]+}} ; var:"arg0" !DIExpression() func:"foo" + +// output gets initialized in main to {1,2,3} on the return of foo. +// CHECK: call void @llvm.dbg.value(metadata <3 x float> , i64 0, metadata {{![0-9]+}}, metadata {{![0-9]+}}), !dbg {{![0-9]+}} ; var:"output" !DIExpression() func:"main" + +// arg1 gets initialized in main to {1,2,3} by copying from output before the +// call to bar. +// CHECK: call void @llvm.dbg.value(metadata <3 x float> , i64 0, metadata {{![0-9]+}}, metadata {{![0-9]+}}), !dbg {{![0-9]+}} ; var:"arg1" !DIExpression() func:"bar" + +// arg1 gets updated in bar to {2, 4, 6}. +// CHECK: call void @llvm.dbg.value(metadata float 2.000000e+00, i64 0, metadata {{![0-9]+}}, metadata {{![0-9]+}}), !dbg {{![0-9]+}} ; var:"arg1" !DIExpression(DW_OP_bit_piece, 0, 32) func:"bar" +// CHECK-NEXT: call void @llvm.dbg.value(metadata float 4.000000e+00, i64 0, metadata {{![0-9]+}}, metadata {{![0-9]+}}), !dbg {{![0-9]+}} ; var:"arg1" !DIExpression(DW_OP_bit_piece, 32, 32) func:"bar" +// CHECK-NEXT: call void @llvm.dbg.value(metadata float 6.000000e+00, i64 0, metadata {{![0-9]+}}, metadata {{![0-9]+}}), !dbg {{![0-9]+}} ; var:"arg1" !DIExpression(DW_OP_bit_piece, 64, 32) func:"bar" + +// arg1 gets copied back to output on the return of bar, setting output to {2, +// 4, 6}. +// CHECK: call void @llvm.dbg.value(metadata float 2.000000e+00, i64 0, metadata {{![0-9]+}}, metadata {{![0-9]+}}), !dbg {{![0-9]+}} ; var:"output" !DIExpression(DW_OP_bit_piece, 0, 32) func:"main" +// CHECK-NEXT: call void @llvm.dbg.value(metadata float 4.000000e+00, i64 0, metadata {{![0-9]+}}, metadata {{![0-9]+}}), !dbg {{![0-9]+}} ; var:"output" !DIExpression(DW_OP_bit_piece, 32, 32) func:"main" +// CHECK-NEXT: call void @llvm.dbg.value(metadata float 6.000000e+00, i64 0, metadata {{![0-9]+}}, metadata {{![0-9]+}}), !dbg {{![0-9]+}} ; var:"output" !DIExpression(DW_OP_bit_piece, 64, 32) func:"main" + +// CHECK-NOT: DW_OP_deref +// CHECK: !llvm.dbg.cu void foo(out float3 arg0) { arg0 = float3(1,2,3); // @BREAK From 2a0995a376d0009c23cda16331e4ad45e55e6e0b Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 5 Jul 2023 14:49:11 -0500 Subject: [PATCH 95/98] Revert "Updating test" This reverts commit 3307009c2c446b2f26e4ae661ac781bc9814941f. --- .../hlsl/types/vector/VectorIndexingAsArgument.hlsl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl index 92affbf1b5..5cbaf6ce90 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl @@ -8,12 +8,10 @@ // CHECK:%[[A4:.*]] = alloca i32 // CHECK:%[[A5:.*]] = alloca i32 // CHECK:%[[A6:.*]] = alloca i32 -// CHECK:%[[A7:.*]] = alloca i32 -// CHECK:%[[A8:.*]] = alloca i32 -// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A2]], i32* nonnull dereferenceable(4) %[[A1]], i32* nonnull dereferenceable(4) %[[A0]]) -// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A5]], i32* nonnull dereferenceable(4) %[[A4]], i32* nonnull dereferenceable(4) %[[A3]]) -// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A8]], i32* nonnull dereferenceable(4) %[[A7]], i32* nonnull dereferenceable(4) %[[A6]]) +// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A0]], i32* nonnull dereferenceable(4) %[[A5]], i32* nonnull dereferenceable(4) %[[A6]]) +// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A4]], i32* nonnull dereferenceable(4) %[[A3]], i32* nonnull dereferenceable(4) %[[A6]]) +// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A2]], i32* nonnull dereferenceable(4) %[[A1]], i32* nonnull dereferenceable(4) %[[A6]]) struct DimStruct { uint2 Dims; From 336ac33db961c2f58f3bd028187b3eb327623e34 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 5 Jul 2023 15:43:28 -0500 Subject: [PATCH 96/98] Fixing failing test --- .../vector/VectorIndexingAsArgument.hlsl | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl index 5cbaf6ce90..5a7308e0b3 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/types/vector/VectorIndexingAsArgument.hlsl @@ -1,17 +1,17 @@ // RUN: %dxc -E main -T lib_6_3 %s | FileCheck %s // Make sure all pointer operand of foo is from alloca. -// CHECK:%[[A0:.*]] = alloca i32 -// CHECK:%[[A1:.*]] = alloca i32 -// CHECK:%[[A2:.*]] = alloca i32 -// CHECK:%[[A3:.*]] = alloca i32 -// CHECK:%[[A4:.*]] = alloca i32 -// CHECK:%[[A5:.*]] = alloca i32 -// CHECK:%[[A6:.*]] = alloca i32 +// CHECK: [[A0:%[0-9]+]] = alloca i32 +// CHECK: [[A1:%[0-9]+]] = alloca i32 +// CHECK: [[A2:%[0-9]+]] = alloca i32 +// CHECK: [[A3:%[0-9]+]] = alloca i32 +// CHECK: [[A4:%[0-9]+]] = alloca i32 +// CHECK: [[A5:%[0-9]+]] = alloca i32 +// CHECK: [[A6:%[0-9]+]] = alloca i32 -// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A0]], i32* nonnull dereferenceable(4) %[[A5]], i32* nonnull dereferenceable(4) %[[A6]]) -// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A4]], i32* nonnull dereferenceable(4) %[[A3]], i32* nonnull dereferenceable(4) %[[A6]]) -// CHECK:call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) %[[A2]], i32* nonnull dereferenceable(4) %[[A1]], i32* nonnull dereferenceable(4) %[[A6]]) +// CHECK: call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) [[A0]], i32* nonnull dereferenceable(4) [[A2]], i32* nonnull dereferenceable(4) [[A1]]) +// CHECK: call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) [[A4]], i32* nonnull dereferenceable(4) [[A3]], i32* nonnull dereferenceable(4) [[A1]]) +// CHECK: call void @"\01?foo{{[@$?.A-Za-z0-9_]+}}"(i32 0, i32* nonnull dereferenceable(4) [[A6]], i32* nonnull dereferenceable(4) [[A5]], i32* nonnull dereferenceable(4) [[A1]]) struct DimStruct { uint2 Dims; From 1d26d6e9b467a4df0641331cb66ff3f2d7167e6f Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 19 Sep 2023 14:03:11 -0500 Subject: [PATCH 97/98] [nfc] clang-format sroa ../lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp --- .../Scalar/ScalarReplAggregatesHLSL.cpp | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp index 5418af2660..c07d3693ed 100644 --- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp +++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp @@ -1965,15 +1965,17 @@ bool SROAGlobalAndAllocas(HLModule &HLM, bool bHasDbgInfo) { if (NewEltGV == dbgOffset.base) continue; - if (GV != NewEltGV) { - GVDbgOffsetMap[NewEltGV] = dbgOffset; - // Remove GV from GVDbgOffsetMap. - GVDbgOffsetMap.erase(GV); - if (GV != dbgOffset.base) { - // Remove GV when it is replaced by NewEltGV and is not a base GV. - GV->removeDeadConstantUsers(); - GV->eraseFromParent(); - staticGVs.remove(GV); + if (GV != NewEltGV) { + GVDbgOffsetMap[NewEltGV] = dbgOffset; + // Remove GV from GVDbgOffsetMap. + GVDbgOffsetMap.erase(GV); + if (GV != dbgOffset.base) { + // Remove GV when it is replaced by NewEltGV and is not a base GV. + GV->removeDeadConstantUsers(); + GV->eraseFromParent(); + staticGVs.remove(GV); + } + GV = NewEltGV; } } else { // SROA_Parameter_HLSL has no access to a domtree, if one is needed, @@ -5445,9 +5447,9 @@ void SROA_Parameter_HLSL::flattenArgument( if (Ty->isPointerTy()) Ty = Ty->getPointerElementType(); unsigned size = DL.getTypeAllocSize(Ty); -#if 0 // HLSL Change +#if 0 // HLSL Change DIExpression *DDIExp = DIB.createBitPieceExpression(debugOffset, size); -#else // HLSL Change +#else // HLSL Change Type *argTy = Arg->getType(); if (argTy->isPointerTy()) argTy = argTy->getPointerElementType(); From 24314976ccfb1f2674eed7c2311c573b80897eb6 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 20 Oct 2023 12:44:42 -0500 Subject: [PATCH 98/98] Fix dropped function decl --- tools/clang/lib/CodeGen/CGHLSLMS.cpp | 3 ++- tools/clang/lib/CodeGen/CGHLSLRuntime.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 0269816044..eaa1b169ec 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -212,7 +212,8 @@ class CGMSHLSLRuntime : public CGHLSLRuntime { void ConstructFieldAttributedAnnotation(DxilFieldAnnotation &fieldAnnotation, QualType fieldTy, bool bDefaultRowMajor); - LValue EmitResourceParamAnnotation(CodeGenFunction& CGF, const CastExpr *E) override; + LValue EmitResourceParamAnnotation(CodeGenFunction &CGF, + const CastExpr *E) override; std::unordered_map m_ConstVarAnnotationMap; StringSet<> m_PreciseOutputSet; diff --git a/tools/clang/lib/CodeGen/CGHLSLRuntime.h b/tools/clang/lib/CodeGen/CGHLSLRuntime.h index 66b6f978e9..3a9d01ffd9 100644 --- a/tools/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/tools/clang/lib/CodeGen/CGHLSLRuntime.h @@ -163,6 +163,9 @@ class CGHLSLRuntime { virtual void EmitHLSLMartrixCastForStoreOp( CodeGenFunction &CGF, llvm::SmallVector &IRCallArgs, llvm::SmallVector &ArgTys) = 0; + + virtual LValue EmitResourceParamAnnotation(CodeGenFunction &CGF, + const CastExpr *E) = 0; }; /// Create an instance of a HLSL runtime class.