blob: bb1a50a467540d7b2d14932503d68ab8a67fb933 [file] [log] [blame]
Amaury Sechete8ea7d82016-02-04 23:26:19 +00001//===-- echo.cpp - tool for testing libLLVM and llvm-c API ----------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the --echo commands in llvm-c-test.
11//
12// This command uses the C API to read a module and output an exact copy of it
13// as output. It is used to check that the resulting module matches the input
14// to validate that the C API can read and write modules properly.
15//
16//===----------------------------------------------------------------------===//
17
18#include "llvm-c-test.h"
19#include "llvm/ADT/DenseMap.h"
20
21#include <stdio.h>
22#include <stdlib.h>
23
24using namespace llvm;
25
26// Provide DenseMapInfo for C API opaque types.
27template<typename T>
28struct CAPIDenseMap {};
29
30// The default DenseMapInfo require to know about pointer alignement.
31// Because the C API uses opaques pointer types, their alignement is unknown.
32// As a result, we need to roll out our own implementation.
33template<typename T>
34struct CAPIDenseMap<T*> {
35 struct CAPIDenseMapInfo {
36 static inline T* getEmptyKey() {
37 uintptr_t Val = static_cast<uintptr_t>(-1);
38 return reinterpret_cast<T*>(Val);
39 }
40 static inline T* getTombstoneKey() {
41 uintptr_t Val = static_cast<uintptr_t>(-2);
42 return reinterpret_cast<T*>(Val);
43 }
44 static unsigned getHashValue(const T *PtrVal) {
45 return hash_value(PtrVal);
46 }
47 static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
48 };
49
50 typedef DenseMap<T*, T*, CAPIDenseMapInfo> Map;
51};
52
53typedef CAPIDenseMap<LLVMValueRef>::Map ValueMap;
54
55static LLVMTypeRef clone_type(LLVMTypeRef Src, LLVMContextRef Ctx) {
56 LLVMTypeKind Kind = LLVMGetTypeKind(Src);
57 switch (Kind) {
58 case LLVMVoidTypeKind:
59 return LLVMVoidTypeInContext(Ctx);
60 case LLVMHalfTypeKind:
61 return LLVMHalfTypeInContext(Ctx);
62 case LLVMFloatTypeKind:
63 return LLVMFloatTypeInContext(Ctx);
64 case LLVMDoubleTypeKind:
65 return LLVMDoubleTypeInContext(Ctx);
66 case LLVMX86_FP80TypeKind:
67 return LLVMX86FP80TypeInContext(Ctx);
68 case LLVMFP128TypeKind:
69 return LLVMFP128TypeInContext(Ctx);
70 case LLVMPPC_FP128TypeKind:
71 return LLVMPPCFP128TypeInContext(Ctx);
72 case LLVMLabelTypeKind:
73 return LLVMLabelTypeInContext(Ctx);
74 case LLVMIntegerTypeKind:
75 return LLVMIntTypeInContext(Ctx, LLVMGetIntTypeWidth(Src));
76 case LLVMFunctionTypeKind: {
77 unsigned ParamCount = LLVMCountParamTypes(Src);
78 LLVMTypeRef* Params = nullptr;
79 if (ParamCount > 0) {
80 Params = (LLVMTypeRef*) malloc(ParamCount * sizeof(LLVMTypeRef));
81 LLVMGetParamTypes(Src, Params);
82 for (unsigned i = 0; i < ParamCount; i++) {
83 Params[i] = clone_type(Params[i], Ctx);
84 }
85 }
86
87 LLVMTypeRef FunTy = LLVMFunctionType(
88 clone_type(LLVMGetReturnType(Src), Ctx),
89 Params, ParamCount,
90 LLVMIsFunctionVarArg(Src)
91 );
92
93 if (ParamCount > 0)
94 free(Params);
95
96 return FunTy;
97 }
98 case LLVMStructTypeKind:
99 break;
100 case LLVMArrayTypeKind:
101 return LLVMArrayType(
102 clone_type(LLVMGetElementType(Src), Ctx),
103 LLVMGetArrayLength(Src)
104 );
105 case LLVMPointerTypeKind:
106 return LLVMPointerType(
107 clone_type(LLVMGetElementType(Src), Ctx),
108 LLVMGetPointerAddressSpace(Src)
109 );
110 case LLVMVectorTypeKind:
111 return LLVMVectorType(
112 clone_type(LLVMGetElementType(Src), Ctx),
113 LLVMGetVectorSize(Src)
114 );
115 case LLVMMetadataTypeKind:
116 break;
117 case LLVMX86_MMXTypeKind:
118 return LLVMX86MMXTypeInContext(Ctx);
119 default:
120 break;
121 }
122
123 fprintf(stderr, "%d is not a supported typekind\n", Kind);
124 exit(-1);
125}
126
127static LLVMValueRef clone_literal(LLVMValueRef Src, LLVMContextRef Ctx) {
128 LLVMTypeRef Ty = clone_type(LLVMTypeOf(Src), Ctx);
129
130 LLVMTypeKind Kind = LLVMGetTypeKind(Ty);
131 switch (Kind) {
132 case LLVMIntegerTypeKind:
133 return LLVMConstInt(Ty, LLVMConstIntGetZExtValue(Src), false);
134 default:
135 break;
136 }
137
138 fprintf(stderr, "%d is not a supported constant typekind\n", Kind);
139 exit(-1);
140}
141
142static LLVMModuleRef get_module(LLVMBuilderRef Builder) {
143 LLVMBasicBlockRef BB = LLVMGetInsertBlock(Builder);
144 LLVMValueRef Fn = LLVMGetBasicBlockParent(BB);
145 return LLVMGetGlobalParent(Fn);
146}
147
148// Try to clone everything in the llvm::Value hierarchy.
149static LLVMValueRef clone_value(LLVMValueRef Src, LLVMBuilderRef Builder, ValueMap &VMap) {
150 const char *Name = LLVMGetValueName(Src);
151
152 // First, the value may be constant.
153 if (LLVMIsAConstant(Src)) {
154 LLVMModuleRef M = get_module(Builder);
155
156 // Maybe it is a symbol
157 if (LLVMIsAGlobalValue(Src)) {
158 // Try function
159 LLVMValueRef Dst = LLVMGetNamedFunction(M, Name);
160 if (Dst != nullptr)
161 return Dst;
162
163 // Try global variable
164 Dst = LLVMGetNamedGlobal(M, Name);
165 if (Dst != nullptr)
166 return Dst;
167
168 fprintf(stderr, "Could not find @%s\n", Name);
169 exit(-1);
170 }
171
172 // Try literal
173 LLVMContextRef Ctx = LLVMGetModuleContext(M);
174 return clone_literal(Src, Ctx);
175 }
176
177 // Try undef
178 if (LLVMIsUndef(Src)) {
179 LLVMContextRef Ctx = LLVMGetModuleContext(get_module(Builder));
180 LLVMTypeRef Ty = clone_type(LLVMTypeOf(Src), Ctx);
181 return LLVMGetUndef(Ty);
182 }
183
184 // Check if this is something we already computed.
185 {
186 auto i = VMap.find(Src);
187 if (i != VMap.end())
188 return i->second;
189 }
190
191 // We tried everything, it must be an instruction
192 // that hasn't been generated already.
193 LLVMValueRef Dst = nullptr;
194
195 LLVMOpcode Op = LLVMGetInstructionOpcode(Src);
196 switch(Op) {
197 case LLVMRet: {
198 int OpCount = LLVMGetNumOperands(Src);
199 if (OpCount == 0)
200 Dst = LLVMBuildRetVoid(Builder);
201 else
202 Dst = LLVMBuildRet(Builder, clone_value(LLVMGetOperand(Src, 0),
203 Builder, VMap));
204 break;
205 }
206 case LLVMBr:
207 case LLVMSwitch:
208 case LLVMIndirectBr:
209 case LLVMInvoke:
210 case LLVMUnreachable:
211 break;
212 case LLVMAdd: {
213 LLVMValueRef LHS = clone_value(LLVMGetOperand(Src, 0), Builder, VMap);
214 LLVMValueRef RHS = clone_value(LLVMGetOperand(Src, 1), Builder, VMap);
215 Dst = LLVMBuildAdd(Builder, LHS, RHS, Name);
216 break;
217 }
218 case LLVMAlloca: {
219 LLVMTypeRef Ty = LLVMGetElementType(LLVMTypeOf(Src));
220 Dst = LLVMBuildAlloca(Builder, Ty, Name);
221 break;
222 }
223 case LLVMCall: {
224 int ArgCount = LLVMGetNumOperands(Src) - 1;
225 SmallVector<LLVMValueRef, 8> Args;
226 for (int i = 0; i < ArgCount; i++)
227 Args.push_back(clone_value(LLVMGetOperand(Src, i), Builder, VMap));
228 LLVMValueRef Fn = clone_value(LLVMGetOperand(Src, ArgCount), Builder, VMap);
229 Dst = LLVMBuildCall(Builder, Fn, Args.data(), ArgCount, Name);
230 break;
231 }
232 default:
233 break;
234 }
235
236 if (Dst == nullptr) {
237 fprintf(stderr, "%d is not a supported opcode\n", Op);
238 exit(-1);
239 }
240
241 return VMap[Src] = Dst;
242}
243
244static LLVMBasicBlockRef clone_bb(LLVMBasicBlockRef Src, LLVMValueRef Dst, ValueMap &VMap) {
245 LLVMBasicBlockRef BB = LLVMAppendBasicBlock(Dst, "");
246
247 LLVMValueRef First = LLVMGetFirstInstruction(Src);
248 LLVMValueRef Last = LLVMGetLastInstruction(Src);
249
250 if (First == nullptr) {
251 if (Last != nullptr) {
252 fprintf(stderr, "Has no first instruction, but last one\n");
253 exit(-1);
254 }
255
256 return BB;
257 }
258
259 LLVMContextRef Ctx = LLVMGetModuleContext(LLVMGetGlobalParent(Dst));
260 LLVMBuilderRef Builder = LLVMCreateBuilderInContext(Ctx);
261 LLVMPositionBuilderAtEnd(Builder, BB);
262
263 LLVMValueRef Cur = First;
264 LLVMValueRef Next = nullptr;
265 while(true) {
266 clone_value(Cur, Builder, VMap);
267 Next = LLVMGetNextInstruction(Cur);
268 if (Next == nullptr) {
269 if (Cur != Last) {
270 fprintf(stderr, "Final instruction does not match Last\n");
271 exit(-1);
272 }
273
274 break;
275 }
276
277 LLVMValueRef Prev = LLVMGetPreviousInstruction(Next);
278 if (Prev != Cur) {
279 fprintf(stderr, "Next.Previous instruction is not Current\n");
280 exit(-1);
281 }
282
283 Cur = Next;
284 }
285
286 LLVMDisposeBuilder(Builder);
287 return BB;
288}
289
290static void clone_bbs(LLVMValueRef Src, LLVMValueRef Dst, ValueMap &VMap) {
291 unsigned Count = LLVMCountBasicBlocks(Src);
292 if (Count == 0)
293 return;
294
295 LLVMBasicBlockRef First = LLVMGetFirstBasicBlock(Src);
296 LLVMBasicBlockRef Last = LLVMGetLastBasicBlock(Src);
297
298 LLVMBasicBlockRef Cur = First;
299 LLVMBasicBlockRef Next = nullptr;
300 while(true) {
301 clone_bb(Cur, Dst, VMap);
302 Count--;
303 Next = LLVMGetNextBasicBlock(Cur);
304 if (Next == nullptr) {
305 if (Cur != Last) {
306 fprintf(stderr, "Final basic block does not match Last\n");
307 exit(-1);
308 }
309
310 break;
311 }
312
313 LLVMBasicBlockRef Prev = LLVMGetPreviousBasicBlock(Next);
314 if (Prev != Cur) {
315 fprintf(stderr, "Next.Previous basic bloc is not Current\n");
316 exit(-1);
317 }
318
319 Cur = Next;
320 }
321
322 if (Count != 0) {
323 fprintf(stderr, "Basic block count does not match iterration\n");
324 exit(-1);
325 }
326}
327
328static ValueMap clone_params(LLVMValueRef Src, LLVMValueRef Dst) {
329 unsigned Count = LLVMCountParams(Src);
330 if (Count != LLVMCountParams(Dst)) {
331 fprintf(stderr, "Parameter count mismatch\n");
332 exit(-1);
333 }
334
335 ValueMap VMap;
336 if (Count == 0)
337 return VMap;
338
339 LLVMValueRef SrcFirst = LLVMGetFirstParam(Src);
340 LLVMValueRef DstFirst = LLVMGetFirstParam(Dst);
341 LLVMValueRef SrcLast = LLVMGetLastParam(Src);
342 LLVMValueRef DstLast = LLVMGetLastParam(Dst);
343
344 LLVMValueRef SrcCur = SrcFirst;
345 LLVMValueRef DstCur = DstFirst;
346 LLVMValueRef SrcNext = nullptr;
347 LLVMValueRef DstNext = nullptr;
348 while (true) {
349 const char *Name = LLVMGetValueName(SrcCur);
350 LLVMSetValueName(DstCur, Name);
351
352 VMap[SrcCur] = DstCur;
353
354 Count--;
355 SrcNext = LLVMGetNextParam(SrcCur);
356 DstNext = LLVMGetNextParam(DstCur);
357 if (SrcNext == nullptr && DstNext == nullptr) {
358 if (SrcCur != SrcLast) {
359 fprintf(stderr, "SrcLast param does not match End\n");
360 exit(-1);
361 }
362
363 if (DstCur != DstLast) {
364 fprintf(stderr, "DstLast param does not match End\n");
365 exit(-1);
366 }
367
368 break;
369 }
370
371 if (SrcNext == nullptr) {
372 fprintf(stderr, "SrcNext was unexpectedly null\n");
373 exit(-1);
374 }
375
376 if (DstNext == nullptr) {
377 fprintf(stderr, "DstNext was unexpectedly null\n");
378 exit(-1);
379 }
380
381 LLVMValueRef SrcPrev = LLVMGetPreviousParam(SrcNext);
382 if (SrcPrev != SrcCur) {
383 fprintf(stderr, "SrcNext.Previous param is not Current\n");
384 exit(-1);
385 }
386
387 LLVMValueRef DstPrev = LLVMGetPreviousParam(DstNext);
388 if (DstPrev != DstCur) {
389 fprintf(stderr, "DstNext.Previous param is not Current\n");
390 exit(-1);
391 }
392
393 SrcCur = SrcNext;
394 DstCur = DstNext;
395 }
396
397 if (Count != 0) {
398 fprintf(stderr, "Parameter count does not match iteration\n");
399 exit(-1);
400 }
401
402 return VMap;
403}
404
405static LLVMValueRef clone_function(LLVMValueRef Src, LLVMModuleRef Dst) {
406 const char *Name = LLVMGetValueName(Src);
407 LLVMValueRef Fun = LLVMGetNamedFunction(Dst, Name);
408 if (Fun != nullptr)
409 return Fun;
410
411 LLVMTypeRef SrcTy = LLVMTypeOf(Src);
412 LLVMTypeRef DstTy = clone_type(SrcTy, LLVMGetModuleContext(Dst));
413 LLVMTypeRef FunTy = LLVMGetElementType(DstTy);
414
415 Fun = LLVMAddFunction(Dst, Name, FunTy);
416
417 ValueMap VMap = clone_params(Src, Fun);
418 clone_bbs(Src, Fun, VMap);
419
420 return Fun;
421}
422
423static void clone_functions(LLVMModuleRef Src, LLVMModuleRef Dst) {
424 LLVMValueRef Begin = LLVMGetFirstFunction(Src);
425 LLVMValueRef End = LLVMGetLastFunction(Src);
426
427 LLVMValueRef Cur = Begin;
428 LLVMValueRef Next = nullptr;
429 while (true) {
430 clone_function(Cur, Dst);
431 Next = LLVMGetNextFunction(Cur);
432 if (Next == nullptr) {
433 if (Cur != End) {
434 fprintf(stderr, "Last function does not match End\n");
435 exit(-1);
436 }
437
438 break;
439 }
440
441 LLVMValueRef Prev = LLVMGetPreviousFunction(Next);
442 if (Prev != Cur) {
443 fprintf(stderr, "Next.Previous function is not Current\n");
444 exit(-1);
445 }
446
447 Cur = Next;
448 }
449}
450
451int echo(void) {
452 LLVMEnablePrettyStackTrace();
453
454 LLVMModuleRef Src = load_module(false, true);
455
456 LLVMContextRef Ctx = LLVMContextCreate();
457 LLVMModuleRef Dst = LLVMModuleCreateWithNameInContext("<stdin>", Ctx);
458
459 clone_functions(Src, Dst);
460 char *Str = LLVMPrintModuleToString(Dst);
461 fputs(Str, stdout);
462
463 LLVMDisposeMessage(Str);
464 LLVMDisposeModule(Dst);
465 LLVMContextDispose(Ctx);
466
467 return 0;
468}