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

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

Potential bug fix for 32-bit. Modified MRemap to check for Linux OS support. Added MMapAdvise to CBuilder.

File size: 27.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 <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
278Value * CBuilder::CreateMRemap(Value * addr, Value * oldSize, Value * newSize) {
279    Triple T(mMod->getTargetTriple());
280    Value * ptr = nullptr;
281    if (T.isOSLinux()) {
282        DataLayout DL(mMod);
283        PointerType * const voidPtrTy = getVoidPtrTy();
284        IntegerType * const sizeTy = getSizeTy();
285        IntegerType * const intTy = getIntPtrTy(DL);
286        Function * fMRemap = mMod->getFunction("mremap");
287        if (LLVM_UNLIKELY(fMRemap == nullptr)) {
288            FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, sizeTy, sizeTy, intTy}, false);
289            fMRemap = Function::Create(fty, Function::ExternalLinkage, "mremap", mMod);
290        }
291        addr = CreatePointerCast(addr, voidPtrTy);
292        oldSize = CreateZExtOrTrunc(oldSize, sizeTy);
293        newSize = CreateZExtOrTrunc(newSize, sizeTy);
294        ConstantInt * const flags = ConstantInt::get(intTy, MREMAP_MAYMOVE);
295        ptr = CreateCall(fMRemap, {addr, oldSize, newSize, flags});
296        if (codegen::EnableAsserts) {
297            CreateAssert(CheckMMapSuccess(ptr), "CreateMRemap: mremap failed to allocate memory");
298        }
299    } else { // no OS mremap support
300        ptr = CreateAnonymousMMap(newSize);
301        CreateMemCpy(ptr, addr, oldSize, getpagesize());
302        CreateMUnmap(addr, oldSize);
303    }
304    return ptr;
305}
306
307Value * CBuilder::CreateMUnmap(Value * addr, Value * size) {
308    IntegerType * const sizeTy = getSizeTy();
309    PointerType * const voidPtrTy = getVoidPtrTy();
310    Function * fMUnmap = mMod->getFunction("munmap");
311    if (LLVM_UNLIKELY(fMUnmap == nullptr)) {
312        DataLayout DL(mMod);
313        IntegerType * const intTy = getIntPtrTy(DL);
314        FunctionType * fty = FunctionType::get(intTy, {voidPtrTy, sizeTy}, false);
315        fMUnmap = Function::Create(fty, Function::ExternalLinkage, "munmap", mMod);
316    }
317    if (codegen::EnableAsserts) {
318        Value * const pageOffset = CreateURem(CreatePtrToInt(addr, sizeTy), getSize(getpagesize()));
319        CreateAssert(CreateICmpEQ(pageOffset, getSize(0)), "CreateMUnmap: addr must be a multiple of the page size");
320    }
321    addr = CreatePointerCast(addr, voidPtrTy);
322    size = CreateZExtOrTrunc(size, sizeTy);
323    CallInst * result = CreateCall(fMUnmap, {addr, size});
324    if (codegen::EnableAsserts) {
325        CreateAssert(CreateICmpEQ(result, ConstantInt::getNullValue(result->getType())), "CreateMUnmap: failed");
326    }
327    return result;
328}
329
330void CBuilder::CreateFree(Value * const ptr) {
331    assert (ptr->getType()->isPointerTy());
332    Module * const m = getModule();
333    PointerType * const voidPtrTy = getVoidPtrTy();
334    Function * free = m->getFunction("free");
335    if (free == nullptr) {
336        FunctionType * fty = FunctionType::get(getVoidTy(), {voidPtrTy}, false);
337        free = Function::Create(fty, Function::ExternalLinkage, "free", mMod);
338        free->setCallingConv(CallingConv::C);
339    }
340    CallInst * const ci = CreateCall(free, CreatePointerCast(ptr, voidPtrTy));
341    ci->setTailCall();
342    ci->setCallingConv(free->getCallingConv());
343}
344
345void CBuilder::CreateAlignedFree(Value * const ptr, const bool testForNullAddress) {
346    // WARNING: this will segfault if the value of the ptr at runtime is null but testForNullAddress was not set
347    PointerType * type = cast<PointerType>(ptr->getType());
348    BasicBlock * exit = nullptr;
349    if (testForNullAddress) {
350        LLVMContext & C = getContext();
351        BasicBlock * bb = GetInsertBlock();
352        Function * f = bb->getParent();
353        exit = BasicBlock::Create(C, "", f, bb);
354        BasicBlock * entry = BasicBlock::Create(C, "", f, exit);
355        Value * cond = CreateICmpEQ(ptr, ConstantPointerNull::get(type));
356        CreateCondBr(cond, exit, entry);
357        SetInsertPoint(entry);
358    }
359    DataLayout DL(getModule());
360    IntegerType * const intTy = getIntPtrTy(DL);
361    const auto byteWidth = (intTy->getBitWidth() / 8);
362    Value * prefix = CreatePtrToInt(ptr, intTy);
363    prefix = CreateSub(prefix, ConstantInt::get(intTy, byteWidth));
364    prefix = CreateIntToPtr(prefix, intTy->getPointerTo());
365    prefix = CreateIntToPtr(CreateAlignedLoad(prefix, byteWidth), type);
366    CreateFree(prefix);
367    if (testForNullAddress) {
368        CreateBr(exit);
369        SetInsertPoint(exit);
370    }
371}
372
373Value * CBuilder::CreateRealloc(Value * ptr, Value * size) {
374    DataLayout DL(getModule());
375    IntegerType * const intTy = getIntPtrTy(DL);
376    PointerType * type = cast<PointerType>(ptr->getType());
377    if (size->getType() != intTy) {
378        if (isa<Constant>(size)) {
379            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
380        } else {
381            size = CreateZExtOrTrunc(size, intTy);
382        }
383    }
384    Module * const m = getModule();
385    Function * realloc = m->getFunction("realloc");
386    if (realloc == nullptr) {
387        PointerType * const voidPtrTy = getVoidPtrTy();
388        FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, intTy}, false);
389        realloc = Function::Create(fty, Function::ExternalLinkage, "realloc", mMod);
390        realloc->setCallingConv(CallingConv::C);
391        realloc->setDoesNotAlias(1);
392    }
393    assert (size->getType() == intTy);
394    CallInst * ci = CreateCall(realloc, {ptr, size});
395    ci->setTailCall();
396    ci->setCallingConv(realloc->getCallingConv());
397    return CreateBitOrPointerCast(ci, type);
398}
399
400PointerType * CBuilder::getVoidPtrTy() const {
401    return TypeBuilder<void *, true>::get(getContext());
402}
403
404LoadInst * CBuilder::CreateAtomicLoadAcquire(Value * ptr) {
405    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
406    LoadInst * inst = CreateAlignedLoad(ptr, alignment);
407    inst->setOrdering(AtomicOrdering::Acquire);
408    return inst;
409   
410}
411
412StoreInst * CBuilder::CreateAtomicStoreRelease(Value * val, Value * ptr) {
413    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
414    StoreInst * inst = CreateAlignedStore(val, ptr, alignment);
415    inst->setOrdering(AtomicOrdering::Release);
416    return inst;
417}
418
419PointerType * CBuilder::getFILEptrTy() {
420    if (mFILEtype == nullptr) {
421        mFILEtype = StructType::create(getContext(), "struct._IO_FILE");
422    }
423    return mFILEtype->getPointerTo();
424}
425
426Value * CBuilder::CreateFOpenCall(Value * filename, Value * mode) {
427    Function * fOpenFunc = mMod->getFunction("fopen");
428    if (fOpenFunc == nullptr) {
429        FunctionType * fty = FunctionType::get(getFILEptrTy(), {getInt8Ty()->getPointerTo(), getInt8Ty()->getPointerTo()}, false);
430        fOpenFunc = Function::Create(fty, Function::ExternalLinkage, "fopen", mMod);
431        fOpenFunc->setCallingConv(CallingConv::C);
432    }
433    return CreateCall(fOpenFunc, {filename, mode});
434}
435
436Value * CBuilder::CreateFReadCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
437    Function * fReadFunc = mMod->getFunction("fread");
438    PointerType * const voidPtrTy = getVoidPtrTy();
439    if (fReadFunc == nullptr) {
440        IntegerType * const sizeTy = getSizeTy();
441        FunctionType * fty = FunctionType::get(sizeTy, {voidPtrTy, sizeTy, sizeTy, getFILEptrTy()}, false);
442        fReadFunc = Function::Create(fty, Function::ExternalLinkage, "fread", mMod);
443        fReadFunc->setCallingConv(CallingConv::C);
444    }
445    ptr = CreatePointerCast(ptr, voidPtrTy);
446    return CreateCall(fReadFunc, {ptr, size, nitems, stream});
447}
448
449Value * CBuilder::CreateFWriteCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
450    Function * fWriteFunc = mMod->getFunction("fwrite");
451    PointerType * const voidPtrTy = getVoidPtrTy();
452    if (fWriteFunc == nullptr) {
453        IntegerType * const sizeTy = getSizeTy();
454        FunctionType * fty = FunctionType::get(sizeTy, {voidPtrTy, sizeTy, sizeTy, getFILEptrTy()}, false);
455        fWriteFunc = Function::Create(fty, Function::ExternalLinkage, "fwrite", mMod);
456        fWriteFunc->setCallingConv(CallingConv::C);
457    }
458    ptr = CreatePointerCast(ptr, voidPtrTy);
459    return CreateCall(fWriteFunc, {ptr, size, nitems, stream});
460}
461
462Value * CBuilder::CreateFCloseCall(Value * stream) {
463    Function * fCloseFunc = mMod->getFunction("fclose");
464    if (fCloseFunc == nullptr) {
465        FunctionType * fty = FunctionType::get(getInt32Ty(), {getFILEptrTy()}, false);
466        fCloseFunc = Function::Create(fty, Function::ExternalLinkage, "fclose", mMod);
467        fCloseFunc->setCallingConv(CallingConv::C);
468    }
469    return CreateCall(fCloseFunc, {stream});
470}
471
472Value * CBuilder::CreatePThreadCreateCall(Value * thread, Value * attr, Function * start_routine, Value * arg) {
473    Type * const voidPtrTy = getVoidPtrTy();
474    Function * pthreadCreateFunc = mMod->getFunction("pthread_create");
475    if (pthreadCreateFunc == nullptr) {
476        Type * pthreadTy = getSizeTy();
477        FunctionType * funVoidPtrVoidTy = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
478        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy->getPointerTo(), voidPtrTy, funVoidPtrVoidTy->getPointerTo(), voidPtrTy}, false);
479        pthreadCreateFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_create", mMod);
480        pthreadCreateFunc->setCallingConv(CallingConv::C);
481    }
482    return CreateCall(pthreadCreateFunc, {thread, attr, start_routine, CreatePointerCast(arg, voidPtrTy)});
483}
484
485Value * CBuilder::CreatePThreadExitCall(Value * value_ptr) {
486    Function * pthreadExitFunc = mMod->getFunction("pthread_exit");
487    if (pthreadExitFunc == nullptr) {
488        FunctionType * fty = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
489        pthreadExitFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_exit", mMod);
490        pthreadExitFunc->addFnAttr(Attribute::NoReturn);
491        pthreadExitFunc->setCallingConv(CallingConv::C);
492    }
493    CallInst * exitThread = CreateCall(pthreadExitFunc, {value_ptr});
494    exitThread->setDoesNotReturn();
495    return exitThread;
496}
497
498Value * CBuilder::CreatePThreadJoinCall(Value * thread, Value * value_ptr){
499    Function * pthreadJoinFunc = mMod->getFunction("pthread_join");
500    if (pthreadJoinFunc == nullptr) {
501        Type * pthreadTy = getSizeTy();
502        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy, getVoidPtrTy()->getPointerTo()}, false);
503        pthreadJoinFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_join", mMod);
504        pthreadJoinFunc->setCallingConv(CallingConv::C);
505    }
506    return CreateCall(pthreadJoinFunc, {thread, value_ptr});
507}
508
509void CBuilder::CreateAssert(Value * const assertion, StringRef failureMessage) {
510    if (codegen::EnableAsserts) {
511        Function * function = mMod->getFunction("__assert");
512        if (LLVM_UNLIKELY(function == nullptr)) {
513            auto ip = saveIP();
514            FunctionType * fty = FunctionType::get(getVoidTy(), { getInt1Ty(), getInt8PtrTy(), getSizeTy() }, false);
515            function = Function::Create(fty, Function::PrivateLinkage, "__assert", mMod);
516            function->setDoesNotThrow();
517            function->setDoesNotAlias(2);
518            BasicBlock * const entry = BasicBlock::Create(getContext(), "", function);
519            BasicBlock * const failure = BasicBlock::Create(getContext(), "", function);
520            BasicBlock * const success = BasicBlock::Create(getContext(), "", function);
521            auto arg = function->arg_begin();
522            arg->setName("assertion");
523            Value * e = &*arg++;
524            arg->setName("msg");
525            Value * msg = &*arg++;
526            arg->setName("sz");
527            Value * sz = &*arg;
528            SetInsertPoint(entry);
529            CreateCondBr(e, failure, success);
530            SetInsertPoint(failure);
531            Value * len = CreateAdd(sz, getSize(21));
532            ConstantInt * _11 = getSize(11);
533            Value * bytes = CreatePointerCast(CreateMalloc(len), getInt8PtrTy());
534            CreateMemCpy(bytes, GetString("Assertion `"), _11, 1);
535            CreateMemCpy(CreateGEP(bytes, _11), msg, sz, 1);
536            CreateMemCpy(CreateGEP(bytes, CreateAdd(sz, _11)), GetString("' failed.\n"), getSize(10), 1);
537            CreateWriteCall(getInt32(2), bytes, len);
538
539
540            CreateExit(-1);
541            CreateBr(success); // necessary to satisfy the LLVM verifier. this is not actually executed.
542            SetInsertPoint(success);
543            CreateRetVoid();
544            restoreIP(ip);
545        }
546        CreateCall(function, {CreateICmpEQ(assertion, Constant::getNullValue(assertion->getType())), GetString(failureMessage), getSize(failureMessage.size())});
547    }
548}
549
550void CBuilder::CreateExit(const int exitCode) {
551    Function * exit = mMod->getFunction("exit");
552    if (LLVM_UNLIKELY(exit == nullptr)) {
553        FunctionType * fty = FunctionType::get(getVoidTy(), {getInt32Ty()}, false);
554        exit = Function::Create(fty, Function::ExternalLinkage, "exit", mMod);
555        exit->setDoesNotReturn();
556        exit->setDoesNotThrow();
557    }
558    CreateCall(exit, getInt32(exitCode));
559}
560
561BranchInst * CBuilder::CreateLikelyCondBr(Value * Cond, BasicBlock * True, BasicBlock * False, const int probability) {
562    MDBuilder mdb(getContext());
563    if (probability < 0 || probability > 100) {
564        report_fatal_error("branch weight probability must be in [0,100]");
565    }
566    return CreateCondBr(Cond, True, False, mdb.createBranchWeights(probability, 100 - probability));
567}
568
569inline static unsigned ceil_log2(const unsigned v) {
570    assert ("log2(0) is undefined!" && v != 0);
571    return 32 - __builtin_clz(v - 1);
572}
573
574Value * CBuilder::CreatePopcount(Value * bits) {
575    Value * ctpopFunc = Intrinsic::getDeclaration(mMod, Intrinsic::ctpop, bits->getType());
576    return CreateCall(ctpopFunc, bits);
577}
578
579Value * CBuilder::CreateCountForwardZeroes(Value * value) {
580    Value * cttzFunc = Intrinsic::getDeclaration(mMod, Intrinsic::cttz, value->getType());
581    return CreateCall(cttzFunc, {value, ConstantInt::getFalse(getContext())});
582}
583
584Value * CBuilder::CreateCountReverseZeroes(Value * value) {
585    Value * ctlzFunc = Intrinsic::getDeclaration(mMod, Intrinsic::ctlz, value->getType());
586    return CreateCall(ctlzFunc, {value, ConstantInt::getFalse(getContext())});
587}
588
589Value * CBuilder::CreateCeilLog2(Value * value) {
590    IntegerType * ty = cast<IntegerType>(value->getType());
591    CreateAssert(value, "CreateCeilLog2: value cannot be zero");
592    Value * m = CreateCountForwardZeroes(CreateSub(value, ConstantInt::get(ty, 1)));
593    return CreateSub(ConstantInt::get(m->getType(), ty->getBitWidth() - 1), m);
594}
595
596Value * CBuilder::GetString(StringRef Str) {
597    Value * ptr = mMod->getGlobalVariable(Str, true);
598    if (ptr == nullptr) {
599        ptr = CreateGlobalString(Str, Str);
600    }
601    Value * zero = getInt32(0);
602    return CreateInBoundsGEP(ptr, { zero, zero });
603}
604
605CBuilder::CBuilder(Module * const m, const unsigned GeneralRegisterWidthInBits, const bool SupportsIndirectBr, const unsigned CacheLineAlignmentInBytes)
606: IRBuilder<>(m->getContext())
607, mMod(m)
608, mCacheLineAlignment(CacheLineAlignmentInBytes)
609, mSizeType(getIntNTy(GeneralRegisterWidthInBits))
610, mFILEtype(nullptr)
611, mSupportsIndirectBr(SupportsIndirectBr) {
612}
Note: See TracBrowser for help on using the repository browser.