source: icGREP/icgrep-devel/icgrep/IR_Gen/CBuilder.cpp @ 5486

Last change on this file since 5486 was 5486, checked in by nmedfort, 22 months ago

Initial attempt to improve debugging capabilities with compilation stack traces on error.

File size: 37.4 KB
Line 
1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6
7#include "CBuilder.h"
8#include <llvm/IR/Module.h>
9#include <llvm/IR/Constants.h>
10#include <llvm/IR/Intrinsics.h>
11#include <llvm/IR/TypeBuilder.h>
12#include <llvm/IR/MDBuilder.h>
13#include <llvm/Support/raw_ostream.h>
14#include <llvm/Support/Format.h>
15#include <toolchain/toolchain.h>
16#include <toolchain/driver.h>
17#include <set>
18#include <thread>
19#include <stdlib.h>
20#include <sys/mman.h>
21#include <unistd.h>
22#include <stdio.h>
23#ifdef HAS_ADDRESS_SANITIZER
24#include <sanitizer/asan_interface.h>
25#endif
26#ifdef HAVE_LIBUNWIND
27#define UNW_LOCAL_ONLY
28#include <libunwind.h>
29#else
30using unw_word_t = uint64_t;
31#endif
32
33using namespace llvm;
34
35void __report_failure(const char * msg, const unw_word_t * trace) {
36    raw_fd_ostream out(STDERR_FILENO, false);
37    #ifdef HAVE_LIBUNWIND
38    if (trace) {
39        out.changeColor(raw_fd_ostream::WHITE, true);
40        out << "Compilation Stacktrace:\n";
41        out.resetColor();
42        while (*trace) {
43            const auto pc = *trace++;
44            out << format_hex(pc, 16) << "   ";
45            const auto len = codegen::ProgramName.length() + 32;
46            char cmd[len];
47            snprintf(cmd, len,"addr2line -fpCe %s %p", codegen::ProgramName.data(), reinterpret_cast<void *>(pc));
48            FILE * f = popen(cmd, "r");
49            if (f) {
50                char buffer[1024] = {0};
51                while(fgets(buffer, sizeof(buffer), f)) {
52                    out << buffer;
53                }
54                pclose(f);
55            }
56            ++trace;
57        }
58    }
59    #endif
60    out.changeColor(raw_fd_ostream::WHITE, true);
61    out << "Assertion `" << msg << "' failed.\n";
62    out.resetColor();
63    out.flush();
64}
65
66Value * CBuilder::CreateOpenCall(Value * filename, Value * oflag, Value * mode) {
67    Module * const m = getModule();
68    Function * openFn = m->getFunction("open");
69    if (openFn == nullptr) {
70        IntegerType * int32Ty = getInt32Ty();
71        PointerType * int8PtrTy = getInt8PtrTy();
72        openFn = cast<Function>(m->getOrInsertFunction("open",
73                                                         int32Ty, int8PtrTy, int32Ty, int32Ty, nullptr));
74    }
75    return CreateCall(openFn, {filename, oflag, mode});
76}
77
78// ssize_t write(int fildes, const void *buf, size_t nbyte);
79Value * CBuilder::CreateWriteCall(Value * fileDescriptor, Value * buf, Value * nbyte) {
80    PointerType * voidPtrTy = getVoidPtrTy();
81    Module * const m = getModule();
82    Function * write = m->getFunction("write");
83    if (write == nullptr) {
84        IntegerType * sizeTy = getSizeTy();
85        IntegerType * int32Ty = getInt32Ty();
86        write = cast<Function>(m->getOrInsertFunction("write",
87                                                        AttributeSet().addAttribute(getContext(), 2U, Attribute::NoAlias),
88                                                        sizeTy, int32Ty, voidPtrTy, sizeTy, nullptr));
89    }
90    buf = CreatePointerCast(buf, voidPtrTy);
91    return CreateCall(write, {fileDescriptor, buf, nbyte});
92}
93
94Value * CBuilder::CreateReadCall(Value * fileDescriptor, Value * buf, Value * nbyte) {
95    PointerType * voidPtrTy = getVoidPtrTy();
96    Module * const m = getModule();
97    Function * readFn = m->getFunction("read");
98    if (readFn == nullptr) {
99        IntegerType * sizeTy = getSizeTy();
100        IntegerType * int32Ty = getInt32Ty();
101        readFn = cast<Function>(m->getOrInsertFunction("read",
102                                                         AttributeSet().addAttribute(getContext(), 2U, Attribute::NoAlias),
103                                                         sizeTy, int32Ty, voidPtrTy, sizeTy, nullptr));
104    }
105    buf = CreatePointerCast(buf, voidPtrTy);
106    return CreateCall(readFn, {fileDescriptor, buf, nbyte});
107}
108
109Value * CBuilder::CreateCloseCall(Value * fileDescriptor) {
110    Module * const m = getModule();
111    Function * closeFn = m->getFunction("close");
112    if (closeFn == nullptr) {
113        IntegerType * int32Ty = getInt32Ty();
114        FunctionType * fty = FunctionType::get(int32Ty, {int32Ty}, true);
115        closeFn = Function::Create(fty, Function::ExternalLinkage, "close", m);
116    }
117    return CreateCall(closeFn, fileDescriptor);
118}
119
120Value * CBuilder::CreateUnlinkCall(Value * path) {
121    Module * const m = getModule();
122    Function * unlinkFunc = m->getFunction("unlink");
123    if (unlinkFunc == nullptr) {
124        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt8PtrTy()}, false);
125        unlinkFunc = Function::Create(fty, Function::ExternalLinkage, "unlink", m);
126        unlinkFunc->setCallingConv(CallingConv::C);
127    }
128    return CreateCall(unlinkFunc, path);
129}
130
131Value * CBuilder::CreateMkstempCall(Value * ftemplate) {
132    Module * const m = getModule();
133    Function * mkstempFn = m->getFunction("mkstemp");
134    if (mkstempFn == nullptr) {
135        mkstempFn = cast<Function>(m->getOrInsertFunction("mkstemp", getInt32Ty(), getInt8PtrTy(), nullptr));
136    }
137    return CreateCall(mkstempFn, ftemplate);
138}
139
140Value * CBuilder::CreateStrlenCall(Value * str) {
141    Module * const m = getModule();
142    Function * strlenFn = m->getFunction("strlen");
143    if (strlenFn == nullptr) {
144        strlenFn = cast<Function>(m->getOrInsertFunction("strlen", getSizeTy(), getInt8PtrTy(), nullptr));
145    }
146    return CreateCall(strlenFn, str);
147}
148
149Function * CBuilder::GetPrintf() {
150    Module * const m = getModule();
151    Function * printf = m->getFunction("printf");
152    if (printf == nullptr) {
153        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt8PtrTy()}, true);
154        printf = Function::Create(fty, Function::ExternalLinkage, "printf", m);
155        printf->addAttribute(1, Attribute::NoAlias);
156    }
157    return printf;
158}
159
160Function * CBuilder::GetDprintf() {
161    Module * const m = getModule();
162    Function * dprintf = m->getFunction("dprintf");
163    if (dprintf == nullptr) {
164        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt32Ty(), getInt8PtrTy()}, true);
165        dprintf = Function::Create(fty, Function::ExternalLinkage, "dprintf", m);
166    }
167    return dprintf;
168}
169
170void CBuilder::CallPrintInt(const std::string & name, Value * const value) {
171    Module * const m = getModule();
172    Constant * printRegister = m->getFunction("PrintInt");
173    IntegerType * int64Ty = getInt64Ty();
174    if (LLVM_UNLIKELY(printRegister == nullptr)) {
175        FunctionType *FT = FunctionType::get(getVoidTy(), { getInt8PtrTy(), int64Ty }, false);
176        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintInt", m);
177        auto arg = function->arg_begin();
178        std::string out = "%-40s = %" PRIx64 "\n";
179        BasicBlock * entry = BasicBlock::Create(getContext(), "entry", function);
180        IRBuilder<> builder(entry);
181        std::vector<Value *> args;
182        args.push_back(GetString(out.c_str()));
183        Value * const name = &*(arg++);
184        name->setName("name");
185        args.push_back(name);
186        Value * value = &*arg;
187        value->setName("value");
188        args.push_back(value);
189        builder.CreateCall(GetPrintf(), args);
190        builder.CreateRetVoid();
191
192        printRegister = function;
193    }
194    Value * num = nullptr;
195    if (value->getType()->isPointerTy()) {
196        num = CreatePtrToInt(value, int64Ty);
197    } else {
198        num = CreateZExtOrBitCast(value, int64Ty);
199    }
200    assert (num->getType()->isIntegerTy());
201    CreateCall(printRegister, {GetString(name.c_str()), num});
202}
203
204void CBuilder::CallPrintIntToStderr(const std::string & name, Value * const value) {
205    Module * const m = getModule();
206    Constant * printRegister = m->getFunction("PrintIntToStderr");
207    if (LLVM_UNLIKELY(printRegister == nullptr)) {
208        FunctionType *FT = FunctionType::get(getVoidTy(), { PointerType::get(getInt8Ty(), 0), getSizeTy() }, false);
209        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintIntToStderr", m);
210        auto arg = function->arg_begin();
211        std::string out = "%-40s = %" PRIx64 "\n";
212        BasicBlock * entry = BasicBlock::Create(getContext(), "entry", function);
213        IRBuilder<> builder(entry);
214        std::vector<Value *> args;
215        args.push_back(getInt32(2));    // fd 2 (stderr)
216        args.push_back(GetString(out.c_str()));
217        Value * const name = &*(arg++);
218        name->setName("name");
219        args.push_back(name);
220        Value * value = &*arg;
221        value->setName("value");
222        args.push_back(value);
223        builder.CreateCall(GetDprintf(), args);
224        builder.CreateRetVoid();
225
226        printRegister = function;
227    }
228    Value * num = nullptr;
229    if (value->getType()->isPointerTy()) {
230        num = CreatePtrToInt(value, getSizeTy());
231    } else {
232        num = CreateZExtOrBitCast(value, getSizeTy());
233    }
234    assert (num->getType()->isIntegerTy());
235    CreateCall(printRegister, {GetString(name.c_str()), num});
236}
237
238void CBuilder::CallPrintMsgToStderr(const std::string & message) {
239    Module * const m = getModule();
240    Constant * printMsg = m->getFunction("PrintMsgToStderr");
241    if (LLVM_UNLIKELY(printMsg == nullptr)) {
242        FunctionType *FT = FunctionType::get(getVoidTy(), { PointerType::get(getInt8Ty(), 0) }, false);
243        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintMsgToStderr", m);
244        auto arg = function->arg_begin();
245        std::string out = "%s\n";
246        BasicBlock * entry = BasicBlock::Create(getContext(), "entry", function);
247        IRBuilder<> builder(entry);
248        std::vector<Value *> args;
249        args.push_back(getInt32(2));    // fd 2 (stderr)
250        args.push_back(GetString(out.c_str()));
251        Value * const msg = &*(arg++);
252        msg->setName("msg");
253        args.push_back(msg);
254        builder.CreateCall(GetDprintf(), args);
255        builder.CreateRetVoid();
256
257        printMsg = function;
258    }
259    CreateCall(printMsg, {GetString(message.c_str())});
260}
261
262Value * CBuilder::CreateMalloc(Value * size) {
263    Module * const m = getModule();
264    IntegerType * const sizeTy = getSizeTy();   
265    Function * f = m->getFunction("malloc");
266    if (f == nullptr) {
267        PointerType * const voidPtrTy = getVoidPtrTy();
268        FunctionType * fty = FunctionType::get(voidPtrTy, {sizeTy}, false);
269        f = Function::Create(fty, Function::ExternalLinkage, "malloc", m);
270        f->setCallingConv(CallingConv::C);
271        f->setDoesNotAlias(0);
272    }
273    size = CreateZExtOrTrunc(size, sizeTy);
274    CallInst * const ptr = CreateCall(f, size);
275    ptr->setTailCall();
276    CreateAssert(ptr, "CreateMalloc: returned null pointer");
277    return ptr;
278}
279
280Value * CBuilder::CreateAlignedMalloc(Value * size, const unsigned alignment) {
281    if (LLVM_UNLIKELY((alignment & (alignment - 1)) != 0)) {
282        report_fatal_error("CreateAlignedMalloc: alignment must be a power of 2");
283    }
284    Module * const m = getModule();
285    IntegerType * const sizeTy = getSizeTy();
286    PointerType * const voidPtrTy = getVoidPtrTy();
287    #ifdef STDLIB_HAS_ALIGNED_ALLOC
288    Function * f = m->getFunction("aligned_alloc");
289    if (LLVM_UNLIKELY(f == nullptr)) {
290        FunctionType * const fty = FunctionType::get(voidPtrTy, {sizeTy, sizeTy}, false);
291        f = Function::Create(fty, Function::ExternalLinkage, "aligned_alloc", m);
292        f->setCallingConv(CallingConv::C);
293        f->setDoesNotAlias(0);
294    }
295    #else
296    Function * f = m->getFunction("posix_memalign");
297    if (LLVM_UNLIKELY(f == nullptr)) {
298        FunctionType * const fty = FunctionType::get(getInt32Ty(), {voidPtrTy->getPointerTo(), sizeTy, sizeTy}, false);
299        f = Function::Create(fty, Function::ExternalLinkage, "posix_memalign", m);
300        f->setCallingConv(CallingConv::C);
301        f->setDoesNotAlias(1);
302    }
303    #endif
304    size = CreateZExtOrTrunc(size, sizeTy);
305    ConstantInt * const align = ConstantInt::get(sizeTy, alignment);
306    if (codegen::EnableAsserts) {
307        CreateAssert(CreateICmpEQ(CreateURem(size, align), ConstantInt::get(sizeTy, 0)),
308                     "CreateAlignedMalloc: size must be an integral multiple of alignment.");
309    }
310    #ifdef STDLIB_HAS_ALIGNED_ALLOC
311    CallInst * const ptr = CreateCall(f, {align, size});
312    ptr->setTailCall();
313    #else
314    Value * ptr = CreateAlloca(voidPtrTy);
315    CallInst * success = CreateCall(f, {ptr, align, size});
316    success->setTailCall();
317    if (codegen::EnableAsserts) {
318        CreateAssert(CreateICmpEQ(success, getInt32(0)),
319                     "CreateAlignedMalloc: posix_memalign reported bad allocation");
320    }
321    ptr = CreateLoad(ptr);
322    #endif
323    CreateAssert(ptr, "CreateAlignedMalloc: returned null pointer.");
324    return ptr;
325}
326
327Value * CBuilder::CreateRealloc(Value * const ptr, Value * size) {
328    Module * const m = getModule();
329    IntegerType * const sizeTy = getSizeTy();
330    PointerType * const voidPtrTy = getVoidPtrTy();
331    Function * f = m->getFunction("realloc");
332    if (f == nullptr) {
333        FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, sizeTy}, false);
334        f = Function::Create(fty, Function::ExternalLinkage, "realloc", m);
335        f->setCallingConv(CallingConv::C);
336        f->setDoesNotAlias(0);
337        f->setDoesNotAlias(1);
338    }
339    Value * const addr = CreatePointerCast(ptr, voidPtrTy);
340    size = CreateZExtOrTrunc(size, sizeTy);
341    CallInst * const ci = CreateCall(f, {addr, size});
342    ci->setTailCall();
343    return CreatePointerCast(ci, ptr->getType());
344}
345
346void CBuilder::CreateFree(Value * ptr) {
347    assert (ptr->getType()->isPointerTy());
348    Module * const m = getModule();
349    Type * const voidPtrTy =  getVoidPtrTy();
350    Function * f = m->getFunction("free");
351    if (f == nullptr) {
352        FunctionType * fty = FunctionType::get(getVoidTy(), {voidPtrTy}, false);
353        f = Function::Create(fty, Function::ExternalLinkage, "free", m);
354        f->setCallingConv(CallingConv::C);
355    }
356    ptr = CreatePointerCast(ptr, voidPtrTy);
357    CreateCall(f, ptr)->setTailCall();
358}
359
360Value * CBuilder::CreateAnonymousMMap(Value * size) {
361    PointerType * const voidPtrTy = getVoidPtrTy();
362    IntegerType * const intTy = getInt32Ty();
363    IntegerType * const sizeTy = getSizeTy();
364    size = CreateZExtOrTrunc(size, sizeTy);
365    ConstantInt * const prot =  ConstantInt::get(intTy, PROT_READ | PROT_WRITE);
366    ConstantInt * const flags =  ConstantInt::get(intTy, MAP_PRIVATE | MAP_ANON);
367    ConstantInt * const fd =  ConstantInt::get(intTy, -1);
368    Constant * const offset = ConstantInt::get(sizeTy, 0);
369    return CreateMMap(ConstantPointerNull::getNullValue(voidPtrTy), size, prot, flags, fd, offset);
370}
371
372Value * CBuilder::CreateFileSourceMMap(Value * fd, Value * size) {
373    PointerType * const voidPtrTy = getVoidPtrTy();
374    IntegerType * const intTy = getInt32Ty();
375    fd = CreateZExtOrTrunc(fd, intTy);
376    IntegerType * const sizeTy = getSizeTy();
377    size = CreateZExtOrTrunc(size, sizeTy);
378    ConstantInt * const prot =  ConstantInt::get(intTy, PROT_READ);
379    ConstantInt * const flags =  ConstantInt::get(intTy, MAP_PRIVATE);
380    Constant * const offset = ConstantInt::get(sizeTy, 0);       
381    return CreateMMap(ConstantPointerNull::getNullValue(voidPtrTy), size, prot, flags, fd, offset);
382}
383
384Value * CBuilder::CreateMMap(Value * const addr, Value * size, Value * const prot, Value * const flags, Value * const fd, Value * const offset) {
385    Module * const m = getModule();
386    Function * fMMap = m->getFunction("mmap");
387    if (LLVM_UNLIKELY(fMMap == nullptr)) {
388        PointerType * const voidPtrTy = getVoidPtrTy();
389        IntegerType * const intTy = getInt32Ty();
390        IntegerType * const sizeTy = getSizeTy();
391        FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, sizeTy, intTy, intTy, intTy, sizeTy}, false);
392        fMMap = Function::Create(fty, Function::ExternalLinkage, "mmap", m);
393    }
394    Value * ptr = CreateCall(fMMap, {addr, size, prot, flags, fd, offset});
395    if (codegen::EnableAsserts) {
396        DataLayout DL(m);
397        IntegerType * const intTy = getIntPtrTy(DL);
398        Value * success = CreateICmpNE(CreatePtrToInt(addr, intTy), ConstantInt::getAllOnesValue(intTy)); // MAP_FAILED = -1
399        CreateAssert(success, "CreateMMap: mmap failed to allocate memory");
400    }
401    return ptr;
402}
403
404/**
405 * @brief CBuilder::CreateMAdvise
406 * @param addr
407 * @param length
408 * @param advice
409 *
410 * Note: this funcition can fail if a kernel resource was temporarily unavailable. Test if this is more than a simple hint and handle accordingly.
411 *
412 *  ADVICE_NORMAL
413 *      No special treatment. This is the default.
414 *  ADVICE_RANDOM
415 *      Expect page references in random order. (Hence, read ahead may be less useful than normally.)
416 *  ADVICE_SEQUENTIAL
417 *      Expect page references in sequential order. (Hence, pages in the given range can be aggressively read ahead, and may be freed
418 *      soon after they are accessed.)
419 *  ADVICE_WILLNEED
420 *      Expect access in the near future. (Hence, it might be a good idea to read some pages ahead.)
421 *  ADVICE_DONTNEED
422 *      Do not expect access in the near future. (For the time being, the application is finished with the given range, so the kernel
423 *      can free resources associated with it.) Subsequent accesses of pages in this range will succeed, but will result either in
424 *      reloading of the memory contents from the underlying mapped file (see mmap(2)) or zero-fill-on-demand pages for mappings
425 *      without an underlying file.
426 *
427 * @return Value indicating success (0) or failure (-1).
428 */
429Value * CBuilder::CreateMAdvise(Value * addr, Value * length, Advice advice) {
430    Triple T(mTriple);
431    Value * result = nullptr;
432    if (T.isOSLinux() || T.isOSDarwin()) {
433        Module * const m = getModule();
434        IntegerType * const intTy = getInt32Ty();
435        IntegerType * const sizeTy = getSizeTy();
436        PointerType * const voidPtrTy = getVoidPtrTy();
437        Function * MAdviseFunc = m->getFunction("madvise");
438        if (LLVM_UNLIKELY(MAdviseFunc == nullptr)) {
439            FunctionType * fty = FunctionType::get(intTy, {voidPtrTy, sizeTy, intTy}, false);
440            MAdviseFunc = Function::Create(fty, Function::ExternalLinkage, "madvise", m);
441        }
442        addr = CreatePointerCast(addr, voidPtrTy);
443        length = CreateZExtOrTrunc(length, sizeTy);
444        int madv_flag = 0;
445        switch (advice) {
446            case Advice::ADVICE_NORMAL:
447                madv_flag = MADV_NORMAL; break;
448            case Advice::ADVICE_RANDOM:
449                madv_flag = MADV_RANDOM; break;
450            case Advice::ADVICE_SEQUENTIAL:
451                madv_flag = MADV_SEQUENTIAL; break;
452            case Advice::ADVICE_WILLNEED:
453                madv_flag = MADV_WILLNEED; break;
454            case Advice::ADVICE_DONTNEED:
455                madv_flag = MADV_DONTNEED; break;
456        }
457        result = CreateCall(MAdviseFunc, {addr, length, ConstantInt::get(intTy, madv_flag)});
458    }
459    return result;
460}
461
462#ifndef MREMAP_MAYMOVE
463#define MREMAP_MAYMOVE  1
464#endif
465
466Value * CBuilder::CreateMRemap(Value * addr, Value * oldSize, Value * newSize) {
467    Triple T(mTriple);
468    Value * ptr = nullptr;
469    if (T.isOSLinux()) {
470        Module * const m = getModule();
471        DataLayout DL(m);
472        PointerType * const voidPtrTy = getVoidPtrTy();
473        IntegerType * const sizeTy = getSizeTy();
474        IntegerType * const intTy = getIntPtrTy(DL);
475        Function * fMRemap = m->getFunction("mremap");
476        if (LLVM_UNLIKELY(fMRemap == nullptr)) {
477            FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, sizeTy, sizeTy, intTy}, false);
478            fMRemap = Function::Create(fty, Function::ExternalLinkage, "mremap", m);
479        }
480        addr = CreatePointerCast(addr, voidPtrTy);
481        oldSize = CreateZExtOrTrunc(oldSize, sizeTy);
482        newSize = CreateZExtOrTrunc(newSize, sizeTy);
483        ConstantInt * const flags = ConstantInt::get(intTy, MREMAP_MAYMOVE);
484        ptr = CreateCall(fMRemap, {addr, oldSize, newSize, flags});
485        if (codegen::EnableAsserts) {
486            Value * success = CreateICmpNE(CreatePtrToInt(addr, intTy), ConstantInt::getAllOnesValue(intTy)); // MAP_FAILED = -1
487            CreateAssert(success, "CreateMRemap: mremap failed to allocate memory");
488        }
489    } else { // no OS mremap support
490        ptr = CreateAnonymousMMap(newSize);
491        CreateMemCpy(ptr, addr, oldSize, getpagesize());
492        CreateMUnmap(addr, oldSize);
493    }
494    return ptr;
495}
496
497Value * CBuilder::CreateMUnmap(Value * addr, Value * len) {
498    IntegerType * const sizeTy = getSizeTy();
499    PointerType * const voidPtrTy = getVoidPtrTy();
500    Module * const m = getModule();
501    Function * munmapFunc = m->getFunction("munmap");
502    if (LLVM_UNLIKELY(munmapFunc == nullptr)) {
503        FunctionType * const fty = FunctionType::get(sizeTy, {voidPtrTy, sizeTy}, false);
504        munmapFunc = Function::Create(fty, Function::ExternalLinkage, "munmap", m);
505    }
506    len = CreateZExtOrTrunc(len, sizeTy);
507    if (codegen::EnableAsserts) {
508        DataLayout DL(getModule());
509        IntegerType * const intPtrTy = getIntPtrTy(DL);
510        CreateAssert(len, "CreateMUnmap: length cannot be 0");
511        Value * const addrValue = CreatePtrToInt(addr, intPtrTy);
512        Value * const pageOffset = CreateURem(addrValue, ConstantInt::get(intPtrTy, getpagesize()));
513        CreateAssert(CreateICmpEQ(pageOffset, ConstantInt::getNullValue(intPtrTy)), "CreateMUnmap: addr must be a multiple of the page size");
514        Value * const boundCheck = CreateICmpULT(addrValue, CreateSub(ConstantInt::getAllOnesValue(intPtrTy), CreateZExtOrTrunc(len, intPtrTy)));
515        CreateAssert(boundCheck, "CreateMUnmap: addresses in [addr, addr+len) are outside the valid address space range");
516    }
517    addr = CreatePointerCast(addr, voidPtrTy);
518    return CreateCall(munmapFunc, {addr, len});
519}
520
521PointerType * CBuilder::getVoidPtrTy() const {
522    return TypeBuilder<void *, true>::get(getContext());
523}
524
525LoadInst * CBuilder::CreateAtomicLoadAcquire(Value * ptr) {
526    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
527    LoadInst * inst = CreateAlignedLoad(ptr, alignment);
528    inst->setOrdering(AtomicOrdering::Acquire);
529    return inst;
530   
531}
532
533StoreInst * CBuilder::CreateAtomicStoreRelease(Value * val, Value * ptr) {
534    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
535    StoreInst * inst = CreateAlignedStore(val, ptr, alignment);
536    inst->setOrdering(AtomicOrdering::Release);
537    return inst;
538}
539
540PointerType * CBuilder::getFILEptrTy() {
541    if (mFILEtype == nullptr) {
542        mFILEtype = StructType::create(getContext(), "struct._IO_FILE");
543    }
544    return mFILEtype->getPointerTo();
545}
546
547Value * CBuilder::CreateFOpenCall(Value * filename, Value * mode) {
548    Module * const m = getModule();
549    Function * fOpenFunc = m->getFunction("fopen");
550    if (fOpenFunc == nullptr) {
551        FunctionType * fty = FunctionType::get(getFILEptrTy(), {getInt8Ty()->getPointerTo(), getInt8Ty()->getPointerTo()}, false);
552        fOpenFunc = Function::Create(fty, Function::ExternalLinkage, "fopen", m);
553        fOpenFunc->setCallingConv(CallingConv::C);
554    }
555    return CreateCall(fOpenFunc, {filename, mode});
556}
557
558Value * CBuilder::CreateFReadCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
559    Module * const m = getModule();
560    Function * fReadFunc = m->getFunction("fread");
561    PointerType * const voidPtrTy = getVoidPtrTy();
562    if (fReadFunc == nullptr) {
563        IntegerType * const sizeTy = getSizeTy();
564        FunctionType * fty = FunctionType::get(sizeTy, {voidPtrTy, sizeTy, sizeTy, getFILEptrTy()}, false);
565        fReadFunc = Function::Create(fty, Function::ExternalLinkage, "fread", m);
566        fReadFunc->setCallingConv(CallingConv::C);
567    }
568    ptr = CreatePointerCast(ptr, voidPtrTy);
569    return CreateCall(fReadFunc, {ptr, size, nitems, stream});
570}
571
572Value * CBuilder::CreateFWriteCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
573    Module * const m = getModule();
574    Function * fWriteFunc = m->getFunction("fwrite");
575    PointerType * const voidPtrTy = getVoidPtrTy();
576    if (fWriteFunc == nullptr) {
577        IntegerType * const sizeTy = getSizeTy();
578        FunctionType * fty = FunctionType::get(sizeTy, {voidPtrTy, sizeTy, sizeTy, getFILEptrTy()}, false);
579        fWriteFunc = Function::Create(fty, Function::ExternalLinkage, "fwrite", m);
580        fWriteFunc->setCallingConv(CallingConv::C);
581    }
582    ptr = CreatePointerCast(ptr, voidPtrTy);
583    return CreateCall(fWriteFunc, {ptr, size, nitems, stream});
584}
585
586Value * CBuilder::CreateFCloseCall(Value * stream) {
587    Module * const m = getModule();
588    Function * fCloseFunc = m->getFunction("fclose");
589    if (fCloseFunc == nullptr) {
590        FunctionType * fty = FunctionType::get(getInt32Ty(), {getFILEptrTy()}, false);
591        fCloseFunc = Function::Create(fty, Function::ExternalLinkage, "fclose", m);
592        fCloseFunc->setCallingConv(CallingConv::C);
593    }
594    return CreateCall(fCloseFunc, {stream});
595}
596
597Value * CBuilder::CreateRenameCall(Value * oldName, Value * newName) {
598    Module * const m = getModule();
599    Function * renameFunc = m->getFunction("rename");
600    if (renameFunc == nullptr) {
601        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt8PtrTy(), getInt8PtrTy()}, false);
602        renameFunc = Function::Create(fty, Function::ExternalLinkage, "rename", m);
603        renameFunc->setCallingConv(CallingConv::C);
604    }
605    return CreateCall(renameFunc, {oldName, newName});
606}
607
608Value * CBuilder::CreateRemoveCall(Value * path) {
609    Module * const m = getModule();
610    Function * removeFunc = m->getFunction("remove");
611    if (removeFunc == nullptr) {
612        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt8PtrTy()}, false);
613        removeFunc = Function::Create(fty, Function::ExternalLinkage, "remove", m);
614        removeFunc->setCallingConv(CallingConv::C);
615    }
616    return CreateCall(removeFunc, {path});
617}
618
619Value * CBuilder::CreatePThreadCreateCall(Value * thread, Value * attr, Function * start_routine, Value * arg) {
620    Module * const m = getModule();
621    Type * const voidPtrTy = getVoidPtrTy();
622    Function * pthreadCreateFunc = m->getFunction("pthread_create");
623    if (pthreadCreateFunc == nullptr) {
624        Type * pthreadTy = getSizeTy();
625        FunctionType * funVoidPtrVoidTy = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
626        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy->getPointerTo(), voidPtrTy, funVoidPtrVoidTy->getPointerTo(), voidPtrTy}, false);
627        pthreadCreateFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_create", m);
628        pthreadCreateFunc->setCallingConv(CallingConv::C);
629    }
630    return CreateCall(pthreadCreateFunc, {thread, attr, start_routine, CreatePointerCast(arg, voidPtrTy)});
631}
632
633Value * CBuilder::CreatePThreadYield() {
634    Module * const m = getModule();
635    Function * f = m->getFunction("pthread_yield");
636    if (f == nullptr) {
637        FunctionType * fty = FunctionType::get(getInt32Ty(), false);
638        f = Function::Create(fty, Function::ExternalLinkage, "pthread_yield", m);
639        f->setCallingConv(CallingConv::C);
640    }
641    return CreateCall(f);
642}
643
644Value * CBuilder::CreatePThreadExitCall(Value * value_ptr) {
645    Module * const m = getModule();
646    Function * pthreadExitFunc = m->getFunction("pthread_exit");
647    if (pthreadExitFunc == nullptr) {
648        FunctionType * fty = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
649        pthreadExitFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_exit", m);
650        pthreadExitFunc->addFnAttr(Attribute::NoReturn);
651        pthreadExitFunc->setCallingConv(CallingConv::C);
652    }
653    CallInst * exitThread = CreateCall(pthreadExitFunc, {value_ptr});
654    exitThread->setDoesNotReturn();
655    return exitThread;
656}
657
658Value * CBuilder::CreatePThreadJoinCall(Value * thread, Value * value_ptr){
659    Module * const m = getModule();
660    Function * pthreadJoinFunc = m->getFunction("pthread_join");
661    if (pthreadJoinFunc == nullptr) {
662        FunctionType * fty = FunctionType::get(getInt32Ty(), {getSizeTy(), getVoidPtrTy()->getPointerTo()}, false);
663        pthreadJoinFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_join", m);
664        pthreadJoinFunc->setCallingConv(CallingConv::C);
665    }
666    return CreateCall(pthreadJoinFunc, {thread, value_ptr});
667}
668
669void CBuilder::CreateAssert(Value * assertion, StringRef failureMessage) {
670    if (LLVM_UNLIKELY(codegen::EnableAsserts)) {
671        Module * const m = getModule();
672        Function * function = m->getFunction("assert");
673        IntegerType * const int1Ty = getInt1Ty();
674        if (LLVM_UNLIKELY(function == nullptr)) {
675            auto ip = saveIP();
676            PointerType * const int8PtrTy = getInt8PtrTy();
677            IntegerType * const unwWordTy = TypeBuilder<unw_word_t, false>::get(getContext());
678            PointerType * const unwWordPtrTy = unwWordTy->getPointerTo();
679            FunctionType * fty = FunctionType::get(getVoidTy(), { int1Ty, int8PtrTy, unwWordPtrTy }, false);
680            function = Function::Create(fty, Function::PrivateLinkage, "assert", m);
681            function->setDoesNotThrow();
682            function->setDoesNotAlias(2);
683            BasicBlock * const entry = BasicBlock::Create(getContext(), "", function);
684            BasicBlock * const failure = BasicBlock::Create(getContext(), "", function);
685            BasicBlock * const success = BasicBlock::Create(getContext(), "", function);
686            auto arg = function->arg_begin();
687            arg->setName("assertion");
688            Value * assertion = &*arg++;
689            arg->setName("msg");
690            Value * msg = &*arg++;
691            arg->setName("trace");
692            Value * trace = &*arg++;
693            SetInsertPoint(entry);
694            IRBuilder<>::CreateCondBr(assertion, success, failure);
695            IRBuilder<>::SetInsertPoint(failure);
696            IRBuilder<>::CreateCall(LinkFunction("__report_failure", __report_failure), { msg, trace });
697            CreateExit(-1);
698            IRBuilder<>::CreateBr(success); // necessary to satisfy the LLVM verifier. this is never executed.
699            SetInsertPoint(success);
700            IRBuilder<>::CreateRetVoid();
701            restoreIP(ip);
702        }
703        if (assertion->getType() != int1Ty) {
704            assertion = CreateICmpNE(assertion, Constant::getNullValue(assertion->getType()));
705        }
706        IntegerType * const unwWordTy = TypeBuilder<unw_word_t, false>::get(getContext());
707        PointerType * const unwWordPtrTy = unwWordTy->getPointerTo();
708        #ifdef HAVE_LIBUNWIND
709        std::vector<unw_word_t> stack;
710        unw_context_t context;
711        unw_cursor_t cursor;
712        // Initialize cursor to current frame for local unwinding.
713        unw_getcontext(&context);
714        unw_init_local(&cursor, &context);
715        // Unwind frames one by one, going up the frame stack.
716        stack.reserve(64);
717        while (unw_step(&cursor) > 0) {
718            unw_word_t pc;
719            unw_get_reg(&cursor, UNW_REG_IP, &pc);
720            stack.push_back(pc);
721            if (pc == 0) {
722                break;
723            }
724        }
725        GlobalVariable * global = nullptr;
726        const auto n = stack.size();
727        IntegerType * const unwTy = TypeBuilder<unw_word_t, false>::get(getContext());
728        for (GlobalVariable & gv : m->getGlobalList()) {
729            Type * const ty = gv.getValueType();
730            if (ty->isArrayTy() && ty->getArrayElementType() == unwTy && ty->getArrayNumElements() == n) {
731                const ConstantDataArray * const array = cast<ConstantDataArray>(gv.getOperand(0));
732                bool found = true;
733                for (auto i = n - 1; i != 0; --i) {
734                    if (LLVM_LIKELY(array->getElementAsInteger(i) != stack[i])) {
735                        found = false;
736                        break;
737                    }
738                }
739                if (LLVM_UNLIKELY(found)) {
740                    global = &gv;
741                    break;
742                }
743            }
744        }
745        if (LLVM_LIKELY(global == nullptr)) {
746            Constant * const initializer = ConstantDataArray::get(getContext(), stack);
747            global = new GlobalVariable(*m, initializer->getType(), true, GlobalVariable::InternalLinkage, initializer);
748        }
749        Value * const trace = CreatePointerCast(global, unwWordPtrTy);
750        #else
751        Constant * const trace = ConstantPointerNull::get(unwWordPtrTy);
752        #endif
753        IRBuilder<>::CreateCall(function, {assertion, GetString(failureMessage), trace});
754    }
755}
756
757void CBuilder::CreateExit(const int exitCode) {
758    Module * const m = getModule();
759    Function * exit = m->getFunction("exit");
760    if (LLVM_UNLIKELY(exit == nullptr)) {
761        FunctionType * fty = FunctionType::get(getVoidTy(), {getInt32Ty()}, false);
762        exit = Function::Create(fty, Function::ExternalLinkage, "exit", m);
763        exit->setDoesNotReturn();
764        exit->setDoesNotThrow();
765    }
766    CreateCall(exit, getInt32(exitCode));
767}
768
769BasicBlock * CBuilder::CreateBasicBlock(std::string && name) {
770    return BasicBlock::Create(getContext(), name, GetInsertBlock()->getParent());
771}
772
773BranchInst * CBuilder::CreateLikelyCondBr(Value * Cond, BasicBlock * True, BasicBlock * False, const int probability) {
774    MDBuilder mdb(getContext());
775    if (probability < 0 || probability > 100) {
776        report_fatal_error("branch weight probability must be in [0,100]");
777    }
778    return CreateCondBr(Cond, True, False, mdb.createBranchWeights(probability, 100 - probability));
779}
780
781Value * CBuilder::CreatePopcount(Value * bits) {
782    Value * ctpopFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::ctpop, bits->getType());
783    return CreateCall(ctpopFunc, bits);
784}
785
786Value * CBuilder::CreateCountForwardZeroes(Value * value) {
787    Value * cttzFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::cttz, value->getType());
788    return CreateCall(cttzFunc, {value, ConstantInt::getFalse(getContext())});
789}
790
791Value * CBuilder::CreateCountReverseZeroes(Value * value) {
792    Value * ctlzFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::ctlz, value->getType());
793    return CreateCall(ctlzFunc, {value, ConstantInt::getFalse(getContext())});
794}
795
796Value * CBuilder::CreateResetLowestBit(Value * bits) {
797    return CreateAnd(bits, CreateSub(bits, ConstantInt::get(bits->getType(), 1)));
798}
799
800Value * CBuilder::CreateIsolateLowestBit(Value * bits) {
801    return CreateAnd(bits, CreateNeg(bits));
802}
803
804Value * CBuilder::CreateMaskToLowestBitInclusive(Value * bits) {
805    return CreateXor(bits, CreateSub(bits, ConstantInt::get(bits->getType(), 1)));
806}
807
808Value * CBuilder::CreateMaskToLowestBitExclusive(Value * bits) {
809    return CreateAnd(CreateSub(bits, ConstantInt::get(bits->getType(), 1)), CreateNot(bits));
810}
811
812Value * CBuilder::CreateExtractBitField(Value * bits, Value * start, Value * length) {
813    Constant * One = ConstantInt::get(bits->getType(), 1);
814    return CreateAnd(CreateLShr(bits, start), CreateSub(CreateShl(One, length), One));
815}
816
817Value * CBuilder::CreateCeilLog2(Value * value) {
818    IntegerType * ty = cast<IntegerType>(value->getType());
819    CreateAssert(value, "CreateCeilLog2: value cannot be zero");
820    Value * m = CreateCountReverseZeroes(CreateSub(value, ConstantInt::get(ty, 1)));
821    return CreateSub(ConstantInt::get(m->getType(), ty->getBitWidth() - 1), m);
822}
823
824Value * CBuilder::GetString(StringRef Str) {
825    Module * const m = getModule();
826    Value * ptr = m->getGlobalVariable(Str, true);
827    if (ptr == nullptr) {
828        ptr = CreateGlobalString(Str, Str);
829    }
830    Value * zero = getInt32(0);
831    return CreateInBoundsGEP(ptr, { zero, zero });
832}
833
834Value * CBuilder::CreateReadCycleCounter() {
835    Module * const m = getModule();
836    Value * cycleCountFunc = Intrinsic::getDeclaration(m, Intrinsic::readcyclecounter);
837    return CreateCall(cycleCountFunc, std::vector<Value *>({}));
838}
839
840Function * CBuilder::LinkFunction(StringRef name, FunctionType * type, void * functionPtr) const {
841    assert (mDriver);
842    return mDriver->addLinkFunction(getModule(), name, type, functionPtr);
843}
844
845#ifdef HAS_ADDRESS_SANITIZER
846
847#define CHECK_ADDRESS(Ptr) \
848    if (codegen::EnableAsserts) { \
849        Module * const m = getModule(); \
850        PointerType * voidPtrTy = getVoidPtrTy(); \
851        IntegerType * sizeTy = getSizeTy(); \
852        Function * isPoisoned = m->getFunction("__asan_region_is_poisoned"); \
853        if (isPoisoned == nullptr) { \
854            auto isPoisonedTy = FunctionType::get(voidPtrTy, {voidPtrTy, sizeTy}, false); \
855            isPoisoned = Function::Create(isPoisonedTy, Function::ExternalLinkage, "__asan_region_is_poisoned", m); \
856        } \
857        Value * const addr = CreatePointerCast(Ptr, voidPtrTy); \
858        Constant * const size = ConstantInt::get(sizeTy, Ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits()); \
859        Value * check = CreateCall(isPoisoned, { addr, size }); \
860        check = CreateICmpEQ(check, ConstantPointerNull::get(voidPtrTy)); \
861        CreateAssert(check, "Valid memory address"); \
862    }
863
864LoadInst * CBuilder::CreateLoad(Value *Ptr, const char * Name) {
865    CHECK_ADDRESS(Ptr);
866    return IRBuilder<>::CreateLoad(Ptr, Name);
867}
868
869LoadInst * CBuilder::CreateLoad(Value * Ptr, const Twine & Name) {
870    CHECK_ADDRESS(Ptr);
871    return IRBuilder<>::CreateLoad(Ptr, Name);
872}
873
874LoadInst * CBuilder::CreateLoad(Type *Ty, Value *Ptr, const Twine & Name) {
875    CHECK_ADDRESS(Ptr);
876    return IRBuilder<>::CreateLoad(Ty, Ptr, Name);
877}
878
879LoadInst * CBuilder::CreateLoad(Value *Ptr, bool isVolatile, const Twine & Name) {
880    CHECK_ADDRESS(Ptr);
881    return IRBuilder<>::CreateLoad(Ptr, isVolatile, Name);
882}
883
884StoreInst * CBuilder::CreateStore(Value * Val, Value * Ptr, bool isVolatile) {
885    CHECK_ADDRESS(Ptr);
886    return IRBuilder<>::CreateStore(Val, Ptr, isVolatile);
887}
888
889#undef CHECK_ADDRESS
890
891#endif
892
893CBuilder::CBuilder(LLVMContext & C, const unsigned GeneralRegisterWidthInBits)
894: IRBuilder<>(C)
895, mCacheLineAlignment(64)
896, mSizeType(getIntNTy(GeneralRegisterWidthInBits))
897, mFILEtype(nullptr)
898, mDriver(nullptr) {
899
900}
Note: See TracBrowser for help on using the repository browser.