Skip to content

Commit

Permalink
[CIR] Refactor StructElementAddr into GetMemberOp
Browse files Browse the repository at this point in the history
Improves a few aspects of the old CIR GEP equivalent:

 * Generalize the name to GetMemberOp, since it can be used for
   unions, classes, structs, and others.
 * Add custom assembly format to improve readability.
 * Add a new CIR dialect operation to represent the operation.
 * Remove redundancy from arguments names (e.g. "member_index" to just
   "index") for terseness.
 * Add verifier to check if:
    * The index is within bounds.
    * The type is a record (has members to be accessed).
    * The result type matches the type of the member.
 * Use CIRGenBuilder when building GetMemberOps.
 * Also add some getter wrappers.

ghstack-source-id: f28916ea336724caaa21beab34e7e4feafd7c8b1
Pull Request resolved: #228
  • Loading branch information
sitio-couto authored and lanza committed Nov 1, 2024
1 parent 4675a63 commit b0a6140
Show file tree
Hide file tree
Showing 16 changed files with 115 additions and 74 deletions.
54 changes: 34 additions & 20 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1409,41 +1409,47 @@ def VTableAddrPointOp : CIR_Op<"vtable.address_point",
}

//===----------------------------------------------------------------------===//
// StructElementAddr
// GetMemberOp
//===----------------------------------------------------------------------===//

