https://github.com/vishruth-thimmaiah updated https://github.com/llvm/llvm-project/pull/173512
>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 1/2] [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 + } +} >From 4403653f9f1d5ecf148d20c1bd74713dcf1cc00d Mon Sep 17 00:00:00 2001 From: vishruth-thimmaiah <[email protected]> Date: Fri, 26 Dec 2025 01:35:10 +0530 Subject: [PATCH 2/2] Add more tests Signed-off-by: vishruth-thimmaiah <[email protected]> --- clang/test/CIR/IR/invalid-struct.cir | 43 ++++++++++++++++++++++++++++ clang/test/CIR/IR/struct.cir | 13 +++++++++ 2 files changed, 56 insertions(+) create mode 100644 clang/test/CIR/IR/invalid-struct.cir diff --git a/clang/test/CIR/IR/invalid-struct.cir b/clang/test/CIR/IR/invalid-struct.cir new file mode 100644 index 0000000000000..d34534c79eb44 --- /dev/null +++ b/clang/test/CIR/IR/invalid-struct.cir @@ -0,0 +1,43 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +!u8i = !cir.int<u, 8> +!u32i = !cir.int<u, 32> +!rec_S = !cir.record<struct "S" {!u8i, !u32i}> + +module { + cir.func @struct_extract_member_invalid_element_type() { + %0 = cir.const #cir.const_record<{#cir.int<1> : !u8i, #cir.int<3> : !u32i}> : !rec_S + // expected-error @below {{member type mismatch}} + %1 = cir.extract_member %0[1] : !rec_S -> !u8i + cir.return + } +} + +// ----- + +!u8i = !cir.int<u, 8> +!u32i = !cir.int<u, 32> +!rec_S = !cir.record<struct "S" {!u8i, !u32i}> + +module { + cir.func @struct_extract_member_invalid_index_value() { + %0 = cir.const #cir.const_record<{#cir.int<1> : !u8i, #cir.int<3> : !u32i}> : !rec_S + // expected-error @below {{member index out of bounds}} + %1 = cir.extract_member %0[2] : !rec_S -> !u8i + cir.return + } +} + +// ----- + +!u32i = !cir.int<u, 32> +!rec_U = !cir.record<union "U" {!u32i}> + +module { + cir.func @extract_member_invalid_for_union() { + %0 = cir.const #cir.const_record<{#cir.int<1> : !u32i}> : !rec_U + // expected-error @below {{cir.extract_member currently does not work on unions}} + %1 = cir.extract_member %0[2] : !rec_U -> !u32i + cir.return + } +} diff --git a/clang/test/CIR/IR/struct.cir b/clang/test/CIR/IR/struct.cir index 2e011fba36b26..0f36e1a418ca4 100644 --- a/clang/test/CIR/IR/struct.cir +++ b/clang/test/CIR/IR/struct.cir @@ -76,4 +76,17 @@ module { // CHECK: cir.func @structs() { // CHECK: %0 = cir.alloca !cir.ptr<!rec_Sc>, !cir.ptr<!cir.ptr<!rec_Sc>>, ["sc", init] // CHECK: %1 = cir.alloca !cir.ptr<!rec_U>, !cir.ptr<!cir.ptr<!rec_U>>, ["u", init] + +cir.func @struct_extract_member_test() { + %0 = cir.const #cir.const_record<{#cir.int<1> : !u8i, #cir.int<2> : !u16i, #cir.int<3> : !u32i}> : !rec_Sc + %1 = cir.extract_member %0[0] : !rec_Sc -> !u8i + cir.return +} + +// CHECK: cir.func{{.*}} @struct_extract_member_test() { +// CHECK: %0 = cir.const #cir.const_record<{#cir.int<1> : !u8i, #cir.int<2> : !u16i, #cir.int<3> : !u32i}> : !rec_Sc +// CHECK: %1 = cir.extract_member %0[0] : !rec_Sc -> !u8i +// CHECK: cir.return +// CHECK: } + } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
