case Expr::CXXPseudoDestructorExprClass:
case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::CXXNewExprClass:
- case Expr::CXXThisExprClass:
case Expr::CXXNullPtrLiteralExprClass:
case Expr::ImaginaryLiteralClass:
case Expr::GNUNullExprClass:
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<ConstantExpr>(E)->getSubExpr());
return EmitOMPArraySectionExpr(cast<OMPArraySectionExpr>(E));
case Expr::ExtVectorElementExprClass:
return EmitExtVectorElementExpr(cast<ExtVectorElementExpr>(E));
+ case Expr::CXXThisExprClass:
+ return MakeAddrLValue(LoadCXXThisAddress(), E->getType());
case Expr::MemberExprClass:
return EmitMemberExpr(cast<MemberExpr>(E));
case Expr::CompoundLiteralExprClass:
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);
auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
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,
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,
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
}
}
- 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)
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;
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,
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
-// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *' lvalue ->h 0x{{[0-9A-Fa-f]+}}
-// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const RWBuffer<element_type> *' implicit this
+// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
+// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const RWBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
-// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *' lvalue ->h 0x{{[0-9A-Fa-f]+}}
-// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWBuffer<element_type> *' implicit this
+// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
+// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -disable-llvm-passes -o - -hlsl-entry main %s | FileCheck %s\r
+\r
+template<typename K, typename V>\r
+struct Pair {\r
+ K First;\r
+ V Second;\r
+\r
+ K getFirst() {\r
+ return this.First;\r
+ }\r
+\r
+ V getSecond() {\r
+ return Second;\r
+ }\r
+};\r
+\r
+[numthreads(1, 1, 1)]\r
+void main() {\r
+ Pair<int, float> Vals = {1, 2.0};\r
+ Vals.First = Vals.getFirst();\r
+ Vals.Second = Vals.getSecond();\r
+}\r
+\r
+// CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:8:3, line:10:3> line:8:5 getFirst 'K ()' implicit-inline\r
+// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:16, line:10:3>\r
+// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:9:4, col:16>\r
+// CHECK-NEXT:-CXXDependentScopeMemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> '<dependent type>' lvalue .First\r
+// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:11> 'Pair<K, V>' lvalue this\r
+// CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:12:3, line:14:3> line:12:5 getSecond 'V ()' implicit-inline\r
+// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:17, line:14:3>\r
+// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:13:5, col:12>\r
+// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'V' lvalue .Second 0x{{[0-9A-Fa-f]+}}\r
+// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'Pair<K, V>' lvalue implicit this\r
+\r
+// CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:8:3, line:10:3> line:8:5 used getFirst 'int ()' implicit-inline\r
+// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:16, line:10:3>\r
+// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:9:4, col:16>\r
+// CHECK-NEXT:-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> 'int':'int' <LValueToRValue>\r
+// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> 'int':'int' lvalue .First 0x{{[0-9A-Fa-f]+}}\r
+// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:11> 'Pair<int, float>' lvalue this\r
+// CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:12:3, line:14:3> line:12:5 used getSecond 'float ()' implicit-inline\r
+// CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:17, line:14:3>\r
+// CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:13:5, col:12>\r
+// CHECK-NEXT:-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'float':'float' <LValueToRValue>\r
+// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'float':'float' lvalue .Second 0x{{[0-9A-Fa-f]+}}\r
+// CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'Pair<int, float>' lvalue implicit this\r
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -disable-llvm-passes -o - -hlsl-entry main %s | FileCheck %s\r
+\r
+class Pair {\r
+ int First;\r
+ int Second;\r
+\r
+ int getFirst() {\r
+ return this.First;\r
+ }\r
+\r
+ int getSecond() {\r
+ return Second;\r
+ }\r
+};\r
+\r
+class PairInfo : Pair {\r
+ int Sum;\r
+\r
+ int getSum() {\r
+ return this.First + Second;\r
+ }\r
+};\r
+\r
+[numthreads(1, 1, 1)]\r
+void main() {\r
+ Pair Vals = {1, 2};\r
+ Vals.First = Vals.getFirst();\r
+ Vals.Second = Vals.getSecond();\r
+\r
+ PairInfo ValsInfo;\r
+ ValsInfo.First = Vals.First;\r
+ ValsInfo.Second = Vals.Second;\r
+ ValsInfo.Sum = ValsInfo.getSum();\r
+\r
+}\r
+\r
+// CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:7:3, line:9:3> line:7:7 used getFirst 'int ()' implicit-inline\r
+// CHECK-NEXT:`-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:18, line:9:3>\r
+// CHECK-NEXT:`-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:8:4, col:16>\r
+// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> 'int' <LValueToRValue>\r
+// CHECK-NEXT:`-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> 'int' lvalue .First 0x{{[0-9A-Fa-f]+}}\r
+// CHECK-NEXT:`-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:11> 'Pair' lvalue this\r
+// CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:11:3, line:13:3> line:11:7 used getSecond 'int ()' implicit-inline\r
+// CHECK-NEXT:`-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:19, line:13:3>\r
+// CHECK-NEXT:`-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:12:5, col:12>\r
+// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'int' <LValueToRValue>\r
+// CHECK-NEXT:`-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'int' lvalue .Second 0x{{[0-9A-Fa-f]+}}\r
+// CHECK-NEXT:`-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'Pair' lvalue implicit this\r
+\r
+\r
+// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:19:3, line:21:3> line:19:7 used getSum 'int ()' implicit-inline\r
+// CHECK-NEXT:`-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:16, line:21:3>\r
+// CHECK-NEXT:`-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:20:5, col:25>\r
+// CHECK-NEXT:`-BinaryOperator 0x{{[0-9A-Fa-f]+}} <col:12, col:25> 'int' '+'\r
+// CHECK-NEXT:-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:12, col:17> 'int' <LValueToRValue>\r
+// CHECK-NEXT:`-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:12, col:17> 'int' lvalue .First 0x{{[0-9A-Fa-f]+}}\r
+// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'Pair' lvalue <UncheckedDerivedToBase (Pair)>\r
+// CHECK-NEXT:`-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:12> 'PairInfo' lvalue this\r
+// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:25> 'int' <LValueToRValue>\r
+// CHECK-NEXT:`-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:25> 'int' lvalue .Second 0x{{[0-9A-Fa-f]+}}\r
+// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:25> 'Pair' lvalue <UncheckedDerivedToBase (Pair)>\r
+// CHECK-NEXT:`-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:25> 'PairInfo' lvalue implicit this\r
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -disable-llvm-passes -o - -std=hlsl202x %s | FileCheck %s\r
+\r
+struct Pair {\r
+ int First;\r
+ int Second;\r
+ int getFirst() {\r
+ Pair Another = {5, 10};\r
+ this = Another;\r
+ return this.First;\r
+ }\r
+ int getSecond() {\r
+ this = Pair();\r
+ return Second;\r
+ }\r
+ void operator=(Pair P) {\r
+ First = P.First;\r
+ Second = 2;\r
+ }\r
+};\r
+[numthreads(1, 1, 1)]\r
+void main() {\r
+ Pair Vals = {1, 2};\r
+ Vals.First = Vals.getFirst();\r
+ Vals.Second = Vals.getSecond();\r
+}\r
+\r
+// This test makes a probably safe assumption that HLSL 202x includes operator overloading for assignment operators.\r
+// CHECK: define linkonce_odr noundef i32 @"?getFirst@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %this) #2 align 2 {\r
+// CHECK-NEXT:entry:\r
+// CHECK-NEXT:%this.addr = alloca ptr, align 4\r
+// CHECK-NEXT:%Another = alloca %struct.Pair, align 4\r
+// CHECK-NEXT:%agg.tmp = alloca %struct.Pair, align 4\r
+// CHECK-NEXT:store ptr %this, ptr %this.addr, align 4\r
+// CHECK-NEXT:%this1 = load ptr, ptr %this.addr, align 4\r
+// CHECK-NEXT:%First = getelementptr inbounds %struct.Pair, ptr %Another, i32 0, i32 0\r
+// CHECK-NEXT:store i32 5, ptr %First, align 4\r
+// CHECK-NEXT:%Second = getelementptr inbounds %struct.Pair, ptr %Another, i32 0, i32 1\r
+// CHECK-NEXT:store i32 10, ptr %Second, align 4\r
+// CHECK-NEXT:call void @llvm.memcpy.p0.p0.i32(ptr align 4 %agg.tmp, ptr align 4 %Another, i32 8, i1 false)\r
+// CHECK-NEXT:call void @"??4Pair@@QAAXU0@@Z"(ptr noundef nonnull align 4 dereferenceable(8) %this1, ptr noundef byval(%struct.Pair) align 4 %agg.tmp)\r
+// CHECK-NEXT:%First2 = getelementptr inbounds %struct.Pair, ptr %this1, i32 0, i32 0\r
+// CHECK-NEXT:%0 = load i32, ptr %First2, align 4\r
+// CHECK-NEXT:ret i32 %0\r
+\r
+// CHECK: define linkonce_odr noundef i32 @"?getSecond@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %this) #2 align 2 {\r
+// CHECK-NEXT:entry:\r
+// CHECK-NEXT:%this.addr = alloca ptr, align 4\r
+// CHECK-NEXT:%agg.tmp = alloca %struct.Pair, align 4\r
+// CHECK-NEXT:store ptr %this, ptr %this.addr, align 4\r
+// CHECK-NEXT:%this1 = load ptr, ptr %this.addr, align 4\r
+// CHECK-NEXT:call void @llvm.memset.p0.i32(ptr align 4 %agg.tmp, i8 0, i32 8, i1 false)\r
+// CHECK-NEXT:call void @"??4Pair@@QAAXU0@@Z"(ptr noundef nonnull align 4 dereferenceable(8) %this1, ptr noundef byval(%struct.Pair) align 4 %agg.tmp)\r
+// CHECK-NEXT:%Second = getelementptr inbounds %struct.Pair, ptr %this1, i32 0, i32 1\r
+// CHECK-NEXT:%0 = load i32, ptr %Second, align 4\r
+// CHECK-NEXT:ret i32 %0\r
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s | FileCheck %s\r
+\r
+struct Pair {\r
+ int First;\r
+ int Second;\r
+\r
+ int getFirst() {\r
+ Pair Another = {5, 10};\r
+ this = Another;\r
+ return this.First;\r
+ }\r
+\r
+ int getSecond() {\r
+ this = Pair();\r
+ return Second;\r
+ }\r
+};\r
+\r
+[numthreads(1, 1, 1)]\r
+void main() {\r
+ Pair Vals = {1, 2.0};\r
+ Vals.First = Vals.getFirst();\r
+ Vals.Second = Vals.getSecond();\r
+}\r
+\r
+// This tests reference like implicit this in HLSL\r
+// CHECK: define linkonce_odr noundef i32 @"?getFirst@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %this) #3 align 2 {\r
+// CHECK-NEXT:entry:\r
+// CHECK-NEXT:%this.addr = alloca ptr, align 4\r
+// CHECK-NEXT:%Another = alloca %struct.Pair, align 4\r
+// CHECK-NEXT:store ptr %this, ptr %this.addr, align 4\r
+// CHECK-NEXT:%this1 = load ptr, ptr %this.addr, align 4\r
+// 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)\r
+// CHECK-NEXT:call void @llvm.memcpy.p0.p0.i32(ptr align 4 %this1, ptr align 4 %Another, i32 8, i1 false)\r
+// CHECK-NEXT:%First = getelementptr inbounds %struct.Pair, ptr %this1, i32 0, i32 0\r
+\r
+// CHECK: define linkonce_odr noundef i32 @"?getSecond@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %this) #3 align 2 {\r
+// CHECK-NEXT:entry:\r
+// CHECK-NEXT:%this.addr = alloca ptr, align 4\r
+// CHECK-NEXT:%ref.tmp = alloca %struct.Pair, align 4\r
+// CHECK-NEXT:store ptr %this, ptr %this.addr, align 4\r
+// CHECK-NEXT:%this1 = load ptr, ptr %this.addr, align 4\r
+// CHECK-NEXT:call void @llvm.memset.p0.i32(ptr align 4 %ref.tmp, i8 0, i32 8, i1 false)\r
+// CHECK-NEXT:call void @llvm.memcpy.p0.p0.i32(ptr align 4 %this1, ptr align 4 %ref.tmp, i32 8, i1 false)\r
+// CHECK-NEXT:%Second = getelementptr inbounds %struct.Pair, ptr %this1, i32 0, i32 1\r
--- /dev/null
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s | FileCheck %s\r
+\r
+struct Pair {\r
+ int First;\r
+ float Second;\r
+\r
+ int getFirst() {\r
+ return this.First;\r
+ }\r
+\r
+ float getSecond() {\r
+ return Second;\r
+ }\r
+};\r
+\r
+[numthreads(1, 1, 1)]\r
+void main() {\r
+ Pair Vals = {1, 2.0};\r
+ Vals.First = Vals.getFirst();\r
+ Vals.Second = Vals.getSecond();\r
+}\r
+\r
+// This tests reference like `this` in HLSL\r
+ // CHECK: %call = call noundef i32 @"?getFirst@Pair@@QAAHXZ"(ptr noundef nonnull align 4 dereferenceable(8) %Vals)\r
+ // CHECK-NEXT: %First = getelementptr inbounds %struct.Pair, ptr %Vals, i32 0, i32 0\r
+ // CHECK-NEXT: store i32 %call, ptr %First, align 4\r
+ // CHECK-NEXT: %call1 = call noundef float @"?getSecond@Pair@@QAAMXZ"(ptr noundef nonnull align 4 dereferenceable(8) %Vals)\r
+ // CHECK-NEXT: %Second = getelementptr inbounds %struct.Pair, ptr %Vals, i32 0, i32 1\r