Skip to content

Commit 7e29448

Browse files
[CIR] Upstream var arg copy builtin (#169415)
This PR upstreams `__builtin_va_copy`, and extends the existing tests.
1 parent 5d87609 commit 7e29448

File tree

4 files changed

+70
-2
lines changed

4 files changed

+70
-2
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4820,6 +4820,37 @@ def CIR_VAEndOp : CIR_Op<"va_end"> {
48204820
}];
48214821
}
48224822

4823+
def CIR_VACopyOp : CIR_Op<"va_copy"> {
4824+
let summary = "Copied a variable argument list";
4825+
let description = [{
4826+
The `cir.copy` operation models the C/C++ va_copy macro.
4827+
The variable argument list passed as the `$src_list` is copied to an
4828+
unitialized `va_list` in the destination operand. The next argument that
4829+
can be extracted from the copied list is the same as the next argument in
4830+
the source list. The copied list must be destroyed with `va_end`.
4831+
4832+
Example:
4833+
4834+
```mlir
4835+
// %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
4836+
%p = cir.cast array_to_ptrdecay %args
4837+
: !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
4838+
-> !cir.ptr<!rec___va_list_tag>
4839+
cir.va_copy %p to %dst
4840+
: (!cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>)
4841+
```
4842+
}];
4843+
4844+
let arguments = (ins
4845+
CIR_PointerType:$dst_list,
4846+
CIR_PointerType:$src_list
4847+
);
4848+
4849+
let assemblyFormat = [{
4850+
$src_list `to` $dst_list attr-dict `:` type(operands)
4851+
}];
4852+
}
4853+
48234854
def CIR_VAArgOp : CIR_Op<"va_arg"> {
48244855
let summary = "Fetches next variadic element as a given type";
48254856
let description = [{

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,12 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
266266
case Builtin::BI__builtin_va_end:
267267
emitVAEnd(emitVAListRef(e->getArg(0)).getPointer());
268268
return {};
269-
269+
case Builtin::BI__builtin_va_copy: {
270+
mlir::Value dstPtr = emitVAListRef(e->getArg(0)).getPointer();
271+
mlir::Value srcPtr = emitVAListRef(e->getArg(1)).getPointer();
272+
cir::VACopyOp::create(builder, dstPtr.getLoc(), dstPtr, srcPtr);
273+
return {};
274+
}
270275
case Builtin::BIcos:
271276
case Builtin::BIcosf:
272277
case Builtin::BIcosl:

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4061,6 +4061,18 @@ mlir::LogicalResult CIRToLLVMVAEndOpLowering::matchAndRewrite(
40614061
return mlir::success();
40624062
}
40634063

4064+
mlir::LogicalResult CIRToLLVMVACopyOpLowering::matchAndRewrite(
4065+
cir::VACopyOp op, OpAdaptor adaptor,
4066+
mlir::ConversionPatternRewriter &rewriter) const {
4067+
auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext());
4068+
auto dstList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,
4069+
adaptor.getDstList());
4070+
auto srcList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,
4071+
adaptor.getSrcList());
4072+
rewriter.replaceOpWithNewOp<mlir::LLVM::VaCopyOp>(op, dstList, srcList);
4073+
return mlir::success();
4074+
}
4075+
40644076
mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite(
40654077
cir::VAArgOp op, OpAdaptor adaptor,
40664078
mlir::ConversionPatternRewriter &rewriter) const {

clang/test/CIR/CodeGen/var_arg.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ int stdarg_start(int count, ...) {
141141
// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40
142142
// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem
143143
//
144-
// OGCG: vaarg.in_reg:
144+
// OGCG: vaarg.in_reg:
145145
// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3
146146
// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
147147
// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]]
@@ -164,3 +164,23 @@ int stdarg_start(int count, ...) {
164164
// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]])
165165
// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
166166
// OGCG: ret i32 %[[VAL]]
167+
168+
void stdarg_copy() {
169+
__builtin_va_list src, dest;
170+
__builtin_va_copy(src, dest);
171+
}
172+
173+
// CIR-LABEL: @stdarg_copy
174+
// CIR: %{{.*}} = cir.cast array_to_ptrdecay %{{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
175+
// CIR: %{{.*}} = cir.cast array_to_ptrdecay %{{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
176+
// CIR: cir.va_copy %{{.*}} to %{{.*}} : !cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>
177+
178+
// LLVM-LABEL: @stdarg_copy
179+
// LLVM: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
180+
// LLVM: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
181+
// LLVM: call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}}
182+
183+
// OGCG-LABEL: @stdarg_copy
184+
// OGCG: %{{.*}} = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %{{.*}}
185+
// OGCG: %{{.*}} = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %{{.*}}
186+
// OGCG: call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}}

0 commit comments

Comments
 (0)