[clang] c3d7f77 - [CIR] Lower PsuedoObjectExpr LValues (#192108)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 15 05:59:54 PDT 2026
Author: Erich Keane
Date: 2026-04-15T05:59:49-07:00
New Revision: c3d7f77a2b27ee92366aeac1b9114a33be3245ba
URL: https://github.com/llvm/llvm-project/commit/c3d7f77a2b27ee92366aeac1b9114a33be3245ba
DIFF: https://github.com/llvm/llvm-project/commit/c3d7f77a2b27ee92366aeac1b9114a33be3245ba.diff
LOG: [CIR] Lower PsuedoObjectExpr LValues (#192108)
This ends up being pretty much copy/paste from classic-codegen, so it
doesn't have anything particularly novel.
I DID switch the return type of the helper function to be a variant
instead of a manually-put-together pair, and switched to range-for, but
otherwise it should be identical.
However, I was uanble to reproduce a few of the branches, so NYIs were
left in place until we can figure them out. At least some of them are
going to be for RValue versions.
Added:
Modified:
clang/lib/CIR/CodeGen/CIRGenFunction.cpp
clang/lib/CIR/CodeGen/CIRGenFunction.h
clang/test/CIR/CodeGen/three-way-cmp.cpp
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index fcfbeb809371e..0113ccaf64fe7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/CIR/MissingFeatures.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/IR/FPEnv.h"
#include <cassert>
@@ -1010,6 +1011,85 @@ clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd,
return retTy;
}
+static std::variant<LValue, RValue>
+emitPseudoObjectExpr(CIRGenFunction &cgf, const PseudoObjectExpr *e,
+ bool forLValue, AggValueSlot slot) {
+ using OVMD = CIRGenFunction::OpaqueValueMappingData;
+ SmallVector<OVMD> opaques;
+ llvm::scope_exit opaque_cleanup{
+ [&]() { llvm::for_each(opaques, [&](OVMD &o) { o.unbind(cgf); }); }};
+
+ // Find the result expression, if any.
+ const Expr *resultExpr = e->getResultExpr();
+ std::variant<LValue, RValue> result;
+
+ for (const Expr *semantic : e->semantics()) {
+ // If this semantic expression is an opaque value, bind it
+ // to the result of its source expression.
+ if (const auto *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
+
+ // Skip unique OVEs.
+ if (ov->isUnique()) {
+ // FIXME: This doesn't really affect anything, but I cannot find a test
+ // for this, so leave an ErrorNYI here until we can find one.
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "emitPseudoObjectExpr skipped for uniqueness");
+ assert(ov != resultExpr &&
+ "A unique OVE cannot be used as the result expression");
+ continue;
+ }
+
+ // If this is the result expression, we may need to evaluate
+ // directly into the slot.
+ OVMD opaqueData;
+ if (ov == resultExpr && ov->isPRValue() && !forLValue &&
+ CIRGenFunction::hasAggregateEvaluationKind(ov->getType())) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "emitPseudoObjectExpr for RValue & aggregate kind");
+ } else {
+ opaqueData = OVMD::bind(cgf, ov, ov->getSourceExpr());
+
+ // If this is the result, also evaluate the result now.
+ if (ov == resultExpr) {
+ // FIXME: This doesn't really affect anything, but I cannot find a
+ // test for this, so leave an ErrorNYI here until we can find one.
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "emitPseudoObjectExpr as result");
+ if (forLValue)
+ result = cgf.emitLValue(ov);
+ else
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "emitPseudoObjectExpr as an RValue");
+ }
+ }
+ opaques.push_back(opaqueData);
+ } else if (semantic == resultExpr) {
+ // Otherwise, if the expression is the result, evaluate it
+ // and remember the result.
+ if (forLValue)
+ result = cgf.emitLValue(semantic);
+ else
+ cgf.cgm.errorNYI(
+ e->getSourceRange(),
+ "emitPseudoObjectExpr as an RValue, when semantic is result");
+ } else {
+ // FIXME: best I can tell, this is only reachable as an r-value, so this
+ // isn't properly tested.
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "emitPseudoObjectExpr as an ignored value");
+ // Otherwise, evaluate the expression in an ignored context.
+ cgf.emitIgnoredExpr(semantic);
+ }
+ }
+
+ return result;
+}
+
+LValue CIRGenFunction::emitPseudoObjectLValue(const PseudoObjectExpr *e) {
+ return std::get<LValue>(emitPseudoObjectExpr(*this, e, /*forLValue=*/true,
+ AggValueSlot::ignored()));
+}
+
/// Emit code to compute a designator that specifies the location
/// of the expression.
/// FIXME: document this function better.
@@ -1095,6 +1175,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
return emitLValue(cast<ChooseExpr>(e)->getChosenSubExpr());
case Expr::SubstNonTypeTemplateParmExprClass:
return emitLValue(cast<SubstNonTypeTemplateParmExpr>(e)->getReplacement());
+ case Expr::PseudoObjectExprClass:
+ return emitPseudoObjectLValue(cast<PseudoObjectExpr>(e));
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 08677d53eba59..b83f37cc6dc59 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1507,6 +1507,8 @@ class CIRGenFunction : public CIRGenTypeCache {
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d,
mlir::OpBuilder::InsertPoint ip = {});
+ LValue emitPseudoObjectLValue(const PseudoObjectExpr *E);
+
/// Emit code and set up symbol table for a variable declaration with auto,
/// register, or no storage class specifier. These turn into simple stack
/// objects, globals depending on target.
diff --git a/clang/test/CIR/CodeGen/three-way-cmp.cpp b/clang/test/CIR/CodeGen/three-way-cmp.cpp
index e59483206a2eb..af8c401610361 100644
--- a/clang/test/CIR/CodeGen/three-way-cmp.cpp
+++ b/clang/test/CIR/CodeGen/three-way-cmp.cpp
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir
-// RUN: FileCheck %s --input-file=%t-before.cir --check-prefix=BEFORE
+// RUN: FileCheck %s --input-file=%t-before.cir --check-prefix=BEFORE,BOTH
// RUN: FileCheck %s --input-file=%t.cir --check-prefix=AFTER
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=AFTER
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=AFTER,BOTH
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-llvm %s -o %t.ll 2>&1
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
@@ -93,3 +93,196 @@ auto three_way_partial(float x, float y) {
// OGCG: %[[SEL_GT_EQUN:.*]] = select i1 %[[CMP_GT]], i8 1, i8 %[[SEL_EQ_UN]]
// OGCG: %[[CMP_LT:.*]] = fcmp olt float %[[LHS]], %[[RHS]]
// OGCG: %[[RES:.*]] = select i1 %[[CMP_LT]], i8 -1, i8 %[[SEL_GT_EQUN]]
+
+struct Member {
+ bool operator==(const Member&) const;
+ bool operator<(const Member&) const;
+};
+
+struct HasMember {
+ Member m;
+ std::strong_ordering operator<=>(const HasMember&) const = default;
+};
+
+void use_pseudo_ordering(HasMember m1, HasMember m2) {
+ // BOTH: cir.func {{.*}}@_ZNK9HasMemberssERKS_(%{{.*}}: !cir.ptr<!rec_HasMember>{{.*}}, %{{.*}}: !cir.ptr<!rec_HasMember>{{.*}}) -> !rec_std3A3A__13A3Astrong_ordering
+ // BOTH: %[[LHS_ALLOCA:.*]] = cir.alloca !cir.ptr<!rec_HasMember>, !cir.ptr<!cir.ptr<!rec_HasMember>>, ["this", init]
+ // BOTH: %[[RHS_ALLOCA:.*]] = cir.alloca !cir.ptr<!rec_HasMember>, !cir.ptr<!cir.ptr<!rec_HasMember>>, ["", init, const]
+ // BOTH: %[[RET_ALLOCA:.*]] = cir.alloca !rec_std3A3A__13A3Astrong_ordering, !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>, ["__retval"]
+ // BOTH: %[[LHS_LOAD:.*]] = cir.load deref %[[LHS_ALLOCA]] : !cir.ptr<!cir.ptr<!rec_HasMember>>, !cir.ptr<!rec_HasMember>
+ // BOTH: cir.scope {
+ // BOTH: %[[CMP_RES:.*]] = cir.alloca !rec_std3A3A__13A3Astrong_ordering, !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>, ["cmp", init]
+ // BOTH: %[[CMP_TEMP:.*]] = cir.alloca !rec_std3A3A__13A3Astrong_ordering, !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>, ["agg.tmp0"]
+ // BOTH: %[[LHS_MEMBER:.*]] = cir.cast bitcast %[[LHS_LOAD]] : !cir.ptr<!rec_HasMember> -> !cir.ptr<!rec_Member>
+ // BOTH: %[[RHS_LOAD:.*]] = cir.load %[[RHS_ALLOCA]] : !cir.ptr<!cir.ptr<!rec_HasMember>>, !cir.ptr<!rec_HasMember>
+ // BOTH: %[[RHS_MEMBER:.*]] = cir.cast bitcast %[[RHS_LOAD]] : !cir.ptr<!rec_HasMember> -> !cir.ptr<!rec_Member>
+ // BOTH: %[[EQ_RES:.*]] = cir.call @_ZNK6MembereqERKS_(%[[LHS_MEMBER]], %[[RHS_MEMBER]]) : (!cir.ptr<!rec_Member> {{.*}}, !cir.ptr<!rec_Member> {{.*}})
+ // BOTH: %[[TOP_TERN_RES:.*]] = cir.ternary(%[[EQ_RES]], true {
+ // BOTH: %[[EQ_GLOB:.*]] = cir.get_global @_ZNSt3__115strong_ordering5equalE : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: cir.yield %[[EQ_GLOB]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: }, false {
+ // BOTH: %[[LT_RES:.*]] = cir.call @_ZNK6MemberltERKS_(%[[LHS_MEMBER]], %[[RHS_MEMBER]]) : (!cir.ptr<!rec_Member> {{.*}}, !cir.ptr<!rec_Member> {{.*}}) -> (!cir.bool {{.*}})
+ // BOTH: %[[TERN_LT_RES:.*]] = cir.ternary(%[[LT_RES]], true {
+ // BOTH: %[[LT_GLOB:.*]] = cir.get_global @_ZNSt3__115strong_ordering4lessE : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: cir.yield %[[LT_GLOB]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: }, false {
+ // BOTH: %[[GT_GLOB:.*]] = cir.get_global @_ZNSt3__115strong_ordering7greaterE : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: cir.yield %[[GT_GLOB]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: }) : (!cir.bool) -> !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: cir.yield %[[TERN_LT_RES]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: }) : (!cir.bool) -> !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: cir.copy %[[TOP_TERN_RES]] to %[[CMP_RES]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: cir.copy %[[CMP_RES]] to %[[CMP_TEMP]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: %[[UNSPEC_TEMP:.*]] = cir.const #cir.const_record<{#cir.int<0> : !s64i, #cir.int<0> : !s64i}>
+ // BOTH: %[[CMP_TEMP_LOAD:.*]] = cir.load {{.*}}%[[CMP_TEMP]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>, !rec_std3A3A__13A3Astrong_ordering
+ // BOTH: %[[SO_NE_RES:.*]] = cir.call @_ZNSt3__1neENS_15strong_orderingEMNS_19_CmpUnspecifiedTypeEFvvE(%14, %[[UNSPEC_TEMP]])
+ // BOTH: cir.if %[[SO_NE_RES]] {
+ // BOTH: cir.copy %[[CMP_RES]] to %[[RET_ALLOCA]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: %[[RET_LOAD:.*]] = cir.load %[[RET_ALLOCA]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>, !rec_std3A3A__13A3Astrong_ordering
+ // BOTH: cir.return %[[RET_LOAD]] : !rec_std3A3A__13A3Astrong_ordering
+ // BOTH: }
+ // BOTH: }
+ // BOTH: %[[EQ_GLOB:.*]] = cir.get_global @_ZNSt3__115strong_ordering5equalE : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: cir.copy %[[EQ_GLOB]] to %[[RET_ALLOCA]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ // BOTH: %[[RET_LOAD:.*]] = cir.load %[[RET_ALLOCA]] : !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>, !rec_std3A3A__13A3Astrong_ordering
+ // BOTH: cir.return %[[RET_LOAD]] : !rec_std3A3A__13A3Astrong_ordering
+
+ // BOTH: cir.func {{.*}} @_Z19use_pseudo_ordering9HasMemberS_(%[[M1:.*]]: !rec_HasMember{{.*}}, %[[M2:.*]]: !rec_HasMember{{.*}})
+ // BOTH: %[[M1_ALLOCA:.*]] = cir.alloca !rec_HasMember, !cir.ptr<!rec_HasMember>, ["m1", init]
+ // BOTH: %[[M2_ALLOCA:.*]] = cir.alloca !rec_HasMember, !cir.ptr<!rec_HasMember>, ["m2", init] {alignment = 1 : i64}
+ // BOTH: %[[G_ALLOCA:.*]] = cir.alloca !rec_std3A3A__13A3Astrong_ordering, !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>, ["g", init]
+ // BOTH: %[[CALL_RES:.*]] = cir.call @_ZNK9HasMemberssERKS_(%[[M1_ALLOCA]], %[[M2_ALLOCA]]) : (!cir.ptr<!rec_HasMember> {{.*}}, !cir.ptr<!rec_HasMember> {{.*}}) -> !rec_std3A3A__13A3Astrong_ordering
+ // BOTH: cir.store {{.*}}%[[CALL_RES]], %[[G_ALLOCA]] : !rec_std3A3A__13A3Astrong_ordering, !cir.ptr<!rec_std3A3A__13A3Astrong_ordering>
+ std::strong_ordering g = (m1 <=> m2);
+ // LLVM: define {{.*}} @_ZNK9HasMemberssERKS_(ptr {{.*}}, ptr {{.*}})
+ // LLVM: %[[TMP_SO:.*]] = alloca %"class.std::__1::strong_ordering"
+ // LLVM: %[[RET_ALLOCA:.*]] = alloca %"class.std::__1::strong_ordering"
+ // LLVM: %[[LHS_ALLOCA:.*]] = alloca ptr
+ // LLVM: %[[RHS_ALLOCA:.*]] = alloca ptr
+ // LLVM: %[[TMP_SO2:.*]] = alloca %"class.std::__1::strong_ordering"
+ // LLVM: %[[LHS_LOAD:.*]] = load ptr, ptr %[[LHS_ALLOCA]]
+ //
+ // LLVM: %[[RHS_LOAD:.*]] = load ptr, ptr %[[RHS_ALLOCA]]
+ // LLVM: %[[EQ_RES:.*]] = call noundef i1 @_ZNK6MembereqERKS_(ptr {{.*}}%[[LHS_LOAD]], ptr {{.*}}%[[RHS_LOAD]])
+ // LLVM: br i1 %[[EQ_RES]], label %[[EQ_TRUE:.*]], label %[[EQ_FALSE:.*]]
+ //
+ // LLVM: [[EQ_TRUE]]:
+ // LLVM: br label %20
+ //
+ // LLVM: [[EQ_FALSE]]:
+ // LLVM: %[[LT_RES:.*]] = call noundef i1 @_ZNK6MemberltERKS_(ptr {{.*}}%[[LHS_LOAD]], ptr {{.*}}%[[RHS_LOAD]])
+ // LLVM: br i1 %[[LT_RES]], label %[[LT_TRUE:.*]], label %[[LT_FALSE:.*]]
+ //
+ // LLVM: [[LT_TRUE]]:
+ // LLVM: br label %[[AFTER_LT:.*]]
+ //
+ // LLVM: [[LT_FALSE]]:
+ // LLVM: br label %[[AFTER_LT]]
+ //
+ // LLVM: [[AFTER_LT]]:
+ // LLVM: %[[LT_RES_PHI:.*]] = phi ptr [ @_ZNSt3__115strong_ordering7greaterE, %[[LT_FALSE]] ], [ @_ZNSt3__115strong_ordering4lessE, %[[LT_TRUE]] ]
+ // LLVM: br label %[[AFTER_LT_CTD:.*]]
+ //
+ // LLVM: [[AFTER_LT_CTD]]:
+ // LLVM: br label %[[AFTER_CMPS:.*]]
+ //
+ // LLVM: [[AFTER_CMPS]]:
+ // LLVM: %[[CMP_RES:.*]] = phi ptr [ %[[LT_RES_PHI]], %[[AFTER_LT_CTD]] ], [ @_ZNSt3__115strong_ordering5equalE, %[[EQ_TRUE]] ]
+ // LLVM: br label %[[AFTER_CMPS_CTD:.*]]
+ //
+ // LLVM: [[AFTER_CMPS_CTD]]:
+ // LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[TMP_SO]], ptr %[[CMP_RES]], i64 1, i1 false)
+ // LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[RET_ALLOCA]], ptr %[[TMP_SO]], i64 1, i1 false)
+ // LLVM: %[[RET_LOAD:.*]] = load %"class.std::__1::strong_ordering", ptr %[[RET_ALLOCA]]
+ // LLVM: %[[SO_NE_RES:.*]] = call noundef i1 @_ZNSt3__1neENS_15strong_orderingEMNS_19_CmpUnspecifiedTypeEFvvE(%"class.std::__1::strong_ordering" %[[RET_LOAD]],
+ // LLVM: br i1 %[[SO_NE_RES]], label %[[SO_NE_RES_TRUE:.*]], label %[[SO_NE_RES_FALSE:.*]]
+ //
+ // LLVM: [[SO_NE_RES_TRUE]]:
+ // LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[TMP_SO2]], ptr %[[TMP_SO]], i64 1, i1 false)
+ // LLVM: %[[TMP_SO2_LOAD:.*]] = load %"class.std::__1::strong_ordering", ptr %[[TMP_SO2]]
+ // LLVM: ret %"class.std::__1::strong_ordering" %[[TMP_SO2_LOAD]]
+ //
+ // LLVM: [[SO_NE_RES_FALSE]]:
+ // LLVM: br label %[[SO_NE_RES_FALSE_CTD:.*]]
+ //
+ // LLVM: [[SO_NE_RES_FALSE_CTD]]:
+ // LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[TMP_SO2]], ptr @_ZNSt3__115strong_ordering5equalE, i64 1, i1 false)
+ // LLVM: %[[TMP_SO2_LOAD:.*]] = load %"class.std::__1::strong_ordering", ptr %[[TMP_SO2]]
+ // LLVM: ret %"class.std::__1::strong_ordering" %[[TMP_SO2_LOAD]]
+ // LLVM: }
+
+ // LLVM: define {{.*}}void @_Z19use_pseudo_ordering9HasMemberS_(%struct.HasMember %{{.*}}, %struct.HasMember %{{.*}}) #0 {
+ // LLVM: %[[M1_ALLOCA:.*]] = alloca %struct.HasMember
+ // LLVM: %[[M2_ALLOCA:.*]] = alloca %struct.HasMember
+ // LLVM: %[[G_ALLOCA:.*]] = alloca %"class.std::__1::strong_ordering"
+ // LLVM: %[[CALL_RES:.*]] = call %"class.std::__1::strong_ordering" @_ZNK9HasMemberssERKS_(ptr {{.*}}%[[M1_ALLOCA]], ptr {{.*}}%[[M2_ALLOCA]])
+ // LLVM: store %"class.std::__1::strong_ordering" %[[CALL_RES]], ptr %[[G_ALLOCA]]
+ // LLVM: ret void
+ // LLVM: }
+
+ // OGCG: define {{.*}}void @_Z19use_pseudo_ordering9HasMemberS_()
+ // OGCG: %[[M1_ALLOCA:.*]] = alloca %struct.HasMember
+ // OGCG: %[[M2_ALLOCA:.*]] = alloca %struct.HasMember
+ // OGCG: %[[G_ALLOCA:.*]] = alloca %"class.std::__1::strong_ordering"
+ // OGCG: %[[CALL_RES:.*]] = call i8 @_ZNK9HasMemberssERKS_(ptr {{.*}}%[[M1_ALLOCA]], ptr {{.*}}%[[M2_ALLOCA]])
+ // OGCG: %[[G_COERCE:.*]] = getelementptr inbounds nuw %"class.std::__1::strong_ordering", ptr %[[G_ALLOCA]], i32 0, i32 0
+ // OGCG: store i8 %[[CALL_RES]], ptr %[[G_COERCE]]
+ // OGCG: ret void
+ // OGCG: }
+ //
+ // OGCG: define {{.*}}i8 @_ZNK9HasMemberssERKS_(ptr {{.*}}, ptr {{.*}})
+ // OGCG: %[[RET_ALLOCA:.*]] = alloca %"class.std::__1::strong_ordering"
+ // OGCG: %[[LHS_ALLOCA:.*]] = alloca ptr
+ // OGCG: %[[RHS_ALLOCA:.*]] = alloca ptr
+ // OGCG: %[[CMP_RES:.*]] = alloca %"class.std::__1::strong_ordering"
+ // OGCG: %[[CMP_TEMP:.*]] = alloca %"class.std::__1::strong_ordering"
+ // OGCG: %[[COERCE_ALLOCA:.*]] = alloca { i64, i64 }
+ // OGCG: %[[LHS_LOAD:.*]] = load ptr, ptr %[[LHS_ALLOCA]]
+ // OGCG: %[[RHS_LOAD:.*]] = load ptr, ptr %[[RHS_ALLOCA]]
+ // OGCG: %[[EQ_RES:.*]] = call {{.*}}i1 @_ZNK6MembereqERKS_(ptr {{.*}}%[[LHS_LOAD]], ptr {{.*}}%[[RHS_LOAD]])
+ // OGCG: br i1 %[[EQ_RES]], label %[[EQ_TRUE:.*]], label %[[EQ_FALSE:.*]]
+ //
+ // OGCG: [[EQ_TRUE]]:
+ // OGCG: br label %[[AFTER_COND:.*]]
+ //
+ // OGCG: [[EQ_FALSE]]:
+ // OGCG: %[[LT_RES:.*]] = call {{.*}}i1 @_ZNK6MemberltERKS_(ptr {{.*}}%[[LHS_LOAD]], ptr {{.*}}%[[RHS_LOAD]])
+ // OGCG: br i1 %[[LT_RES]], label %[[LT_TRUE:.*]], label %[[LT_FALSE:.*]]
+ //
+ // OGCG: [[LT_TRUE]]:
+ // OGCG: br label %[[AFTER_LT:.*]]
+ //
+ // OGCG: [[LT_FALSE]]:
+ // OGCG: br label %[[AFTER_LT]]
+ //
+ // OGCG: [[AFTER_LT]]:
+ // OGCG: %[[AFTER_LT_RES:.*]] = phi ptr [ @_ZNSt3__115strong_ordering4lessE, %[[LT_TRUE]] ], [ @_ZNSt3__115strong_ordering7greaterE, %[[LT_FALSE]] ]
+ // OGCG: br label %cond.end5
+ //
+ // OGCG: [[AFTER_COND]]:
+ // OGCG: %[[MEM_EQ_RES:.*]] = phi ptr [ @_ZNSt3__115strong_ordering5equalE, %[[EQ_TRUE]] ], [ %[[AFTER_LT_RES]], %[[AFTER_LT]] ]
+ // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[CMP_RES]], ptr align 1 %[[MEM_EQ_RES]], i64 1, i1 false)
+ // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[CMP_TEMP]], ptr align 1 %[[CMP_RES]], i64 1, i1 false)
+ // OGCG: %[[UNSPEC_TEMP:.*]] = getelementptr inbounds nuw %"class.std::__1::strong_ordering", ptr %[[CMP_TEMP]], i32 0, i32 0
+ // OGCG: %[[UNSPEC_LOAD:.*]] = load i8, ptr %[[UNSPEC_TEMP]]
+ // OGCG: store { i64, i64 } zeroinitializer, ptr %[[COERCE_ALLOCA]]
+ // OGCG: %[[COERCE_L_GEP:.*]] = getelementptr inbounds nuw { i64, i64 }, ptr %[[COERCE_ALLOCA]], i32 0, i32 0
+ // OGCG: %[[COERCE_L:.*]] = load i64, ptr %[[COERCE_L_GEP]]
+ // OGCG: %[[COERCE_R_GEP:.*]] = getelementptr inbounds nuw { i64, i64 }, ptr %[[COERCE_ALLOCA]], i32 0, i32 1
+ // OGCG: %[[COERCE_R:.*]] = load i64, ptr %[[COERCE_R_GEP]]
+ // OGCG: %[[UNSPEC_RES:.*]] = call noundef zeroext i1 @_ZNSt3__1neENS_15strong_orderingEMNS_19_CmpUnspecifiedTypeEFvvE(i8 %[[UNSPEC_LOAD]], i64 %[[COERCE_L]], i64 %[[COERCE_R]])
+ // OGCG: br i1 %[[UNSPEC_RES]], label %[[UNSPEC_TRUE:.*]], label %[[UNSPEC_FALSE:.*]]
+ //
+ // OGCG: [[UNSPEC_TRUE]]:
+ // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[RET_ALLOCA]], ptr align 1 %[[CMP_RES]], i64 1, i1 false)
+ // OGCG: br label %[[RETURN_BLOCK:.*]]
+ //
+ // OGCG: [[UNSPEC_FALSE]]:
+ // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[RET_ALLOCA]], ptr align 1 @_ZNSt3__115strong_ordering5equalE, i64 1, i1 false)
+ // OGCG: br label %[[RETURN_BLOCK]]
+ //
+ // OGCG: [[RETURN_BLOCK]]:
+ // OGCG: %[[GEP_RET:.*]] = getelementptr inbounds nuw %"class.std::__1::strong_ordering", ptr %[[RET_ALLOCA]], i32 0, i32 0
+ // OGCG: %[[GEP_RET_LOAD:.*]] = load i8, ptr %[[GEP_RET]]
+ // OGCG: ret i8 %[[GEP_RET_LOAD]]
+}
More information about the cfe-commits
mailing list