@@ -3614,4 +3614,86 @@ def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> {
3614
3614
}];
3615
3615
}
3616
3616
3617
+ //===----------------------------------------------------------------------===//
3618
+ // Variadic Operations
3619
+ //===----------------------------------------------------------------------===//
3620
+
3621
+ def CIR_VAStartOp : CIR_Op<"va_start"> {
3622
+ let summary = "Starts a variable argument list";
3623
+ let description = [{
3624
+ The cir.va_start operation models the C/C++ va_start macro by
3625
+ initializing a variable argument list at the given va_list storage
3626
+ location.
3627
+
3628
+ The first operand must be a pointer to the target's `va_list`
3629
+ representation. This operation has no results and produces its effect by
3630
+ mutating the storage referenced by the pointer operand. The second operand
3631
+ must be an integer value that contains the expected number of arguments in
3632
+ that list.
3633
+
3634
+ Each `cir.va_start` must be paired with a corresponding `cir.va_end`
3635
+ on the same logical `va_list` object along all control-flow paths. After
3636
+ `cir.va_end`, the `va_list` must not be accessed unless reinitialized
3637
+ with another `cir.va_start`.
3638
+
3639
+ Lowering maps this to the LLVM intrinsic `llvm.va_start`, passing the
3640
+ appropriately decayed pointer to the underlying `va_list` storage.
3641
+
3642
+ Example:
3643
+
3644
+ ```mlir
3645
+ // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
3646
+ %p = cir.cast(array_to_ptrdecay, %args
3647
+ : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
3648
+ !cir.ptr<!rec___va_list_tag>
3649
+ %count = cir.load %0 : !cir.ptr<!s32i>, !s32i
3650
+ cir.va_start %p %count : !cir.ptr<!rec___va_list_tag>, !s32i
3651
+ ```
3652
+ }];
3653
+ let arguments = (ins
3654
+ CIR_PointerType:$arg_list,
3655
+ CIR_AnyFundamentalIntType:$count
3656
+ );
3657
+
3658
+ let assemblyFormat = [{
3659
+ $arg_list $count attr-dict `:` type(operands)
3660
+ }];
3661
+ }
3662
+
3663
+ def CIR_VAEndOp : CIR_Op<"va_end"> {
3664
+ let summary = "Ends a variable argument list";
3665
+ let description = [{
3666
+ The `cir.va_end` operation models the C/C++ va_end macro by finalizing
3667
+ and cleaning up a variable argument list previously initialized with
3668
+ `cir.va_start`.
3669
+
3670
+ The operand must be a pointer to the target's `va_list` representation.
3671
+ This operation has no results and produces its effect by mutating the
3672
+ storage referenced by the pointer operand.
3673
+
3674
+ `cir.va_end` must only be called after a matching `cir.va_start` on the
3675
+ same `va_list` along all control-flow paths. After `cir.va_end`, the
3676
+ `va_list` is invalid and must not be accessed unless reinitialized.
3677
+
3678
+ Lowering typically maps this to the LLVM intrinsic `llvm.va_end`,
3679
+ passing the appropriately decayed pointer to the underlying `va_list`
3680
+ storage.
3681
+
3682
+ Example:
3683
+ ```mlir
3684
+ // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
3685
+ %p = cir.cast(array_to_ptrdecay, %args
3686
+ : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
3687
+ !cir.ptr<!rec___va_list_tag>
3688
+ cir.va_end %p : !cir.ptr<!rec___va_list_tag>
3689
+ ```
3690
+ }];
3691
+
3692
+ let arguments = (ins CIR_PointerType:$arg_list);
3693
+
3694
+ let assemblyFormat = [{
3695
+ $arg_list attr-dict `:` type(operands)
3696
+ }];
3697
+ }
3698
+
3617
3699
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
0 commit comments