-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[CIR] Upstream var arg copy builtin #169415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-clangir Author: Hendrik Hübner (HendrikHuebner) ChangesThis PR upstreams Full diff: https://github.com/llvm/llvm-project/pull/169415.diff 4 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index a19c4f951fff9..78143ab44fa7e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4704,6 +4704,40 @@ 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
+ ```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 = [{
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index d220fdf4dc8a7..95ddfdfc7358a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -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:
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6136d48204e0c..f3c1b92fafcd3 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4034,6 +4034,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 {
diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c
index f5b92c61e11ad..82de39a3db58a 100644
--- a/clang/test/CIR/CodeGen/var_arg.c
+++ b/clang/test/CIR/CodeGen/var_arg.c
@@ -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,104 @@ 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]]
+
+int stdarg_copy(int count, ...) {
+ __builtin_va_list args;
+ __builtin_stdarg_start(args, 12345);
+ __builtin_va_list dup;
+ __builtin_va_copy(args, dup);
+ int res = __builtin_va_arg(dup, int);
+ __builtin_va_end(args);
+ __builtin_va_end(dup);
+ return res;
+}
+
+// CIR-LABEL: cir.func dso_local @stdarg_copy(
+// CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init]
+// CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
+// CIR: %[[DUP_AREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["dup"]
+// CIR: %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init]
+// CIR: cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[VA_PTR0:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: %[[C12345:.+]] = cir.const #cir.int<12345> : !s32i
+// CIR: cir.va_start %[[VA_PTR0]] %[[C12345]] : !cir.ptr<!rec___va_list_tag>, !s32i
+// CIR: %[[VA_PTR_SRC:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_PTR_DEST:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: cir.va.copy %[[VA_PTR_DEST]] to %[[VA_PTR_SRC]] : !cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_PTR_COPY:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR_COPY]] : (!cir.ptr<!rec___va_list_tag>) -> !s32i
+// CIR: cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[VA_PTR2:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_PTR3:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: cir.va_end %[[VA_PTR3]] : !cir.ptr<!rec___va_list_tag>
+// CIR: %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.return %[[RETVAL]] : !s32i
+
+// LLVM-LABEL: define dso_local i32 @stdarg_copy(
+// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
+// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}}
+// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
+// LLVM: %[[DUP_AREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
+// LLVM: %[[RES_ADDR:.+]] = alloca i32{{.*}}
+// LLVM: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
+// LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM: %[[VA_PTR_DUP:.+]] = getelementptr %struct.__va_list_tag, ptr %[[DUP_AREA]], i32 0
+// LLVM: call void @llvm.va_copy.p0(ptr %[[VA_PTR1]], ptr %[[VA_PTR_DUP]])
+// LLVM: %[[VA_PTR_DUP2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[DUP_AREA]], i32 0
+// LLVM: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR_DUP2]], i32
+// LLVM: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
+// LLVM: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
+// LLVM: %[[VA_PTR3:.+]] = getelementptr %struct.__va_list_tag, ptr %[[DUP_AREA]], i32 0
+// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR3]])
+// LLVM: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
+// LLVM: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
+// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
+// LLVM: ret i32 %[[RETVAL]]
+
+// OGCG-LABEL: define dso_local i32 @stdarg_copy
+// OGCG: %[[COUNT_ADDR:.+]] = alloca i32
+// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// OGCG: %[[DUP_AREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// OGCG: %[[RES_ADDR:.+]] = alloca i32
+// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
+// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]])
+// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
+// OGCG: %[[DECAY_DUP:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
+// OGCG: call void @llvm.va_copy.p0(ptr %[[DECAY1]], ptr %[[DECAY_DUP]])
+// OGCG: %[[DECAY_DUP2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
+// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 0
+// OGCG: %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]]
+// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40
+// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem
+//
+// OGCG: vaarg.in_reg:
+// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 3
+// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
+// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]]
+// OGCG: %[[NEXT_GPOFFSET:.+]] = add i32 %[[GPOFFSET]], 8
+// OGCG: store i32 %[[NEXT_GPOFFSET]], ptr %[[GPOFFSET_PTR]]
+// OGCG: br label %vaarg.end
+//
+// OGCG: vaarg.in_mem:
+// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 2
+// OGCG: %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]]
+// OGCG: %[[OVERFLOW_NEXT:.+]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8
+// OGCG: store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]]
+// OGCG: br label %vaarg.end
+//
+// OGCG: vaarg.end:
+// OGCG: %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ %[[OVERFLOW]], %vaarg.in_mem ]
+// OGCG: %[[LOADED:.+]] = load i32, ptr %[[PHI]]
+// OGCG: store i32 %[[LOADED]], ptr %[[RES_ADDR]]
+// OGCG: %[[DECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
+// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]])
+// OGCG: %[[DECAY_DUP3:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
+// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY_DUP3]])
+// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
+// OGCG: ret i32 %[[VAL]]
|
|
@llvm/pr-subscribers-clang Author: Hendrik Hübner (HendrikHuebner) ChangesThis PR upstreams Full diff: https://github.com/llvm/llvm-project/pull/169415.diff 4 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index a19c4f951fff9..78143ab44fa7e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4704,6 +4704,40 @@ 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
+ ```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 = [{
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index d220fdf4dc8a7..95ddfdfc7358a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -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:
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6136d48204e0c..f3c1b92fafcd3 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4034,6 +4034,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 {
diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c
index f5b92c61e11ad..82de39a3db58a 100644
--- a/clang/test/CIR/CodeGen/var_arg.c
+++ b/clang/test/CIR/CodeGen/var_arg.c
@@ -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,104 @@ 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]]
+
+int stdarg_copy(int count, ...) {
+ __builtin_va_list args;
+ __builtin_stdarg_start(args, 12345);
+ __builtin_va_list dup;
+ __builtin_va_copy(args, dup);
+ int res = __builtin_va_arg(dup, int);
+ __builtin_va_end(args);
+ __builtin_va_end(dup);
+ return res;
+}
+
+// CIR-LABEL: cir.func dso_local @stdarg_copy(
+// CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init]
+// CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
+// CIR: %[[DUP_AREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["dup"]
+// CIR: %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init]
+// CIR: cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[VA_PTR0:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: %[[C12345:.+]] = cir.const #cir.int<12345> : !s32i
+// CIR: cir.va_start %[[VA_PTR0]] %[[C12345]] : !cir.ptr<!rec___va_list_tag>, !s32i
+// CIR: %[[VA_PTR_SRC:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_PTR_DEST:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: cir.va.copy %[[VA_PTR_DEST]] to %[[VA_PTR_SRC]] : !cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_PTR_COPY:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR_COPY]] : (!cir.ptr<!rec___va_list_tag>) -> !s32i
+// CIR: cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[VA_PTR2:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_PTR3:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR: cir.va_end %[[VA_PTR3]] : !cir.ptr<!rec___va_list_tag>
+// CIR: %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.return %[[RETVAL]] : !s32i
+
+// LLVM-LABEL: define dso_local i32 @stdarg_copy(
+// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
+// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}}
+// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
+// LLVM: %[[DUP_AREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
+// LLVM: %[[RES_ADDR:.+]] = alloca i32{{.*}}
+// LLVM: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
+// LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM: %[[VA_PTR_DUP:.+]] = getelementptr %struct.__va_list_tag, ptr %[[DUP_AREA]], i32 0
+// LLVM: call void @llvm.va_copy.p0(ptr %[[VA_PTR1]], ptr %[[VA_PTR_DUP]])
+// LLVM: %[[VA_PTR_DUP2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[DUP_AREA]], i32 0
+// LLVM: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR_DUP2]], i32
+// LLVM: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
+// LLVM: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
+// LLVM: %[[VA_PTR3:.+]] = getelementptr %struct.__va_list_tag, ptr %[[DUP_AREA]], i32 0
+// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR3]])
+// LLVM: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
+// LLVM: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
+// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
+// LLVM: ret i32 %[[RETVAL]]
+
+// OGCG-LABEL: define dso_local i32 @stdarg_copy
+// OGCG: %[[COUNT_ADDR:.+]] = alloca i32
+// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// OGCG: %[[DUP_AREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// OGCG: %[[RES_ADDR:.+]] = alloca i32
+// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
+// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]])
+// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
+// OGCG: %[[DECAY_DUP:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
+// OGCG: call void @llvm.va_copy.p0(ptr %[[DECAY1]], ptr %[[DECAY_DUP]])
+// OGCG: %[[DECAY_DUP2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
+// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 0
+// OGCG: %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]]
+// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40
+// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem
+//
+// OGCG: vaarg.in_reg:
+// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 3
+// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
+// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]]
+// OGCG: %[[NEXT_GPOFFSET:.+]] = add i32 %[[GPOFFSET]], 8
+// OGCG: store i32 %[[NEXT_GPOFFSET]], ptr %[[GPOFFSET_PTR]]
+// OGCG: br label %vaarg.end
+//
+// OGCG: vaarg.in_mem:
+// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 2
+// OGCG: %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]]
+// OGCG: %[[OVERFLOW_NEXT:.+]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8
+// OGCG: store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]]
+// OGCG: br label %vaarg.end
+//
+// OGCG: vaarg.end:
+// OGCG: %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ %[[OVERFLOW]], %vaarg.in_mem ]
+// OGCG: %[[LOADED:.+]] = load i32, ptr %[[PHI]]
+// OGCG: store i32 %[[LOADED]], ptr %[[RES_ADDR]]
+// OGCG: %[[DECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
+// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]])
+// OGCG: %[[DECAY_DUP3:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
+// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY_DUP3]])
+// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
+// OGCG: ret i32 %[[VAL]]
|
andykaylor
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code here looks good, but the test is showing a problem.
clang/test/CIR/CodeGen/var_arg.c
Outdated
| // LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 | ||
| // LLVM: %[[VA_PTR_DUP:.+]] = getelementptr %struct.__va_list_tag, ptr %[[DUP_AREA]], i32 0 | ||
| // LLVM: call void @llvm.va_copy.p0(ptr %[[VA_PTR1]], ptr %[[VA_PTR_DUP]]) | ||
| // LLVM: %[[VA_PTR_DUP2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[DUP_AREA]], i32 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like we've got something missing here that has nothing to do with this PR. Can you use a test that does just the vaarg copy? Maybe something like this (in a different test file):
void test_vaarg_copy() {
__builtin_va_list args, dup;
__builtin_va_copy(args, dup);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah lets use a simpler test case.
This PR upstreams
__builtin_va_copy, and extends the existing tests.