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

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

Removed non-functional CUDA code from icgrep and consolidated grep and multigrep mode into a single function; allowed segment parallel pipeline to utilize process as its initial thread; modified MMapSourceKernel to map and perform mmap directly and advise the OS to drop consumed data streams.

File size: 29.9 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    MADV_NORMAL
254        No special treatment. This is the default.
255    MADV_RANDOM
256        Expect page references in random order. (Hence, read ahead may be less useful than normally.)
257    MADV_SEQUENTIAL
258        Expect page references in sequential order. (Hence, pages in the given range can be aggressively read ahead, and may be freed
259        soon after they are accessed.)
260    MADV_WILLNEED
261        Expect access in the near future. (Hence, it might be a good idea to read some pages ahead.)
262    MADV_DONTNEED
263        Do not expect access in the near future. (For the time being, the application is finished with the given range, so the kernel
264        can free resources associated with it.) Subsequent accesses of pages in this range will succeed, but will result either in
265        reloading of the memory contents from the underlying mapped file (see mmap(2)) or zero-fill-on-demand pages for mappings
266        without an underlying file.
267*/
268
269Value * CBuilder::CreateMAdvise(Value * addr, Value * length, std::initializer_list<MAdviceFlags> advice) {
270    Triple T(mMod->getTargetTriple());
271    Value * result = nullptr;
272    if (T.isOSLinux()) {
273        DataLayout DL(mMod);
274        IntegerType * const intTy = getIntPtrTy(DL);
275        IntegerType * const sizeTy = getSizeTy();
276        PointerType * const voidPtrTy = getVoidPtrTy();
277        Function * MAdviseFunc = mMod->getFunction("madvise");
278        if (LLVM_UNLIKELY(MAdviseFunc == nullptr)) {
279            FunctionType * fty = FunctionType::get(intTy, {voidPtrTy, sizeTy, intTy}, false);
280            MAdviseFunc = Function::Create(fty, Function::ExternalLinkage, "madvise", mMod);
281        }
282        addr = CreatePointerCast(addr, voidPtrTy);
283        length = CreateZExtOrTrunc(length, sizeTy);
284        int adviceFlags = 0;
285        for (const MAdviceFlags adv : advice) {
286            switch (adv) {
287                case MAdviceFlags::MMAP_NORMAL: adviceFlags |= MADV_NORMAL; break;
288                case MAdviceFlags::MMAP_RANDOM: adviceFlags |= MADV_RANDOM; break;
289                case MAdviceFlags::MMAP_SEQUENTIAL: adviceFlags |= MADV_SEQUENTIAL; break;
290                case MAdviceFlags::MMAP_DONTNEED: adviceFlags |= MADV_DONTNEED; break;
291                case MAdviceFlags::MMAP_WILLNEED: adviceFlags |= MADV_WILLNEED; break;
292//                case MADV::REMOVE: adviceFlags |= MADV_REMOVE; break;
293//                case MADV::DONTFORK: adviceFlags |= MADV_DONTFORK; break;
294//                case MADV::DOFORK: adviceFlags |= MADV_DOFORK; break;
295//                case MADV::HWPOISON: adviceFlags |= MADV_HWPOISON; break;
296//                case MADV::MERGEABLE: adviceFlags |= MADV_MERGEABLE; break;
297//                case MADV::UNMERGEABLE: adviceFlags |= MADV_UNMERGEABLE; break;
298//                case MADV::HUGEPAGE: adviceFlags |= MADV_HUGEPAGE; break;
299//                case MADV::NOHUGEPAGE: adviceFlags |= MADV_NOHUGEPAGE; break;
300//                case MADV::DONTDUMP: adviceFlags |= MADV_DONTDUMP; break;
301//                case MADV::DODUMP: adviceFlags |= MADV_DODUMP; break;
302            }
303        }
304        result = CreateCall(MAdviseFunc, {addr, length, ConstantInt::get(intTy, adviceFlags)});
305        if (codegen::EnableAsserts) {
306            CreateAssert(CreateICmpEQ(result, ConstantInt::getNullValue(result->getType())), "CreateMMapAdvise: failed");
307        }
308    }
309    return result;
310}
311
312Value * CBuilder::CheckMMapSuccess(Value * const addr) {
313    DataLayout DL(mMod);
314    IntegerType * const intTy = getIntPtrTy(DL);
315    return CreateICmpNE(CreatePtrToInt(addr, intTy), ConstantInt::getAllOnesValue(intTy)); // MAP_FAILED = -1
316}
317
318#ifndef MREMAP_MAYMOVE
319#define MREMAP_MAYMOVE  1
320#endif
321
322Value * CBuilder::CreateMRemap(Value * addr, Value * oldSize, Value * newSize) {
323    Triple T(mMod->getTargetTriple());
324    Value * ptr = nullptr;
325    if (T.isOSLinux()) {
326        DataLayout DL(mMod);
327        PointerType * const voidPtrTy = getVoidPtrTy();
328        IntegerType * const sizeTy = getSizeTy();
329        IntegerType * const intTy = getIntPtrTy(DL);
330        Function * fMRemap = mMod->getFunction("mremap");
331        if (LLVM_UNLIKELY(fMRemap == nullptr)) {
332            FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, sizeTy, sizeTy, intTy}, false);
333            fMRemap = Function::Create(fty, Function::ExternalLinkage, "mremap", mMod);
334        }
335        addr = CreatePointerCast(addr, voidPtrTy);
336        oldSize = CreateZExtOrTrunc(oldSize, sizeTy);
337        newSize = CreateZExtOrTrunc(newSize, sizeTy);
338        ConstantInt * const flags = ConstantInt::get(intTy, MREMAP_MAYMOVE);
339        ptr = CreateCall(fMRemap, {addr, oldSize, newSize, flags});
340        if (codegen::EnableAsserts) {
341            CreateAssert(CheckMMapSuccess(ptr), "CreateMRemap: mremap failed to allocate memory");
342        }
343    } else { // no OS mremap support
344        ptr = CreateAnonymousMMap(newSize);
345        CreateMemCpy(ptr, addr, oldSize, getpagesize());
346        CreateMUnmap(addr, oldSize);
347    }
348    return ptr;
349}
350
351Value * CBuilder::CreateMUnmap(Value * addr, Value * size) {
352    IntegerType * const sizeTy = getSizeTy();
353    PointerType * const voidPtrTy = getVoidPtrTy();
354    Function * fMUnmap = mMod->getFunction("munmap");
355    if (LLVM_UNLIKELY(fMUnmap == nullptr)) {
356        DataLayout DL(mMod);
357        IntegerType * const intTy = getIntPtrTy(DL);
358        FunctionType * fty = FunctionType::get(intTy, {voidPtrTy, sizeTy}, false);
359        fMUnmap = Function::Create(fty, Function::ExternalLinkage, "munmap", mMod);
360    }
361    if (codegen::EnableAsserts) {
362        Value * const pageOffset = CreateURem(CreatePtrToInt(addr, sizeTy), getSize(getpagesize()));
363        CreateAssert(CreateICmpEQ(pageOffset, getSize(0)), "CreateMUnmap: addr must be a multiple of the page size");
364    }
365    addr = CreatePointerCast(addr, voidPtrTy);
366    size = CreateZExtOrTrunc(size, sizeTy);
367    CallInst * result = CreateCall(fMUnmap, {addr, size});
368    if (codegen::EnableAsserts) {
369        CreateAssert(CreateICmpEQ(result, ConstantInt::getNullValue(result->getType())), "CreateMUnmap: failed");
370    }
371    return result;
372}
373
374void CBuilder::CreateFree(Value * const ptr) {
375    assert (ptr->getType()->isPointerTy());
376    Module * const m = getModule();
377    PointerType * const voidPtrTy = getVoidPtrTy();
378    Function * free = m->getFunction("free");
379    if (free == nullptr) {
380        FunctionType * fty = FunctionType::get(getVoidTy(), {voidPtrTy}, false);
381        free = Function::Create(fty, Function::ExternalLinkage, "free", mMod);
382        free->setCallingConv(CallingConv::C);
383    }
384    CallInst * const ci = CreateCall(free, CreatePointerCast(ptr, voidPtrTy));
385    ci->setTailCall();
386    ci->setCallingConv(free->getCallingConv());
387}
388
389void CBuilder::CreateAlignedFree(Value * const ptr, const bool testForNullAddress) {
390    // WARNING: this will segfault if the value of the ptr at runtime is null but testForNullAddress was not set
391    PointerType * type = cast<PointerType>(ptr->getType());
392    BasicBlock * exit = nullptr;
393    if (testForNullAddress) {
394        LLVMContext & C = getContext();
395        BasicBlock * bb = GetInsertBlock();
396        Function * f = bb->getParent();
397        exit = BasicBlock::Create(C, "", f, bb);
398        BasicBlock * entry = BasicBlock::Create(C, "", f, exit);
399        Value * cond = CreateICmpEQ(ptr, ConstantPointerNull::get(type));
400        CreateCondBr(cond, exit, entry);
401        SetInsertPoint(entry);
402    }
403    DataLayout DL(getModule());
404    IntegerType * const intTy = getIntPtrTy(DL);
405    const auto byteWidth = (intTy->getBitWidth() / 8);
406    Value * prefix = CreatePtrToInt(ptr, intTy);
407    prefix = CreateSub(prefix, ConstantInt::get(intTy, byteWidth));
408    prefix = CreateIntToPtr(prefix, intTy->getPointerTo());
409    prefix = CreateIntToPtr(CreateAlignedLoad(prefix, byteWidth), type);
410    CreateFree(prefix);
411    if (testForNullAddress) {
412        CreateBr(exit);
413        SetInsertPoint(exit);
414    }
415}
416
417Value * CBuilder::CreateRealloc(Value * ptr, Value * size) {
418    DataLayout DL(getModule());
419    IntegerType * const intTy = getIntPtrTy(DL);
420    PointerType * type = cast<PointerType>(ptr->getType());
421    if (size->getType() != intTy) {
422        if (isa<Constant>(size)) {
423            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
424        } else {
425            size = CreateZExtOrTrunc(size, intTy);
426        }
427    }
428    Module * const m = getModule();
429    Function * realloc = m->getFunction("realloc");
430    if (realloc == nullptr) {
431        PointerType * const voidPtrTy = getVoidPtrTy();
432        FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, intTy}, false);
433        realloc = Function::Create(fty, Function::ExternalLinkage, "realloc", mMod);
434        realloc->setCallingConv(CallingConv::C);
435        realloc->setDoesNotAlias(1);
436    }
437    assert (size->getType() == intTy);
438    CallInst * ci = CreateCall(realloc, {ptr, size});
439    ci->setTailCall();
440    ci->setCallingConv(realloc->getCallingConv());
441    return CreateBitOrPointerCast(ci, type);
442}
443
444PointerType * CBuilder::getVoidPtrTy() const {
445    return TypeBuilder<void *, true>::get(getContext());
446}
447
448LoadInst * CBuilder::CreateAtomicLoadAcquire(Value * ptr) {
449    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
450    LoadInst * inst = CreateAlignedLoad(ptr, alignment);
451    inst->setOrdering(AtomicOrdering::Acquire);
452    return inst;
453   
454}
455
456StoreInst * CBuilder::CreateAtomicStoreRelease(Value * val, Value * ptr) {
457    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
458    StoreInst * inst = CreateAlignedStore(val, ptr, alignment);
459    inst->setOrdering(AtomicOrdering::Release);
460    return inst;
461}
462
463PointerType * CBuilder::getFILEptrTy() {
464    if (mFILEtype == nullptr) {
465        mFILEtype = StructType::create(getContext(), "struct._IO_FILE");
466    }
467    return mFILEtype->getPointerTo();
468}
469
470Value * CBuilder::CreateFOpenCall(Value * filename, Value * mode) {
471    Function * fOpenFunc = mMod->getFunction("fopen");
472    if (fOpenFunc == nullptr) {
473        FunctionType * fty = FunctionType::get(getFILEptrTy(), {getInt8Ty()->getPointerTo(), getInt8Ty()->getPointerTo()}, false);
474        fOpenFunc = Function::Create(fty, Function::ExternalLinkage, "fopen", mMod);
475        fOpenFunc->setCallingConv(CallingConv::C);
476    }
477    return CreateCall(fOpenFunc, {filename, mode});
478}
479
480Value * CBuilder::CreateFReadCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
481    Function * fReadFunc = mMod->getFunction("fread");
482    PointerType * const voidPtrTy = getVoidPtrTy();
483    if (fReadFunc == nullptr) {
484        IntegerType * const sizeTy = getSizeTy();
485        FunctionType * fty = FunctionType::get(sizeTy, {voidPtrTy, sizeTy, sizeTy, getFILEptrTy()}, false);
486        fReadFunc = Function::Create(fty, Function::ExternalLinkage, "fread", mMod);
487        fReadFunc->setCallingConv(CallingConv::C);
488    }
489    ptr = CreatePointerCast(ptr, voidPtrTy);
490    return CreateCall(fReadFunc, {ptr, size, nitems, stream});
491}
492
493Value * CBuilder::CreateFWriteCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
494    Function * fWriteFunc = mMod->getFunction("fwrite");
495    PointerType * const voidPtrTy = getVoidPtrTy();
496    if (fWriteFunc == nullptr) {
497        IntegerType * const sizeTy = getSizeTy();
498        FunctionType * fty = FunctionType::get(sizeTy, {voidPtrTy, sizeTy, sizeTy, getFILEptrTy()}, false);
499        fWriteFunc = Function::Create(fty, Function::ExternalLinkage, "fwrite", mMod);
500        fWriteFunc->setCallingConv(CallingConv::C);
501    }
502    ptr = CreatePointerCast(ptr, voidPtrTy);
503    return CreateCall(fWriteFunc, {ptr, size, nitems, stream});
504}
505
506Value * CBuilder::CreateFCloseCall(Value * stream) {
507    Function * fCloseFunc = mMod->getFunction("fclose");
508    if (fCloseFunc == nullptr) {
509        FunctionType * fty = FunctionType::get(getInt32Ty(), {getFILEptrTy()}, false);
510        fCloseFunc = Function::Create(fty, Function::ExternalLinkage, "fclose", mMod);
511        fCloseFunc->setCallingConv(CallingConv::C);
512    }
513    return CreateCall(fCloseFunc, {stream});
514}
515
516Value * CBuilder::CreateRenameCall(Value * oldName, Value * newName) {
517    Function * renameFunc = mMod->getFunction("rename");
518    if (renameFunc == nullptr) {
519        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt8PtrTy(), getInt8PtrTy()}, false);
520        renameFunc = Function::Create(fty, Function::ExternalLinkage, "rename", mMod);
521        renameFunc->setCallingConv(CallingConv::C);
522    }
523    return CreateCall(renameFunc, {oldName, newName});
524}
525
526Value * CBuilder::CreateRemoveCall(Value * path) {
527    Function * removeFunc = mMod->getFunction("remove");
528    if (removeFunc == nullptr) {
529        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt8PtrTy()}, false);
530        removeFunc = Function::Create(fty, Function::ExternalLinkage, "remove", mMod);
531        removeFunc->setCallingConv(CallingConv::C);
532    }
533    return CreateCall(removeFunc, {path});
534}
535
536Value * CBuilder::CreatePThreadCreateCall(Value * thread, Value * attr, Function * start_routine, Value * arg) {
537    Type * const voidPtrTy = getVoidPtrTy();
538    Function * pthreadCreateFunc = mMod->getFunction("pthread_create");
539    if (pthreadCreateFunc == nullptr) {
540        Type * pthreadTy = getSizeTy();
541        FunctionType * funVoidPtrVoidTy = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
542        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy->getPointerTo(), voidPtrTy, funVoidPtrVoidTy->getPointerTo(), voidPtrTy}, false);
543        pthreadCreateFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_create", mMod);
544        pthreadCreateFunc->setCallingConv(CallingConv::C);
545    }
546    return CreateCall(pthreadCreateFunc, {thread, attr, start_routine, CreatePointerCast(arg, voidPtrTy)});
547}
548
549Value * CBuilder::CreatePThreadExitCall(Value * value_ptr) {
550    Function * pthreadExitFunc = mMod->getFunction("pthread_exit");
551    if (pthreadExitFunc == nullptr) {
552        FunctionType * fty = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
553        pthreadExitFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_exit", mMod);
554        pthreadExitFunc->addFnAttr(Attribute::NoReturn);
555        pthreadExitFunc->setCallingConv(CallingConv::C);
556    }
557    CallInst * exitThread = CreateCall(pthreadExitFunc, {value_ptr});
558    exitThread->setDoesNotReturn();
559    return exitThread;
560}
561
562Value * CBuilder::CreatePThreadJoinCall(Value * thread, Value * value_ptr){
563    Function * pthreadJoinFunc = mMod->getFunction("pthread_join");
564    if (pthreadJoinFunc == nullptr) {
565        Type * pthreadTy = getSizeTy();
566        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy, getVoidPtrTy()->getPointerTo()}, false);
567        pthreadJoinFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_join", mMod);
568        pthreadJoinFunc->setCallingConv(CallingConv::C);
569    }
570    return CreateCall(pthreadJoinFunc, {thread, value_ptr});
571}
572
573void CBuilder::CreateAssert(Value * const assertion, StringRef failureMessage) {
574    if (codegen::EnableAsserts) {
575        Function * function = mMod->getFunction("__assert");
576        if (LLVM_UNLIKELY(function == nullptr)) {
577            auto ip = saveIP();
578            FunctionType * fty = FunctionType::get(getVoidTy(), { getInt1Ty(), getInt8PtrTy(), getSizeTy() }, false);
579            function = Function::Create(fty, Function::PrivateLinkage, "__assert", mMod);
580            function->setDoesNotThrow();
581            function->setDoesNotAlias(2);
582            BasicBlock * const entry = BasicBlock::Create(getContext(), "", function);
583            BasicBlock * const failure = BasicBlock::Create(getContext(), "", function);
584            BasicBlock * const success = BasicBlock::Create(getContext(), "", function);
585            auto arg = function->arg_begin();
586            arg->setName("assertion");
587            Value * e = &*arg++;
588            arg->setName("msg");
589            Value * msg = &*arg++;
590            arg->setName("sz");
591            Value * sz = &*arg;
592            SetInsertPoint(entry);
593            CreateCondBr(e, failure, success);
594            SetInsertPoint(failure);
595            Value * len = CreateAdd(sz, getSize(21));
596            ConstantInt * _11 = getSize(11);
597            Value * bytes = CreatePointerCast(CreateMalloc(len), getInt8PtrTy());
598            CreateMemCpy(bytes, GetString("Assertion `"), _11, 1);
599            CreateMemCpy(CreateGEP(bytes, _11), msg, sz, 1);
600            CreateMemCpy(CreateGEP(bytes, CreateAdd(sz, _11)), GetString("' failed.\n"), getSize(10), 1);
601            CreateWriteCall(getInt32(2), bytes, len);
602
603
604            CreateExit(-1);
605            CreateBr(success); // necessary to satisfy the LLVM verifier. this is not actually executed.
606            SetInsertPoint(success);
607            CreateRetVoid();
608            restoreIP(ip);
609        }
610        CreateCall(function, {CreateICmpEQ(assertion, Constant::getNullValue(assertion->getType())), GetString(failureMessage), getSize(failureMessage.size())});
611    }
612}
613
614void CBuilder::CreateExit(const int exitCode) {
615    Function * exit = mMod->getFunction("exit");
616    if (LLVM_UNLIKELY(exit == nullptr)) {
617        FunctionType * fty = FunctionType::get(getVoidTy(), {getInt32Ty()}, false);
618        exit = Function::Create(fty, Function::ExternalLinkage, "exit", mMod);
619        exit->setDoesNotReturn();
620        exit->setDoesNotThrow();
621    }
622    CreateCall(exit, getInt32(exitCode));
623}
624
625BranchInst * CBuilder::CreateLikelyCondBr(Value * Cond, BasicBlock * True, BasicBlock * False, const int probability) {
626    MDBuilder mdb(getContext());
627    if (probability < 0 || probability > 100) {
628        report_fatal_error("branch weight probability must be in [0,100]");
629    }
630    return CreateCondBr(Cond, True, False, mdb.createBranchWeights(probability, 100 - probability));
631}
632
633inline static unsigned ceil_log2(const unsigned v) {
634    assert ("log2(0) is undefined!" && v != 0);
635    return 32 - __builtin_clz(v - 1);
636}
637
638Value * CBuilder::CreatePopcount(Value * bits) {
639    Value * ctpopFunc = Intrinsic::getDeclaration(mMod, Intrinsic::ctpop, bits->getType());
640    return CreateCall(ctpopFunc, bits);
641}
642
643Value * CBuilder::CreateCountForwardZeroes(Value * value) {
644    Value * cttzFunc = Intrinsic::getDeclaration(mMod, Intrinsic::cttz, value->getType());
645    return CreateCall(cttzFunc, {value, ConstantInt::getFalse(getContext())});
646}
647
648Value * CBuilder::CreateCountReverseZeroes(Value * value) {
649    Value * ctlzFunc = Intrinsic::getDeclaration(mMod, Intrinsic::ctlz, value->getType());
650    return CreateCall(ctlzFunc, {value, ConstantInt::getFalse(getContext())});
651}
652
653Value * CBuilder::CreateCeilLog2(Value * value) {
654    IntegerType * ty = cast<IntegerType>(value->getType());
655    CreateAssert(value, "CreateCeilLog2: value cannot be zero");
656    Value * m = CreateCountForwardZeroes(CreateSub(value, ConstantInt::get(ty, 1)));
657    return CreateSub(ConstantInt::get(m->getType(), ty->getBitWidth() - 1), m);
658}
659
660Value * CBuilder::GetString(StringRef Str) {
661    Value * ptr = mMod->getGlobalVariable(Str, true);
662    if (ptr == nullptr) {
663        ptr = CreateGlobalString(Str, Str);
664    }
665    Value * zero = getInt32(0);
666    return CreateInBoundsGEP(ptr, { zero, zero });
667}
668
669CBuilder::CBuilder(Module * const m, const unsigned GeneralRegisterWidthInBits, const bool SupportsIndirectBr, const unsigned CacheLineAlignmentInBytes)
670: IRBuilder<>(m->getContext())
671, mMod(m)
672, mCacheLineAlignment(CacheLineAlignmentInBytes)
673, mSizeType(getIntNTy(GeneralRegisterWidthInBits))
674, mFILEtype(nullptr)
675, mSupportsIndirectBr(SupportsIndirectBr) {
676}
Note: See TracBrowser for help on using the repository browser.