Skip to content

Commit 42f9055

Browse files
authored
Merge pull request #28 from GuillaumeGomez/non-null
Add support for multiple integers value for attribute and `NonNull`
2 parents a033810 + 6f65575 commit 42f9055

9 files changed

+650
-69
lines changed

gcc/jit/dummy-frontend.cc

+455-26
Large diffs are not rendered by default.

gcc/jit/jit-playback.cc

+36-42
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,8 @@ const char* fn_attribute_to_string(gcc_jit_fn_attribute attr)
539539
return "const";
540540
case GCC_JIT_FN_ATTRIBUTE_WEAK:
541541
return "weak";
542+
case GCC_JIT_FN_ATTRIBUTE_NONNULL:
543+
return "nonnull";
542544
}
543545
return NULL;
544546
}
@@ -566,6 +568,7 @@ new_function (location *loc,
566568
enum built_in_function builtin_id,
567569
const std::vector<gcc_jit_fn_attribute> &attributes,
568570
const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes,
571+
const std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> &int_array_attributes,
569572
int is_target_builtin)
570573
{
571574
int i;
@@ -601,6 +604,8 @@ new_function (location *loc,
601604
DECL_RESULT (fndecl) = resdecl;
602605
DECL_CONTEXT (resdecl) = fndecl;
603606

607+
tree fn_attributes = NULL_TREE;
608+
604609
if (is_target_builtin)
605610
{
606611
tree *decl = target_builtins.get(name);
@@ -654,48 +659,24 @@ new_function (location *loc,
654659
DECL_DECLARED_INLINE_P (fndecl) = 1;
655660

656661
/* Add attribute "always_inline": */
657-
DECL_ATTRIBUTES (fndecl) =
662+
fn_attributes =
658663
tree_cons (get_identifier ("always_inline"),
659664
NULL,
660-
DECL_ATTRIBUTES (fndecl));
665+
fn_attributes);
661666
}
662667

668+
/* All attributes need to be declared in `dummy-frontend.cc` and more
669+
specifically in `jit_attribute_table`. */
663670
for (auto attr: attributes)
664671
{
665-
if (attr == GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE)
666-
{
672+
if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE)
667673
DECL_DECLARED_INLINE_P (fndecl) = 1;
668-
DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
669-
}
670-
else if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE)
671-
DECL_DECLARED_INLINE_P (fndecl) = 1;
672-
else if (attr == GCC_JIT_FN_ATTRIBUTE_NOINLINE)
673-
DECL_UNINLINABLE (fndecl) = 1;
674-
/* See handle_used_attribute in gcc/c-family/c-attribs.cc. */
675-
else if (attr == GCC_JIT_FN_ATTRIBUTE_USED)
676-
{
677-
TREE_USED (fndecl) = 1;
678-
DECL_PRESERVE_P (fndecl) = 1;
679-
}
680-
/* See handle_returns_twice_attribute in gcc/c-family/c-attribs.cc. */
681-
else if (attr == GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE)
682-
DECL_IS_RETURNS_TWICE (fndecl) = 1;
683-
/* See handle_pure_attribute in gcc/c-family/c-attribs.cc. */
684-
else if (attr == GCC_JIT_FN_ATTRIBUTE_PURE)
685-
DECL_PURE_P (fndecl) = 1;
686-
/* See handle_const_attribute in gcc/c-family/c-attribs.cc. */
687-
else if (attr == GCC_JIT_FN_ATTRIBUTE_CONST)
688-
TREE_READONLY (fndecl) = 1;
689-
/* See handle_weak_attribute in gcc/c-family/c-attribs.cc. */
690-
else if (attr == GCC_JIT_FN_ATTRIBUTE_WEAK)
691-
declare_weak (fndecl);
692674

693675
const char* attribute = fn_attribute_to_string (attr);
694676
if (attribute)
695677
{
696678
tree ident = get_identifier (attribute);
697-
DECL_ATTRIBUTES (fndecl) =
698-
tree_cons (ident, NULL_TREE, DECL_ATTRIBUTES (fndecl));
679+
fn_attributes = tree_cons (ident, NULL_TREE, fn_attributes);
699680
}
700681
}
701682

