================
@@ -1473,3 +1425,255 @@ void 
CIRABIRewriteContext::rewriteFunctionAddress(cir::GetGlobalOp addrOp,
                                      cir::CastKind::bitcast, addrOp.getAddr());
   addrOp.getAddr().replaceAllUsesExcept(bitcast.getResult(), bitcast);
 }
+
+mlir::LogicalResult
+CIRABIRewriteContext::rewriteVAArg(mlir::Operation *vaArgOp,
+                                   const ArgClassification &ac,
+                                   mlir::OpBuilder &opBuilder) {
+  auto op = mlir::cast<cir::VAArgOp>(vaArgOp);
+  CIRBaseBuilderTy builder(opBuilder);
+  mlir::Location loc = op.getLoc();
+  mlir::Type resultTy = op.getType();
+  mlir::Value valist = op.getArgList();
+
+  auto reportNYI = [&](llvm::StringRef what) {
+    op->emitOpError() << "va_arg of " << what
+                      << " not yet implemented in CallConvLowering";
+    return mlir::failure();
+  };
+
+  // An ignored type is passed in no register and no stack slot, so the fetch
+  // has nothing to read and must leave the va_list cursor where it found it,
+  // for the fetches that come after this one.  The type holds no bytes, so
+  // the value the fetch produces carries no information either.
+  if (ac.kind == ArgKind::Ignore) {
+    builder.setInsertionPoint(op);
+    op.getResult().replaceAllUsesWith(builder.createDummyValue(
+        loc, resultTy,
+        clang::CharUnits::fromQuantity(dl.getTypeABIAlignment(resultTy))));
+    op->erase();
+    return mlir::success();
+  }
+
+  if (ac.kind == ArgKind::Indirect && !ac.byVal)
+    return reportNYI("a non-trivially-copyable type");
+
+  // How many eightbytes of each register class the fetched type occupies.
+  // Zero of both means the type travels in memory and is read straight from
+  // the overflow area.
+  unsigned neededInt = 0, neededSse = 0;
+  // Which coerced-pair element (0 = low eightbyte, 1 = high) is SSE rather
+  // than INTEGER class.  Only meaningful when isRegPair is set.
+  std::array<bool, 2> pairIsSse = {false, false};
+  bool isRegPair = false;
+
+  if (ac.kind == ArgKind::Extend) {
+    neededInt = 1;
+  } else if (ac.kind == ArgKind::Direct) {
+    if (mlir::Type coerced = ac.coercedType) {
+      if (auto pairTy = mlir::dyn_cast<cir::RecordType>(coerced)) {
+        assert(pairTy.getNumElements() == 2 &&
+               "a register-class coercion spans at most two eightbytes");
+        for (auto [i, memberTy] : llvm::enumerate(pairTy.getMembers())) {
+          if (isSSERegisterClass(memberTy)) {
+            pairIsSse[i] = true;
+            ++neededSse;
+          } else {
+            ++neededInt;
+          }
+        }
+        isRegPair = true;
+      } else if (isSSERegisterClass(coerced)) {
+        if (fitsOneVectorSlot(coerced, dl))
+          neededSse = 1;
+      } else {
+        neededInt = isWide128BitInt(coerced) ? 2 : 1;
+      }
+    } else if (auto fp = mlir::dyn_cast<cir::FPTypeInterface>(resultTy)) {
+      // An uncoerced scalar float is SSE, unless it is x87 long double,
+      // which the SysV ABI always classifies MEMORY.  That is recognized
+      // from the semantics here, because the classification spells a
+      // memory-class scalar the same way it spells a register one.
+      if (&fp.getFloatSemantics() != &llvm::APFloat::x87DoubleExtended())
+        neededSse = 1;
+    } else if (mlir::isa<cir::VectorType>(resultTy)) {
+      if (fitsOneVectorSlot(resultTy, dl))
+        neededSse = 1;
+    } else if (mlir::isa<cir::IntType, cir::PointerType, cir::BoolType>(
+                   resultTy)) {
+      neededInt = isWide128BitInt(resultTy) ? 2 : 1;
+    } else {
+      return reportNYI("this type");
+    }
+  } else if (ac.kind != ArgKind::Indirect) {
+    return reportNYI("a type with an argument classification this fetch does "
+                     "not model");
+  }
+  // Indirect is the one remaining kind, and it takes no register.
+
+  auto vaListRecTy = mlir::cast<cir::RecordType>(
+      mlir::cast<cir::PointerType>(valist.getType()).getPointee());
+  llvm::ArrayRef<mlir::Type> vaFields = vaListRecTy.getMembers();
+  assert(vaFields.size() == 4 &&
+         "expected the four-field gp_offset / fp_offset / overflow_arg_area / "
+         "reg_save_area argument cursor");
+  cir::IntType byteTy = builder.getUIntNTy(8);
+  cir::PointerType bytePtrTy = builder.getPointerTo(byteTy);
+
+  builder.setInsertionPoint(op);
+
+  // Reading the overflow area also advances the cursor past the argument.
+  auto buildMemAddr = [&](CIRBaseBuilderTy &b) -> mlir::Value {
+    mlir::Value overflowP = b.createGetMember(loc, b.getPointerTo(vaFields[2]),
+                                              valist, "overflow_arg_area", 2);
+    mlir::Value overflow = b.createLoad(loc, overflowP);
+    mlir::Value bytePtr = b.createPtrBitcast(overflow, byteTy);
+    uint64_t tyAlign = argumentAreaAlign(resultTy, module, dl);
+    if (tyAlign > 8) {
+      mlir::Type wordTy = b.getUIntNTy(64);
+      mlir::Value asInt = cir::CastOp::create(
+          b, loc, wordTy, cir::CastKind::ptr_to_int, bytePtr);
+      mlir::Value bumped = b.createNUWAdd(
+          loc, asInt, b.getConstantInt(loc, wordTy, tyAlign - 1));
+      mlir::Value rounded = b.createAnd(
+          loc, bumped, b.getConstantInt(loc, wordTy, ~(tyAlign - 1)));
+      bytePtr = cir::CastOp::create(b, loc, bytePtrTy,
+                                    cir::CastKind::int_to_ptr, rounded);
----------------
adams381 wrote:

Alright, we are now using cir.ptr_mask.

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