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

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

lz4d - LZ4 decompressor - initial check-in

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