https://github.com/vishruth-thimmaiah created 
https://github.com/llvm/llvm-project/pull/173512

This PR upstreams `ExtractMemberOp`.

Required for #172554.

>From 410ec8eee9e1643fef3a405b03687846cd1329e1 Mon Sep 17 00:00:00 2001
From: vishruth-thimmaiah <[email protected]>
Date: Thu, 25 Dec 2025 03:34:24 +0530
Subject: [PATCH] [CIR] Upstream ExtractMemberOp

This PR upstreams `ExtractMemberOp`.

Signed-off-by: vishruth-thimmaiah <[email protected]>
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 49 +++++++++++++++++++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 17 +++++++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 29 +++++++++++
 clang/test/CIR/Lowering/struct.cir            | 23 +++++++++
 4 files changed, 118 insertions(+)
 create mode 100644 clang/test/CIR/Lowering/struct.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 8358b076ee7b6..9e1be13476a16 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2727,6 +2727,55 @@ def CIR_GetMemberOp : CIR_Op<"get_member"> {
   let hasVerifier = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// ExtractMemberOp
+//===----------------------------------------------------------------------===//
+
+def CIR_ExtractMemberOp : CIR_Op<"extract_member", [Pure]> {
+  let summary = "Extract the value of a member of a record value";
+  let description = [{
+    The `cir.extract_member` operation extracts the value of a particular 
member
+    from the input record. Unlike `cir.get_member` which derives pointers, this
+    operation operates on values. It takes a value of record type, and extract
+    the value of the specified record member from the input record value.
+
+    Currently `cir.extract_member` does not work on unions.
+
+    Example:
+
+    ```mlir
+    // Suppose we have a record with multiple members.
+    !s32i = !cir.int<s, 32>
+    !s8i = !cir.int<s, 32>
+    !record_ty = !cir.record<"struct.Bar" {!s32i, !s8i}>
+
+    // And suppose we have a value of the record type.
+    %0 = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.int<2> : 
!s8i}> : !record_ty
+
+    // Extract the value of the second member of the record.
+    %1 = cir.extract_member %0[1] : !record_ty -> !s8i
+    ```
+  }];
+
+  let arguments = (ins CIRRecordType:$record, I64Attr:$index);
+  let results = (outs CIR_AnyType:$result);
+
+  let assemblyFormat = [{
+    $record `[` $index `]` attr-dict
+    `:` qualified(type($record)) `->` qualified(type($result))
+  }];
+
+  let builders = [
+    OpBuilder<(ins "mlir::Value":$record, "uint64_t":$index), [{
+      auto recordTy = mlir::cast<cir::RecordType>(record.getType());
+      mlir::Type memberTy = recordTy.getMembers()[index];
+      build($_builder, $_state, memberTy, record, index);
+    }]>
+  ];
+
+  let hasVerifier = 1;
+}
+
 
//===----------------------------------------------------------------------===//
 // GetElementOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 8f0dc705181e6..48893318c977b 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2557,6 +2557,23 @@ LogicalResult cir::GetMemberOp::verify() {
 
   return mlir::success();
 }
+
+//===----------------------------------------------------------------------===//
+// ExtractMemberOp Definitions
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::ExtractMemberOp::verify() {
+  auto recordTy = mlir::cast<cir::RecordType>(getRecord().getType());
+  if (recordTy.getKind() == cir::RecordType::Union)
+    return emitError()
+           << "cir.extract_member currently does not work on unions";
+  if (recordTy.getMembers().size() <= getIndex())
+    return emitError() << "member index out of bounds";
+  if (recordTy.getMembers()[getIndex()] != getType())
+    return emitError() << "member type mismatch";
+  return mlir::success();
+}
+
 
//===----------------------------------------------------------------------===//
 // VecCreateOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 998c93efb768a..ce63cc2823525 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3289,6 +3289,35 @@ mlir::LogicalResult 
CIRToLLVMGetMemberOpLowering::matchAndRewrite(
   }
 }
 
+mlir::LogicalResult CIRToLLVMExtractMemberOpLowering::matchAndRewrite(
+    cir::ExtractMemberOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  std::int64_t indecies[1] = {static_cast<std::int64_t>(op.getIndex())};
+
+  mlir::Type recordTy = op.getRecord().getType();
+  if (auto llvmStructTy =
+          mlir::dyn_cast<mlir::LLVM::LLVMStructType>(recordTy)) {
+    rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
+        op, adaptor.getRecord(), indecies);
+    return mlir::success();
+  }
+
+  auto cirRecordTy = mlir::cast<cir::RecordType>(recordTy);
+  switch (cirRecordTy.getKind()) {
+  case cir::RecordType::Struct:
+  case cir::RecordType::Class: {
+    rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
+        op, adaptor.getRecord(), indecies);
+    return mlir::success();
+  }
+
+  case cir::RecordType::Union: {
+    op.emitError("cir.extract_member cannot extract member from a union");
+    return mlir::failure();
+  }
+  }
+}
+
 mlir::LogicalResult CIRToLLVMUnreachableOpLowering::matchAndRewrite(
     cir::UnreachableOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/Lowering/struct.cir 
b/clang/test/CIR/Lowering/struct.cir
new file mode 100644
index 0000000000000..5ebd0d80afc30
--- /dev/null
+++ b/clang/test/CIR/Lowering/struct.cir
@@ -0,0 +1,23 @@
+// RUN: cir-opt %s -cir-to-llvm -o %t.mlir
+// RUN: FileCheck --input-file=%t.mlir %s
+
+!s32i = !cir.int<s, 32>
+!u8i = !cir.int<u, 8>
+!ty_S = !cir.record<struct "S" {!u8i, !s32i}>
+
+module {
+  // CHECK-LABEL: @test_value
+  cir.func @test_value() {
+    %0 = cir.const #cir.const_record<{#cir.int<1> : !u8i, #cir.int<2> : 
!s32i}> : !ty_S
+    //      CHECK: %[[#v0:]] = llvm.mlir.undef : !llvm.struct<"struct.S", (i8, 
i32)>
+    // CHECK-NEXT: %[[#v1:]] = llvm.mlir.constant(1 : i8) : i8
+    // CHECK-NEXT: %[[#v2:]] = llvm.insertvalue %[[#v1]], %[[#v0]][0] : 
!llvm.struct<"struct.S", (i8, i32)>
+    // CHECK-NEXT: %[[#v3:]] = llvm.mlir.constant(2 : i32) : i32
+    // CHECK-NEXT: %[[#v4:]] = llvm.insertvalue %[[#v3]], %[[#v2]][1] : 
!llvm.struct<"struct.S", (i8, i32)>
+    %1 = cir.extract_member %0[0] : !ty_S -> !u8i
+    // CHECK-NEXT: %{{.+}} = llvm.extractvalue %[[#v4]][0] : 
!llvm.struct<"struct.S", (i8, i32)>
+    %2 = cir.extract_member %0[1] : !ty_S -> !s32i
+    // CHECK-NEXT: %{{.+}} = llvm.extractvalue %[[#v4]][1] : 
!llvm.struct<"struct.S", (i8, i32)>
+    cir.return
+  }
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to