@@ -713,20 +694,33 @@ new_function (location *loc,
713694
if (!ident || !targetm.target_option.valid_attribute_p (fndecl, ident, attribute_value, 0))
714695
continue;
715696

716-
/* See handle_alias_ifunc_attribute in gcc/c-family/c-attribs.cc. */
717-
if (name == GCC_JIT_FN_ATTRIBUTE_ALIAS)
697+
if (ident)
698+
fn_attributes = tree_cons (ident, attribute_value, fn_attributes);
699+
}
700+
701+
for (auto attr: int_array_attributes)
702+
{
703+
gcc_jit_fn_attribute& name = std::get<0>(attr);
704+
std::vector<int>& values = std::get<1>(attr);
705+
706+
const char* attribute = fn_attribute_to_string (name);
707+
tree ident = attribute ? get_identifier (attribute) : NULL;
708+
709+
if (!ident)
710+
continue;
711+
712+
tree tree_list = NULL_TREE;
713+
tree *p_tree_list = &tree_list;
714+
for (auto value : values)
718715
{
719-
tree id = get_identifier (value.c_str ());
720-
/* This counts as a use of the object pointed to. */
721-
TREE_USED (id) = 1;
722-
DECL_INITIAL (fndecl) = error_mark_node;
716+
tree int_value = build_int_cst (integer_type_node, value);
717+
*p_tree_list = build_tree_list (NULL, int_value);
718+
p_tree_list = &TREE_CHAIN (*p_tree_list);
723719
}
724-
725-
if (ident)
726-
DECL_ATTRIBUTES (fndecl) =
727-
tree_cons (ident, attribute_value, DECL_ATTRIBUTES (fndecl));
720+
fn_attributes = tree_cons (ident, tree_list, fn_attributes);
728721
}
729722

