diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -160,7 +160,6 @@ case Expr::CXXPseudoDestructorExprClass: case Expr::UnaryExprOrTypeTraitExprClass: case Expr::CXXNewExprClass: - case Expr::CXXThisExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::ImaginaryLiteralClass: case Expr::GNUNullExprClass: @@ -205,6 +204,10 @@ case Expr::RequiresExprClass: return Cl::CL_PRValue; + // Make HLSL this reference-like + case Expr::CXXThisExprClass: + return Lang.HLSL ? Cl::CL_LValue : Cl::CL_PRValue; + case Expr::ConstantExprClass: return ClassifyInternal(Ctx, cast(E)->getSubExpr()); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1383,6 +1383,8 @@ return EmitOMPArraySectionExpr(cast(E)); case Expr::ExtVectorElementExprClass: return EmitExtVectorElementExpr(cast(E)); + case Expr::CXXThisExprClass: + return MakeAddrLValue(LoadCXXThisAddress(), E->getType()); case Expr::MemberExprClass: return EmitMemberExpr(cast(E)); case Expr::CompoundLiteralExprClass: diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -175,9 +175,11 @@ Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue, SourceLocation(), FPOptionsOverride()); - CXXThisExpr *This = new (AST) - CXXThisExpr(SourceLocation(), Constructor->getThisType(), true); - Expr *Handle = MemberExpr::CreateImplicit(AST, This, true, Fields["h"], + CXXThisExpr *This = new (AST) CXXThisExpr( + SourceLocation(), + Constructor->getThisType().getTypePtr()->getPointeeType(), true); + This->setValueKind(ExprValueKind::VK_LValue); + Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"], Fields["h"]->getType(), VK_LValue, OK_Ordinary); @@ -260,10 +262,12 @@ auto FnProtoLoc = TSInfo->getTypeLoc().getAs(); FnProtoLoc.setParam(0, IdxParam); - auto *This = new (AST) - CXXThisExpr(SourceLocation(), MethodDecl->getThisType(), true); + auto *This = new (AST) CXXThisExpr( + SourceLocation(), + MethodDecl->getThisType().getTypePtr()->getPointeeType(), true); + This->setValueKind(ExprValueKind::VK_LValue); auto *HandleAccess = MemberExpr::CreateImplicit( - AST, This, true, Handle, Handle->getType(), VK_LValue, OK_Ordinary); + AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary); auto *IndexExpr = DeclRefExpr::Create( AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -14681,7 +14681,8 @@ MemberBuilder From(OtherRef, OtherRefType, /*IsArrow=*/false, MemberLookup); - MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/true, MemberLookup); + MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/!LangOpts.HLSL, + MemberLookup); // Build the copy of this field. StmtResult Copy = buildSingleCopyAssign(*this, Loc, FieldType, @@ -14699,9 +14700,16 @@ if (!Invalid) { // Add a "return *this;" - ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc)); + Expr *ThisExpr = nullptr; + if (!LangOpts.HLSL) { + ExprResult ThisObj = + CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc)); + ThisExpr = ThisObj.get(); + } else { + ThisExpr = This.build(*this, Loc); + } - StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); + StmtResult Return = BuildReturnStmt(Loc, ThisExpr); if (Return.isInvalid()) Invalid = true; else diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15587,7 +15587,7 @@ } } - if (getLangOpts().HLSL) { + if (getLangOpts().HLSL && OpLoc.isValid()) { if (Opc == UO_AddrOf) return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 0); if (Opc == UO_Deref) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1390,6 +1390,13 @@ Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit) { + if (getLangOpts().HLSL && Type.getTypePtr()->isPointerType()) { + auto *This = new (Context) + CXXThisExpr(Loc, Type.getTypePtr()->getPointeeType(), IsImplicit); + This->setValueKind(ExprValueKind::VK_LValue); + MarkThisReferenced(This); + return This; + } auto *This = new (Context) CXXThisExpr(Loc, Type, IsImplicit); MarkThisReferenced(This); return This; diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1903,6 +1903,14 @@ if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); baseExpr = BuildCXXThisExpr(loc, ThisTy, /*IsImplicit=*/true); + if (getLangOpts().HLSL && ThisTy.getTypePtr()->isPointerType()) { + ThisTy = ThisTy.getTypePtr()->getPointeeType(); + return BuildMemberReferenceExpr(baseExpr, ThisTy, + /*OpLoc*/ SourceLocation(), + /*IsArrow*/ false, SS, TemplateKWLoc, + /*FirstQualifierInScope*/ nullptr, R, + TemplateArgs, S); + } } return BuildMemberReferenceExpr(baseExpr, ThisTy, diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl --- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl +++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl @@ -46,8 +46,8 @@ // CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <> // CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <> // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type' lvalue -// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type *' lvalue ->h 0x{{[0-9A-Fa-f]+}} -// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> 'const RWBuffer *' implicit this +// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> 'const RWBuffer' lvalue implicit this // CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <> Implicit always_inline @@ -56,8 +56,8 @@ // CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <> // CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <> // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type' lvalue -// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type *' lvalue ->h 0x{{[0-9A-Fa-f]+}} -// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> 'RWBuffer *' implicit this +// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> 'RWBuffer' lvalue implicit this // CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <> Implicit always_inline diff --git a/clang/test/AST/HLSL/this-reference-template.hlsl b/clang/test/AST/HLSL/this-reference-template.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/AST/HLSL/this-reference-template.hlsl @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -disable-llvm-passes -o - -hlsl-entry main %s | FileCheck %s + +template +struct Pair { + K First; + V Second; + + K getFirst() { + return this.First; + } + + V getSecond() { + return Second; + } +}; + +[numthreads(1, 1, 1)] +void main() { + Pair Vals = {1, 2.0}; + Vals.First = Vals.getFirst(); + Vals.Second = Vals.getSecond(); +} + +// CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} line:8:5 getFirst 'K ()' implicit-inline +// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-CXXDependentScopeMemberExpr 0x{{[0-9A-Fa-f]+}} '' lvalue .First +// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} 'Pair' lvalue this +// CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} line:12:5 getSecond 'V ()' implicit-inline +// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} 'V' lvalue .Second 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} 'Pair' lvalue implicit this + +// CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} line:8:5 used getFirst 'int ()' implicit-inline +// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} 'int':'int' +// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} 'int':'int' lvalue .First 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} 'Pair' lvalue this +// CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} line:12:5 used getSecond 'float ()' implicit-inline +// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} 'float':'float' +// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} 'float':'float' lvalue .Second 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} 'Pair' lvalue implicit this diff --git a/clang/test/AST/HLSL/this-reference.hlsl b/clang/test/AST/HLSL/this-reference.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/AST/HLSL/this-reference.hlsl @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -disable-llvm-passes -o - -hlsl-entry main %s | FileCheck %s + +class Pair { + int First; + int Second; + + int getFirst() { + return this.First; + } + + int getSecond() { + return Second; + } +}; + +class PairInfo : Pair { + int Sum; + + int getSum() { + return this.First + Second; + } +}; + +[numthreads(1, 1, 1)] +void main() { + Pair Vals = {1, 2}; + Vals.First = Vals.getFirst(); + Vals.Second = Vals.getSecond(); + + PairInfo ValsInfo; + ValsInfo.First = Vals.First; + ValsInfo.Second = Vals.Second; + ValsInfo.Sum = ValsInfo.getSum(); + +} + +// CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} line:7:7 used getFirst 'int ()' implicit-inline +// CHECK-NEXT:`-CompoundStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-ReturnStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} 'int' +// CHECK-NEXT:`-MemberExpr 0x{{[0-9A-Fa-f]+}} 'int' lvalue .First 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-CXXThisExpr 0x{{[0-9A-Fa-f]+}} 'Pair' lvalue this +// CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} line:11:7 used getSecond 'int ()' implicit-inline +// CHECK-NEXT:`-CompoundStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-ReturnStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} 'int' +// CHECK-NEXT:`-MemberExpr 0x{{[0-9A-Fa-f]+}} 'int' lvalue .Second 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-CXXThisExpr 0x{{[0-9A-Fa-f]+}} 'Pair' lvalue implicit this + + +// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} line:19:7 used getSum 'int ()' implicit-inline +// CHECK-NEXT:`-CompoundStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-ReturnStmt 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-BinaryOperator 0x{{[0-9A-Fa-f]+}} 'int' '+' +// CHECK-NEXT:-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} 'int' +// CHECK-NEXT:`-MemberExpr 0x{{[0-9A-Fa-f]+}} 'int' lvalue .First 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} 'Pair' lvalue +// CHECK-NEXT:`-CXXThisExpr 0x{{[0-9A-Fa-f]+}} 'PairInfo' lvalue this +// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} 'int' +// CHECK-NEXT:`-MemberExpr 0x{{[0-9A-Fa-f]+}} 'int' lvalue .Second 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} 'Pair' lvalue +// CHECK-NEXT:`-CXXThisExpr 0x{{[0-9A-Fa-f]+}} 'PairInfo' lvalue implicit this diff --git a/clang/test/CodeGenHLSL/this-assignment-overload.hlsl b/clang/test/CodeGenHLSL/this-assignment-overload.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenHLSL/this-assignment-overload.hlsl @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -disable-llvm-passes -o - -std=hlsl202x %s | FileCheck %s + +struct Pair { + int First; + int Second; + int getFirst() { + Pair Another = {5, 10}; + this = Another; + return this.First; + } + int getSecond() { + this = Pair(); + return Second; + } + void operator=(Pair P) { + First = P.First; + Second = 2; + } +}; +[numthreads(1, 1, 1)] +void main() { + Pair Vals = {1, 2}; + Vals.First = Vals.getFirst(); + Vals.Second = Vals.getSecond(); +} + +// This test makes a probably safe assumption that HLSL 202x includes operator overloading for assignment operators. +// CHECK: define linkonce_odr noundef i32 @"?getFirst@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %this) #2 align 2 { +// CHECK-NEXT:entry: +// CHECK-NEXT:%this.addr = alloca ptr, align 4 +// CHECK-NEXT:%Another = alloca %struct.Pair, align 4 +// CHECK-NEXT:%agg.tmp = alloca %struct.Pair, align 4 +// CHECK-NEXT:store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT:%this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT:%First = getelementptr inbounds %struct.Pair, ptr %Another, i32 0, i32 0 +// CHECK-NEXT:store i32 5, ptr %First, align 4 +// CHECK-NEXT:%Second = getelementptr inbounds %struct.Pair, ptr %Another, i32 0, i32 1 +// CHECK-NEXT:store i32 10, ptr %Second, align 4 +// CHECK-NEXT:call void @llvm.memcpy.p0.p0.i32(ptr align 4 %agg.tmp, ptr align 4 %Another, i32 8, i1 false) +// CHECK-NEXT:call void @"??4Pair@@QAAXU0@@Z"(ptr noundef nonnull align 4 dereferenceable(8) %this1, ptr noundef byval(%struct.Pair) align 4 %agg.tmp) +// CHECK-NEXT:%First2 = getelementptr inbounds %struct.Pair, ptr %this1, i32 0, i32 0 +// CHECK-NEXT:%0 = load i32, ptr %First2, align 4 +// CHECK-NEXT:ret i32 %0 + +// CHECK: define linkonce_odr noundef i32 @"?getSecond@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %this) #2 align 2 { +// CHECK-NEXT:entry: +// CHECK-NEXT:%this.addr = alloca ptr, align 4 +// CHECK-NEXT:%agg.tmp = alloca %struct.Pair, align 4 +// CHECK-NEXT:store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT:%this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT:call void @llvm.memset.p0.i32(ptr align 4 %agg.tmp, i8 0, i32 8, i1 false) +// CHECK-NEXT:call void @"??4Pair@@QAAXU0@@Z"(ptr noundef nonnull align 4 dereferenceable(8) %this1, ptr noundef byval(%struct.Pair) align 4 %agg.tmp) +// CHECK-NEXT:%Second = getelementptr inbounds %struct.Pair, ptr %this1, i32 0, i32 1 +// CHECK-NEXT:%0 = load i32, ptr %Second, align 4 +// CHECK-NEXT:ret i32 %0 diff --git a/clang/test/CodeGenHLSL/this-assignment.hlsl b/clang/test/CodeGenHLSL/this-assignment.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenHLSL/this-assignment.hlsl @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s | FileCheck %s + +struct Pair { + int First; + int Second; + + int getFirst() { + Pair Another = {5, 10}; + this = Another; + return this.First; + } + + int getSecond() { + this = Pair(); + return Second; + } +}; + +[numthreads(1, 1, 1)] +void main() { + Pair Vals = {1, 2.0}; + Vals.First = Vals.getFirst(); + Vals.Second = Vals.getSecond(); +} + +// This tests reference like implicit this in HLSL +// CHECK: define linkonce_odr noundef i32 @"?getFirst@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %this) #3 align 2 { +// CHECK-NEXT:entry: +// CHECK-NEXT:%this.addr = alloca ptr, align 4 +// CHECK-NEXT:%Another = alloca %struct.Pair, align 4 +// CHECK-NEXT:store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT:%this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT:call void @llvm.memcpy.p0.p0.i32(ptr align 4 %Another, ptr align 4 @"__const.?getFirst@Pair@@QAAHXZ.Another", i32 8, i1 false) +// CHECK-NEXT:call void @llvm.memcpy.p0.p0.i32(ptr align 4 %this1, ptr align 4 %Another, i32 8, i1 false) +// CHECK-NEXT:%First = getelementptr inbounds %struct.Pair, ptr %this1, i32 0, i32 0 + +// CHECK: define linkonce_odr noundef i32 @"?getSecond@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %this) #3 align 2 { +// CHECK-NEXT:entry: +// CHECK-NEXT:%this.addr = alloca ptr, align 4 +// CHECK-NEXT:%ref.tmp = alloca %struct.Pair, align 4 +// CHECK-NEXT:store ptr %this, ptr %this.addr, align 4 +// CHECK-NEXT:%this1 = load ptr, ptr %this.addr, align 4 +// CHECK-NEXT:call void @llvm.memset.p0.i32(ptr align 4 %ref.tmp, i8 0, i32 8, i1 false) +// CHECK-NEXT:call void @llvm.memcpy.p0.p0.i32(ptr align 4 %this1, ptr align 4 %ref.tmp, i32 8, i1 false) +// CHECK-NEXT:%Second = getelementptr inbounds %struct.Pair, ptr %this1, i32 0, i32 1 diff --git a/clang/test/CodeGenHLSL/this-reference.hlsl b/clang/test/CodeGenHLSL/this-reference.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenHLSL/this-reference.hlsl @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s | FileCheck %s + +struct Pair { + int First; + float Second; + + int getFirst() { + return this.First; + } + + float getSecond() { + return Second; + } +}; + +[numthreads(1, 1, 1)] +void main() { + Pair Vals = {1, 2.0}; + Vals.First = Vals.getFirst(); + Vals.Second = Vals.getSecond(); +} + +// This tests reference like `this` in HLSL + // CHECK: %call = call noundef i32 @"?getFirst@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %Vals) + // CHECK-NEXT: %First = getelementptr inbounds %struct.Pair, ptr %Vals, i32 0, i32 0 + // CHECK-NEXT: store i32 %call, ptr %First, align 4 + // CHECK-NEXT: %call1 = call noundef float @"?getSecond@Pair@@QAAMXZ"(ptr noundef nonnull align 4 dereferenceable(8) %Vals) + // CHECK-NEXT: %Second = getelementptr inbounds %struct.Pair, ptr %Vals, i32 0, i32 1