[CIR] Upstream var arg copy builtin (#169415)

This PR upstreams `__builtin_va_copy`, and extends the existing tests.
This commit is contained in:
Hendrik Hübner
2025-12-02 15:28:12 +01:00
committed by GitHub
parent 5d876093b7
commit 7e29448b4e
4 changed files with 70 additions and 2 deletions

View File

@@ -4820,6 +4820,37 @@ def CIR_VAEndOp : CIR_Op<"va_end"> {
}];
}
def CIR_VACopyOp : CIR_Op<"va_copy"> {
let summary = "Copied a variable argument list";
let description = [{
The `cir.copy` operation models the C/C++ va_copy macro.
The variable argument list passed as the `$src_list` is copied to an
unitialized `va_list` in the destination operand. The next argument that
can be extracted from the copied list is the same as the next argument in
the source list. The copied list must be destroyed with `va_end`.
Example:
```mlir
// %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
%p = cir.cast array_to_ptrdecay %args
: !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
-> !cir.ptr<!rec___va_list_tag>
cir.va_copy %p to %dst
: (!cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>)
```
}];
let arguments = (ins
CIR_PointerType:$dst_list,
CIR_PointerType:$src_list
);
let assemblyFormat = [{
$src_list `to` $dst_list attr-dict `:` type(operands)
}];
}
def CIR_VAArgOp : CIR_Op<"va_arg"> {
let summary = "Fetches next variadic element as a given type";
let description = [{

View File

@@ -266,7 +266,12 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_va_end:
emitVAEnd(emitVAListRef(e->getArg(0)).getPointer());
return {};
case Builtin::BI__builtin_va_copy: {
mlir::Value dstPtr = emitVAListRef(e->getArg(0)).getPointer();
mlir::Value srcPtr = emitVAListRef(e->getArg(1)).getPointer();
cir::VACopyOp::create(builder, dstPtr.getLoc(), dstPtr, srcPtr);
return {};
}
case Builtin::BIcos:
case Builtin::BIcosf:
case Builtin::BIcosl:

View File

@@ -4061,6 +4061,18 @@ mlir::LogicalResult CIRToLLVMVAEndOpLowering::matchAndRewrite(
return mlir::success();
}
mlir::LogicalResult CIRToLLVMVACopyOpLowering::matchAndRewrite(
cir::VACopyOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext());
auto dstList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,
adaptor.getDstList());
auto srcList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,
adaptor.getSrcList());
rewriter.replaceOpWithNewOp<mlir::LLVM::VaCopyOp>(op, dstList, srcList);
return mlir::success();
}
mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite(
cir::VAArgOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {

View File

@@ -141,7 +141,7 @@ int stdarg_start(int count, ...) {
// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40
// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem
//
// OGCG: vaarg.in_reg:
// OGCG: vaarg.in_reg:
// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3
// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]]
@@ -164,3 +164,23 @@ int stdarg_start(int count, ...) {
// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]])
// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
// OGCG: ret i32 %[[VAL]]
void stdarg_copy() {
__builtin_va_list src, dest;
__builtin_va_copy(src, dest);
}
// CIR-LABEL: @stdarg_copy
// CIR: %{{.*}} = cir.cast array_to_ptrdecay %{{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
// CIR: %{{.*}} = cir.cast array_to_ptrdecay %{{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
// CIR: cir.va_copy %{{.*}} to %{{.*}} : !cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>
// LLVM-LABEL: @stdarg_copy
// LLVM: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
// LLVM: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
// LLVM: call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}}
// OGCG-LABEL: @stdarg_copy
// OGCG: %{{.*}} = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %{{.*}}
// OGCG: %{{.*}} = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %{{.*}}
// OGCG: call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}}