Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -4804,6 +4804,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 = [{
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4052,6 +4052,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 {
Expand Down
22 changes: 21 additions & 1 deletion clang/test/CIR/CodeGen/var_arg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand All @@ -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 %{{.*}}