723+
decl_attributes (&fndecl, fn_attributes, 0);
730724
function *func = new function (this, fndecl, kind);
731725
m_functions.safe_push (func);
732726
return func;
@@ -2396,7 +2390,7 @@ add_try_catch (location *loc,
23962390
{
23972391
catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
23982392
tree try_catch = build2 (TRY_CATCH_EXPR, void_type_node,
2399-
try_body, catch_body);
2393+
try_body, catch_body);
24002394
add_stmt (try_catch);
24012395
}
24022396
}
@@ -3794,7 +3788,7 @@ void
37943788
playback::context::
37953789
init_types ()
37963790
{
3797-
/* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
3791+
/* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
37983792
for reference. If TYPE_NAME is not set, debug info will not contain types */
37993793
#define NAME_TYPE(t,n) \
38003794
if (t) \

gcc/jit/jit-playback.h

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ namespace gcc {
3737

3838
namespace jit {
3939

40+
const char* fn_attribute_to_string(gcc_jit_fn_attribute attr);
41+
4042
/**********************************************************************
4143
Playback.
4244
**********************************************************************/
@@ -114,6 +116,7 @@ class context : public log_user
114116
enum built_in_function builtin_id,
115117
const std::vector<gcc_jit_fn_attribute> &attributes,
116118
const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes,
119+
const std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> &int_array_attributes,
117120
int is_target_builtin);
118121

119122
lvalue *

gcc/jit/jit-recording.cc

+42
Original file line numberDiff line numberDiff line change
@@ -4260,6 +4260,7 @@ recording::function::function (context *ctxt,
42604260
m_fn_ptr_type (NULL),
42614261
m_attributes(),
42624262
m_string_attributes(),
4263+
m_int_array_attributes(),
42634264
m_is_target_builtin (is_target_builtin)
42644265
{
42654266
for (int i = 0; i< num_params; i++)
@@ -4322,6 +4323,7 @@ recording::function::replay_into (replayer *r)
43224323
m_builtin_id,
43234324
m_attributes,
43244325
m_string_attributes,
4326+
m_int_array_attributes,
43254327
m_is_target_builtin));
43264328
}
43274329

@@ -4401,6 +4403,40 @@ recording::function::new_block (const char *name)
44014403
void
44024404
recording::function::write_to_dump (dump &d)
44034405
{
4406+
for (auto attr: m_attributes)
4407+
{
4408+
const char* attribute = fn_attribute_to_string (attr);
4409+
if (attribute)
4410+
d.write("__attribute(%s)__\n", attribute);
4411+
}
4412+
for (auto attr: m_string_attributes)
4413+
{
4414+
gcc_jit_fn_attribute& name = std::get<0>(attr);
4415+
std::string& value = std::get<1>(attr);
4416+
const char* attribute = fn_attribute_to_string (name);
4417+
4418+
if (attribute)
4419+
d.write("__attribute(%s(\"%s\"))__\n", attribute, value.c_str());
4420+
}
4421+
for (auto attr: m_int_array_attributes)
4422+
{
4423+
gcc_jit_fn_attribute& name = std::get<0>(attr);
4424+
std::vector<int>& values = std::get<1>(attr);
4425+
const char* attribute = fn_attribute_to_string (name);
4426+
if (attribute)
4427+
{
4428+
d.write("__attribute(%s(", attribute);
4429+
for (int i = 0; i < values.size(); ++i)
4430+
{
4431+
if (i > 0)
4432+
d.write(", %d", values[i]);
4433+
else
4434+
d.write("%d", values[i]);
4435+
}
4436+
d.write("))__\n");
4437+
}
4438+
}
4439+
44044440
switch (m_kind)
44054441
{
44064442
default: gcc_unreachable ();
@@ -4615,6 +4651,12 @@ recording::function::add_string_attribute (gcc_jit_fn_attribute attribute, const
46154651
m_string_attributes.push_back (std::make_pair (attribute, std::string (value)));
46164652
}
46174653

4654+
void
4655+
recording::function::add_integer_array_attribute (gcc_jit_fn_attribute attribute, const int* value, size_t length)
4656+
{
4657+
m_int_array_attributes.push_back (std::make_pair (attribute, std::vector<int> (value, value + length)));
4658+
}
4659+
46184660
/* Implementation of recording::memento::make_debug_string for
46194661
functions. */
46204662

gcc/jit/jit-recording.h

+2
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,7 @@ class function : public memento
14831483

14841484
void add_attribute (gcc_jit_fn_attribute attribute);
14851485
void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value);
1486+
void add_integer_array_attribute (gcc_jit_fn_attribute attribute, const int* value, size_t length);
14861487

14871488
private:
14881489
string * make_debug_string () final override;
@@ -1501,6 +1502,7 @@ class function : public memento
15011502
type *m_fn_ptr_type;
15021503
std::vector<gcc_jit_fn_attribute> m_attributes;
15031504
std::vector<std::pair<gcc_jit_fn_attribute, std::string>> m_string_attributes;
1505+
std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> m_int_array_attributes;
15041506
int m_is_target_builtin;
15051507
};
15061508

gcc/jit/libgccjit.cc

+13
Original file line numberDiff line numberDiff line change
@@ -4234,6 +4234,19 @@ gcc_jit_function_add_string_attribute (gcc_jit_function *func, gcc_jit_fn_attrib
42344234
func->add_string_attribute (attribute, value);
42354235
}
42364236

4237+
/* This function adds an attribute with multiple integer values. For example
4238+
`nonnull(1, 2)`. The numbers in `values` are supposed to map how they
4239+
should be written in C code. So for `nonnull(1, 2)`, you should pass `1`
4240+
and `2` in `values` (and set `length` to `2`). */
4241+
void
4242+
gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute, const int* values, size_t length)
4243+
{
4244+
RETURN_IF_FAIL (func, NULL, NULL, "NULL func");
4245+
RETURN_IF_FAIL (values, NULL, NULL, "NULL values");
4246+
4247+
func->add_integer_array_attribute (attribute, values, length);
4248+
}
4249+
42374250
void
42384251
gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, gcc_jit_variable_attribute attribute, const char* value)
42394252
{

gcc/jit/libgccjit.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -2117,16 +2117,19 @@ enum gcc_jit_fn_attribute
21172117
GCC_JIT_FN_ATTRIBUTE_PURE,
21182118
GCC_JIT_FN_ATTRIBUTE_CONST,
21192119
GCC_JIT_FN_ATTRIBUTE_WEAK,
2120+
GCC_JIT_FN_ATTRIBUTE_NONNULL,
21202121
};
21212122

21222123
/* Add an attribute to a function. */
2123-
// TODO: also support integer values.
21242124
extern void
21252125
gcc_jit_function_add_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute);
21262126