// FIXME: rename this among the lines of GetGlobalOp.
def StructElementAddr : CIR_Op<"struct_element_addr"> {
def GetMemberOp : CIR_Op<"get_member"> {
let summary = "Get the address of a member of a struct";
let description = [{
The `cir.struct_element_addr` operaration gets the address of a particular
named member from the input struct.
The `cir.get_member` operation gets the address of a particular named
member from the input record.

It expects a pointer to the base struct as well as the name of the member
It expects a pointer to the base record as well as the name of the member
and its field index.

Example:
```mlir
!ty_22struct2EBar22 = type !cir.struct<"struct.Bar", i32, i8>
...
%0 = cir.alloca !ty_22struct2EBar22, cir.ptr <!ty_22struct2EBar22>
...
%1 = cir.struct_element_addr %0, "Bar.a"
%2 = cir.load %1 : cir.ptr <int>, int
...
// Suppose we have a struct with multiple members.
!s32i = !cir.int<s, 32>
!s8i = !cir.int<s, 32>
!struct_ty = !cir.struct<"struct.Bar" {!s32i, !s8i}>

// Get the address of the member at index 1.
%1 = cir.get_member %0[1] {name = "i"} : (!cir.ptr<!struct_ty>) -> !cir.ptr<!s8i>
```
}];

let arguments = (ins
Arg<CIR_PointerType, "the address to load from", [MemRead]>:$struct_addr,
StrAttr:$member_name,
IndexAttr:$member_index);
Arg<CIR_PointerType, "the address to load from", [MemRead]>:$addr,
StrAttr:$name,
IndexAttr:$index_attr);

let results = (outs Res<CIR_PointerType, "">:$result);

let assemblyFormat = [{
$addr `[` $index_attr `]` attr-dict
`:` qualified(type($addr)) `->` qualified(type($result))
}];

let builders = [
OpBuilder<(ins "Type":$type, "Value":$value, "llvm::StringRef":$name,
"unsigned":$index),
OpBuilder<(ins "Type":$type,
"Value":$value,
"llvm::StringRef":$name,
"unsigned":$index),
[{
mlir::APInt fieldIdx(64, index);
build($_builder, $_state, type, value, name, fieldIdx);
Expand All @@ -1452,10 +1458,18 @@ def StructElementAddr : CIR_Op<"struct_element_addr"> {

let extraClassDeclaration = [{
/// Return the index of the struct member being accessed.
uint64_t getIndex() { return getMemberIndex().getZExtValue(); }
uint64_t getIndex() { return getIndexAttr().getZExtValue(); }

/// Return the record type pointed by the base pointer.
mlir::cir::PointerType getAddrTy() { return getAddr().getType(); }

/// Return the result type.
mlir::cir::PointerType getResultTy() {
return getResult().getType().cast<mlir::cir::PointerType>();
}
}];

// FIXME: add verifier.
let hasVerifier = 1;
}

//===----------------------------------------------------------------------===//
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,13 @@ class CIRGenBuilderTy : public mlir::OpBuilder {
global.getLoc(), getPointerTo(global.getSymType()), global.getName());
}

/// Create a pointer to a record member.
mlir::Value createGetMember(mlir::Location loc, mlir::Type result,
mlir::Value base, llvm::StringRef name,
unsigned index) {
return create<mlir::cir::GetMemberOp>(loc, result, base, name, index);
}

/// Cast the element type of the given address to a different type,
/// preserving information like the alignment.
cir::Address createElementBitCast(mlir::Location loc, cir::Address addr,
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ static Address buildAddrOfFieldStorage(CIRGenFunction &CGF, Address Base,
// For most cases fieldName is the same as field->getName() but for lambdas,
// which do not currently carry the name, so it can be passed down from the
// CaptureStmt.
auto sea = CGF.getBuilder().create<mlir::cir::StructElementAddr>(
auto memberAddr = CGF.getBuilder().createGetMember(
loc, fieldPtr, Base.getPointer(), fieldName, fieldIndex);

// TODO: We could get the alignment from the CIRGenRecordLayout, but given the
// member name based lookup of the member here we probably shouldn't be. We'll
// have to consider this later.
auto addr = Address(sea->getResult(0), CharUnits::One());
auto addr = Address(memberAddr, CharUnits::One());
return addr;
}

Expand Down Expand Up @@ -356,8 +356,7 @@ static CIRGenCallee buildDirectCallee(CIRGenModule &CGM, GlobalDecl GD) {
// When directing calling an inline builtin, call it through it's mangled
// name to make it clear it's not the actual builtin.
auto Fn = cast<mlir::cir::FuncOp>(CGF.CurFn);
if (Fn.getName() != FDInlineName &&
onlyHasInlineBuiltinDeclaration(FD)) {
if (Fn.getName() != FDInlineName && onlyHasInlineBuiltinDeclaration(FD)) {
assert(0 && "NYI");
}

Expand Down
22 changes: 22 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2240,6 +2240,28 @@ LogicalResult MemCpyOp::verify() {
return mlir::success();
}

//===----------------------------------------------------------------------===//
// GetMemberOp Definitions
//===----------------------------------------------------------------------===//

LogicalResult GetMemberOp::verify() {

const auto recordTy = getAddrTy().getPointee().dyn_cast<StructType>();
if (!recordTy)
return emitError() << "expected pointer to a record type";

if (recordTy.getMembers().size() <= getIndex())
return emitError() << "member index out of bounds";

// FIXME(cir): Member type check is disabled for classes and incomplete types
// as the codegen for these still need to be patched.
if (!recordTy.isClass() && !recordTy.getBody() &&
recordTy.getMembers()[getIndex()] != getResultTy().getPointee())
return emitError() << "member type mismatch";

return mlir::success();
}

//===----------------------------------------------------------------------===//
// TableGen'd op method definitions
//===----------------------------------------------------------------------===//
Expand Down
16 changes: 8 additions & 8 deletions clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,12 @@ static std::string getVarNameFromValue(mlir::Value v) {

if (auto allocaOp = dyn_cast<AllocaOp>(srcOp))
return allocaOp.getName().str();
if (auto getElemOp = dyn_cast<StructElementAddr>(srcOp)) {
auto parent = dyn_cast<AllocaOp>(getElemOp.getStructAddr().getDefiningOp());
if (auto getElemOp = dyn_cast<GetMemberOp>(srcOp)) {
auto parent = dyn_cast<AllocaOp>(getElemOp.getAddr().getDefiningOp());
if (parent) {
llvm::SmallString<128> finalName;
llvm::raw_svector_ostream Out(finalName);
Out << parent.getName() << "." << getElemOp.getMemberName();
Out << parent.getName() << "." << getElemOp.getName();
return Out.str().str();
}
}
Expand Down Expand Up @@ -1048,12 +1048,12 @@ void LifetimeCheckPass::classifyAndInitTypeCategories(mlir::Value addr,
// Go through uses of the alloca via `cir.struct_element_addr`, and
// track only the fields that are actually used.
std::for_each(addr.use_begin(), addr.use_end(), [&](mlir::OpOperand &use) {
auto op = dyn_cast<mlir::cir::StructElementAddr>(use.getOwner());
auto op = dyn_cast<mlir::cir::GetMemberOp>(use.getOwner());
if (!op)
return;

auto eltAddr = op.getResult();
// If nothing is using this StructElementAddr, don't bother since
// If nothing is using this GetMemberOp, don't bother since
// it could lead to even more noisy outcomes.
if (eltAddr.use_empty())
return;
Expand All @@ -1063,7 +1063,7 @@ void LifetimeCheckPass::classifyAndInitTypeCategories(mlir::Value addr,

// Classify exploded types. Keep alloca original location.
classifyAndInitTypeCategories(eltAddr, eltTy, loc, ++nestLevel);
fieldVals[op.getMemberIndex().getZExtValue()] = eltAddr;
fieldVals[op.getIndex()] = eltAddr;
});

// In case this aggregate gets initialized at once, the fields need
Expand Down Expand Up @@ -1135,7 +1135,7 @@ void LifetimeCheckPass::checkCoroTaskStore(StoreOp storeOp) {
mlir::Value LifetimeCheckPass::getLambdaFromMemberAccess(mlir::Value addr) {
auto op = addr.getDefiningOp();
// FIXME: we likely want to consider more indirections here...
if (!isa<mlir::cir::StructElementAddr>(op))
if (!isa<mlir::cir::GetMemberOp>(op))
return nullptr;
auto allocaOp =
dyn_cast<mlir::cir::AllocaOp>(op->getOperand(0).getDefiningOp());
Expand Down Expand Up @@ -1443,7 +1443,7 @@ void LifetimeCheckPass::checkPointerDeref(mlir::Value addr, mlir::Location loc,
D << "returned lambda captures local variable";
else if (derefStyle == DerefStyle::CallParam ||
derefStyle == DerefStyle::IndirectCallParam) {
bool isAgg = isa_and_nonnull<StructElementAddr>(addr.getDefiningOp());
bool isAgg = isa_and_nonnull<GetMemberOp>(addr.getDefiningOp());
D << "passing ";
if (!isAgg)
D << "invalid pointer";
Expand Down
15 changes: 7 additions & 8 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1712,23 +1712,22 @@ class CIRBrOpLowering : public mlir::OpConversionPattern<mlir::cir::BrOp> {
}
};

class CIRStructElementAddrOpLowering
: public mlir::OpConversionPattern<mlir::cir::StructElementAddr> {
class CIRGetMemberOpLowering
: public mlir::OpConversionPattern<mlir::cir::GetMemberOp> {
public:
using mlir::OpConversionPattern<
mlir::cir::StructElementAddr>::OpConversionPattern;
using mlir::OpConversionPattern<mlir::cir::GetMemberOp>::OpConversionPattern;

mlir::LogicalResult
matchAndRewrite(mlir::cir::StructElementAddr op, OpAdaptor adaptor,
matchAndRewrite(mlir::cir::GetMemberOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
auto llResTy = getTypeConverter()->convertType(op.getType());
// Since the base address is a pointer to structs, the first offset is
// always zero. The second offset tell us which member it will access.
llvm::SmallVector<mlir::LLVM::GEPArg> offset{0, op.getIndex()};
const auto elementTy = getTypeConverter()->convertType(
op.getStructAddr().getType().getPointee());
op.getAddr().getType().getPointee());
rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
op, llResTy, elementTy, adaptor.getStructAddr(), offset);
op, llResTy, elementTy, adaptor.getAddr(), offset);
return mlir::success();
}
};
Expand Down Expand Up @@ -1784,7 +1783,7 @@ void populateCIRToLLVMConversionPatterns(mlir::RewritePatternSet &patterns,
CIRIfLowering, CIRGlobalOpLowering, CIRGetGlobalOpLowering,
CIRVAStartLowering, CIRVAEndLowering, CIRVACopyLowering,
CIRVAArgLowering, CIRBrOpLowering, CIRTernaryOpLowering,
CIRStructElementAddrOpLowering, CIRSwitchOpLowering,
CIRGetMemberOpLowering, CIRSwitchOpLowering,
CIRPtrDiffOpLowering, CIRCopyOpLowering, CIRMemCpyOpLowering>(
converter, patterns.getContext());
}
Expand Down
10 changes: 5 additions & 5 deletions clang/test/CIR/CodeGen/String.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ void test() {
// CHECK-NEXT: %0 = cir.alloca !cir.ptr<!ty_22String22>
// CHECK-NEXT: cir.store %arg0, %0
// CHECK-NEXT: %1 = cir.load %0
// CHECK-NEXT: %2 = "cir.struct_element_addr"(%1) <{member_index = 0 : index, member_name = "storage"}>
// CHECK-NEXT: %2 = cir.get_member %1[0] {name = "storage"}
// CHECK-NEXT: %3 = cir.const(#cir.null : !cir.ptr<!s8i>) : !cir.ptr<!s8i>
// CHECK-NEXT: cir.store %3, %2 : !cir.ptr<!s8i>, cir.ptr <!cir.ptr<!s8i>>
// CHECK-NEXT: %4 = "cir.struct_element_addr"(%1) <{member_index = 1 : index, member_name = "size"}> : (!cir.ptr<!ty_22String22>) -> !cir.ptr<!s64i>
// CHECK-NEXT: %4 = cir.get_member %1[1] {name = "size"} : !cir.ptr<!ty_22String22> -> !cir.ptr<!s64i>
// CHECK-NEXT: %5 = cir.const(#cir.int<0> : !s32i) : !s32i
// CHECK-NEXT: %6 = cir.cast(integral, %5 : !s32i), !s64i
// CHECK-NEXT: cir.store %6, %4 : !s64i, cir.ptr <!s64i>
Expand All @@ -36,10 +36,10 @@ void test() {
// CHECK-NEXT: cir.store %arg0, %0
// CHECK-NEXT: cir.store %arg1, %1
// CHECK-NEXT: %2 = cir.load %0
// CHECK-NEXT: %3 = "cir.struct_element_addr"(%2) <{member_index = 0 : index, member_name = "storage"}>
// CHECK-NEXT: %3 = cir.get_member %2[0] {name = "storage"}
// CHECK-NEXT: %4 = cir.const(#cir.null : !cir.ptr<!s8i>)
// CHECK-NEXT: cir.store %4, %3
// CHECK-NEXT: %5 = "cir.struct_element_addr"(%2) <{member_index = 1 : index, member_name = "size"}> : (!cir.ptr<!ty_22String22>) -> !cir.ptr<!s64i>
// CHECK-NEXT: %5 = cir.get_member %2[1] {name = "size"} : !cir.ptr<!ty_22String22> -> !cir.ptr<!s64i>
// CHECK-NEXT: %6 = cir.load %1 : cir.ptr <!s32i>, !s32i
// CHECK-NEXT: %7 = cir.cast(integral, %6 : !s32i), !s64i
// CHECK-NEXT: cir.store %7, %5 : !s64i, cir.ptr <!s64i>
Expand All @@ -52,7 +52,7 @@ void test() {
// CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!ty_22String22>, cir.ptr <!cir.ptr<!ty_22String22>>
// CHECK-NEXT: cir.store %arg1, %1 : !cir.ptr<!s8i>, cir.ptr <!cir.ptr<!s8i>>
// CHECK-NEXT: %2 = cir.load %0 : cir.ptr <!cir.ptr<!ty_22String22>>, !cir.ptr<!ty_22String22>
// CHECK-NEXT: %3 = "cir.struct_element_addr"(%2) <{member_index = 0 : index, member_name = "storage"}> : (!cir.ptr<!ty_22String22>) -> !cir.ptr<!cir.ptr<!s8i>>
// CHECK-NEXT: %3 = cir.get_member %2[0] {name = "storage"} : !cir.ptr<!ty_22String22> -> !cir.ptr<!cir.ptr<!s8i>>
// CHECK-NEXT: %4 = cir.const(#cir.null : !cir.ptr<!s8i>) : !cir.ptr<!s8i>
// CHECK-NEXT: cir.store %4, %3 : !cir.ptr<!s8i>, cir.ptr <!cir.ptr<!s8i>>
// CHECK-NEXT: cir.return
Expand Down
10 changes: 5 additions & 5 deletions clang/test/CIR/CodeGen/agg-init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ void use() { yop{}; }

// CHECK: cir.func @_Z3usev()
// CHECK: %0 = cir.alloca !ty_22yep_22, cir.ptr <!ty_22yep_22>, ["agg.tmp0"] {alignment = 4 : i64}
// CHECK: %1 = "cir.struct_element_addr"(%0) <{member_index = 0 : index, member_name = "Status"}> : (!cir.ptr<!ty_22yep_22>) -> !cir.ptr<!u32i>
// CHECK: %1 = cir.get_member %0[0] {name = "Status"} : !cir.ptr<!ty_22yep_22> -> !cir.ptr<!u32i>
// CHECK: %2 = cir.const(#cir.int<0> : !u32i) : !u32i
// CHECK: cir.store %2, %1 : !u32i, cir.ptr <!u32i>
// CHECK: %3 = "cir.struct_element_addr"(%0) <{member_index = 1 : index, member_name = "HC"}> : (!cir.ptr<!ty_22yep_22>) -> !cir.ptr<!u32i>
// CHECK: %3 = cir.get_member %0[1] {name = "HC"} : !cir.ptr<!ty_22yep_22> -> !cir.ptr<!u32i>
// CHECK: %4 = cir.const(#cir.int<0> : !u32i) : !u32i
// CHECK: cir.store %4, %3 : !u32i, cir.ptr <!u32i>
// CHECK: cir.return
Expand Down Expand Up @@ -68,12 +68,12 @@ void yo() {
// CHECK: %1 = cir.alloca !ty_22Yo22, cir.ptr <!ty_22Yo22>, ["ext2", init] {alignment = 8 : i64}
// CHECK: %2 = cir.const(#cir.const_struct<{#cir.int<1000070000> : !u32i, #cir.null : !cir.ptr<!void>, #cir.int<0> : !u64i}> : !ty_22Yo22) : !ty_22Yo22
// CHECK: cir.store %2, %0 : !ty_22Yo22, cir.ptr <!ty_22Yo22>
// CHECK: %3 = "cir.struct_element_addr"(%1) <{member_index = 0 : index, member_name = "type"}> : (!cir.ptr<!ty_22Yo22>) -> !cir.ptr<!u32i>
// CHECK: %3 = cir.get_member %1[0] {name = "type"} : !cir.ptr<!ty_22Yo22> -> !cir.ptr<!u32i>
// CHECK: %4 = cir.const(#cir.int<1000066001> : !u32i) : !u32i
// CHECK: cir.store %4, %3 : !u32i, cir.ptr <!u32i>
// CHECK: %5 = "cir.struct_element_addr"(%1) <{member_index = 1 : index, member_name = "next"}> : (!cir.ptr<!ty_22Yo22>) -> !cir.ptr<!cir.ptr<!void>>
// CHECK: %5 = cir.get_member %1[1] {name = "next"} : !cir.ptr<!ty_22Yo22> -> !cir.ptr<!cir.ptr<!void>>
// CHECK: %6 = cir.cast(bitcast, %0 : !cir.ptr<!ty_22Yo22>), !cir.ptr<!void>
// CHECK: cir.store %6, %5 : !cir.ptr<!void>, cir.ptr <!cir.ptr<!void>>
// CHECK: %7 = "cir.struct_element_addr"(%1) <{member_index = 2 : index, member_name = "createFlags"}> : (!cir.ptr<!ty_22Yo22>) -> !cir.ptr<!u64i>
// CHECK: %7 = cir.get_member %1[2] {name = "createFlags"} : !cir.ptr<!ty_22Yo22> -> !cir.ptr<!u64i>
// CHECK: %8 = cir.const(#cir.int<0> : !u64i) : !u64i
// CHECK: cir.store %8, %7 : !u64i, cir.ptr <!u64i>
8 changes: 4 additions & 4 deletions clang/test/CIR/CodeGen/assign-operator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ struct String {

// Get address of `this->size`

// CHECK: %3 = "cir.struct_element_addr"(%2) <{member_index = 0 : index, member_name = "size"}>
// CHECK: %3 = cir.get_member %2[0] {name = "size"}

// Get address of `s`

// CHECK: %4 = cir.load %1 : cir.ptr <!cir.ptr<!ty_22String22>>

// Get the address of s.size

// CHECK: %5 = "cir.struct_element_addr"(%4) <{member_index = 0 : index, member_name = "size"}>
// CHECK: %5 = cir.get_member %4[0] {name = "size"}

// Load value from s.size and store in this->size

Expand All @@ -53,9 +53,9 @@ struct String {
// CHECK: cir.store %arg1, %1 : !cir.ptr<!ty_22StringView22>
// CHECK: %3 = cir.load deref %0 : cir.ptr <!cir.ptr<!ty_22StringView22>>
// CHECK: %4 = cir.load %1 : cir.ptr <!cir.ptr<!ty_22StringView22>>
// CHECK: %5 = "cir.struct_element_addr"(%4) <{member_index = 0 : index, member_name = "size"}>
// CHECK: %5 = cir.get_member %4[0] {name = "size"}
// CHECK: %6 = cir.load %5 : cir.ptr <!s64i>, !s64i
// CHECK: %7 = "cir.struct_element_addr"(%3) <{member_index = 0 : index, member_name = "size"}>
// CHECK: %7 = cir.get_member %3[0] {name = "size"}
// CHECK: cir.store %6, %7 : !s64i, cir.ptr <!s64i>
// CHECK: cir.store %3, %2 : !cir.ptr<!ty_22StringView22>
// CHECK: %8 = cir.load %2 : cir.ptr <!cir.ptr<!ty_22StringView22>>
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CIR/CodeGen/ctor-member-lvalue-to-rvalue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ struct String {
// CHECK: cir.store %arg0, %0
// CHECK: cir.store %arg1, %1
// CHECK: %2 = cir.load %0
// CHECK: %3 = "cir.struct_element_addr"(%2) <{member_index = 0 : index, member_name = "size"}>
// CHECK: %3 = cir.get_member %2[0] {name = "size"}
// CHECK: %4 = cir.load %1
// CHECK: %5 = "cir.struct_element_addr"(%4) <{member_index = 0 : index, member_name = "size"}>
// CHECK: %5 = cir.get_member %4[0] {name = "size"}
// CHECK: %6 = cir.load %5 : cir.ptr <!s64i>, !s64i
// CHECK: cir.store %6, %3 : !s64i, cir.ptr <!s64i>
// CHECK: cir.return
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CIR/CodeGen/derived-to-base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void C3::Layer::Initialize() {

// CHECK: cir.scope {
// CHECK: %2 = cir.base_class_addr(%1 : cir.ptr <!ty_22C33A3ALayer22>) -> cir.ptr <!ty_22C23A3ALayer22>
// CHECK: %3 = "cir.struct_element_addr"(%2) <{member_index = 0 : index, member_name = "m_C1"}> : (!cir.ptr<!ty_22C23A3ALayer22>) -> !cir.ptr<!cir.ptr<!ty_22C222>>
// CHECK: %3 = cir.get_member %2[0] {name = "m_C1"} : !cir.ptr<!ty_22C23A3ALayer22> -> !cir.ptr<!cir.ptr<!ty_22C222>>
// CHECK: %4 = cir.load %3 : cir.ptr <!cir.ptr<!ty_22C222>>, !cir.ptr<!ty_22C222>
// CHECK: %5 = cir.const(#cir.null : !cir.ptr<!ty_22C222>) : !cir.ptr<!ty_22C222>
// CHECK: %6 = cir.cmp(eq, %4, %5) : !cir.ptr<!ty_22C222>, !cir.bool
Expand Down Expand Up @@ -155,4 +155,4 @@ class B : public A {
void t() {
B b;
b.foo();
}
}
Loading

0 comments on commit b0a6140

Please sign in to comment.