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

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

Bug fix for mmap-ing 0-length files

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