https://github.com/banach-space created 
https://github.com/llvm/llvm-project/pull/176782

- **[CIR] Add cir.libc.memcpy Op**
- **[Clang][CIR] Implement CIRGen logic for __builtin_bit_cast**


From 8704f04fe26c14cfe4cfa47bbc3fc4b79b592b4d Mon Sep 17 00:00:00 2001
From: Andrzej Warzynski <[email protected]>
Date: Mon, 19 Jan 2026 15:42:06 +0000
Subject: [PATCH 1/2] [CIR] Add cir.libc.memcpy Op

The operation is a 1:1 mapping to libc's memcpy.

NOTE: This patch merely upstreams code from
  * https://github.com/llvm/clangir.

This Op was originally implemented by Vinicius Couto Espindola. Further
modification were made by other ClangIR contributors.

co-authored-by: Vinicius Couto Espindola <[email protected]>
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 47 +++++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         | 10 ++++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  9 ++++
 clang/test/CIR/IR/invalid-memcpy.cir          | 37 +++++++++++++++
 clang/test/CIR/IR/libc-memcpy.cir             | 10 ++++
 clang/test/CIR/Lowering/libc.cir              | 12 +++++
 6 files changed, 125 insertions(+)
 create mode 100644 clang/test/CIR/IR/invalid-memcpy.cir
 create mode 100644 clang/test/CIR/IR/libc-memcpy.cir
 create mode 100644 clang/test/CIR/Lowering/libc.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index db1696d50848c..c7f4df200d909 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3439,6 +3439,53 @@ def CIR_CopyOp : CIR_Op<"copy",[
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// MemCpyOp && MemMoveOp
+//===----------------------------------------------------------------------===//
+
+class CIR_MemOp<string mnemonic> : CIR_Op<mnemonic, [
+  AllTypesMatch<["dst", "src"]>
+]> {
+  dag commonArgs = (ins
+    Arg<CIR_VoidPtrType, "", [MemWrite]>:$dst,
+    Arg<CIR_VoidPtrType, "", [MemRead]>:$src
+  );
+}
+
+def CIR_MemCpyOp : CIR_MemOp<"libc.memcpy"> {
+  let summary = "Equivalent to libc's `memcpy`";
+  let description = [{
+    Given two CIR pointers, `src` and `dst`, `cir.libc.memcpy` will copy `len`
+    bytes from the memory pointed by `src` to the memory pointed by `dst`.
+
+    While `cir.copy` is meant to be used for implicit copies in the code where
+    the length of the copy is known, `cir.memcpy` copies only from and to void
+    pointers, requiring the copy length to be passed as an argument.
+
+    Examples:
+
+    ```mlir
+      // Copying 2 bytes from one array to a record:
+      %2 = cir.const #cir.int<2> : !u32i
+      cir.libc.memcpy %2 bytes from %arr to %record : !cir.ptr<!arr> -> 
!cir.ptr<!record>
+    ```
+  }];
+
+  let arguments = !con(commonArgs, (ins CIR_AnyFundamentalUIntType:$len));
+
+  let assemblyFormat = [{
+    $len `bytes` `from` $src `to` $dst attr-dict
+    `:` type($len) `` `,` qualified(type($src)) `->` qualified(type($dst))
+  }];
+
+  let extraClassDeclaration = [{
+    /// Returns the byte length type.
+    cir::IntType getLenTy() { return getLen().getType(); }
+  }];
+}
+
+// TODO: MemMoveOp
+
 
//===----------------------------------------------------------------------===//
 // ReturnAddrOp and FrameAddrOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index ff492edf0b04e..dc1ce9a901381 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -189,6 +189,16 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     return getType<cir::RecordType>(nameAttr, kind);
   }
 