21272127
extern void
21282128
gcc_jit_function_add_string_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const char* value);
21292129

2130+
extern void
2131+
gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const int* value, size_t length);
2132+
21302133
/* Variable attributes. */
21312134
enum gcc_jit_variable_attribute
21322135
{

gcc/jit/libgccjit.map

+1
Original file line numberDiff line numberDiff line change
@@ -335,4 +335,5 @@ LIBGCCJIT_ABI_34 {
335335
LIBGCCJIT_ABI_35 {
336336
global:
337337
gcc_jit_context_new_sizeof;
338+
gcc_jit_function_add_integer_array_attribute;
338339
} LIBGCCJIT_ABI_34;

gcc/testsuite/jit.dg/test-nonnull.c

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/* { dg-do compile { target x86_64-*-* } } */
2+
3+
#include <stdlib.h>
4+
#include <stdio.h>
5+
6+
#include "libgccjit.h"
7+
8+
/* We don't want set_options() in harness.h to set -O2 to see that the nonnull
9+
attribute affects the optimizations. */
10+
#define TEST_ESCHEWS_SET_OPTIONS
11+
static void set_options (gcc_jit_context *ctxt, const char *argv0)
12+
{
13+
// Set "-O2".
14+
gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
15+
}
16+
17+
#define TEST_COMPILING_TO_FILE
18+
#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
19+
#define OUTPUT_FILENAME "output-of-test-nonnull.c.s"
20+
#include "harness.h"
21+
22+
void
23+
create_code (gcc_jit_context *ctxt, void *user_data)
24+
{
25+
/* Let's try to inject the equivalent of:
26+
27+
__attribute__((nonnull(1)))
28+
int t(int *a) {
29+
if (!a) {
30+
return -1;
31+
}
32+
return *a;
33+
}
34+
*/
35+
gcc_jit_type *int_type =
36+
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
37+
gcc_jit_type *pint_type = gcc_jit_type_get_pointer(int_type);
38+
39+
gcc_jit_param *a =
40+
gcc_jit_context_new_param (ctxt, NULL, pint_type, "a");
41+
42+
gcc_jit_function *func_t =
43+
gcc_jit_context_new_function (ctxt, NULL,
44+
GCC_JIT_FUNCTION_EXPORTED,
45+
int_type,
46+
"t",
47+
1, &a,
48+
0);
49+
/* Adding `nonnull(1)` attribute. */
50+
int indexes[1] = {1};
51+
gcc_jit_function_add_integer_array_attribute (
52+
func_t,
53+
GCC_JIT_FN_ATTRIBUTE_NONNULL,
54+
indexes,
55+
1
56+
);
57+
58+
/* if (!a) {
59+
return -1;
60+
} */
61+
gcc_jit_block *if_cond =
62+
gcc_jit_function_new_block (func_t, "if_cond");
63+
gcc_jit_block *if_body =
64+
gcc_jit_function_new_block (func_t, "if_body");
65+
gcc_jit_block *after_if =
66+
gcc_jit_function_new_block (func_t, "after_if");
67+
68+
/* if (!a) */
69+
gcc_jit_block_end_with_conditional (
70+
if_cond, NULL,
71+
gcc_jit_context_new_comparison (
72+
ctxt, NULL,
73+
GCC_JIT_COMPARISON_EQ,
74+
gcc_jit_param_as_rvalue (a),
75+
gcc_jit_context_null (ctxt, pint_type)),
76+
if_body,
77+
after_if);
78+
/* return -1; */
79+
gcc_jit_block_end_with_return (
80+
if_body, NULL,
81+
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, -1));
82+
83+
/* return *a; */
84+
gcc_jit_block_end_with_return (
85+
after_if, NULL,
86+
gcc_jit_lvalue_as_rvalue (
87+
gcc_jit_rvalue_dereference (
88+
gcc_jit_param_as_rvalue (a), NULL)));
89+
}
90+
91+
/* { dg-final { jit-verify-output-file-was-created "" } } */
92+
/* Check that the "if block" was optimized away */
93+
/* { dg-final { jit-verify-assembler-output-not "testq" } } */
94+
/* { dg-final { jit-verify-assembler-output-not "-1" } } */

0 commit comments

Comments
 (0)