[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