From patchwork Sun Nov 10 04:29:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Schrodinger ZHU Yifan X-Patchwork-Id: 2009186 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; secure) header.d=zhuyi.fan header.i=@zhuyi.fan header.a=rsa-sha256 header.s=protonmail3 header.b=WJyO7Mbp; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XmKVF74hxz1xyD for ; Sun, 10 Nov 2024 15:30:25 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 954AE3858C32 for ; Sun, 10 Nov 2024 04:30:22 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-4022.proton.ch (mail-4022.proton.ch [185.70.40.22]) by sourceware.org (Postfix) with ESMTPS id 12C653858D28 for ; Sun, 10 Nov 2024 04:29:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 12C653858D28 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=zhuyi.fan Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=zhuyi.fan ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 12C653858D28 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=185.70.40.22 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1731212994; cv=none; b=msdc+nEvltBziPyQsPDWC+OxJSdNy14DiQq5eH7P1oMGHtNN/WroxZRhxxvSUE/+l4Zyj/qfhxHRmohTGPx0kWdmHaMszy7F3LRr0pr3Fdaw/szj9KtuQVPEZmRBc2dL4ctDB91Ny8iK/Q/AU52Rf0apSqpayWaXE5oc5boDNdQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1731212994; c=relaxed/simple; bh=GhVuFvGP0yDomZgIMjRNRWToQFdUhG2aO9cY6zQ0sNs=; h=DKIM-Signature:Date:To:From:Subject:Message-ID:MIME-Version; b=bYi1ipMudYpl605Ntsu0fbG1RpQ63PWPv3bqo/tsnK704++DEfzTJe+IOCz+CX1AaW29WOl8ibwOtv0SpULndohvOc07FthdeHH2NOqWOysNTulwyQtXH81+KwAOuEKC0Jms6jTP5S70+QRJwLNn+y1tHUq2yZwArOL1SXM5TPY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zhuyi.fan; s=protonmail3; t=1731212987; x=1731472187; bh=EtRJip/NrRqULZ0aUjMnJxE+5bUTS+qS8Ocyjlzcm7w=; h=Date:To:From:Subject:Message-ID:Feedback-ID:From:To:Cc:Date: Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector: List-Unsubscribe:List-Unsubscribe-Post; b=WJyO7MbpTjf+HnDx3dKaJzk7TGUOE9zwwiB7iVGHIOff0zlhzidkLBUUXbPlIw2da xMxIu0hPfXSi7qPkRDL8+QUrp+8/b6g3S4tNqi5oIAIia2mZExMKAv8dreyyac80p5 WMeqGqQctEBvAz6GkhRbYlbFfAggZ8ToMJr4y8Yu3PSq5x+eEtdF4M1fkNJFNRZgUS 41wx6HYGYm4N7CrUtNajAtzGGUq5HDQWWBEz2t8GT9SObsUJP9lhXZXOzYaNOnvMfT zs4ffEGQsgCBPdviHBdElfXtmkfcv9pprZ1WvGPJ8Yhx1nZ4ECHQSmteAI+po/BOQ2 Q9PMAqAr9S9Xg== Date: Sun, 10 Nov 2024 04:29:42 +0000 To: i@zhuyi.fan, gcc-patches@gcc.gnu.org, jit@gcc.gnu.org From: Schrodinger ZHU Yifan Subject: [PATCH] [GCCJIT] support dynamic alloca stub Message-ID: <20241110042152.772-2-i@zhuyi.fan> Feedback-ID: 25959550:user:proton X-Pm-Message-ID: b05500bb6d7a950b4dd220bb14f524ce2db4e5cd MIME-Version: 1.0 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org This patch adds dynamic alloca stubs support to GCCJIT. DEF_BUILTIN_STUB only define the enum for builtins instead of providing the type. Therefore, builtins with stub will lead to ICE before this patch. This applies to `alloca_with_align`, `stack_save` and `stack_restore`. This patch add special handling for builtins defined by DEF_BUILTIN_STUB. Additionally, it fixes `fold_builtin_with_align` by adding an addtional check on the presence of supercontext. For blocks created by GCCJIT, such field does not exist while the folder implementation assumes the existence on default. This is my first patch to GCC and GCCJIT. I mainly work on LLVM and other github-based projects before. So it is a bit hard for me to get familiar with the workflow. I managed to pass the GNU Style check locally but I don't think I am doing the correct formatting. Also, I tried the changelog script but I don't think the patch contains the changelog list. Is it because I did not invoke it as a g it-hook? Please refer me to more detailed guideline to correct the format or changelog if needed. I am *really really* for the inconvenience. Signed-off-by: Andrew Pinski --- gcc/jit/jit-builtins.cc | 66 +++++++- gcc/jit/jit-builtins.h | 7 + gcc/testsuite/jit.dg/test-aligned-alloca.c | 141 ++++++++++++++++++ .../jit.dg/test-stack-save-restore.c | 116 ++++++++++++++ gcc/tree-ssa-ccp.cc | 3 +- 5 files changed, 329 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-aligned-alloca.c create mode 100644 gcc/testsuite/jit.dg/test-stack-save-restore.c diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc index 0c13c8db586..bf4251701d3 100644 --- a/gcc/jit/jit-builtins.cc +++ b/gcc/jit/jit-builtins.cc @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "jit-playback.h" #include "stringpool.h" +#include "tree-core.h" # include "jit-builtins.h" @@ -185,7 +186,8 @@ builtins_manager::make_builtin_function (enum built_in_function builtin_id) { const struct builtin_data& bd = builtin_data[builtin_id]; enum jit_builtin_type type_id = bd.type; - recording::type *t = get_type (type_id); + recording::type *t = type_id == BT_LAST ? get_type_for_stub (builtin_id) + : get_type (type_id); if (!t) return NULL; recording::function_type *func_type = t->as_a_function_type (); @@ -333,6 +335,49 @@ builtins_manager::get_type (enum jit_builtin_type type_id) return m_types[type_id]; } +/* Create the recording::type for special builtins whose types are not defined + in builtin-types.def. */ + +recording::type * +builtins_manager::make_type_for_stub (enum built_in_function builtin_id) +{ + switch (builtin_id) + { + default: + return reinterpret_cast(-1); + case BUILT_IN_ALLOCA_WITH_ALIGN: { + recording::type * p = m_ctxt->get_ type (GCC_JIT_TYPE_SIZE_T); + recording::type * r = m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR); + recording::type * params[2] = {p, p}; + return m_ctxt->new_function_type (r,2,params,false); + } + case BUILT_IN_STACK_SAVE: { + recording::type * r = m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR); + return m_ctxt->new_function_type (r,0,nullptr,false); + } + case BUILT_IN_STACK_RESTORE: { + recording::type * p = m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR); + recording::type * r = m_ctxt->get_type (GCC_JIT_TYPE_VOID); + recording::type * params[1] = {p}; + return m_ctxt->new_function_type (r,1,params,false); + } + } +} + +/* Get the recording::type for a given type of builtin function, + by ID, creating it if it doesn't already exist. */ + +recording::type * +builtins_manager::get_type_for_stub (enum built_in_function type_id) +{ + if (m_types[type_id] == nullptr) + m_types[type_id] = make_type_for_stub (typ e_id); + recording::type* t = m_types[type_id]; + if (reinterpret_cast(t) == -1) + return nullptr; + return t; +} + /* Create the recording::type for a given type of builtin function. */ recording::type * @@ -661,15 +706,30 @@ tree builtins_manager::get_attrs_tree (enum built_in_function builtin_id) { enum built_in_attribute attr = builtin_data[builtin_id].attr; + if (attr == ATTR_LAST) + return get_attrs_tree_for_stub (builtin_id); return get_attrs_tree (attr); } -/* As above, but for an enum built_in_attribute. */ +/* Get attributes for builtin stubs. */ + +tree +builtins_manager::get_attrs_tree_for_stub (enum built_in_function builtin_id) +{ + switch (builtin_id) + { + default: + return NULL_TREE; + case BUILT_IN_ALLOCA_WITH_ALIGN: + return get_attrs_tree (BUILT_IN_ALLOCA); + } +} + +/* As get_attrs_tree, but for an enum built_in_attribute. */ tree builtins_manager::get_attrs_tree (enum built_in_attribute attr) { - gcc_assert (attr < ATTR_LAST); if (!m_attributes [attr]) m_attributes [attr] = make_attrs_tree (attr); return m_attributes [attr]; diff --git a/gcc/jit/jit-builtins.h b/gcc/jit/jit-builtins.h index 17e118481d6..f4de3707201 100644 --- a/gcc/jit/jit-builtins.h +++ b/gcc/jit/jit-builtins.h @@ -124,6 +124,9 @@ public: tree get_attrs_tree (enum built_in_function builtin_id); + tree + get_attrs_tree_for_stub (enum built_in_function builtin_id); + tree get_attrs_tree (enum built_in_attribute attr); @@ -146,6 +149,10 @@ private: recording::type * make_type (enum jit_builtin_type type_id); + recording::type *get_type_for_stub (enum built_in_function type_id); + + recording::type *make_type_for_stub (enum built_in_function type_id); + recording::type* make_primitive_type (enum jit_builtin_type type_id); diff --git a/gcc/testsuite/jit.dg/test-aligned-alloca.c b/gcc/testsuite/jit.dg/t est-aligned-alloca.c new file mode 100644 index 00000000000..e107746b82f --- /dev/null +++ b/gcc/testsuite/jit.dg/test-aligned-alloca.c @@ -0,0 +1,141 @@ +#include +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +fill (void *ptr) { + for (int i = 0; i < 100; i++) + ((int *)ptr)[i] = i; +} + +void +sum (void *ptr, int *sum) { + *sum = 0; + for (int i = 0; i < 100; i++) + *sum += ((int *)ptr)[i]; +} + + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* + bool test_aligned_alloca (typeof(fill) *fill, typeof(sum) *sum, int* sum_p) { + size_t addr; + void *p; + + p = __builtin_alloca_with_align (sizeof (int) * 100, 128); + addr = (size_t)p; + fill (p); + sum (p, sum_p); + return (addr & 127) == 0; + } + */ + + /* Types */ + gcc_jit_type *size_t_type + = gcc_jit_context_g et_type (ctxt, GCC_JIT_TYPE_SIZE_T); + gcc_jit_type *int_type + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *int_ptr_type + = gcc_jit_type_get_pointer (int_type); + gcc_jit_type *void_ptr_type + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); + gcc_jit_type *bool_type + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL); + gcc_jit_type *void_type + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *fill_ptr_type + = gcc_jit_context_new_function_ptr_type (ctxt, NULL, void_type, 1, &void_ptr_type, 0); + gcc_jit_type *sum_params[] = {void_ptr_type, int_ptr_type}; + gcc_jit_type *sum_ptr_type + = gcc_jit_context_new_function_ptr_type (ctxt, NULL, void_type, 2, sum_params, 0); + + /* Function */ + gcc_jit_param *fill_param + = gcc_jit_context_new_param (ctxt, NULL, fill_ptr_type, "fill"); + gcc_jit_rvalue *rv_fill = gcc_jit_pa ram_as_rvalue (fill_param); + gcc_jit_param *sum_param + = gcc_jit_context_new_param (ctxt, NULL, sum_ptr_type, "sum"); + gcc_jit_rvalue *rv_sum = gcc_jit_param_as_rvalue (sum_param); + gcc_jit_param *sum_p_param + = gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "sum_p"); + gcc_jit_rvalue *rv_sum_p = gcc_jit_param_as_rvalue (sum_p_param); + gcc_jit_param *params[] = {fill_param, sum_param, sum_p_param}; + gcc_jit_function *test_aligned_alloca + = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, bool_type, "test_aligned_alloca", 3, params, 0); + + + /* Variables */ + gcc_jit_lvalue *addr + = gcc_jit_function_new_local (test_aligned_alloca, NULL, size_t_type, "addr"); + gcc_jit_lvalue *p + = gcc_jit_function_new_local (test_aligned_alloca, NULL, void_ptr_type, "p"); + gcc_jit_rvalue *rv_addr = gcc_jit_lvalue_as_rvalue (addr); + gcc_jit_rvalue *rv_p = gcc_jit_lvalue_as_rv alue (p); + + + /* Blocks */ + gcc_jit_block *block + = gcc_jit_function_new_block (test_aligned_alloca, NULL); + + /* p = __builtin_alloca_with_align (sizeof (int) * 100, 128); */ + gcc_jit_rvalue *sizeof_int + = gcc_jit_context_new_sizeof(ctxt, int_type); + gcc_jit_rvalue *c100 + = gcc_jit_context_new_rvalue_from_int(ctxt, int_type, 100); + gcc_jit_rvalue *size + = gcc_jit_context_new_binary_op(ctxt, NULL, GCC_JIT_BINARY_OP_MULT, size_t_type, sizeof_int, c100); + gcc_jit_rvalue *c128 + = gcc_jit_context_new_rvalue_from_int(ctxt, size_t_type, 128); + gcc_jit_function *alloca_with_align + = gcc_jit_context_get_builtin_function (ctxt, "__builtin_alloca_with_align"); + gcc_jit_rvalue *args[] = {size, c128}; + gcc_jit_rvalue *alloca_with_align_call + = gcc_jit_context_new_call (ctxt, NULL, alloca_with_align, 2, args); + gcc_jit_block_add_assignment (block, NULL, p, alloca_with_align_ call); + + /* addr = (size_t)p; */ + gcc_jit_rvalue *cast_p + = gcc_jit_context_new_bitcast (ctxt, NULL, rv_p, size_t_type); + gcc_jit_block_add_assignment (block, NULL, addr, cast_p); + + /* fill (p); */ + gcc_jit_rvalue * call_fill = gcc_jit_context_new_call_through_ptr( + ctxt, NULL, rv_fill, 1, &rv_p); + gcc_jit_block_add_eval (block, NULL, call_fill); + + /* sum (p, sum_p); */ + gcc_jit_rvalue * sum_args[] = {rv_p, rv_sum_p}; + gcc_jit_rvalue * call_sum = gcc_jit_context_new_call_through_ptr( + ctxt, NULL, rv_sum, 2, sum_args); + gcc_jit_block_add_eval (block, NULL, call_sum); + + /* return (addr & 127) == 0; */ + gcc_jit_rvalue *c127 + = gcc_jit_context_new_rvalue_from_int(ctxt, size_t_type, 127); + gcc_jit_rvalue *and_op + = gcc_jit_context_new_binary_op(ctxt, NULL, GCC_JIT_BINARY_OP_BITWISE_AND, size_t_type, rv_addr, c127); + gcc_jit_rvalue *c0 + = gcc_jit_context_new_rva lue_from_int(ctxt, size_t_type, 0); + gcc_jit_rvalue *eq_op + = gcc_jit_context_new_comparison(ctxt, NULL, GCC_JIT_COMPARISON_EQ, and_op, c0); + gcc_jit_block_end_with_return (block, NULL, eq_op); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef void (*fn_type) (typeof(fill) *, typeof(sum) *, int *); + CHECK_NON_NULL (result); + fn_type test_aligned_alloca = + (fn_type)gcc_jit_result_get_code (result, "test_aligned_alloca"); + CHECK_NON_NULL (test_aligned_alloca); + int value; + test_aligned_alloca (fill, sum, &value); + CHECK (value == 4950); +} diff --git a/gcc/testsuite/jit.dg/test-stack-save-restore.c b/gcc/testsuite/jit.dg/test-stack-save-restore.c new file mode 100644 index 00000000000..0bee247be9f --- /dev/null +++ b/gcc/testsuite/jit.dg/test-stack-save-restore.c @@ -0,0 +1,116 @@ +#include +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* + size_t test_stack_save_restore() { + void *p; + size_t a, b; + p = __builtin_stack_save(); + a = (size_t)__builtin_alloca(1024); + __builtin_stack_restore(p); + + p = __builtin_stack_save(); + b = (size_t)__builtin_alloca(512); + __builtin_stack_restore(p); + + return b - a; + } + */ + + /* Types */ + gcc_jit_type *size_t_type + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T); + gcc_jit_type *void_ptr_type + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); + + /* Function */ + gcc_jit_function *test_stack_save_restore + = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, size_t_type, "test_stack_save_restore", 0, NULL, 0); + + + /* Variables */ + gcc_jit_lvalue *p + = gcc_jit_function_new_local (test_stack_save_restore, NULL, void_ptr_type, "p"); + gcc_jit_lv alue *a + = gcc_jit_function_new_local (test_stack_save_restore, NULL, size_t_type, "a"); + gcc_jit_lvalue *b + = gcc_jit_function_new_local (test_stack_save_restore, NULL, size_t_type, "b"); + gcc_jit_rvalue *rv_p = gcc_jit_lvalue_as_rvalue (p); + gcc_jit_rvalue *rv_a = gcc_jit_lvalue_as_rvalue (a); + gcc_jit_rvalue *rv_b = gcc_jit_lvalue_as_rvalue (b); + + + /* Blocks */ + gcc_jit_block *block + = gcc_jit_function_new_block (test_stack_save_restore, NULL); + + /* Builtin functions */ + gcc_jit_function *stack_save + = gcc_jit_context_get_builtin_function(ctxt, "__builtin_stack_save"); + gcc_jit_function *stack_restore + = gcc_jit_context_get_builtin_function(ctxt, "__builtin_stack_restore"); + gcc_jit_function *alloca + = gcc_jit_context_get_builtin_function(ctxt, "__builtin_alloca"); + + /* Common code */ + gcc_jit_rvalue *call_stack_save + = gcc_jit_context_new_call(ctxt, NULL, stack_save, 0, NULL); + gcc_jit_rvalue * call_stack_restore + = gcc_jit_context_new_call(ctxt, NULL, stack_restore, 1, &rv_p); + + + /* p = __builtin_stack_save(); */ + gcc_jit_block_add_assignment (block, NULL, p, call_stack_save); + + /* a = (size_t)__builtin_alloca(1024); */ + gcc_jit_rvalue *c1024 + = gcc_jit_context_new_rvalue_from_int (ctxt, size_t_type, 1024); + gcc_jit_rvalue *call_alloca_1024 + = gcc_jit_context_new_call(ctxt, NULL, alloca, 1, &c1024); + gcc_jit_rvalue *cast_alloca_1024 + = gcc_jit_context_new_bitcast(ctxt, NULL, call_alloca_1024, size_t_type); + gcc_jit_block_add_assignment (block, NULL, a, cast_alloca_1024); + + /* __builtin_stack_restore(p); */ + gcc_jit_block_add_eval (block, NULL, call_stack_restore); + + /* p = __builtin_stack_save(); */ + gcc_jit_block_add_assignment (block, NULL, p, call_stack_save); + + /* b = (size_t)__builtin_alloca(512); */ + gcc_jit_rvalue *c512 + = gcc_jit_context_new_rvalue_from_int (ctxt, size_t_type, 512); + gcc_jit_rv alue *call_alloca_512 + = gcc_jit_context_new_call(ctxt, NULL, alloca, 1, &c512); + gcc_jit_rvalue *cast_alloca_512 + = gcc_jit_context_new_bitcast(ctxt, NULL, call_alloca_512, size_t_type); + gcc_jit_block_add_assignment (block, NULL, b, cast_alloca_512); + + /* __builtin_stack_restore(p); */ + gcc_jit_block_add_eval (block, NULL, call_stack_restore); + + /* return b - a; */ + gcc_jit_rvalue *sub + = gcc_jit_context_new_binary_op(ctxt, NULL, GCC_JIT_BINARY_OP_MINUS, size_t_type, rv_b, rv_a); + gcc_jit_block_end_with_return (block, NULL, sub); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef size_t (*fn_type) (void); + CHECK_NON_NULL (result); + fn_type test_stack_save_restore = + (fn_type)gcc_jit_result_get_code (result, "test_stack_save_restore"); + CHECK_NON_NULL (test_stack_save_restore); + size_t value = test_stack_save_restore(); + CHECK (value == 512); +} diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tre e-ssa-ccp.cc index fcb91c58335..d721c471f74 100644 --- a/gcc/tree-ssa-ccp.cc +++ b/gcc/tree-ssa-ccp.cc @@ -2671,7 +2671,8 @@ fold_builtin_alloca_with_align (gimple *stmt) block = gimple_block (stmt); if (!(cfun->after_inlining && block - && TREE_CODE (BLOCK_SUPERCONTEXT (block)) == FUNCTION_DECL)) + && BLOCK_SUPERCONTEXT (block) + && TREE_CODE (BLOCK_SUPERCONTEXT (block)) == FUNCTION_DECL)) threshold /= 10; if (size > threshold) return NULL_TREE;