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

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

Changes towards separate compilation

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