+  //
+  // Operation creation helpers
+  // --------------------------
+  //
+  cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst,
+                             mlir::Value src, mlir::Value len) {
+    return cir::MemCpyOp::create(*this, loc, dst, src, len);
+  }
+  // ---------------------------
+
   cir::DataMemberAttr getDataMemberAttr(cir::DataMemberType ty,
                                         unsigned memberIndex) {
     return cir::DataMemberAttr::get(ty, memberIndex);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7625bcccd520f..a774b0dcc6ba8 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -187,6 +187,15 @@ mlir::LogicalResult 
CIRToLLVMCopyOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMMemCpyOpLowering::matchAndRewrite(
+    cir::MemCpyOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  rewriter.replaceOpWithNewOp<mlir::LLVM::MemcpyOp>(
+      op, adaptor.getDst(), adaptor.getSrc(), adaptor.getLen(),
+      /*isVolatile=*/false);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMSqrtOpLowering::matchAndRewrite(
     cir::SqrtOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/IR/invalid-memcpy.cir 
b/clang/test/CIR/IR/invalid-memcpy.cir
new file mode 100644
index 0000000000000..805d03adcb95f
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-memcpy.cir
@@ -0,0 +1,37 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+!s8i = !cir.int<s, 8>
+module {
+  // Should not memcpy with invalid length type.
+  cir.func @invalid_memcpy_len(%arg0 : !cir.ptr<!cir.void>, %arg1 : !s8i) {
+    // expected-error@+1 {{'cir.libc.memcpy' op operand #2 must be fundamental 
unsigned integer type, but got '!cir.int<s, 8>'}}
+    cir.libc.memcpy %arg1 bytes from %arg0 to %arg0 : !s8i, 
!cir.ptr<!cir.void> -> !cir.ptr<!cir.void>
+    cir.return
+  }
+}
+
+// -----
+
+!s8i = !cir.int<s, 8>
+!u32i = !cir.int<u, 32>
+module {
+  // Should not memcpy non-void pointers.
+  cir.func @invalid_memcpy_pointer_0(%arg0 : !cir.ptr<!s8i>, %arg1 : !u32i) {
+    // expected-error@+1 {{'cir.libc.memcpy' op operand #0 must be pointer to 
void type, but got '!cir.ptr<!cir.int<s, 8>>'}}
+    cir.libc.memcpy %arg1 bytes from %arg0 to %arg0 : !u32i, !cir.ptr<!s8i> -> 
!cir.ptr<!s8i>
+    cir.return
+  }
+}
+
+// -----
+
+!s8i = !cir.int<s, 8>
+!u32i = !cir.int<u, 32>
+module {
+  // Should not memcpy non-void pointers.
+  cir.func @invalid_memcpy_pointer_1(%arg0 : !cir.ptr<!cir.void>, %arg1 : 
!cir.ptr<!s8i>, %arg2 : !u32i) {
+    // expected-error@+1 {{'cir.libc.memcpy' op operand #1 must be pointer to 
void type, but got '!cir.ptr<!cir.int<s, 8>>'}}
+    cir.libc.memcpy %arg2 bytes from %arg1 to %arg0 : !u32i, !cir.ptr<!s8i> -> 
!cir.ptr<!cir.void>
+    cir.return
+  }
+}
diff --git a/clang/test/CIR/IR/libc-memcpy.cir 
b/clang/test/CIR/IR/libc-memcpy.cir
new file mode 100644
index 0000000000000..6769092f3beb1
--- /dev/null
+++ b/clang/test/CIR/IR/libc-memcpy.cir
@@ -0,0 +1,10 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!u32i = !cir.int<u, 32>
+module {
+  cir.func @shouldParseLibcMemcpyOp(%arg0 : !cir.ptr<!cir.void>, %arg1 : 
!u32i) {
+    // CHECK: cir.libc.memcpy 
+    cir.libc.memcpy %arg1 bytes from %arg0 to %arg0 : !u32i, 
!cir.ptr<!cir.void> -> !cir.ptr<!cir.void>
+    cir.return
+  }
+}
diff --git a/clang/test/CIR/Lowering/libc.cir b/clang/test/CIR/Lowering/libc.cir
new file mode 100644
index 0000000000000..74e384d08a74b
--- /dev/null
+++ b/clang/test/CIR/Lowering/libc.cir
@@ -0,0 +1,12 @@
+// RUN: cir-opt %s -cir-to-llvm -o %t.mlir
+// RUN: FileCheck --input-file=%t.mlir %s
+
+!void = !cir.void
+!u64i = !cir.int<u, 64>
+module {
+  cir.func @shouldLowerLibcMemcpyBuiltin(%arg0: !cir.ptr<!void>, %arg1: 
!cir.ptr<!void>, %arg2: !u64i) {
+    cir.libc.memcpy %arg2 bytes from %arg0 to %arg1 : !u64i, !cir.ptr<!void> 
-> !cir.ptr<!void>
+    // CHECK: "llvm.intr.memcpy"(%{{.+}}, %{{.+}}, %{{.+}}) <{isVolatile = 
false}> : (!llvm.ptr, !llvm.ptr, i64) -> ()
+    cir.return
+  }
+}

