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

Last change on this file since 5412 was 5412, checked in by nmedfort, 2 years ago

Fix for compiling in Darwin

File size: 27.5 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 <kernels/toolchain.h>
15#include <fcntl.h>
16#include <unistd.h>
17#include <sys/mman.h>
18#include <errno.h>
19#include <llvm/ADT/Triple.h>
20
21using namespace llvm;
22
23Value * CBuilder::CreateOpenCall(Value * filename, Value * oflag, Value * mode) {
24    Function * openFn = mMod->getFunction("open");
25    if (openFn == nullptr) {
26        IntegerType * int32Ty = getInt32Ty();
27        PointerType * int8PtrTy = getInt8PtrTy();
28        openFn = cast<Function>(mMod->getOrInsertFunction("open",
29                                                         int32Ty, int8PtrTy, int32Ty, int32Ty, nullptr));
30    }
31    return CreateCall(openFn, {filename, oflag, mode});
32}
33
34// ssize_t write(int fildes, const void *buf, size_t nbyte);
35Value * CBuilder::CreateWriteCall(Value * fildes, Value * buf, Value * nbyte) {
36    Function * write = mMod->getFunction("write");
37    if (write == nullptr) {
38        IntegerType * sizeTy = getSizeTy();
39        IntegerType * int32Ty = getInt32Ty();
40        PointerType * int8PtrTy = getInt8PtrTy();
41        write = cast<Function>(mMod->getOrInsertFunction("write",
42                                                        AttributeSet().addAttribute(mMod->getContext(), 2U, Attribute::NoAlias),
43                                                        sizeTy, int32Ty, int8PtrTy, sizeTy, nullptr));
44    }
45    return CreateCall(write, {fildes, buf, nbyte});
46}
47
48Value * CBuilder::CreateReadCall(Value * fildes, Value * buf, Value * nbyte) {
49    Function * readFn = mMod->getFunction("read");
50    if (readFn == nullptr) {
51        IntegerType * sizeTy = getSizeTy();
52        IntegerType * int32Ty = getInt32Ty();
53        PointerType * int8PtrTy = getInt8PtrTy();
54        readFn = cast<Function>(mMod->getOrInsertFunction("read",
55                                                         AttributeSet().addAttribute(mMod->getContext(), 2U, Attribute::NoAlias),
56                                                         sizeTy, int32Ty, int8PtrTy, sizeTy, nullptr));
57    }
58    return CreateCall(readFn, {fildes, buf, nbyte});
59}
60
61Value * CBuilder::CreateCloseCall(Value * fildes) {
62    Function * closeFn = mMod->getFunction("close");
63    if (closeFn == nullptr) {
64        IntegerType * int32Ty = getInt32Ty();
65        FunctionType * fty = FunctionType::get(int32Ty, {int32Ty}, true);
66        closeFn = Function::Create(fty, Function::ExternalLinkage, "close", mMod);
67    }
68    return CreateCall(closeFn, {fildes});
69}
70
71Function * CBuilder::GetPrintf() {
72    Function * printf = mMod->getFunction("printf");
73    if (printf == nullptr) {
74        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt8PtrTy()}, true);
75        printf = Function::Create(fty, Function::ExternalLinkage, "printf", mMod);
76        printf->addAttribute(1, Attribute::NoAlias);
77    }
78    return printf;
79}
80
81void CBuilder::CallPrintInt(const std::string & name, Value * const value) {
82    Constant * printRegister = mMod->getFunction("PrintInt");
83    IntegerType * int64Ty = getInt64Ty();
84    if (LLVM_UNLIKELY(printRegister == nullptr)) {
85        FunctionType *FT = FunctionType::get(getVoidTy(), { getInt8PtrTy(), int64Ty }, false);
86        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintInt", mMod);
87        auto arg = function->arg_begin();
88        std::string out = "%-40s = %" PRIx64 "\n";
89        BasicBlock * entry = BasicBlock::Create(mMod->getContext(), "entry", function);
90        IRBuilder<> builder(entry);
91        std::vector<Value *> args;
92        args.push_back(GetString(out.c_str()));
93        Value * const name = &*(arg++);
94        name->setName("name");
95        args.push_back(name);
96        Value * value = &*arg;
97        value->setName("value");
98        args.push_back(value);
99        builder.CreateCall(GetPrintf(), args);
100        builder.CreateRetVoid();
101
102        printRegister = function;
103    }
104    Value * num = nullptr;
105    if (value->getType()->isPointerTy()) {
106        num = CreatePtrToInt(value, int64Ty);
107    } else {
108        num = CreateZExtOrBitCast(value, int64Ty);
109    }
110    assert (num->getType()->isIntegerTy());
111    CreateCall(printRegister, {GetString(name.c_str()), num});
112}
113
114Value * CBuilder::CreateMalloc(Value * size) {
115    Module * const m = getModule();
116    DataLayout DL(m);
117    IntegerType * const intTy = getIntPtrTy(DL);
118    if (size->getType() != intTy) {
119        if (isa<Constant>(size)) {
120            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
121        } else {
122            size = CreateZExtOrTrunc(size, intTy);
123        }
124    }   
125    PointerType * const voidPtrTy = getVoidPtrTy();
126    Function * malloc = m->getFunction("malloc");
127    if (malloc == nullptr) {
128        FunctionType * fty = FunctionType::get(voidPtrTy, {intTy}, false);
129        malloc = Function::Create(fty, Function::ExternalLinkage, "malloc", mMod);
130        malloc->setCallingConv(CallingConv::C);
131        malloc->setDoesNotAlias(0);
132    }
133    assert (size->getType() == intTy);
134    CallInst * ci = CreateCall(malloc, size); assert (ci);
135    ci->setTailCall();
136    ci->setCallingConv(malloc->getCallingConv());
137    Value * ptr = CreatePointerCast(ci, voidPtrTy); assert (ptr);
138    CreateAssert(ptr, "FATAL ERROR: out of memory");
139    return ptr;
140}
141
142Value * CBuilder::CreateAlignedMalloc(Value * size, const unsigned alignment) {
143    if (LLVM_UNLIKELY((alignment & (alignment - 1)) != 0)) {
144        report_fatal_error("CreateAlignedMalloc: alignment must be a power of 2");
145    }
146    DataLayout DL(mMod);
147    IntegerType * const intTy = getIntPtrTy(DL);
148    Function * aligned_malloc = mMod->getFunction("aligned_malloc" + std::to_string(alignment));
149    if (LLVM_UNLIKELY(aligned_malloc == nullptr)) {
150        const auto ip = saveIP();
151        PointerType * const voidPtrTy = getVoidPtrTy();
152        FunctionType * fty = FunctionType::get(voidPtrTy, {intTy}, false);
153        aligned_malloc = Function::Create(fty, Function::InternalLinkage, "aligned_malloc" + std::to_string(alignment), mMod);
154        aligned_malloc->setCallingConv(CallingConv::C);
155        aligned_malloc->setDoesNotAlias(0);
156        aligned_malloc->addFnAttr(Attribute::AlwaysInline);
157        Value * size = &*aligned_malloc->arg_begin();
158        SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", aligned_malloc));
159        const auto byteWidth = (intTy->getBitWidth() / 8);
160        Constant * const offset = ConstantInt::get(intTy, alignment + byteWidth - 1);
161        size = CreateAdd(size, offset);
162        Value * unaligned = CreatePtrToInt(CreateMalloc(size), intTy);
163        Value * aligned = CreateAnd(CreateAdd(unaligned, offset), ConstantExpr::getNot(ConstantInt::get(intTy, alignment - 1)));
164        Value * prefix = CreateIntToPtr(CreateSub(aligned, ConstantInt::get(intTy, byteWidth)), intTy->getPointerTo());
165        assert (unaligned->getType() == prefix->getType()->getPointerElementType());
166        CreateAlignedStore(unaligned, prefix, byteWidth);
167        CreateRet(CreateIntToPtr(aligned, voidPtrTy));
168        restoreIP(ip);
169    }
170    return CreateCall(aligned_malloc, {CreateZExtOrTrunc(size, intTy)});
171}
172
173Value * CBuilder::CreateAnonymousMMap(Value * size) {
174    PointerType * const voidPtrTy = getVoidPtrTy();
175    IntegerType * const intTy = getInt32Ty();
176    IntegerType * const sizeTy = getSizeTy();
177    size = CreateZExtOrTrunc(size, sizeTy);
178    ConstantInt * const prot =  ConstantInt::get(intTy, PROT_READ | PROT_WRITE);
179    ConstantInt * const flags =  ConstantInt::get(intTy, MAP_PRIVATE | MAP_ANON);
180    ConstantInt * const fd =  ConstantInt::get(intTy, -1);
181    Constant * const offset = ConstantInt::get(sizeTy, 0);
182    return CreateMMap(ConstantPointerNull::getNullValue(voidPtrTy), size, prot, flags, fd, offset);
183}
184
185Value * CBuilder::CreateFileSourceMMap(Value * const fd, Value * size) {
186    PointerType * const voidPtrTy = getVoidPtrTy();
187    IntegerType * const intTy = getInt32Ty();
188    IntegerType * const sizeTy = getSizeTy();
189    size = CreateZExtOrTrunc(size, sizeTy);
190    ConstantInt * const prot =  ConstantInt::get(intTy, PROT_READ);
191    ConstantInt * const flags =  ConstantInt::get(intTy, MAP_PRIVATE);
192    Constant * const offset = ConstantInt::get(sizeTy, 0);
193    return CreateMMap(ConstantPointerNull::getNullValue(voidPtrTy), size, prot, flags, fd, offset);
194}
195
196Value * CBuilder::CreateMMap(Value * const addr, Value * size, Value * const prot, Value * const flags, Value * const fd, Value * const offset) {
197    Function * fMMap = mMod->getFunction("mmap");
198    if (LLVM_UNLIKELY(fMMap == nullptr)) {
199        PointerType * const voidPtrTy = getVoidPtrTy();
200        IntegerType * const intTy = getInt32Ty();
201        IntegerType * const sizeTy = getSizeTy();
202        FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, sizeTy, intTy, intTy, intTy, sizeTy}, false);
203        fMMap = Function::Create(fty, Function::ExternalLinkage, "mmap", mMod);
204    }
205    Value * ptr = CreateCall(fMMap, {addr, size, prot, flags, fd, offset});
206    if (codegen::EnableAsserts) {
207        CreateAssert(CheckMMapSuccess(ptr), "CreateMMap: mmap failed to allocate memory");
208    }
209    return ptr;
210}
211
212/*
213    MADV_NORMAL
214        No special treatment. This is the default.
215    MADV_RANDOM
216        Expect page references in random order. (Hence, read ahead may be less useful than normally.)
217    MADV_SEQUENTIAL
218        Expect page references in sequential order. (Hence, pages in the given range can be aggressively read ahead, and may be freed
219        soon after they are accessed.)
220    MADV_WILLNEED
221        Expect access in the near future. (Hence, it might be a good idea to read some pages ahead.)
222    MADV_DONTNEED
223        Do not expect access in the near future. (For the time being, the application is finished with the given range, so the kernel
224        can free resources associated with it.) Subsequent accesses of pages in this range will succeed, but will result either in
225        reloading of the memory contents from the underlying mapped file (see mmap(2)) or zero-fill-on-demand pages for mappings
226        without an underlying file.
227*/
228
229Value * CBuilder::CreateMMapAdvise(Value * addr, Value * length, std::initializer_list<MADV> advice) {
230    Triple T(mMod->getTargetTriple());
231    Value * result = nullptr;
232    if (T.isOSLinux()) {
233        DataLayout DL(mMod);
234        IntegerType * const intTy = getIntPtrTy(DL);
235        IntegerType * const sizeTy = getSizeTy();
236        PointerType * const voidPtrTy = getVoidPtrTy();
237        Function * MAdviseFunc = mMod->getFunction("madvise");
238        if (LLVM_UNLIKELY(MAdviseFunc == nullptr)) {
239            FunctionType * fty = FunctionType::get(intTy, {voidPtrTy, sizeTy, intTy}, false);
240            MAdviseFunc = Function::Create(fty, Function::ExternalLinkage, "madvise", mMod);
241        }
242        addr = CreatePointerCast(addr, voidPtrTy);
243        length = CreateZExtOrTrunc(length, sizeTy);
244        int adviceFlags = 0;
245        for (const MADV adv : advice) {
246            switch (adv) {
247                case MADV::NORMAL: adviceFlags |= MADV_NORMAL; break;
248                case MADV::RANDOM: adviceFlags |= MADV_RANDOM; break;
249                case MADV::SEQUENTIAL: adviceFlags |= MADV_SEQUENTIAL; break;
250                case MADV::DONTNEED: adviceFlags |= MADV_DONTNEED; break;
251                case MADV::WILLNEED: adviceFlags |= MADV_WILLNEED; break;
252//                case MADV::REMOVE: adviceFlags |= MADV_REMOVE; break;
253//                case MADV::DONTFORK: adviceFlags |= MADV_DONTFORK; break;
254//                case MADV::DOFORK: adviceFlags |= MADV_DOFORK; break;
255//                case MADV::HWPOISON: adviceFlags |= MADV_HWPOISON; break;
256//                case MADV::MERGEABLE: adviceFlags |= MADV_MERGEABLE; break;
257//                case MADV::UNMERGEABLE: adviceFlags |= MADV_UNMERGEABLE; break;
258//                case MADV::HUGEPAGE: adviceFlags |= MADV_HUGEPAGE; break;
259//                case MADV::NOHUGEPAGE: adviceFlags |= MADV_NOHUGEPAGE; break;
260//                case MADV::DONTDUMP: adviceFlags |= MADV_DONTDUMP; break;
261//                case MADV::DODUMP: adviceFlags |= MADV_DODUMP; break;
262            }
263        }
264        result = CreateCall(MAdviseFunc, {addr, length, ConstantInt::get(intTy, adviceFlags)});
265        if (codegen::EnableAsserts) {
266            CreateAssert(CreateICmpEQ(result, ConstantInt::getNullValue(result->getType())), "CreateMMapAdvise: failed");
267        }
268    }
269    return result;
270}
271
272Value * CBuilder::CheckMMapSuccess(Value * const addr) {
273    DataLayout DL(mMod);
274    IntegerType * const intTy = getIntPtrTy(DL);
275    return CreateICmpNE(CreatePtrToInt(addr, intTy), ConstantInt::getAllOnesValue(intTy)); // MAP_FAILED = -1
276}
277
278#ifndef MREMAP_MAYMOVE
279#define MREMAP_MAYMOVE  1
280#endif
281
282Value * CBuilder::CreateMRemap(Value * addr, Value * oldSize, Value * newSize) {
283    Triple T(mMod->getTargetTriple());
284    Value * ptr = nullptr;
285    if (T.isOSLinux()) {
286        DataLayout DL(mMod);
287        PointerType * const voidPtrTy = getVoidPtrTy();
288        IntegerType * const sizeTy = getSizeTy();
289        IntegerType * const intTy = getIntPtrTy(DL);
290        Function * fMRemap = mMod->getFunction("mremap");
291        if (LLVM_UNLIKELY(fMRemap == nullptr)) {
292            FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, sizeTy, sizeTy, intTy}, false);
293            fMRemap = Function::Create(fty, Function::ExternalLinkage, "mremap", mMod);
294        }
295        addr = CreatePointerCast(addr, voidPtrTy);
296        oldSize = CreateZExtOrTrunc(oldSize, sizeTy);
297        newSize = CreateZExtOrTrunc(newSize, sizeTy);
298        ConstantInt * const flags = ConstantInt::get(intTy, MREMAP_MAYMOVE);
299        ptr = CreateCall(fMRemap, {addr, oldSize, newSize, flags});
300        if (codegen::EnableAsserts) {
301            CreateAssert(CheckMMapSuccess(ptr), "CreateMRemap: mremap failed to allocate memory");
302        }
303    } else { // no OS mremap support
304        ptr = CreateAnonymousMMap(newSize);
305        CreateMemCpy(ptr, addr, oldSize, getpagesize());
306        CreateMUnmap(addr, oldSize);
307    }
308    return ptr;
309}
310
311Value * CBuilder::CreateMUnmap(Value * addr, Value * size) {
312    IntegerType * const sizeTy = getSizeTy();
313    PointerType * const voidPtrTy = getVoidPtrTy();
314    Function * fMUnmap = mMod->getFunction("munmap");
315    if (LLVM_UNLIKELY(fMUnmap == nullptr)) {
316        DataLayout DL(mMod);
317        IntegerType * const intTy = getIntPtrTy(DL);
318        FunctionType * fty = FunctionType::get(intTy, {voidPtrTy, sizeTy}, false);
319        fMUnmap = Function::Create(fty, Function::ExternalLinkage, "munmap", mMod);
320    }
321    if (codegen::EnableAsserts) {
322        Value * const pageOffset = CreateURem(CreatePtrToInt(addr, sizeTy), getSize(getpagesize()));
323        CreateAssert(CreateICmpEQ(pageOffset, getSize(0)), "CreateMUnmap: addr must be a multiple of the page size");
324    }
325    addr = CreatePointerCast(addr, voidPtrTy);
326    size = CreateZExtOrTrunc(size, sizeTy);
327    CallInst * result = CreateCall(fMUnmap, {addr, size});
328    if (codegen::EnableAsserts) {
329        CreateAssert(CreateICmpEQ(result, ConstantInt::getNullValue(result->getType())), "CreateMUnmap: failed");
330    }
331    return result;
332}
333
334void CBuilder::CreateFree(Value * const ptr) {
335    assert (ptr->getType()->isPointerTy());
336    Module * const m = getModule();
337    PointerType * const voidPtrTy = getVoidPtrTy();
338    Function * free = m->getFunction("free");
339    if (free == nullptr) {
340        FunctionType * fty = FunctionType::get(getVoidTy(), {voidPtrTy}, false);
341        free = Function::Create(fty, Function::ExternalLinkage, "free", mMod);
342        free->setCallingConv(CallingConv::C);
343    }
344    CallInst * const ci = CreateCall(free, CreatePointerCast(ptr, voidPtrTy));
345    ci->setTailCall();
346    ci->setCallingConv(free->getCallingConv());
347}
348
349void CBuilder::CreateAlignedFree(Value * const ptr, const bool testForNullAddress) {
350    // WARNING: this will segfault if the value of the ptr at runtime is null but testForNullAddress was not set
351    PointerType * type = cast<PointerType>(ptr->getType());
352    BasicBlock * exit = nullptr;
353    if (testForNullAddress) {
354        LLVMContext & C = getContext();
355        BasicBlock * bb = GetInsertBlock();
356        Function * f = bb->getParent();
357        exit = BasicBlock::Create(C, "", f, bb);
358        BasicBlock * entry = BasicBlock::Create(C, "", f, exit);
359        Value * cond = CreateICmpEQ(ptr, ConstantPointerNull::get(type));
360        CreateCondBr(cond, exit, entry);
361        SetInsertPoint(entry);
362    }
363    DataLayout DL(getModule());
364    IntegerType * const intTy = getIntPtrTy(DL);
365    const auto byteWidth = (intTy->getBitWidth() / 8);
366    Value * prefix = CreatePtrToInt(ptr, intTy);
367    prefix = CreateSub(prefix, ConstantInt::get(intTy, byteWidth));
368    prefix = CreateIntToPtr(prefix, intTy->getPointerTo());
369    prefix = CreateIntToPtr(CreateAlignedLoad(prefix, byteWidth), type);
370    CreateFree(prefix);
371    if (testForNullAddress) {
372        CreateBr(exit);
373        SetInsertPoint(exit);
374    }
375}
376
377Value * CBuilder::CreateRealloc(Value * ptr, Value * size) {
378    DataLayout DL(getModule());
379    IntegerType * const intTy = getIntPtrTy(DL);
380    PointerType * type = cast<PointerType>(ptr->getType());
381    if (size->getType() != intTy) {
382        if (isa<Constant>(size)) {
383            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
384        } else {
385            size = CreateZExtOrTrunc(size, intTy);
386        }
387    }
388    Module * const m = getModule();
389    Function * realloc = m->getFunction("realloc");
390    if (realloc == nullptr) {
391        PointerType * const voidPtrTy = getVoidPtrTy();
392        FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, intTy}, false);
393        realloc = Function::Create(fty, Function::ExternalLinkage, "realloc", mMod);
394        realloc->setCallingConv(CallingConv::C);
395        realloc->setDoesNotAlias(1);
396    }
397    assert (size->getType() == intTy);
398    CallInst * ci = CreateCall(realloc, {ptr, size});
399    ci->setTailCall();
400    ci->setCallingConv(realloc->getCallingConv());
401    return CreateBitOrPointerCast(ci, type);
402}
403
404PointerType * CBuilder::getVoidPtrTy() const {
405    return TypeBuilder<void *, true>::get(getContext());
406}
407
408LoadInst * CBuilder::CreateAtomicLoadAcquire(Value * ptr) {
409    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
410    LoadInst * inst = CreateAlignedLoad(ptr, alignment);
411    inst->setOrdering(AtomicOrdering::Acquire);
412    return inst;
413   
414}
415
416StoreInst * CBuilder::CreateAtomicStoreRelease(Value * val, Value * ptr) {
417    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
418    StoreInst * inst = CreateAlignedStore(val, ptr, alignment);
419    inst->setOrdering(AtomicOrdering::Release);
420    return inst;
421}
422
423PointerType * CBuilder::getFILEptrTy() {
424    if (mFILEtype == nullptr) {
425        mFILEtype = StructType::create(getContext(), "struct._IO_FILE");
426    }
427    return mFILEtype->getPointerTo();
428}
429
430Value * CBuilder::CreateFOpenCall(Value * filename, Value * mode) {
431    Function * fOpenFunc = mMod->getFunction("fopen");
432    if (fOpenFunc == nullptr) {
433        FunctionType * fty = FunctionType::get(getFILEptrTy(), {getInt8Ty()->getPointerTo(), getInt8Ty()->getPointerTo()}, false);
434        fOpenFunc = Function::Create(fty, Function::ExternalLinkage, "fopen", mMod);
435        fOpenFunc->setCallingConv(CallingConv::C);
436    }
437    return CreateCall(fOpenFunc, {filename, mode});
438}
439
440Value * CBuilder::CreateFReadCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
441    Function * fReadFunc = mMod->getFunction("fread");
442    PointerType * const voidPtrTy = getVoidPtrTy();
443    if (fReadFunc == nullptr) {
444        IntegerType * const sizeTy = getSizeTy();
445        FunctionType * fty = FunctionType::get(sizeTy, {voidPtrTy, sizeTy, sizeTy, getFILEptrTy()}, false);
446        fReadFunc = Function::Create(fty, Function::ExternalLinkage, "fread", mMod);
447        fReadFunc->setCallingConv(CallingConv::C);
448    }
449    ptr = CreatePointerCast(ptr, voidPtrTy);
450    return CreateCall(fReadFunc, {ptr, size, nitems, stream});
451}
452
453Value * CBuilder::CreateFWriteCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
454    Function * fWriteFunc = mMod->getFunction("fwrite");
455    PointerType * const voidPtrTy = getVoidPtrTy();
456    if (fWriteFunc == nullptr) {
457        IntegerType * const sizeTy = getSizeTy();
458        FunctionType * fty = FunctionType::get(sizeTy, {voidPtrTy, sizeTy, sizeTy, getFILEptrTy()}, false);
459        fWriteFunc = Function::Create(fty, Function::ExternalLinkage, "fwrite", mMod);
460        fWriteFunc->setCallingConv(CallingConv::C);
461    }
462    ptr = CreatePointerCast(ptr, voidPtrTy);
463    return CreateCall(fWriteFunc, {ptr, size, nitems, stream});
464}
465
466Value * CBuilder::CreateFCloseCall(Value * stream) {
467    Function * fCloseFunc = mMod->getFunction("fclose");
468    if (fCloseFunc == nullptr) {
469        FunctionType * fty = FunctionType::get(getInt32Ty(), {getFILEptrTy()}, false);
470        fCloseFunc = Function::Create(fty, Function::ExternalLinkage, "fclose", mMod);
471        fCloseFunc->setCallingConv(CallingConv::C);
472    }
473    return CreateCall(fCloseFunc, {stream});
474}
475
476Value * CBuilder::CreatePThreadCreateCall(Value * thread, Value * attr, Function * start_routine, Value * arg) {
477    Type * const voidPtrTy = getVoidPtrTy();
478    Function * pthreadCreateFunc = mMod->getFunction("pthread_create");
479    if (pthreadCreateFunc == nullptr) {
480        Type * pthreadTy = getSizeTy();
481        FunctionType * funVoidPtrVoidTy = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
482        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy->getPointerTo(), voidPtrTy, funVoidPtrVoidTy->getPointerTo(), voidPtrTy}, false);
483        pthreadCreateFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_create", mMod);
484        pthreadCreateFunc->setCallingConv(CallingConv::C);
485    }
486    return CreateCall(pthreadCreateFunc, {thread, attr, start_routine, CreatePointerCast(arg, voidPtrTy)});
487}
488
489Value * CBuilder::CreatePThreadExitCall(Value * value_ptr) {
490    Function * pthreadExitFunc = mMod->getFunction("pthread_exit");
491    if (pthreadExitFunc == nullptr) {
492        FunctionType * fty = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
493        pthreadExitFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_exit", mMod);
494        pthreadExitFunc->addFnAttr(Attribute::NoReturn);
495        pthreadExitFunc->setCallingConv(CallingConv::C);
496    }
497    CallInst * exitThread = CreateCall(pthreadExitFunc, {value_ptr});
498    exitThread->setDoesNotReturn();
499    return exitThread;
500}
501
502Value * CBuilder::CreatePThreadJoinCall(Value * thread, Value * value_ptr){
503    Function * pthreadJoinFunc = mMod->getFunction("pthread_join");
504    if (pthreadJoinFunc == nullptr) {
505        Type * pthreadTy = getSizeTy();
506        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy, getVoidPtrTy()->getPointerTo()}, false);
507        pthreadJoinFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_join", mMod);
508        pthreadJoinFunc->setCallingConv(CallingConv::C);
509    }
510    return CreateCall(pthreadJoinFunc, {thread, value_ptr});
511}
512
513void CBuilder::CreateAssert(Value * const assertion, StringRef failureMessage) {
514    if (codegen::EnableAsserts) {
515        Function * function = mMod->getFunction("__assert");
516        if (LLVM_UNLIKELY(function == nullptr)) {
517            auto ip = saveIP();
518            FunctionType * fty = FunctionType::get(getVoidTy(), { getInt1Ty(), getInt8PtrTy(), getSizeTy() }, false);
519            function = Function::Create(fty, Function::PrivateLinkage, "__assert", mMod);
520            function->setDoesNotThrow();
521            function->setDoesNotAlias(2);
522            BasicBlock * const entry = BasicBlock::Create(getContext(), "", function);
523            BasicBlock * const failure = BasicBlock::Create(getContext(), "", function);
524            BasicBlock * const success = BasicBlock::Create(getContext(), "", function);
525            auto arg = function->arg_begin();
526            arg->setName("assertion");
527            Value * e = &*arg++;
528            arg->setName("msg");
529            Value * msg = &*arg++;
530            arg->setName("sz");
531            Value * sz = &*arg;
532            SetInsertPoint(entry);
533            CreateCondBr(e, failure, success);
534            SetInsertPoint(failure);
535            Value * len = CreateAdd(sz, getSize(21));
536            ConstantInt * _11 = getSize(11);
537            Value * bytes = CreatePointerCast(CreateMalloc(len), getInt8PtrTy());
538            CreateMemCpy(bytes, GetString("Assertion `"), _11, 1);
539            CreateMemCpy(CreateGEP(bytes, _11), msg, sz, 1);
540            CreateMemCpy(CreateGEP(bytes, CreateAdd(sz, _11)), GetString("' failed.\n"), getSize(10), 1);
541            CreateWriteCall(getInt32(2), bytes, len);
542
543
544            CreateExit(-1);
545            CreateBr(success); // necessary to satisfy the LLVM verifier. this is not actually executed.
546            SetInsertPoint(success);
547            CreateRetVoid();
548            restoreIP(ip);
549        }
550        CreateCall(function, {CreateICmpEQ(assertion, Constant::getNullValue(assertion->getType())), GetString(failureMessage), getSize(failureMessage.size())});
551    }
552}
553
554void CBuilder::CreateExit(const int exitCode) {
555    Function * exit = mMod->getFunction("exit");
556    if (LLVM_UNLIKELY(exit == nullptr)) {
557        FunctionType * fty = FunctionType::get(getVoidTy(), {getInt32Ty()}, false);
558        exit = Function::Create(fty, Function::ExternalLinkage, "exit", mMod);
559        exit->setDoesNotReturn();
560        exit->setDoesNotThrow();
561    }
562    CreateCall(exit, getInt32(exitCode));
563}
564
565BranchInst * CBuilder::CreateLikelyCondBr(Value * Cond, BasicBlock * True, BasicBlock * False, const int probability) {
566    MDBuilder mdb(getContext());
567    if (probability < 0 || probability > 100) {
568        report_fatal_error("branch weight probability must be in [0,100]");
569    }
570    return CreateCondBr(Cond, True, False, mdb.createBranchWeights(probability, 100 - probability));
571}
572
573inline static unsigned ceil_log2(const unsigned v) {
574    assert ("log2(0) is undefined!" && v != 0);
575    return 32 - __builtin_clz(v - 1);
576}
577
578Value * CBuilder::CreatePopcount(Value * bits) {
579    Value * ctpopFunc = Intrinsic::getDeclaration(mMod, Intrinsic::ctpop, bits->getType());
580    return CreateCall(ctpopFunc, bits);
581}
582
583Value * CBuilder::CreateCountForwardZeroes(Value * value) {
584    Value * cttzFunc = Intrinsic::getDeclaration(mMod, Intrinsic::cttz, value->getType());
585    return CreateCall(cttzFunc, {value, ConstantInt::getFalse(getContext())});
586}
587
588Value * CBuilder::CreateCountReverseZeroes(Value * value) {
589    Value * ctlzFunc = Intrinsic::getDeclaration(mMod, Intrinsic::ctlz, value->getType());
590    return CreateCall(ctlzFunc, {value, ConstantInt::getFalse(getContext())});
591}
592
593Value * CBuilder::CreateCeilLog2(Value * value) {
594    IntegerType * ty = cast<IntegerType>(value->getType());
595    CreateAssert(value, "CreateCeilLog2: value cannot be zero");
596    Value * m = CreateCountForwardZeroes(CreateSub(value, ConstantInt::get(ty, 1)));
597    return CreateSub(ConstantInt::get(m->getType(), ty->getBitWidth() - 1), m);
598}
599
600Value * CBuilder::GetString(StringRef Str) {
601    Value * ptr = mMod->getGlobalVariable(Str, true);
602    if (ptr == nullptr) {
603        ptr = CreateGlobalString(Str, Str);
604    }
605    Value * zero = getInt32(0);
606    return CreateInBoundsGEP(ptr, { zero, zero });
607}
608
609CBuilder::CBuilder(Module * const m, const unsigned GeneralRegisterWidthInBits, const bool SupportsIndirectBr, const unsigned CacheLineAlignmentInBytes)
610: IRBuilder<>(m->getContext())
611, mMod(m)
612, mCacheLineAlignment(CacheLineAlignmentInBytes)
613, mSizeType(getIntNTy(GeneralRegisterWidthInBits))
614, mFILEtype(nullptr)
615, mSupportsIndirectBr(SupportsIndirectBr) {
616}
Note: See TracBrowser for help on using the repository browser.