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

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

Continued refactoring work. PabloKernel? now abstract base type with a 'generatePabloMethod' hook to generate Pablo code.

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