From 7654a990f19351041c0e7bdd9d30b44554ac3778 Mon Sep 17 00:00:00 2001
From: Andrzej Warzynski <[email protected]>
Date: Mon, 19 Jan 2026 17:11:58 +0000
Subject: [PATCH 2/2] [Clang][CIR] Implement CIRGen logic for
 __builtin_bit_cast

NOTE: This patch merely upstreams code from
  * https://github.com/llvm/clangir.

This Op was originally implemented by Sirui Mu in #762 Further
modification were made by other ClangIR contributors.

co-authored-by: Sirui Mu <[email protected]>
---
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp |  24 ++++
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp    |  17 +++
 clang/test/CIR/CodeGen/builtin-bit-cast.cpp   | 135 ++++++++++++++++++
 3 files changed, 176 insertions(+)
 create mode 100644 clang/test/CIR/CodeGen/builtin-bit-cast.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 8fcff6d0f9b84..9610d81929673 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -232,6 +232,30 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
   // Stubs -- These should be moved up when they are implemented.
   void VisitCastExpr(CastExpr *e) {
     switch (e->getCastKind()) {
+    case CK_LValueToRValueBitCast: {
+      if (dest.isIgnored()) {
+        cgf.emitAnyExpr(e->getSubExpr(), AggValueSlot::ignored(),
+                        /*ignoreResult=*/true);
+        break;
+      }
+
+      LValue sourceLV = cgf.emitLValue(e->getSubExpr());
+      Address sourceAddress = sourceLV.getAddress();
+      Address destAddress = dest.getAddress();
+
+      auto loc = cgf.getLoc(e->getExprLoc());
+      mlir::Value srcPtr = cgf.getBuilder().createBitcast(
+          loc, sourceAddress.getPointer(), cgf.voidPtrTy);
+      mlir::Value dstPtr = cgf.getBuilder().createBitcast(
+          loc, destAddress.getPointer(), cgf.voidPtrTy);
+
+      mlir::Value sizeVal = cgf.getBuilder().getConstInt(
+          loc, cgf.sizeTy,
+          cgf.getContext().getTypeSizeInChars(e->getType()).getQuantity());
+      cgf.getBuilder().createMemCpy(loc, dstPtr, srcPtr, sizeVal);
+
+      break;
+    }
     case CK_LValueToRValue:
       // If we're loading from a volatile type, force the destination
       // into existence.
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 4ce38f4e0a1f9..ce6f5e4e22891 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -2072,6 +2072,23 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr 
*ce) {
     llvm_unreachable("dependent cast kind in CIR gen!");
   case clang::CK_BuiltinFnToFnPtr:
     llvm_unreachable("builtin functions are handled elsewhere");
+  case CK_LValueBitCast:
+  case CK_LValueToRValueBitCast: {
+    LValue sourceLVal = cgf.emitLValue(subExpr);
+    Address sourceAddr = sourceLVal.getAddress();
+
+    mlir::Type destElemTy = cgf.convertTypeForMem(destTy);
+    mlir::Type destPtrTy = cgf.getBuilder().getPointerTo(destElemTy);
+    mlir::Value destPtr = cgf.getBuilder().createBitcast(
+        cgf.getLoc(subExpr->getExprLoc()), sourceAddr.getPointer(), destPtrTy);
+
+    Address destAddr = Address(destPtr, destElemTy, sourceAddr.getAlignment(),
+                               sourceAddr.isKnownNonNull());
+    LValue destLVal = cgf.makeAddrLValue(destAddr, destTy);
+    // TOOD: Uncomment once TBAA is upstreamed
+    // destLVal.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo());
+    return emitLoadOfLValue(destLVal, ce->getExprLoc());
+  }
 
   case CK_CPointerToObjCPointerCast:
   case CK_BlockPointerToObjCPointerCast:
diff --git a/clang/test/CIR/CodeGen/builtin-bit-cast.cpp 
b/clang/test/CIR/CodeGen/builtin-bit-cast.cpp
new file mode 100644
index 0000000000000..49fb2538472bd
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtin-bit-cast.cpp
@@ -0,0 +1,135 @@
+// RUN: %clang_cc1 -std=c++20 -fclangir -emit-cir %s  -o - | FileCheck 
--check-prefix=CIR %s
+// RUN: %clang_cc1 -std=c++20 -fclangir -emit-llvm %s -o - | FileCheck 
--check-prefixes=LLVM,LLVM-VIA-CIR %s
+// RUN: %clang_cc1 -std=c++20           -emit-llvm %s -o - | FileCheck 
--check-prefixes=LLVM,LLVM-DIRECT %s
+
+//=============================================================================
+// NOTES
+//
+// Major differences between code lowered via ClangIR and directly to LLVM
+// (e.g. different return types) are captured by using LLVM-VIA-CIR and 
LLVM-DIRECT labels.
+//
+// Minor differences (e.g. presence of `noundef` attached to argumens, `align`
+// attribute attached to pointers), look for catch-alls like {{.*}}.
+//
+//=============================================================================
+
+float test_scalar(int &oper) {
+  return __builtin_bit_cast(float, oper);
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z11test_scalarRi
+//       CIR:   %[[#SRC_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+//  CIR-NEXT:   %[[#DST_PTR:]] = cir.cast bitcast %[[#SRC_PTR]] : 
!cir.ptr<!s32i> -> !cir.ptr<!cir.float>
+//  CIR-NEXT:   %{{.+}} = cir.load{{.*}} %[[#DST_PTR]] : !cir.ptr<!cir.float>, 
!cir.float
+
+// LLVM-LABEL: define dso_local{{.*}} float @_Z11test_scalarRi
+//       LLVM:   %[[#PTR:]] = load ptr, ptr %{{.+}}, align 8
+//  LLVM-NEXT:   %{{.+}} = load float, ptr %[[#PTR]], align 4
+
+struct two_ints {
+  int x;
+  int y;
+};
+
+unsigned long test_aggregate_to_scalar(two_ints &ti) {
+  return __builtin_bit_cast(unsigned long, ti);
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z24test_aggregate_to_scalarR8two_ints
+//       CIR:   %[[#SRC_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_two_ints>>, !cir.ptr<!rec_two_ints>
+//  CIR-NEXT:   %[[#DST_PTR:]] = cir.cast bitcast %[[#SRC_PTR]] : 
!cir.ptr<!rec_two_ints> -> !cir.ptr<!u64i>
+//  CIR-NEXT:   %{{.+}} = cir.load{{.*}} %[[#DST_PTR]] : !cir.ptr<!u64i>, !u64i
+
+// LLVM-LABEL: define dso_local{{.*}} i64 
@_Z24test_aggregate_to_scalarR8two_ints
+//       LLVM:   %[[#PTR:]] = load ptr, ptr %{{.+}}, align 8
+//  LLVM-NEXT:   %{{.+}} = load i64, ptr %[[#PTR]], align 4
+
+struct two_floats {
+  float x;
+  float y;
+};
+
+two_floats test_aggregate_record(two_ints& ti) {
+   return __builtin_bit_cast(two_floats, ti);
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z21test_aggregate_recordR8two_ints
+//       CIR:   %[[#SRC_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_two_ints>>, !cir.ptr<!rec_two_ints>
+//  CIR-NEXT:   %[[#SRC_VOID_PTR:]] = cir.cast bitcast %[[#SRC_PTR]] : 
!cir.ptr<!rec_two_ints> -> !cir.ptr<!void>
+//  CIR-NEXT:   %[[#DST_VOID_PTR:]] = cir.cast bitcast %{{.+}} : 
!cir.ptr<!rec_two_floats> -> !cir.ptr<!void>
+//  CIR-NEXT:   %[[#SIZE:]] = cir.const #cir.int<8> : !u64i
+//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] to 
%[[#DST_VOID_PTR]] : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+
+// LLVM-LABEL: define dso_local{{.*}} %struct.two_floats 
@_Z21test_aggregate_recordR8two_ints
+//       LLVM:   %[[DST_SLOT:.*]] = alloca %struct.two_floats{{.*}}, align 4
+//       LLVM:   %[[SRC_PTR:.*]] = load ptr, ptr {{.*}}, align 8
+//  LLVM-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr{{.*}} %[[DST_SLOT]], 
ptr{{.*}} %[[SRC_PTR]], i64 8, i1 false)
+//  LLVM-NEXT:   %{{.+}} = load %struct.two_floats, ptr %[[DST_SLOT]], align 4
+
+two_floats test_aggregate_array(int (&ary)[2]) {
+  return __builtin_bit_cast(two_floats, ary);
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z20test_aggregate_arrayRA2_i
+//       CIR:   %[[#SRC_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 2>>>, !cir.ptr<!cir.array<!s32i x 2>>
+//  CIR-NEXT:   %[[#SRC_VOID_PTR:]] = cir.cast bitcast %[[#SRC_PTR]] : 
!cir.ptr<!cir.array<!s32i x 2>> -> !cir.ptr<!void>
+//  CIR-NEXT:   %[[#DST_VOID_PTR:]] = cir.cast bitcast %{{.+}} : 
!cir.ptr<!rec_two_floats> -> !cir.ptr<!void>
+//  CIR-NEXT:   %[[#SIZE:]] = cir.const #cir.int<8> : !u64i
+//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] to 
%[[#DST_VOID_PTR]] : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+
+// LLVM-LABEL: define dso_local{{.*}} %struct.two_floats 
@_Z20test_aggregate_arrayRA2_i
+//       LLVM:   %[[DST_SLOT:.*]] = alloca %struct.two_floats{{.*}}, align 4
+//       LLVM:   %[[SRC_PTR:.*]] = load ptr, ptr {{.*}}, align 8
+//  LLVM-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr{{.*}} %[[DST_SLOT]], 
ptr{{.*}} %[[SRC_PTR]], i64 8, i1 false)
+//  LLVM-NEXT:   %{{.+}} = load %struct.two_floats, ptr %[[DST_SLOT]], align 4
+
+two_ints test_scalar_to_aggregate(unsigned long ul) {
+  return __builtin_bit_cast(two_ints, ul);
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z24test_scalar_to_aggregatem
+//       CIR:   %[[#SRC_VOID_PTR:]] = cir.cast bitcast %{{.+}} : 
!cir.ptr<!u64i> -> !cir.ptr<!void>
+//  CIR-NEXT:   %[[#DST_VOID_PTR:]] = cir.cast bitcast %{{.+}} : 
!cir.ptr<!rec_two_ints> -> !cir.ptr<!void>
+//  CIR-NEXT:   %[[#SIZE:]] = cir.const #cir.int<8> : !u64i
+//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] to 
%[[#DST_VOID_PTR]] : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+
+// LLVM-DIRECT-LABEL: define dso_local i64 @_Z24test_scalar_to_aggregatem
+// LLVM-VIA-CIR-LABEL: define dso_local %struct.two_ints 
@_Z24test_scalar_to_aggregatem
+//       LLVM:   %[[DST_SLOT:.*]] = alloca %struct.two_ints{{.*}}, align 4
+//       LLVM:   call void @llvm.memcpy.p0.p0.i64(ptr{{.*}} %[[DST_SLOT]], 
ptr{{.*}} %{{.+}}, i64 8, i1 false)
+//  LLVM-DIRECT-NEXT:   %{{.+}} = load i64, ptr %[[DST_SLOT]], align 4
+//  LLVM-VIA-CIR-NEXT:   %{{.+}} = load %struct.two_ints, ptr %[[DST_SLOT]], 
align 4
+
+unsigned long test_array(int (&ary)[2]) {
+  return __builtin_bit_cast(unsigned long, ary);
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z10test_arrayRA2_i
+//      CIR:   %[[#SRC_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!cir.array<!s32i x 2>>>, !cir.ptr<!cir.array<!s32i x 2>>
+// CIR-NEXT:   %[[#DST_PTR:]] = cir.cast bitcast %[[#SRC_PTR]] : 
!cir.ptr<!cir.array<!s32i x 2>> -> !cir.ptr<!u64i>
+// CIR-NEXT:   %{{.+}} = cir.load{{.*}} %[[#DST_PTR]] : !cir.ptr<!u64i>, !u64i
+
+// LLVM-LABEL: define dso_local{{.*}} i64 @_Z10test_arrayRA2_i
+//       LLVM:   %[[SRC_PTR:.*]] = load ptr, ptr %{{.+}}, align 8
+//  LLVM-NEXT:   %{{.+}} = load i64, ptr %[[SRC_PTR]], align 4
+
+two_ints test_rvalue_aggregate() {
+  return __builtin_bit_cast(two_ints, 42ul);
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z21test_rvalue_aggregatev()
+//       CIR:   cir.scope {
+//  CIR-NEXT:     %[[#TMP_SLOT:]] = cir.alloca !u64i, !cir.ptr<!u64i>
+//  CIR-NEXT:     %[[#A:]] = cir.const #cir.int<42> : !u64i
+//  CIR-NEXT:     cir.store{{.*}} %[[#A]], %[[#TMP_SLOT]] : !u64i, 
!cir.ptr<!u64i>
+//  CIR-NEXT:     %[[#SRC_VOID_PTR:]] = cir.cast bitcast %[[#TMP_SLOT]] : 
!cir.ptr<!u64i> -> !cir.ptr<!void>
+//  CIR-NEXT:     %[[#DST_VOID_PTR:]] = cir.cast bitcast %0 : 
!cir.ptr<!rec_two_ints> -> !cir.ptr<!void>
+//  CIR-NEXT:     %[[#SIZE:]] = cir.const #cir.int<8> : !u64i
+//  CIR-NEXT:     cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] to 
%[[#DST_VOID_PTR]] : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+//  CIR-NEXT:   }
+
+// LLVM-DIRECT-LABEL: define dso_local{{.*}} i64 @_Z21test_rvalue_aggregatev
+// LLVM-VIA-CIR-LABEL: define dso_local{{.*}} %struct.two_ints 
@_Z21test_rvalue_aggregatev
+//  LLVM:   %[[SRC_SLOT:.*]] = alloca i64{{.*}}, align 8
+//  LLVM:   store i64 42, ptr %[[SRC_SLOT]], align 8
+//  LLVM-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr{{.*}} %{{.+}}, ptr{{.*}} 
%[[SRC_SLOT]], i64 8, i1 false)

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to