[clang] [CIR] Support CXXThisExpr in emitLValue (PR #227316)

Aman Maurya via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 29 06:53:49 PDT 2026


https://github.com/amanmaurya92 created https://github.com/llvm/llvm-project/pull/227316

Support `CXXThisExpr` in `CIRGenFunction::emitLValue` by wrapping `loadCXXThisAddress()` into an LValue via `makeAddrLValue()`, matching classic Clang codegen (`CGExpr.cpp:1865`).

This enables LValue contexts for `this`, such as member access expressions via `this.field` in languages like HLSL where `this` is reference-like.

Fixes #227193

>From ea039e4cd2cf5325e1612956de8aba63ef93ab8a Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Tue, 29 Sep 2026 19:16:28 +0530
Subject: [PATCH] [CIR] Support CXXThisExpr in emitLValue

Support `CXXThisExpr` in `CIRGenFunction::emitLValue` by wrapping
`loadCXXThisAddress()` into an LValue via `makeAddrLValue()`, matching
classic Clang codegen (`CGExpr.cpp:1865`).

This enables LValue contexts for `this`, such as member access
expressions via `this.field` in languages like HLSL where `this` is
reference-like.

Fixes #227193
---
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      |  3 +-
 .../test/CIR/CodeGenHLSL/cxx-this-lvalue.hlsl | 79 +++++++++++++++++++
 2 files changed, 80 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CIR/CodeGenHLSL/cxx-this-lvalue.hlsl

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 823ccbe1d2e82..ca4cf4be63de3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -1301,8 +1301,7 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
                                "emitLValue: MatrixElementExpr");
     return LValue();
   case Expr::CXXThisExprClass:
-    getCIRGenModule().errorNYI(e->getSourceRange(), "emitLValue: CXXThisExpr");
-    return LValue();
+    return makeAddrLValue(loadCXXThisAddress(), e->getType());
   case Expr::MemberExprClass:
     return emitMemberExpr(cast<MemberExpr>(e));
   case Expr::CompoundLiteralExprClass:
diff --git a/clang/test/CIR/CodeGenHLSL/cxx-this-lvalue.hlsl b/clang/test/CIR/CodeGenHLSL/cxx-this-lvalue.hlsl
new file mode 100644
index 0000000000000..d1bc47215804b
--- /dev/null
+++ b/clang/test/CIR/CodeGenHLSL/cxx-this-lvalue.hlsl
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -x hlsl -triple spirv-unknown-vulkan-library -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -x hlsl -triple spirv-unknown-vulkan-library -fclangir -emit-llvm %s -o %t.cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.cir.ll %s
+// RUN: %clang_cc1 -x hlsl -triple spirv-unknown-vulkan-library -emit-llvm -disable-llvm-passes %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+struct S {
+  int a;
+
+  int getA() {
+    return this.a;
+  }
+
+  void setA(int v) {
+    this.a = v;
+  }
+};
+
+export int testGet() {
+  S s;
+  return s.getA();
+}
+
+// CIR-LABEL: cir.func {{.*}} @_ZN1S4getAEv
+// CIR:   %[[THIS_ADDR:.*]] = cir.alloca "this" {{.*}} : !cir.ptr<!cir.ptr<!rec_S>>
+// CIR:   %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:   %[[MEMBER:.*]] = cir.get_member %[[THIS]][0] {name = "a"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
+// CIR:   %[[VAL:.*]] = cir.load {{.*}} %[[MEMBER]] : !cir.ptr<!s32i>, !s32i
+// CIR:   cir.store %[[VAL]], %[[RETVAL:.*]] : !s32i, !cir.ptr<!s32i>
+// CIR:   cir.return {{.*}} : !s32i
+
+// LLVM-LABEL: define {{.*}} @_ZN1S4getAEv(
+// LLVM-SAME: ptr {{.*}} %[[ARG0:.*]])
+// LLVM:   %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM:   store ptr %[[ARG0]], ptr %[[THIS_ADDR]]
+// LLVM:   %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM:   %[[GEP:.*]] = getelementptr inbounds nuw %struct.S, ptr %[[THIS]], i32 0, i32 0
+// LLVM:   %[[VAL:.*]] = load i32, ptr %[[GEP]]
+// LLVM:   ret i32 %{{.*}}
+
+// OGCG-LABEL: define {{.*}} @_ZN1S4getAEv(
+// OGCG-SAME: ptr {{.*}} %[[ARG0:.*]])
+// OGCG:   %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG:   store ptr %[[ARG0]], ptr %[[THIS_ADDR]]
+// OGCG:   %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG:   %[[GEP:.*]] = getelementptr inbounds nuw %struct.S, ptr %[[THIS]], i32 0, i32 0
+// OGCG:   %[[VAL:.*]] = load i32, ptr %[[GEP]]
+// OGCG:   ret i32 %[[VAL]]
+
+export void testSet(int v) {
+  S s;
+  s.setA(v);
+}
+
+// CIR-LABEL: cir.func {{.*}} @_ZN1S4setAEi
+// CIR:   %[[THIS_ADDR:.*]] = cir.alloca "this" {{.*}} : !cir.ptr<!cir.ptr<!rec_S>>
+// CIR:   %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:   %[[MEMBER:.*]] = cir.get_member %[[THIS]][0] {name = "a"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
+// CIR:   cir.store align(1) {{.*}}, %[[MEMBER]] : !s32i, !cir.ptr<!s32i>
+// CIR:   cir.return
+
+// LLVM-LABEL: define {{.*}} @_ZN1S4setAEi(
+// LLVM-SAME: ptr {{.*}} %[[ARG0:.*]], i32 {{.*}} %[[ARG1:.*]])
+// LLVM:   %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM:   store ptr %[[ARG0]], ptr %[[THIS_ADDR]]
+// LLVM:   %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM:   %[[GEP:.*]] = getelementptr inbounds nuw %struct.S, ptr %[[THIS]], i32 0, i32 0
+// LLVM:   store i32 {{.*}}, ptr %[[GEP]]
+// LLVM:   ret void
+
+// OGCG-LABEL: define {{.*}} @_ZN1S4setAEi(
+// OGCG-SAME: ptr {{.*}} %[[ARG0:.*]], i32 {{.*}} %[[ARG1:.*]])
+// OGCG:   %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG:   store ptr %[[ARG0]], ptr %[[THIS_ADDR]]
+// OGCG:   %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG:   %[[GEP:.*]] = getelementptr inbounds nuw %struct.S, ptr %[[THIS]], i32 0, i32 0
+// OGCG:   store i32 {{.*}}, ptr %[[GEP]]
+// OGCG:   ret void



More information about the cfe-commits mailing list