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

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

Bug fixes for 32-bit systems

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