summaryrefslogtreecommitdiffhomepage
path: root/ir/be/bevarargs.c
diff options
context:
space:
mode:
authorAndreas Fried <andi@0xaf.de>2015-07-31 15:05:04 +0200
committerChristoph Mallon <christoph.mallon@gmx.de>2015-08-14 20:34:22 +0200
commitf833aa2514e33efab8e0212d40c0bf7758f0201d (patch)
tree88ac77eb873e3657cd990b8eecb438261d3297ac /ir/be/bevarargs.c
parent7ce42e19cb1739c6f4c4e2771b0f42ac7bf4b71c (diff)
Implement vararg handling in a more portable way (for now only for IA32).
This adds two builtin kinds, ir_bk_va_start and ir_bk_va_arg. va_arg Builtins are lowered in the lower_builtins pass with a function provided by the backend, whereby most architectures can use be_default_lower_va_args. va_start Builtins are lowered in the backend. Note: This commit breaks all backends except for IA32. SPARC and AMD64 are implemented in later commits. The ARM backend previously miscompiled variadic functions, and will now throw a proper error.
Diffstat (limited to 'ir/be/bevarargs.c')
-rw-r--r--ir/be/bevarargs.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/ir/be/bevarargs.c b/ir/be/bevarargs.c
new file mode 100644
index 0000000..aa6e9ea
--- /dev/null
+++ b/ir/be/bevarargs.c
@@ -0,0 +1,53 @@
+/*
+ * This file is part of libFirm.
+ * Copyright (C) 2012 University of Karlsruhe.
+ */
+
+/**
+ * @file
+ * @brief Default (pointer-based) implementation of variadic functions
+ * @author Andreas Fried
+ */
+
+#include "bevarargs.h"
+
+#include "be.h"
+#include "bitfiddle.h"
+#include "ircons.h"
+#include "irgmod.h"
+#include "irnode.h"
+#include "util.h"
+
+void be_default_lower_va_arg(ir_node *node)
+{
+ ir_node *block = get_nodes_block(node);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_graph *irg = get_irn_irg(node);
+
+ ir_type *const aptype = get_method_res_type(get_Builtin_type(node), 0);
+ ir_node *const ap = get_irn_n(node, 1);
+ ir_node *const node_mem = get_Builtin_mem(node);
+
+ ir_mode *apmode = get_type_mode(aptype);
+ ir_node *res;
+ ir_node *new_mem;
+ if (apmode != NULL) {
+ ir_node *const load = new_rd_Load(dbgi, block, node_mem, ap, apmode, aptype, cons_none);
+ res = new_r_Proj(load, apmode, pn_Load_res);
+ new_mem = new_r_Proj(load, mode_M,pn_Load_M);
+ } else {
+ // aptype has no associated mode, so it is represented
+ // as a pointer.
+ apmode = mode_P;
+ res = ap;
+ new_mem = node_mem;
+ }
+
+ const backend_params *be_params = be_get_backend_param();
+ unsigned round_up = round_up2(get_type_size_bytes(aptype), be_params->stack_param_align);
+ ir_node *const diff_const = new_r_Const_long(irg, mode_Iu, round_up);
+ ir_node *const new_ap = new_rd_Add(dbgi, block, ap, diff_const, mode_P);
+
+ ir_node *const in[] = { new_mem, res, new_ap };
+ turn_into_tuple(node, ARRAY_SIZE(in), in);
+}