1 /*
2 * Copyright (c) 2015-2018, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 #include "gbldefs.h"
19 #include "global.h"
20 #include "ll_builder.h"
21 #include "lldebug.h"
22
23 /*
24 * LLMD_Builder -- Builder for metadata nodes.
25 */
26 struct LLMD_Builder_ {
27 LL_Module *module;
28 unsigned nelems;
29 unsigned capacity;
30 LL_MDRef *elems;
31 enum LL_MDClass mdclass;
32 unsigned is_distinct : 1;
33 LL_MDRef init_elems[32];
34 };
35
36 LLMD_Builder
llmd_init(LL_Module * module)37 llmd_init(LL_Module *module)
38 {
39 LLMD_Builder mdb = (LLMD_Builder)calloc(1, sizeof(struct LLMD_Builder_));
40 mdb->module = module;
41 /* Start out with init_elems to save a malloc() call. */
42 mdb->elems = mdb->init_elems;
43 mdb->capacity = sizeof(mdb->init_elems) / sizeof(mdb->init_elems[0]);
44 return mdb;
45 }
46
47 /* Double the capacity in mdb. */
48 static void
grow(LLMD_Builder mdb)49 grow(LLMD_Builder mdb)
50 {
51 mdb->capacity *= 2;
52 if (mdb->elems == mdb->init_elems) {
53 /* First time we grow, don't free init_elems. */
54 mdb->elems = (LL_MDRef *)malloc(mdb->capacity * sizeof(mdb->elems[0]));
55 memcpy(mdb->elems, mdb->init_elems, sizeof(mdb->init_elems));
56 } else {
57 /* We've grown before. Just realloc. */
58 mdb->elems =
59 (LL_MDRef *)realloc(mdb->elems, mdb->capacity * sizeof(mdb->elems[0]));
60 }
61 }
62
63 void
llmd_add_md(LLMD_Builder mdb,LL_MDRef mdnode)64 llmd_add_md(LLMD_Builder mdb, LL_MDRef mdnode)
65 {
66 if (mdb->nelems >= mdb->capacity)
67 grow(mdb);
68 mdb->elems[mdb->nelems++] = mdnode;
69 }
70
71 void
llmd_add_null(LLMD_Builder mdb)72 llmd_add_null(LLMD_Builder mdb)
73 {
74 llmd_add_md(mdb, ll_get_md_null());
75 }
76
77 void
llmd_add_i1(LLMD_Builder mdb,int value)78 llmd_add_i1(LLMD_Builder mdb, int value)
79 {
80 llmd_add_md(mdb, ll_get_md_i1(value));
81 }
82
83 void
llmd_add_i32(LLMD_Builder mdb,int value)84 llmd_add_i32(LLMD_Builder mdb, int value)
85 {
86 llmd_add_md(mdb, ll_get_md_i32(mdb->module, value));
87 }
88
89 void
llmd_add_i64(LLMD_Builder mdb,long long value)90 llmd_add_i64(LLMD_Builder mdb, long long value)
91 {
92 llmd_add_md(mdb, ll_get_md_i64(mdb->module, value));
93 }
94
95 void
llmd_add_i64_lsb_msb(LLMD_Builder mdb,unsigned lsb,unsigned msb)96 llmd_add_i64_lsb_msb(LLMD_Builder mdb, unsigned lsb, unsigned msb)
97 {
98 long long value = msb;
99 value <<= 32;
100 value |= lsb;
101 llmd_add_i64(mdb, value);
102 }
103
104 void
llmd_add_INT64(LLMD_Builder mdb,DBLINT64 value)105 llmd_add_INT64(LLMD_Builder mdb, DBLINT64 value)
106 {
107 /* DBLINT64 is big-endian (msb, lsb). */
108 llmd_add_i64_lsb_msb(mdb, value[1], value[0]);
109 }
110
111 void
llmd_add_string(LLMD_Builder mdb,const char * value)112 llmd_add_string(LLMD_Builder mdb, const char *value)
113 {
114 llmd_add_md(mdb, value ? ll_get_md_string(mdb->module, value)
115 : LL_MDREF_ctor(0, 0));
116 }
117
118 void
llmd_add_value(LLMD_Builder mdb,LL_Value * value)119 llmd_add_value(LLMD_Builder mdb, LL_Value *value)
120 {
121 llmd_add_md(mdb, ll_get_md_value(mdb->module, value));
122 }
123
124 void
llmd_reverse(LLMD_Builder mdb)125 llmd_reverse(LLMD_Builder mdb)
126 {
127 unsigned i, j;
128 LL_MDRef *e = mdb->elems;
129
130 if (mdb->nelems <= 1)
131 return;
132
133 for (i = 0, j = mdb->nelems - 1; i < j; i++, j--) {
134 LL_MDRef t = e[i];
135 e[i] = e[j];
136 e[j] = t;
137 }
138 }
139
140 unsigned
llmd_get_nelems(LLMD_Builder mdb)141 llmd_get_nelems(LLMD_Builder mdb)
142 {
143 return mdb->nelems;
144 }
145
146 void
llmd_set_distinct(LLMD_Builder mdb)147 llmd_set_distinct(LLMD_Builder mdb)
148 {
149 mdb->is_distinct = true;
150 }
151
152 void
llmd_set_class(LLMD_Builder mdb,enum LL_MDClass mdclass)153 llmd_set_class(LLMD_Builder mdb, enum LL_MDClass mdclass)
154 {
155 mdb->mdclass = mdclass;
156 }
157
158 LL_MDRef
ll_finish_variable(LLMD_Builder mdb,LL_MDRef fwd)159 ll_finish_variable(LLMD_Builder mdb, LL_MDRef fwd)
160 {
161 LL_MDRef mdref;
162 LLVMModuleRef mod = mdb->module;
163 const unsigned mdnodeTop = mod->mdnodes_count;
164
165 /* create the LL_MDRef */
166 if (mdb->is_distinct)
167 mdref =
168 ll_create_distinct_md_node(mod, mdb->mdclass, mdb->elems, mdb->nelems);
169 else
170 mdref = ll_get_md_node(mod, mdb->mdclass, mdb->elems, mdb->nelems);
171
172 /* and move it as needed */
173 if (!LL_MDREF_IS_NULL(fwd)) {
174 hash_data_t data;
175 const unsigned slot = LL_MDREF_value(fwd);
176 const unsigned mdrefSlot = LL_MDREF_value(mdref) - 1;
177 LL_MDNode *newNode = mod->mdnodes[mdrefSlot];
178 ll_set_md_node(mod, slot, newNode);
179 if (mod->mdnodes_count == mdnodeTop + 1)
180 --mod->mdnodes_count;
181 mdref = fwd;
182 data = (hash_data_t)INT2HKEY(slot);
183 hashmap_replace(mod->mdnodes_map, newNode, &data);
184 }
185
186 if (mdb->elems != mdb->init_elems)
187 free(mdb->elems);
188 free(mdb);
189
190 return mdref;
191 }
192
193 LL_MDRef
llmd_finish(LLMD_Builder mdb)194 llmd_finish(LLMD_Builder mdb)
195 {
196 LL_MDRef mdref;
197
198 if (mdb->is_distinct)
199 mdref = ll_create_distinct_md_node(mdb->module, mdb->mdclass, mdb->elems,
200 mdb->nelems);
201 else
202 mdref = ll_get_md_node(mdb->module, mdb->mdclass, mdb->elems, mdb->nelems);
203
204 if (mdb->elems != mdb->init_elems)
205 free(mdb->elems);
206 free(mdb);
207
208 return mdref;
209 }
210