1 | //===- Wasm.h - Wasm object file format -------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines manifest constants for the wasm object file format. |
10 | // See: https://github.com/WebAssembly/design/blob/main/BinaryEncoding.md |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_BINARYFORMAT_WASM_H |
15 | #define LLVM_BINARYFORMAT_WASM_H |
16 | |
17 | #include "llvm/ADT/ArrayRef.h" |
18 | #include "llvm/ADT/SmallVector.h" |
19 | #include "llvm/ADT/StringRef.h" |
20 | #include <optional> |
21 | |
22 | namespace llvm { |
23 | namespace wasm { |
24 | |
25 | // Object file magic string. |
26 | const char WasmMagic[] = {'\0', 'a', 's', 'm'}; |
27 | // Wasm binary format version |
28 | const uint32_t WasmVersion = 0x1; |
29 | // Wasm linking metadata version |
30 | const uint32_t WasmMetadataVersion = 0x2; |
31 | // Wasm uses a 64k page size |
32 | const uint32_t WasmPageSize = 65536; |
33 | |
34 | enum : unsigned { |
35 | WASM_SEC_CUSTOM = 0, // Custom / User-defined section |
36 | WASM_SEC_TYPE = 1, // Function signature declarations |
37 | WASM_SEC_IMPORT = 2, // Import declarations |
38 | WASM_SEC_FUNCTION = 3, // Function declarations |
39 | WASM_SEC_TABLE = 4, // Indirect function table and other tables |
40 | WASM_SEC_MEMORY = 5, // Memory attributes |
41 | WASM_SEC_GLOBAL = 6, // Global declarations |
42 | WASM_SEC_EXPORT = 7, // Exports |
43 | WASM_SEC_START = 8, // Start function declaration |
44 | WASM_SEC_ELEM = 9, // Elements section |
45 | WASM_SEC_CODE = 10, // Function bodies (code) |
46 | WASM_SEC_DATA = 11, // Data segments |
47 | WASM_SEC_DATACOUNT = 12, // Data segment count |
48 | WASM_SEC_TAG = 13, // Tag declarations |
49 | WASM_SEC_LAST_KNOWN = WASM_SEC_TAG, |
50 | }; |
51 | |
52 | // Type immediate encodings used in various contexts. |
53 | enum : unsigned { |
54 | WASM_TYPE_I32 = 0x7F, |
55 | WASM_TYPE_I64 = 0x7E, |
56 | WASM_TYPE_F32 = 0x7D, |
57 | WASM_TYPE_F64 = 0x7C, |
58 | WASM_TYPE_V128 = 0x7B, |
59 | WASM_TYPE_NULLFUNCREF = 0x73, |
60 | WASM_TYPE_NULLEXTERNREF = 0x72, |
61 | WASM_TYPE_NULLREF = 0x71, |
62 | WASM_TYPE_FUNCREF = 0x70, |
63 | WASM_TYPE_EXTERNREF = 0x6F, |
64 | WASM_TYPE_ANYREF = 0x6E, |
65 | WASM_TYPE_EQREF = 0x6D, |
66 | WASM_TYPE_I31REF = 0x6C, |
67 | WASM_TYPE_STRUCTREF = 0x6B, |
68 | WASM_TYPE_ARRAYREF = 0x6A, |
69 | WASM_TYPE_EXNREF = 0x69, |
70 | WASM_TYPE_NONNULLABLE = 0x64, |
71 | WASM_TYPE_NULLABLE = 0x63, |
72 | WASM_TYPE_FUNC = 0x60, |
73 | WASM_TYPE_ARRAY = 0x5E, |
74 | WASM_TYPE_STRUCT = 0x5F, |
75 | WASM_TYPE_SUB = 0x50, |
76 | WASM_TYPE_SUB_FINAL = 0x4F, |
77 | WASM_TYPE_REC = 0x4E, |
78 | WASM_TYPE_NORESULT = 0x40, // for blocks with no result values |
79 | }; |
80 | |
81 | // Kinds of externals (for imports and exports). |
82 | enum : unsigned { |
83 | WASM_EXTERNAL_FUNCTION = 0x0, |
84 | WASM_EXTERNAL_TABLE = 0x1, |
85 | WASM_EXTERNAL_MEMORY = 0x2, |
86 | WASM_EXTERNAL_GLOBAL = 0x3, |
87 | WASM_EXTERNAL_TAG = 0x4, |
88 | }; |
89 | |
90 | // Opcodes used in initializer expressions. |
91 | enum : unsigned { |
92 | WASM_OPCODE_END = 0x0b, |
93 | WASM_OPCODE_CALL = 0x10, |
94 | WASM_OPCODE_LOCAL_GET = 0x20, |
95 | WASM_OPCODE_LOCAL_SET = 0x21, |
96 | WASM_OPCODE_LOCAL_TEE = 0x22, |
97 | WASM_OPCODE_GLOBAL_GET = 0x23, |
98 | WASM_OPCODE_GLOBAL_SET = 0x24, |
99 | WASM_OPCODE_I32_STORE = 0x36, |
100 | WASM_OPCODE_I64_STORE = 0x37, |
101 | WASM_OPCODE_I32_CONST = 0x41, |
102 | WASM_OPCODE_I64_CONST = 0x42, |
103 | WASM_OPCODE_F32_CONST = 0x43, |
104 | WASM_OPCODE_F64_CONST = 0x44, |
105 | WASM_OPCODE_I32_ADD = 0x6a, |
106 | WASM_OPCODE_I32_SUB = 0x6b, |
107 | WASM_OPCODE_I32_MUL = 0x6c, |
108 | WASM_OPCODE_I64_ADD = 0x7c, |
109 | WASM_OPCODE_I64_SUB = 0x7d, |
110 | WASM_OPCODE_I64_MUL = 0x7e, |
111 | WASM_OPCODE_REF_NULL = 0xd0, |
112 | WASM_OPCODE_REF_FUNC = 0xd2, |
113 | WASM_OPCODE_GC_PREFIX = 0xfb, |
114 | }; |
115 | |
116 | // Opcodes in the GC-prefixed space (0xfb) |
117 | enum : unsigned { |
118 | WASM_OPCODE_STRUCT_NEW = 0x00, |
119 | WASM_OPCODE_STRUCT_NEW_DEFAULT = 0x01, |
120 | WASM_OPCODE_ARRAY_NEW = 0x06, |
121 | WASM_OPCODE_ARRAY_NEW_DEFAULT = 0x07, |
122 | WASM_OPCODE_ARRAY_NEW_FIXED = 0x08, |
123 | WASM_OPCODE_REF_I31 = 0x1c, |
124 | // any.convert_extern and extern.convert_any don't seem to be supported by |
125 | // Binaryen. |
126 | }; |
127 | |
128 | // Opcodes used in synthetic functions. |
129 | enum : unsigned { |
130 | WASM_OPCODE_BLOCK = 0x02, |
131 | WASM_OPCODE_BR = 0x0c, |
132 | WASM_OPCODE_BR_TABLE = 0x0e, |
133 | WASM_OPCODE_RETURN = 0x0f, |
134 | WASM_OPCODE_DROP = 0x1a, |
135 | WASM_OPCODE_MISC_PREFIX = 0xfc, |
136 | WASM_OPCODE_MEMORY_INIT = 0x08, |
137 | WASM_OPCODE_MEMORY_FILL = 0x0b, |
138 | WASM_OPCODE_DATA_DROP = 0x09, |
139 | WASM_OPCODE_ATOMICS_PREFIX = 0xfe, |
140 | WASM_OPCODE_ATOMIC_NOTIFY = 0x00, |
141 | WASM_OPCODE_I32_ATOMIC_WAIT = 0x01, |
142 | WASM_OPCODE_I32_ATOMIC_STORE = 0x17, |
143 | WASM_OPCODE_I32_RMW_CMPXCHG = 0x48, |
144 | }; |
145 | |
146 | enum : unsigned { |
147 | WASM_LIMITS_FLAG_NONE = 0x0, |
148 | WASM_LIMITS_FLAG_HAS_MAX = 0x1, |
149 | WASM_LIMITS_FLAG_IS_SHARED = 0x2, |
150 | WASM_LIMITS_FLAG_IS_64 = 0x4, |
151 | }; |
152 | |
153 | enum : unsigned { |
154 | WASM_DATA_SEGMENT_IS_PASSIVE = 0x01, |
155 | WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02, |
156 | }; |
157 | |
158 | enum : unsigned { |
159 | WASM_ELEM_SEGMENT_IS_PASSIVE = 0x01, |
160 | WASM_ELEM_SEGMENT_IS_DECLARATIVE = 0x02, // if passive == 1 |
161 | WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER = 0x02, // if passive == 0 |
162 | WASM_ELEM_SEGMENT_HAS_INIT_EXPRS = 0x04, |
163 | }; |
164 | const unsigned WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND = 0x3; |
165 | |
166 | // Feature policy prefixes used in the custom "target_features" section |
167 | enum : uint8_t { |
168 | WASM_FEATURE_PREFIX_USED = '+', |
169 | WASM_FEATURE_PREFIX_REQUIRED = '=', |
170 | WASM_FEATURE_PREFIX_DISALLOWED = '-', |
171 | }; |
172 | |
173 | // Kind codes used in the custom "name" section |
174 | enum : unsigned { |
175 | WASM_NAMES_MODULE = 0, |
176 | WASM_NAMES_FUNCTION = 1, |
177 | WASM_NAMES_LOCAL = 2, |
178 | WASM_NAMES_GLOBAL = 7, |
179 | WASM_NAMES_DATA_SEGMENT = 9, |
180 | }; |
181 | |
182 | // Kind codes used in the custom "linking" section |
183 | enum : unsigned { |
184 | WASM_SEGMENT_INFO = 0x5, |
185 | WASM_INIT_FUNCS = 0x6, |
186 | WASM_COMDAT_INFO = 0x7, |
187 | WASM_SYMBOL_TABLE = 0x8, |
188 | }; |
189 | |
190 | // Kind codes used in the custom "dylink" section |
191 | enum : unsigned { |
192 | WASM_DYLINK_MEM_INFO = 0x1, |
193 | WASM_DYLINK_NEEDED = 0x2, |
194 | WASM_DYLINK_EXPORT_INFO = 0x3, |
195 | WASM_DYLINK_IMPORT_INFO = 0x4, |
196 | }; |
197 | |
198 | // Kind codes used in the custom "linking" section in the WASM_COMDAT_INFO |
199 | enum : unsigned { |
200 | WASM_COMDAT_DATA = 0x0, |
201 | WASM_COMDAT_FUNCTION = 0x1, |
202 | // GLOBAL, TAG, and TABLE are in here but LLVM doesn't use them yet. |
203 | WASM_COMDAT_SECTION = 0x5, |
204 | }; |
205 | |
206 | // Kind codes used in the custom "linking" section in the WASM_SYMBOL_TABLE |
207 | enum WasmSymbolType : unsigned { |
208 | WASM_SYMBOL_TYPE_FUNCTION = 0x0, |
209 | WASM_SYMBOL_TYPE_DATA = 0x1, |
210 | WASM_SYMBOL_TYPE_GLOBAL = 0x2, |
211 | WASM_SYMBOL_TYPE_SECTION = 0x3, |
212 | WASM_SYMBOL_TYPE_TAG = 0x4, |
213 | WASM_SYMBOL_TYPE_TABLE = 0x5, |
214 | }; |
215 | |
216 | enum WasmSegmentFlag : unsigned { |
217 | WASM_SEG_FLAG_STRINGS = 0x1, |
218 | WASM_SEG_FLAG_TLS = 0x2, |
219 | }; |
220 | |
221 | // Kinds of tag attributes. |
222 | enum WasmTagAttribute : uint8_t { |
223 | WASM_TAG_ATTRIBUTE_EXCEPTION = 0x0, |
224 | }; |
225 | |
226 | const unsigned WASM_SYMBOL_BINDING_MASK = 0x3; |
227 | const unsigned WASM_SYMBOL_VISIBILITY_MASK = 0xc; |
228 | |
229 | const unsigned WASM_SYMBOL_BINDING_GLOBAL = 0x0; |
230 | const unsigned WASM_SYMBOL_BINDING_WEAK = 0x1; |
231 | const unsigned WASM_SYMBOL_BINDING_LOCAL = 0x2; |
232 | const unsigned WASM_SYMBOL_VISIBILITY_DEFAULT = 0x0; |
233 | const unsigned WASM_SYMBOL_VISIBILITY_HIDDEN = 0x4; |
234 | const unsigned WASM_SYMBOL_UNDEFINED = 0x10; |
235 | const unsigned WASM_SYMBOL_EXPORTED = 0x20; |
236 | const unsigned WASM_SYMBOL_EXPLICIT_NAME = 0x40; |
237 | const unsigned WASM_SYMBOL_NO_STRIP = 0x80; |
238 | const unsigned WASM_SYMBOL_TLS = 0x100; |
239 | const unsigned WASM_SYMBOL_ABSOLUTE = 0x200; |
240 | |
241 | #define WASM_RELOC(name, value) name = value, |
242 | |
243 | enum : unsigned { |
244 | #include "WasmRelocs.def" |
245 | }; |
246 | |
247 | #undef WASM_RELOC |
248 | |
249 | struct { |
250 | StringRef ; |
251 | uint32_t ; |
252 | }; |
253 | |
254 | // Subset of types that a value can have |
255 | enum class ValType { |
256 | I32 = WASM_TYPE_I32, |
257 | I64 = WASM_TYPE_I64, |
258 | F32 = WASM_TYPE_F32, |
259 | F64 = WASM_TYPE_F64, |
260 | V128 = WASM_TYPE_V128, |
261 | FUNCREF = WASM_TYPE_FUNCREF, |
262 | EXTERNREF = WASM_TYPE_EXTERNREF, |
263 | // Unmodeled value types include ref types with heap types other than |
264 | // func or extern, and type-specialized funcrefs |
265 | OTHERREF = 0xff, |
266 | }; |
267 | |
268 | struct WasmDylinkImportInfo { |
269 | StringRef Module; |
270 | StringRef Field; |
271 | uint32_t Flags; |
272 | }; |
273 | |
274 | struct WasmDylinkExportInfo { |
275 | StringRef Name; |
276 | uint32_t Flags; |
277 | }; |
278 | |
279 | struct WasmDylinkInfo { |
280 | uint32_t MemorySize; // Memory size in bytes |
281 | uint32_t MemoryAlignment; // P2 alignment of memory |
282 | uint32_t TableSize; // Table size in elements |
283 | uint32_t TableAlignment; // P2 alignment of table |
284 | std::vector<StringRef> Needed; // Shared library dependencies |
285 | std::vector<WasmDylinkImportInfo> ImportInfo; |
286 | std::vector<WasmDylinkExportInfo> ExportInfo; |
287 | }; |
288 | |
289 | struct WasmProducerInfo { |
290 | std::vector<std::pair<std::string, std::string>> Languages; |
291 | std::vector<std::pair<std::string, std::string>> Tools; |
292 | std::vector<std::pair<std::string, std::string>> SDKs; |
293 | }; |
294 | |
295 | struct WasmFeatureEntry { |
296 | uint8_t Prefix; |
297 | std::string Name; |
298 | }; |
299 | |
300 | struct WasmExport { |
301 | StringRef Name; |
302 | uint8_t Kind; |
303 | uint32_t Index; |
304 | }; |
305 | |
306 | struct WasmLimits { |
307 | uint8_t Flags; |
308 | uint64_t Minimum; |
309 | uint64_t Maximum; |
310 | }; |
311 | |
312 | struct WasmTableType { |
313 | ValType ElemType; |
314 | WasmLimits Limits; |
315 | }; |
316 | |
317 | struct WasmTable { |
318 | uint32_t Index; |
319 | WasmTableType Type; |
320 | StringRef SymbolName; // from the "linking" section |
321 | }; |
322 | |
323 | struct WasmInitExprMVP { |
324 | uint8_t Opcode; |
325 | union { |
326 | int32_t Int32; |
327 | int64_t Int64; |
328 | uint32_t Float32; |
329 | uint64_t Float64; |
330 | uint32_t Global; |
331 | } Value; |
332 | }; |
333 | |
334 | // Extended-const init exprs and exprs with GC types are not explicitly |
335 | // modeled, but the raw body of the expr is attached. |
336 | struct WasmInitExpr { |
337 | uint8_t Extended; // Set to non-zero if extended const is used (i.e. more than |
338 | // one instruction) |
339 | WasmInitExprMVP Inst; |
340 | ArrayRef<uint8_t> Body; |
341 | }; |
342 | |
343 | struct WasmGlobalType { |
344 | uint8_t Type; // TODO: make this a ValType? |
345 | bool Mutable; |
346 | }; |
347 | |
348 | struct WasmGlobal { |
349 | uint32_t Index; |
350 | WasmGlobalType Type; |
351 | WasmInitExpr InitExpr; |
352 | StringRef SymbolName; // from the "linking" section |
353 | }; |
354 | |
355 | struct WasmTag { |
356 | uint32_t Index; |
357 | uint32_t SigIndex; |
358 | StringRef SymbolName; // from the "linking" section |
359 | }; |
360 | |
361 | struct WasmImport { |
362 | StringRef Module; |
363 | StringRef Field; |
364 | uint8_t Kind; |
365 | union { |
366 | uint32_t SigIndex; |
367 | WasmGlobalType Global; |
368 | WasmTableType Table; |
369 | WasmLimits Memory; |
370 | }; |
371 | }; |
372 | |
373 | struct WasmLocalDecl { |
374 | uint8_t Type; |
375 | uint32_t Count; |
376 | }; |
377 | |
378 | struct WasmFunction { |
379 | uint32_t Index; |
380 | uint32_t SigIndex; |
381 | std::vector<WasmLocalDecl> Locals; |
382 | ArrayRef<uint8_t> Body; |
383 | uint32_t CodeSectionOffset; |
384 | uint32_t Size; |
385 | uint32_t CodeOffset; // start of Locals and Body |
386 | std::optional<StringRef> ExportName; // from the "export" section |
387 | StringRef SymbolName; // from the "linking" section |
388 | StringRef DebugName; // from the "name" section |
389 | uint32_t Comdat; // from the "comdat info" section |
390 | }; |
391 | |
392 | struct WasmDataSegment { |
393 | uint32_t InitFlags; |
394 | // Present if InitFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX. |
395 | uint32_t MemoryIndex; |
396 | // Present if InitFlags & WASM_DATA_SEGMENT_IS_PASSIVE == 0. |
397 | WasmInitExpr Offset; |
398 | |
399 | ArrayRef<uint8_t> Content; |
400 | StringRef Name; // from the "segment info" section |
401 | uint32_t Alignment; |
402 | uint32_t LinkingFlags; |
403 | uint32_t Comdat; // from the "comdat info" section |
404 | }; |
405 | |
406 | // Represents a Wasm element segment, with some limitations compared the spec: |
407 | // 1) Does not model passive or declarative segments (Segment will end up with |
408 | // an Offset field of i32.const 0) |
409 | // 2) Does not model init exprs (Segment will get an empty Functions list) |
410 | // 2) Does not model types other than basic funcref/externref (see ValType) |
411 | struct WasmElemSegment { |
412 | uint32_t Flags; |
413 | uint32_t TableNumber; |
414 | ValType ElemKind; |
415 | WasmInitExpr Offset; |
416 | std::vector<uint32_t> Functions; |
417 | }; |
418 | |
419 | // Represents the location of a Wasm data symbol within a WasmDataSegment, as |
420 | // the index of the segment, and the offset and size within the segment. |
421 | struct WasmDataReference { |
422 | uint32_t Segment; |
423 | uint64_t Offset; |
424 | uint64_t Size; |
425 | }; |
426 | |
427 | struct WasmRelocation { |
428 | uint8_t Type; // The type of the relocation. |
429 | uint32_t Index; // Index into either symbol or type index space. |
430 | uint64_t Offset; // Offset from the start of the section. |
431 | int64_t Addend; // A value to add to the symbol. |
432 | }; |
433 | |
434 | struct WasmInitFunc { |
435 | uint32_t Priority; |
436 | uint32_t Symbol; |
437 | }; |
438 | |
439 | struct WasmSymbolInfo { |
440 | StringRef Name; |
441 | uint8_t Kind; |
442 | uint32_t Flags; |
443 | // For undefined symbols the module of the import |
444 | std::optional<StringRef> ImportModule; |
445 | // For undefined symbols the name of the import |
446 | std::optional<StringRef> ImportName; |
447 | // For symbols to be exported from the final module |
448 | std::optional<StringRef> ExportName; |
449 | union { |
450 | // For function, table, or global symbols, the index in function, table, or |
451 | // global index space. |
452 | uint32_t ElementIndex; |
453 | // For a data symbols, the address of the data relative to segment. |
454 | WasmDataReference DataRef; |
455 | }; |
456 | }; |
457 | |
458 | enum class NameType { |
459 | FUNCTION, |
460 | GLOBAL, |
461 | DATA_SEGMENT, |
462 | }; |
463 | |
464 | struct WasmDebugName { |
465 | NameType Type; |
466 | uint32_t Index; |
467 | StringRef Name; |
468 | }; |
469 | |
470 | // Info from the linking metadata section of a wasm object file. |
471 | struct WasmLinkingData { |
472 | uint32_t Version; |
473 | std::vector<WasmInitFunc> InitFunctions; |
474 | std::vector<StringRef> Comdats; |
475 | // The linking section also contains a symbol table. This info (represented |
476 | // in a WasmSymbolInfo struct) is stored inside the WasmSymbol object instead |
477 | // of in this structure; this allows vectors of WasmSymbols and |
478 | // WasmLinkingDatas to be reallocated. |
479 | }; |
480 | |
481 | struct WasmSignature { |
482 | SmallVector<ValType, 1> Returns; |
483 | SmallVector<ValType, 4> Params; |
484 | // LLVM can parse types other than functions encoded in the type section, |
485 | // but does not actually model them. Instead a placeholder signature is |
486 | // created in the Object's signature list. |
487 | enum { Function, Tag, Placeholder } Kind = Function; |
488 | // Support empty and tombstone instances, needed by DenseMap. |
489 | enum { Plain, Empty, Tombstone } State = Plain; |
490 | |
491 | WasmSignature(SmallVector<ValType, 1> &&InReturns, |
492 | SmallVector<ValType, 4> &&InParams) |
493 | : Returns(InReturns), Params(InParams) {} |
494 | WasmSignature() = default; |
495 | }; |
496 | |
497 | // Useful comparison operators |
498 | inline bool operator==(const WasmSignature &LHS, const WasmSignature &RHS) { |
499 | return LHS.State == RHS.State && LHS.Returns == RHS.Returns && |
500 | LHS.Params == RHS.Params; |
501 | } |
502 | |
503 | inline bool operator!=(const WasmSignature &LHS, const WasmSignature &RHS) { |
504 | return !(LHS == RHS); |
505 | } |
506 | |
507 | inline bool operator==(const WasmGlobalType &LHS, const WasmGlobalType &RHS) { |
508 | return LHS.Type == RHS.Type && LHS.Mutable == RHS.Mutable; |
509 | } |
510 | |
511 | inline bool operator!=(const WasmGlobalType &LHS, const WasmGlobalType &RHS) { |
512 | return !(LHS == RHS); |
513 | } |
514 | |
515 | inline bool operator==(const WasmLimits &LHS, const WasmLimits &RHS) { |
516 | return LHS.Flags == RHS.Flags && LHS.Minimum == RHS.Minimum && |
517 | (LHS.Flags & WASM_LIMITS_FLAG_HAS_MAX ? LHS.Maximum == RHS.Maximum |
518 | : true); |
519 | } |
520 | |
521 | inline bool operator==(const WasmTableType &LHS, const WasmTableType &RHS) { |
522 | return LHS.ElemType == RHS.ElemType && LHS.Limits == RHS.Limits; |
523 | } |
524 | |
525 | llvm::StringRef toString(WasmSymbolType type); |
526 | llvm::StringRef relocTypetoString(uint32_t type); |
527 | llvm::StringRef sectionTypeToString(uint32_t type); |
528 | bool relocTypeHasAddend(uint32_t type); |
529 | |
530 | } // end namespace wasm |
531 | } // end namespace llvm |
532 | |
533 | #endif |
534 | |