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

Last change on this file since 5415 was 5415, checked in by cameron, 2 years ago

Speed-up file output using new temporary files; unlinking old files

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