shithub: mc

ref: 6b1a6216b40b804dd9c91c2bd54bee954776acaa
dir: /libstd/varargs.myr/

View raw version
use "types.use"

pkg std =
	type valist

	const vastart	: (args : ...# -> valist)
	generic vanext	: (ap : valist -> (@a, valist))
;;

type valist = byte#

/* 
 * a valist is really just a pointer to the varargs.
 * we assume that these sit on the stack nicely,
 * and don't need special handling to get to.
 * 
 * This will be a problem when we switch to a
 * register based convention. We might want to
 * force varargs onto the stack regardless.
 */
const vastart = {args
	var ap, dump : byte#

	(dump, ap) = vanext(args castto(valist))
	-> ap
}

generic vanext = {ap -> (@a, valist)
	var v : @a
	var align
	var p

	/*
	 Assumptions about the ABI:
	 * all types smaller than a word are
	 * aligned to their own size. Larger
	 * types are aligned to word size.
	 */
	if sizeof(@a) > 8
		align = 8
	else
		align = sizeof(@a)
	;;

	/* apply the alignment to the arg pointer */
	p = ap castto(intptr)
	p = (p + align - 1) & ~(align - 1)
	ap = p castto(valist)

	v = (ap castto(@a#))#

	/* only move on after we read through the value */
	ap = ((p castto(intptr)) + sizeof(@a)) castto(valist)
	-> (v, ap)
}