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