llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) <details> <summary>Changes</summary> This implements the ARM-specific CXXABI lowering details for pointers to member functions, including comparsion and cast to bool. This includes updates to several places that we had neglected to insert diagnostics saying that ARM-specific handling was needed. --- Patch is 62.17 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/196592.diff 5 Files Affected: - (modified) clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp (+89-26) - (modified) clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp (+4) - (modified) clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp (+122-68) - (modified) clang/test/CIR/CodeGen/pointer-to-member-func-cmp.cpp (+126-86) - (modified) clang/test/CIR/CodeGen/pointer-to-member-func.cpp (+134-93) ``````````diff diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index 8769975bdc948..636b65f514689 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -33,10 +33,13 @@ namespace { class LowerItaniumCXXABI : public CIRCXXABI { protected: bool useARMMethodPtrABI; + bool use32BitVTableOffsetABI; public: - LowerItaniumCXXABI(LowerModule &lm, bool useARMMethodPtrABI = false) - : CIRCXXABI(lm), useARMMethodPtrABI(useARMMethodPtrABI) {} + LowerItaniumCXXABI(LowerModule &lm, bool useARMMethodPtrABI = false, + bool use32BitVTableOffsetABI = false) + : CIRCXXABI(lm), useARMMethodPtrABI(useARMMethodPtrABI), + use32BitVTableOffsetABI(use32BitVTableOffsetABI) {} /// Lower the given data member pointer type to its ABI type. The returned /// type is also a CIR type. @@ -128,12 +131,18 @@ std::unique_ptr<CIRCXXABI> createItaniumCXXABI(LowerModule &lm) { // include the other 32-bit ARM oddities: constructor/destructor return values // and array cookies. case clang::TargetCXXABI::GenericAArch64: + return std::make_unique<LowerItaniumCXXABI>( + lm, + /*useARMMethodPtrABI=*/true, + /*use32BitVTableOffsetABI=*/false); case clang::TargetCXXABI::AppleARM64: // TODO: this isn't quite right, clang uses AppleARM64CXXABI which inherits // from ARMCXXABI. We'll have to follow suit. assert(!cir::MissingFeatures::appleArm64CXXABI()); - return std::make_unique<LowerItaniumCXXABI>(lm, - /*useARMMethodPtrABI=*/true); + return std::make_unique<LowerItaniumCXXABI>( + lm, + /*useARMMethodPtrABI=*/true, + /*use32BitVTableOffsetABI=*/true); case clang::TargetCXXABI::GenericItanium: return std::make_unique<LowerItaniumCXXABI>(lm); @@ -247,7 +256,12 @@ mlir::TypedAttr LowerItaniumCXXABI::lowerMethodConstant( // least significant bit of adj then makes exactly the same // discrimination as the least significant bit of ptr does for // Itanium. - llvm_unreachable("ARM method ptr abi NYI"); + assert(!cir::MissingFeatures::pointerAuthentication()); + auto ptr = + cir::IntAttr::get(ptrdiffCIRTy, attr.getVtableOffset().value()); + auto one = cir::IntAttr::get(ptrdiffCIRTy, 1); + return cir::ConstRecordAttr::get( + loweredMethodTy, mlir::ArrayAttr::get(attr.getContext(), {ptr, one})); } // Itanium C++ ABI 2.3.2: @@ -321,11 +335,12 @@ void LowerItaniumCXXABI::lowerGetMethod( mlir::Value ptrdiffOne = cir::ConstantOp::create(locBuilder, cir::IntAttr::get(ptrdiffCIRTy, 1)); - mlir::Value adj = + mlir::Value rawAdj = cir::ExtractMemberOp::create(locBuilder, ptrdiffCIRTy, loweredMethod, 1); + mlir::Value adj = rawAdj; if (useARMMethodPtrABI) { - op.emitError("ARM method ptr abi NYI"); - return; + adj = + cir::ShiftOp::create(locBuilder, ptrdiffCIRTy, adj, ptrdiffOne, false); } // Apply the adjustment to the 'this' pointer. @@ -341,14 +356,14 @@ void LowerItaniumCXXABI::lowerGetMethod( // points to a virtual function. mlir::Value methodPtrField = cir::ExtractMemberOp::create(locBuilder, ptrdiffCIRTy, loweredMethod, 0); - mlir::Value virtualBit = - cir::AndOp::create(rewriter, op.getLoc(), methodPtrField, ptrdiffOne); - mlir::Value isVirtual; + mlir::Value virtualBit; if (useARMMethodPtrABI) - llvm_unreachable("ARM method ptr abi NYI"); + virtualBit = cir::AndOp::create(locBuilder, rawAdj, ptrdiffOne); else - isVirtual = cir::CmpOp::create(locBuilder, cir::CmpOpKind::eq, virtualBit, - ptrdiffOne); + virtualBit = + cir::AndOp::create(rewriter, op.getLoc(), methodPtrField, ptrdiffOne); + mlir::Value isVirtual = cir::CmpOp::create(locBuilder, cir::CmpOpKind::eq, + virtualBit, ptrdiffOne); assert(!cir::MissingFeatures::emitCFICheck()); assert(!cir::MissingFeatures::emitVFEInfo()); @@ -371,11 +386,15 @@ void LowerItaniumCXXABI::lowerGetMethod( /*sync_scope=*/cir::SyncScopeKindAttr{}, /*mem_order=*/cir::MemOrderAttr()); - // Get the vtable offset. + // Apply the offset. + // On ARM64, to reserve extra space in virtual member function pointers, + // we only pay attention to the low 32 bits of the offset. mlir::Value vtableOffset = methodPtrField; - assert(!useARMMethodPtrABI && "ARM method ptr abi NYI"); - vtableOffset = cir::SubOp::create(b, loc, vtableOffset.getType(), - vtableOffset, ptrdiffOne); + if (!useARMMethodPtrABI) + vtableOffset = cir::SubOp::create(b, loc, vtableOffset.getType(), + vtableOffset, ptrdiffOne); + if (use32BitVTableOffsetABI) + llvm_unreachable("AppleARM64 method ptr abi NYI"); assert(!cir::MissingFeatures::emitCFICheck()); assert(!cir::MissingFeatures::emitVFEInfo()); @@ -462,11 +481,17 @@ LowerItaniumCXXABI::lowerDerivedDataMember(cir::DerivedDataMemberOp op, static mlir::Value lowerMethodCast(mlir::Operation *op, mlir::Value loweredSrc, std::int64_t offset, bool isDerivedToBase, + bool useARMMethodPtrABI, LowerModule &lowerMod, mlir::OpBuilder &builder) { if (offset == 0) return loweredSrc; + // The this-adjustment is left-shifted by 1 on ARM, since the low bit of the + // adjustment field is used to encode whether the member function is virtual. + if (useARMMethodPtrABI) + offset <<= 1; + cir::IntType ptrdiffCIRTy = getPtrDiffCIRTy(lowerMod); auto adjField = cir::ExtractMemberOp::create(builder, op->getLoc(), ptrdiffCIRTy, loweredSrc, 1); @@ -495,7 +520,8 @@ LowerItaniumCXXABI::lowerBaseMethod(cir::BaseMethodOp op, mlir::Value loweredSrc, mlir::OpBuilder &builder) const { return lowerMethodCast(op, loweredSrc, op.getOffset().getSExtValue(), - /*isDerivedToBase=*/true, lm, builder); + /*isDerivedToBase=*/true, useARMMethodPtrABI, lm, + builder); } mlir::Value @@ -503,7 +529,8 @@ LowerItaniumCXXABI::lowerDerivedMethod(cir::DerivedMethodOp op, mlir::Value loweredSrc, mlir::OpBuilder &builder) const { return lowerMethodCast(op, loweredSrc, op.getOffset().getSExtValue(), - /*isDerivedToBase=*/false, lm, builder); + /*isDerivedToBase=*/false, useARMMethodPtrABI, lm, + builder); } mlir::Value @@ -549,6 +576,23 @@ mlir::Value LowerItaniumCXXABI::lowerMethodCmp(cir::CmpOp op, return cir::OrOp::create(locBuilder, lhs.getType(), lhs, rhs); }; + // Null member function pointers on ARM clear the low bit of Adj, + // so the zero condition has to check that neither low bit is set. + if (useARMMethodPtrABI) { + mlir::Value one = + cir::ConstantOp::create(locBuilder, cir::IntAttr::get(ptrdiffCIRTy, 1)); + + // Compute (lhs.adj | rhs.adj) & 1 and test it against zero. + mlir::Value orAdj = create_or(lhsAdjField, rhsAdjField); + mlir::Value orAdjAnd1 = create_and(orAdj, one); + mlir::Value orAdjAnd1CmpZero = + cir::CmpOp::create(locBuilder, op.getKind(), orAdjAnd1, ptrdiffZero); + if (op.getKind() == cir::CmpOpKind::eq) + ptrCmpToNull = create_and(ptrCmpToNull, orAdjAnd1CmpZero); + else + ptrCmpToNull = create_or(ptrCmpToNull, orAdjAnd1CmpZero); + } + mlir::Value result; if (op.getKind() == cir::CmpOpKind::eq) { // (lhs.ptr == null || lhs.adj == rhs.adj) && lhs.ptr == rhs.ptr @@ -593,18 +637,37 @@ LowerItaniumCXXABI::lowerMethodBitcast(cir::CastOp op, mlir::Type loweredDstTy, mlir::Value LowerItaniumCXXABI::lowerMethodToBoolCast( cir::CastOp op, mlir::Value loweredSrc, mlir::OpBuilder &builder) const { + mlir::ImplicitLocOpBuilder locBuilder(op.getLoc(), builder); + // Itanium C++ ABI 2.3.2: // // In the standard representation, a null member function pointer is // represented with ptr set to a null pointer. The value of adj is // unspecified for null member function pointers. cir::IntType ptrdiffCIRTy = getPtrDiffCIRTy(lm); - mlir::Value ptrdiffZero = cir::ConstantOp::create( - builder, op.getLoc(), cir::IntAttr::get(ptrdiffCIRTy, 0)); - mlir::Value ptrField = cir::ExtractMemberOp::create( - builder, op.getLoc(), ptrdiffCIRTy, loweredSrc, 0); - return cir::CmpOp::create(builder, op.getLoc(), cir::CmpOpKind::ne, ptrField, - ptrdiffZero); + mlir::Value ptrdiffZero = + cir::ConstantOp::create(locBuilder, cir::IntAttr::get(ptrdiffCIRTy, 0)); + mlir::Value ptrField = + cir::ExtractMemberOp::create(locBuilder, ptrdiffCIRTy, loweredSrc, 0); + + mlir::Value result = + cir::CmpOp::create(locBuilder, cir::CmpOpKind::ne, ptrField, ptrdiffZero); + + // On ARM, a member function pointer is also non-null if the low bit of 'adj' + // (the virtual bit) is set. + if (useARMMethodPtrABI) { + mlir::Value one = + cir::ConstantOp::create(locBuilder, cir::IntAttr::get(ptrdiffCIRTy, 1)); + mlir::Value adj = + cir::ExtractMemberOp::create(locBuilder, ptrdiffCIRTy, loweredSrc, 1); + mlir::Value virtualBit = + cir::AndOp::create(locBuilder, ptrdiffCIRTy, adj, one); + mlir::Value isVirtual = cir::CmpOp::create(locBuilder, cir::CmpOpKind::ne, + virtualBit, ptrdiffZero); + result = cir::OrOp::create(locBuilder, result, isVirtual); + } + + return result; } static void buildBadCastCall(mlir::OpBuilder &builder, mlir::Location loc, diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp index dbc05e13c0733..fd1e615c351a8 100644 --- a/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp @@ -6,6 +6,10 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm %s -o %t.ll // RUN: FileCheck --input-file=%t.ll --check-prefix=OGCG %s +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -std=c++17 -fclangir -emit-cir -mmlir -mlir-print-ir-before=cir-cxxabi-lowering %s -o %t-arm.cir 2> %t-arm-before.cir +// RUN: FileCheck --check-prefix=CIR-BEFORE --input-file=%t-arm-before.cir %s +// RUN: FileCheck --check-prefix=CIR-AFTER --input-file=%t-arm.cir %s + struct Foo { int a; }; diff --git a/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp b/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp index 1da7fcb557903..adb28050881e9 100644 --- a/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp @@ -1,10 +1,18 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-cir -mmlir -mlir-print-ir-before=cir-cxxabi-lowering %s -o %t.cir 2> %t-before.cir // RUN: FileCheck --check-prefix=CIR-BEFORE --input-file=%t-before.cir %s -// RUN: FileCheck --check-prefix=CIR-AFTER --input-file=%t.cir %s +// RUN: FileCheck --check-prefixes=CIR-AFTER,CIR-X86-AFTER --input-file=%t.cir %s // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll --check-prefix=LLVM %s +// RUN: FileCheck --input-file=%t-cir.ll --check-prefixes=LLVM,LLVM-X86 %s // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll --check-prefix=OGCG %s +// RUN: FileCheck --input-file=%t.ll --check-prefixes=OGCG,OGCG-X86 %s + +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -std=c++17 -fclangir -emit-cir -mmlir -mlir-print-ir-before=cir-cxxabi-lowering %s -o %t-arm.cir 2> %t-arm-before.cir +// RUN: FileCheck --check-prefix=CIR-BEFORE --input-file=%t-before.cir %s +// RUN: FileCheck --check-prefixes=CIR-AFTER,CIR-ARM-AFTER --input-file=%t-arm.cir %s +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -std=c++17 -fclangir -emit-llvm %s -o %t-arm-cir.ll +// RUN: FileCheck --input-file=%t-arm-cir.ll --check-prefixes=LLVM,LLVM-ARM %s +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -std=c++17 -emit-llvm %s -o %t-arm.ll +// RUN: FileCheck --input-file=%t-arm.ll --check-prefixes=OGCG,OGCG-ARM %s struct Foo { void m1(int); @@ -23,16 +31,34 @@ bool memfunc_to_bool(void (Foo::*func)(int)) { // CIR-BEFORE: cir.func {{.*}} @_Z15memfunc_to_boolM3FooFviE // CIR-BEFORE: %{{.*}} = cir.cast member_ptr_to_bool %{{.*}} : !cir.method<!cir.func<(!cir.ptr<!rec_Foo>, !s32i)> in !rec_Foo> -> !cir.bool -// CIR-AFTER: cir.func {{.*}} @_Z15memfunc_to_boolM3FooFviE -// CIR-AFTER: %[[FUNC:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!rec_anon_struct>, !rec_anon_struct -// CIR-AFTER: %[[NULL_VAL:.*]] = cir.const #cir.int<0> : !s64i -// CIR-AFTER: %[[FUNC_PTR:.*]] = cir.extract_member %[[FUNC]][0] : !rec_anon_struct -> !s64i -// CIR-AFTER: %[[BOOL_VAL:.*]] = cir.cmp ne %[[FUNC_PTR]], %[[NULL_VAL]] : !s64i +// CIR-AFTER: cir.func {{.*}} @_Z15memfunc_to_boolM3FooFviE +// CIR-AFTER: %[[FUNC:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!rec_anon_struct>, !rec_anon_struct +// CIR-AFTER: %[[NULL_VAL:.*]] = cir.const #cir.int<0> : !s64i +// CIR-AFTER: %[[FUNC_PTR:.*]] = cir.extract_member %[[FUNC]][0] : !rec_anon_struct -> !s64i +// CIR-AFTER: %[[BOOL_VAL:.*]] = cir.cmp ne %[[FUNC_PTR]], %[[NULL_VAL]] : !s64i +// CIR-ARM-AFTER: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR-ARM-AFTER: %[[ADJ:.*]] = cir.extract_member %[[FUNC]][1] : !rec_anon_struct -> !s64i +// CIR-ARM-AFTER: %[[AND:.*]] = cir.and %[[ADJ]], %[[ONE]] : !s64i +// CIR-ARM-AFTER: %[[NOT_VIRTUAL:.*]] = cir.cmp ne %[[AND]], %[[NULL_VAL]] : !s64i +// CIR-ARM-AFTER: %[[TMP:.*]] = cir.or %[[BOOL_VAL]], %[[NOT_VIRTUAL]] : !cir.bool +// CIR-X86-AFTER-NOT: cir.extract_member +// CIR-X86-AFTER-NOT: cir.and +// CIR-X86-AFTER-NOT: cir.cmp +// CIR-X86-AFTER-NOT: cir.or + +// LLVM: define {{.*}} i1 @_Z15memfunc_to_boolM3FooFviE +// LLVM: %[[FUNC:.*]] = load { i64, i64 }, ptr %{{.*}} +// LLVM: %[[FUNC_PTR:.*]] = extractvalue { i64, i64 } %[[FUNC]], 0 +// LLVM: %[[BOOL_VAL:.*]] = icmp ne i64 %[[FUNC_PTR]], 0 +// LLVM-ARM: %[[ADJ:.*]] = extractvalue { i64, i64 } %[[FUNC]], 1 +// LLVM-ARM: %[[AND:.*]] = and i64 %[[ADJ]], 1 +// LLVM-ARM: %[[NOT_VIRTUAL:.*]] = icmp ne i64 %[[AND]], 0 +// LLVM-ARM: %[[TMP:.*]] = or i1 %[[BOOL_VAL]], %[[NOT_VIRTUAL]] +// LLVM-X86-NOT: extractvalue +// LLVM-X86-NOT: and +// LLVM-X86-NOT: icmp +// LLVM-X86-NOT: or i1 -// LLVM: define {{.*}} i1 @_Z15memfunc_to_boolM3FooFviE -// LLVM: %[[FUNC:.*]] = load { i64, i64 }, ptr %{{.*}} -// LLVM: %[[FUNC_PTR:.*]] = extractvalue { i64, i64 } %[[FUNC]], 0 -// LLVM: %{{.*}} = icmp ne i64 %[[FUNC_PTR]], 0 // Note: OGCG uses an extra temporary for the function argument because it // composes it from coerced arguments. We'll do that in CIR too after @@ -43,7 +69,15 @@ bool memfunc_to_bool(void (Foo::*func)(int)) { // OGCG: store { i64, i64 } %[[FUNC_TMP]], ptr %[[FUNC_ADDR:.*]] // OGCG: %[[FUNC:.*]] = load { i64, i64 }, ptr %[[FUNC_ADDR]] // OGCG: %[[FUNC_PTR:.*]] = extractvalue { i64, i64 } %[[FUNC]], 0 -// OGCG: %{{.*}} = icmp ne i64 %[[FUNC_PTR]], 0 +// OGCG: %[[BOOL_VAL:.*]] = icmp ne i64 %[[FUNC_PTR]], 0 +// OGCG-ARM: %[[ADJ:.*]] = extractvalue { i64, i64 } %[[FUNC]], 1 +// OGCG-ARM: %[[AND:.*]] = and i64 %[[ADJ]], 1 +// OGCG-ARM: %[[NOT_VIRTUAL:.*]] = icmp ne i64 %[[AND]], 0 +// OGCG-ARM: %[[TMP:.*]] = or i1 %[[BOOL_VAL]], %[[NOT_VIRTUAL]] +// OGCG-X86-NOT: extractvalue +// OGCG-X86-NOT: and +// OGCG-X86-NOT: icmp +// OGCG-X86-NOT: or i1 auto memfunc_reinterpret(void (Foo::*func)(int)) -> void (Bar::*)() { return reinterpret_cast<void (Bar::*)()>(func); @@ -64,11 +98,15 @@ auto memfunc_reinterpret(void (Foo::*func)(int)) -> void (Bar::*)() { // LLVM: %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]] // LLVM: ret { i64, i64 } %[[RET]] -// OGCG: define {{.*}} { i64, i64 } @_Z19memfunc_reinterpretM3FooFviE -// OGCG: %[[FUNC:.*]] = load { i64, i64 }, ptr %{{.*}} -// OGCG: store { i64, i64 } %[[FUNC]], ptr %[[RET_ADDR:.*]] -// OGCG: %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]] -// OGCG: ret { i64, i64 } %[[RET]] +// OGCG-X86: define {{.*}} { i64, i64 } @_Z19memfunc_reinterpretM3FooFviE +// OGCG-ARM: define {{.*}} [2 x i64] @_Z19memfunc_reinterpretM3FooFviE +// OGCG: %[[FUNC:.*]] = load { i64, i64 }, ptr %{{.*}} +// OGCG: store { i64, i64 } %[[FUNC]], ptr %[[FUNC_ADDR:[^,]+]] +// OGCG-X86: %[[RET:.*]] = load { i64, i64 }, ptr %[[FUNC_ADDR]] +// OGCG-ARM: %[[TMP:.*]] = load { i64, i64 }, ptr %[[FUNC_ADDR]] +// OGCG-ARM: store { i64, i64 } %[[TMP]], ptr %[[RET_ADDR:[^,]+]] +// OGCG-ARM: %[[RET:.*]] = load [2 x i64], ptr %[[RET_ADDR]] +// OGCG: ret {{.*}} %[[RET]] struct Base1 { int x; @@ -114,11 +152,13 @@ DerivedMemFunc base_to_derived_zero_offset(Base1MemFunc ptr) { // LLVM: %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]] // LLVM: ret { i64, i64 } %[[RET]] -// OGCG: define {{.*}} { i64, i64 } @_Z27base_to_derived_zero_offsetM5Base1FviE -// OGCG: %[[ARG_ADDR:.*]] = alloca { i64, i64 } -// OGCG: store { i64, i64 } %{{.*}}, ptr %[[ARG_ADDR]] -// OGCG: %[[RET:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]] -// OGCG: ret { i64, i64 } %[[RET]] +// OGCG-X86: define {{.*}} { i64, i64 } @_Z27base_to_derived_zero_offsetM5Base1FviE +// OGCG-ARM: define {{.*}} [2 x i64] @_Z27base_to_derived_zero_offsetM5Base1FviE +// OGCG: %[[ARG_ADDR:.*]] = alloca { i64, i64 } +// OGCG: store { i64, i64 } %{{.*}}, ptr %[[ARG_ADDR]] +// OGCG-X86: %[[RET:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]] +// OGCG-ARM: %[[RET:.*]] = load [2 x i64], ptr %[[ARG_ADDR]] +// OGCG: ret {{.*}} %[[RET]] DerivedMemFunc base_to_derived(Base2MemFunc ptr) { return static_cast<DerivedMemFunc>(ptr); @@ -128,26 +168,30 @@ DerivedMemFunc base_to_derived(Base2MemFunc ptr) { // CIR-BEFORE: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.method<!cir.func<(!cir.ptr<!rec_Base2>, !s32i)> in !rec_Base2>>, !cir.method<!cir.func<(!cir.ptr<!rec_Base2>, !s32i)> in !rec_Base2> // CIR-BEFORE: %{{.*}} = cir.derived_method %[[PTR]][16] : !cir.method<!cir.func<(!cir.ptr<!rec_Base2>, !s32i)> in !rec_Base2> -> !cir.method<!cir.func<(!cir.ptr<!rec_Derived>, !s32i)> in !rec_Derived> -// CIR-AFTER: cir.func {{.*}} @_Z15base_to_derivedM5Base2FviE -// CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!rec_anon_struct>, !rec_anon_struct -// CIR-AFTER: %[[OFFSET:.*]] = cir.extract_member %[[PTR]][1] : !rec_anon_struct -> !s64i -// CIR-AFTER: %[[OFFSET_ADJ:.*]] = cir.const #cir.int<16> : !s64i -// CIR-AFTER: %[[BINOP_KIND:.*]] = cir.add nsw %[[OFFSET]], %[[OFFSET_ADJ]] : !s64i -// CIR-AFTER: %{{.*}} = cir.insert_member %[[PTR]][1], %[[BINOP_KIND]] : !rec_anon_struct, !s64i - -// LLVM: define {{.*}} { i64, i64 } @_Z15base_to_derivedM5Base2FviE -// LLVM: %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}} -// LLVM: %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG]], 1 -// LLVM: %[[ADJ_ADJ:.*]] = add nsw i64 %[[ADJ]], 16 -// LLVM: %{{.*}} = insertvalue { i64, i64 } %[[ARG]], i64 %[[ADJ_ADJ]], 1 - -// OGCG: define {{.*}} { i64, i64 } @_Z15base_to_derivedM5Base2FviE -// OGCG: %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}} -// OGCG: store { i64, i64 } %[[ARG]], ptr %[[ARG_ADDR:.*]] -// OGCG: %[[ARG1:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]] -// OGCG: %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG1]], 1 -// OGCG: %[[ADJ_ADJ:.*]] = add nsw i64 %[[ADJ]], 16 -// OGCG: %{{.*}} = insertvalue { i64, i64 } %[[ARG1]], i64 %[[ADJ_ADJ]], 1 +// CIR-AFTER: cir.func {{.*}} @_Z15base_to_derivedM5Base2FviE +// CIR-AFTER: %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!rec_anon_stru... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/196592 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
