================
@@ -1511,3 +1520,380 @@ void 
CIRABIRewriteContext::rewriteFunctionAddress(cir::GetGlobalOp addrOp,
                                      cir::CastKind::bitcast, addrOp.getAddr());
   addrOp.getAddr().replaceAllUsesExcept(bitcast.getResult(), bitcast);
 }
+
+namespace {
+
+/// What one `va_arg` expansion needs from the op it rewrites.  The x86-64
+/// cursor fields are reached through `vaFields` by index: 0 gp_offset,
+/// 1 fp_offset, 2 overflow_arg_area, 3 reg_save_area.
+struct VAArgFetch {
+  mlir::Location loc;
+  mlir::Value valist;
+  llvm::ArrayRef<mlir::Type> vaFields;
+  mlir::Type resultTy;
+  const ArgClassification &ac;
+  const mlir::DataLayout &dl;
+  mlir::ModuleOp module;
+};
+
+/// The cursor fields a register fetch reads, and the predicate saying every
+/// class it needs still has room.  An offset is null when the fetch needs no
+/// register of that class.
+struct RegisterCursor {
+  mlir::Value gpOffsetP;
+  mlir::Value fpOffsetP;
+  mlir::Value gpOffset;
+  mlir::Value fpOffset;
+  mlir::Value inRegs;
+};
+
+mlir::LogicalResult reportVAArgNYI(cir::VAArgOp op, llvm::StringRef what) {
+  op->emitOpError() << "va_arg of " << what
+                    << " not yet implemented in CallConvLowering";
+  return mlir::failure();
+}
+
+/// Sets \p isRegPair when a two-register argument is a coerced pair, one
+/// register per member, rather than a single wide scalar, and records in
+/// \p pairIsSse which element is SSE class.  Fails on a coercion that is not
+/// two eightbytes.
+mlir::LogicalResult classifyRegisterPair(cir::VAArgOp op,
+                                         const ArgClassification &ac,
+                                         std::array<bool, 2> &pairIsSse,
+                                         bool &isRegPair) {
+  auto pairTy = mlir::dyn_cast<cir::RecordType>(ac.coercedType);
+  if (!pairTy)
+    return mlir::success();
+
+  if (pairTy.getNumElements() != 2)
+    return reportVAArgNYI(op, "a register coercion that is not two 
eightbytes");
+
+  assert(!ac.directOffset &&
+         "a pair already spans both eightbytes, so it cannot also start "
+         "partway into the value");
+  for (auto [i, memberTy] : llvm::enumerate(pairTy.getMembers()))
+    pairIsSse[i] = isSSERegisterClass(memberTy);
+  isRegPair = true;
+  return mlir::success();
+}
+
+/// The alignment an argument is placed at.  A record can require more than
+/// the types of its members imply, from an `aligned` attribute on the record
+/// or on one of its fields, and neither raises the alignment of any type.
+/// Only the record layout knows, so the member-derived value alone can be too
+/// small.
+uint64_t argumentAreaAlign(mlir::Type ty, mlir::ModuleOp modOp,
+                           const mlir::DataLayout &dl) {
+  uint64_t align = dl.getTypeABIAlignment(ty);
+  if (auto recTy = mlir::dyn_cast<cir::RecordType>(ty))
+    if (auto layout = cir::tryGetRecordLayout(modOp, recTy.getName()))
+      align = std::max<uint64_t>(align, layout.getRecordAlign());
+  return align;
+}
+
+mlir::Value roundPointerUpToAlignment(CIRBaseBuilderTy &b, mlir::Location loc,
+                                      mlir::Value bytePtr, uint64_t align,
+                                      const mlir::DataLayout &dl) {
+  assert(llvm::isPowerOf2_64(align) &&
+         "mask rounding needs a power-of-two alignment");
+  mlir::Value bumped =
+      b.createPtrStride(loc, bytePtr, b.getSignedInt(loc, align - 1, 32));
+  std::optional<uint64_t> indexWidth =
+      dl.getTypeIndexBitwidth(bytePtr.getType());
+  assert(indexWidth && "a pointer in the argument area has an index width");
+  mlir::Value mask = b.getSignedInt(loc, -static_cast<int64_t>(align),
+                                    static_cast<unsigned>(*indexWidth));
+  return cir::PtrMaskOp::create(b, loc, bytePtr.getType(), bumped, mask);
+}
+
+/// Reads the argument's address out of the overflow area, which also advances
+/// the cursor past the argument.
+mlir::Value buildOverflowAddr(CIRBaseBuilderTy &b, const VAArgFetch &f) {
----------------
adams381 wrote:

Renamed to buildOverflowAddrAndAdvance. I avoided `get` because it reads as a 
side-effect-free accessor.

Yes. An over-aligned record was loading at `align 1` against OGCG's `align 32`. 
The load uses argumentAreaAlign now.


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

Reply via email to