[clang] [CIR] Upstream ExtractMemberOp (PR #173512)
Vishruth Thimmaiah via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 24 14:14:15 PST 2025
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 <vishruththimmaiah at gmail.com>
Date: Thu, 25 Dec 2025 03:34:24 +0530
Subject: [PATCH] [CIR] Upstream ExtractMemberOp
This PR upstreams `ExtractMemberOp`.
Signed-off-by: vishruth-thimmaiah <vishruththimmaiah at gmail.com>
---
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
+ }
+}
More information about the cfe-commits
mailing list