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

Last change on this file since 5486 was 5486, checked in by nmedfort, 2 years 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.