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

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

Bug fix for long advance

File size: 18.4 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 <fcntl.h>
14#include <toolchain.h>
15
16#include <llvm/Support/raw_ostream.h>
17
18using namespace llvm;
19
20Value * CBuilder::CreateOpenCall(Value * filename, Value * oflag, Value * mode) {
21    Function * openFn = mMod->getFunction("open");
22    if (openFn == nullptr) {
23        IntegerType * int32Ty = getInt32Ty();
24        PointerType * int8PtrTy = getInt8PtrTy();
25        openFn = cast<Function>(mMod->getOrInsertFunction("open",
26                                                         int32Ty, int8PtrTy, int32Ty, int32Ty, nullptr));
27    }
28    return CreateCall(openFn, {filename, oflag, mode});
29}
30
31// ssize_t write(int fildes, const void *buf, size_t nbyte);
32Value * CBuilder::CreateWriteCall(Value * fildes, Value * buf, Value * nbyte) {
33    Function * write = mMod->getFunction("write");
34    if (write == nullptr) {
35        IntegerType * sizeTy = getSizeTy();
36        IntegerType * int32Ty = getInt32Ty();
37        PointerType * int8PtrTy = getInt8PtrTy();
38        write = cast<Function>(mMod->getOrInsertFunction("write",
39                                                        AttributeSet().addAttribute(mMod->getContext(), 2U, Attribute::NoAlias),
40                                                        sizeTy, int32Ty, int8PtrTy, sizeTy, nullptr));
41    }
42    return CreateCall(write, {fildes, buf, nbyte});
43}
44
45Value * CBuilder::CreateReadCall(Value * fildes, Value * buf, Value * nbyte) {
46    Function * readFn = mMod->getFunction("read");
47    if (readFn == nullptr) {
48        IntegerType * sizeTy = getSizeTy();
49        IntegerType * int32Ty = getInt32Ty();
50        PointerType * int8PtrTy = getInt8PtrTy();
51        readFn = cast<Function>(mMod->getOrInsertFunction("read",
52                                                         AttributeSet().addAttribute(mMod->getContext(), 2U, Attribute::NoAlias),
53                                                         sizeTy, int32Ty, int8PtrTy, sizeTy, nullptr));
54    }
55    return CreateCall(readFn, {fildes, buf, nbyte});
56}
57
58Value * CBuilder::CreateCloseCall(Value * fildes) {
59    Function * closeFn = mMod->getFunction("close");
60    if (closeFn == nullptr) {
61        IntegerType * int32Ty = getInt32Ty();
62        FunctionType * fty = FunctionType::get(int32Ty, {int32Ty}, true);
63        closeFn = Function::Create(fty, Function::ExternalLinkage, "close", mMod);
64    }
65    return CreateCall(closeFn, {fildes});
66}
67
68Function * CBuilder::GetPrintf() {
69    Function * printf = mMod->getFunction("printf");
70    if (printf == nullptr) {
71        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt8PtrTy()}, true);
72        printf = Function::Create(fty, Function::ExternalLinkage, "printf", mMod);
73        printf->addAttribute(1, Attribute::NoAlias);
74    }
75    return printf;
76}
77
78void CBuilder::CallPrintInt(const std::string & name, Value * const value) {
79    Constant * printRegister = mMod->getFunction("PrintInt");
80    if (LLVM_UNLIKELY(printRegister == nullptr)) {
81        FunctionType *FT = FunctionType::get(getVoidTy(), { PointerType::get(getInt8Ty(), 0), getSizeTy() }, false);
82        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintInt", mMod);
83        auto arg = function->arg_begin();
84        std::string out = "%-40s = %" PRIx64 "\n";
85        BasicBlock * entry = BasicBlock::Create(mMod->getContext(), "entry", function);
86        IRBuilder<> builder(entry);
87        std::vector<Value *> args;
88        args.push_back(CreateGlobalStringPtr(out.c_str()));
89        Value * const name = &*(arg++);
90        name->setName("name");
91        args.push_back(name);
92        Value * value = &*arg;
93        value->setName("value");
94        args.push_back(value);
95        builder.CreateCall(GetPrintf(), args);
96        builder.CreateRetVoid();
97
98        printRegister = function;
99    }
100    Value * num = nullptr;
101    if (value->getType()->isPointerTy()) {
102        num = CreatePtrToInt(value, getSizeTy());
103    } else {
104        num = CreateZExtOrBitCast(value, getSizeTy());
105    }
106    assert (num->getType()->isIntegerTy());
107    CreateCall(printRegister, {CreateGlobalStringPtr(name.c_str()), num});
108}
109
110Value * CBuilder::CreateMalloc(Value * size) {
111    Module * const m = getModule();
112    DataLayout DL(m);
113    IntegerType * const intTy = getIntPtrTy(DL);
114    if (size->getType() != intTy) {
115        if (isa<Constant>(size)) {
116            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
117        } else {
118            size = CreateZExtOrTrunc(size, intTy);
119        }
120    }   
121    PointerType * const voidPtrTy = getVoidPtrTy();
122    Function * malloc = m->getFunction("malloc");
123    if (malloc == nullptr) {
124        FunctionType * fty = FunctionType::get(voidPtrTy, {intTy}, false);
125        malloc = Function::Create(fty, Function::ExternalLinkage, "malloc", mMod);
126        malloc->setCallingConv(CallingConv::C);
127        malloc->setDoesNotAlias(0);
128    }
129    assert (size->getType() == intTy);
130    CallInst * ci = CreateCall(malloc, size); assert (ci);
131    ci->setTailCall();
132    ci->setCallingConv(malloc->getCallingConv());
133    Value * ptr = CreatePointerCast(ci, voidPtrTy); assert (ptr);
134    CreateAssert(ptr, "FATAL ERROR: out of memory");
135    return ptr;
136}
137
138Value * CBuilder::CreateAlignedMalloc(Value * size, const unsigned alignment) {
139    if (LLVM_UNLIKELY((alignment & (alignment - 1)) != 0)) {
140        report_fatal_error("CreateAlignedMalloc: alignment must be a power of 2");
141    }
142    DataLayout DL(mMod);
143    IntegerType * const intTy = getIntPtrTy(DL);
144    Function * aligned_malloc = mMod->getFunction("aligned_malloc" + std::to_string(alignment));
145    if (LLVM_UNLIKELY(aligned_malloc == nullptr)) {
146        const auto ip = saveIP();
147        PointerType * const voidPtrTy = getVoidPtrTy();
148        FunctionType * fty = FunctionType::get(voidPtrTy, {intTy}, false);
149        aligned_malloc = Function::Create(fty, Function::InternalLinkage, "aligned_malloc" + std::to_string(alignment), mMod);
150        aligned_malloc->setCallingConv(CallingConv::C);
151        aligned_malloc->setDoesNotAlias(0);
152        aligned_malloc->addFnAttr(Attribute::AlwaysInline);
153        Value * size = &*aligned_malloc->arg_begin();
154        SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", aligned_malloc));
155        const auto byteWidth = (intTy->getBitWidth() / 8);
156        Constant * const offset = ConstantInt::get(intTy, alignment + byteWidth - 1);
157        size = CreateAdd(size, offset);
158        Value * unaligned = CreatePtrToInt(CreateMalloc(size), intTy);
159        Value * aligned = CreateAnd(CreateAdd(unaligned, offset), ConstantExpr::getNot(ConstantInt::get(intTy, alignment - 1)));
160        Value * prefix = CreateIntToPtr(CreateSub(aligned, ConstantInt::get(intTy, byteWidth)), intTy->getPointerTo());
161        assert (unaligned->getType() == prefix->getType()->getPointerElementType());
162        CreateAlignedStore(unaligned, prefix, byteWidth);
163        CreateRet(CreateIntToPtr(aligned, voidPtrTy));
164        restoreIP(ip);
165    }
166    return CreateCall(aligned_malloc, {CreateZExtOrTrunc(size, intTy)});
167}
168
169void CBuilder::CreateFree(Value * const ptr) {
170    assert (ptr->getType()->isPointerTy());
171    Module * const m = getModule();
172    PointerType * const voidPtrTy = getVoidPtrTy();
173    Function * free = m->getFunction("free");
174    if (free == nullptr) {
175        FunctionType * fty = FunctionType::get(getVoidTy(), {voidPtrTy}, false);
176        free = Function::Create(fty, Function::ExternalLinkage, "free", mMod);
177        free->setCallingConv(CallingConv::C);
178    }
179    CallInst * const ci = CreateCall(free, CreatePointerCast(ptr, voidPtrTy));
180    ci->setTailCall();
181    ci->setCallingConv(free->getCallingConv());
182}
183
184void CBuilder::CreateAlignedFree(Value * const ptr, const bool testForNullAddress) {
185    // WARNING: this will segfault if the value of the ptr at runtime is null but testForNullAddress was not set
186    PointerType * type = cast<PointerType>(ptr->getType());
187    BasicBlock * exit = nullptr;
188    if (testForNullAddress) {
189        LLVMContext & C = getContext();
190        BasicBlock * bb = GetInsertBlock();
191        Function * f = bb->getParent();
192        exit = BasicBlock::Create(C, "", f, bb);
193        BasicBlock * entry = BasicBlock::Create(C, "", f, exit);
194        Value * cond = CreateICmpEQ(ptr, ConstantPointerNull::get(type));
195        CreateCondBr(cond, exit, entry);
196        SetInsertPoint(entry);
197    }
198    DataLayout DL(getModule());
199    IntegerType * const intTy = getIntPtrTy(DL);
200    const auto byteWidth = (intTy->getBitWidth() / 8);
201    Value * prefix = CreatePtrToInt(ptr, intTy);
202    prefix = CreateSub(prefix, ConstantInt::get(intTy, byteWidth));
203    prefix = CreateIntToPtr(prefix, intTy->getPointerTo());
204    prefix = CreateIntToPtr(CreateAlignedLoad(prefix, byteWidth), type);
205    CreateFree(prefix);
206    if (testForNullAddress) {
207        CreateBr(exit);
208        SetInsertPoint(exit);
209    }
210}
211
212Value * CBuilder::CreateRealloc(Value * ptr, Value * size) {
213    DataLayout DL(getModule());
214    IntegerType * const intTy = getIntPtrTy(DL);
215    PointerType * type = cast<PointerType>(ptr->getType());
216    if (size->getType() != intTy) {
217        if (isa<Constant>(size)) {
218            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
219        } else {
220            size = CreateZExtOrTrunc(size, intTy);
221        }
222    }
223    Module * const m = getModule();
224    Function * realloc = m->getFunction("realloc");
225    if (realloc == nullptr) {
226        PointerType * const voidPtrTy = getVoidPtrTy();
227        FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, intTy}, false);
228        realloc = Function::Create(fty, Function::ExternalLinkage, "realloc", mMod);
229        realloc->setCallingConv(CallingConv::C);
230        realloc->setDoesNotAlias(1);
231    }
232    assert (size->getType() == intTy);
233    CallInst * ci = CreateCall(realloc, {ptr, size});
234    ci->setTailCall();
235    ci->setCallingConv(realloc->getCallingConv());
236    return CreateBitOrPointerCast(ci, type);
237}
238
239PointerType * CBuilder::getVoidPtrTy() const {
240    return TypeBuilder<void *, false>::get(getContext());
241}
242
243LoadInst * CBuilder::CreateAtomicLoadAcquire(Value * ptr) {
244    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
245    LoadInst * inst = CreateAlignedLoad(ptr, alignment);
246    inst->setOrdering(AtomicOrdering::Acquire);
247    return inst;
248   
249}
250
251StoreInst * CBuilder::CreateAtomicStoreRelease(Value * val, Value * ptr) {
252    const auto alignment = ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
253    StoreInst * inst = CreateAlignedStore(val, ptr, alignment);
254    inst->setOrdering(AtomicOrdering::Release);
255    return inst;
256}
257
258PointerType * CBuilder::getFILEptrTy() {
259    if (mFILEtype == nullptr) {
260        mFILEtype = StructType::create(getContext(), "struct._IO_FILE");
261    }
262    return mFILEtype->getPointerTo();
263}
264
265Value * CBuilder::CreateFOpenCall(Value * filename, Value * mode) {
266    Function * fOpenFunc = mMod->getFunction("fopen");
267    if (fOpenFunc == nullptr) {
268        FunctionType * fty = FunctionType::get(getFILEptrTy(), {getInt8Ty()->getPointerTo(), getInt8Ty()->getPointerTo()}, false);
269        fOpenFunc = Function::Create(fty, Function::ExternalLinkage, "fopen", mMod);
270        fOpenFunc->setCallingConv(CallingConv::C);
271    }
272    return CreateCall(fOpenFunc, {filename, mode});
273}
274
275Value * CBuilder::CreateFReadCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
276    Function * fReadFunc = mMod->getFunction("fread");
277    if (fReadFunc == nullptr) {
278        FunctionType * fty = FunctionType::get(getSizeTy(), {getVoidPtrTy(), getSizeTy(), getSizeTy(), getFILEptrTy()}, false);
279        fReadFunc = Function::Create(fty, Function::ExternalLinkage, "fread", mMod);
280        fReadFunc->setCallingConv(CallingConv::C);
281    }
282    return CreateCall(fReadFunc, {ptr, size, nitems, stream});
283}
284
285Value * CBuilder::CreateFWriteCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
286    Function * fWriteFunc = mMod->getFunction("fwrite");
287    if (fWriteFunc == nullptr) {
288        FunctionType * fty = FunctionType::get(getSizeTy(), {getVoidPtrTy(), getSizeTy(), getSizeTy(), getFILEptrTy()}, false);
289        fWriteFunc = Function::Create(fty, Function::ExternalLinkage, "fwrite", mMod);
290        fWriteFunc->setCallingConv(CallingConv::C);
291    }
292    return CreateCall(fWriteFunc, {ptr, size, nitems, stream});
293}
294
295Value * CBuilder::CreateFCloseCall(Value * stream) {
296    Function * fCloseFunc = mMod->getFunction("fclose");
297    if (fCloseFunc == nullptr) {
298        FunctionType * fty = FunctionType::get(getInt32Ty(), {getFILEptrTy()}, false);
299        fCloseFunc = Function::Create(fty, Function::ExternalLinkage, "fclose", mMod);
300        fCloseFunc->setCallingConv(CallingConv::C);
301    }
302    return CreateCall(fCloseFunc, {stream});
303}
304
305Value * CBuilder::CreatePThreadCreateCall(Value * thread, Value * attr, Function * start_routine, Value * arg) {
306    Function * pthreadCreateFunc = mMod->getFunction("pthread_create");
307    if (pthreadCreateFunc == nullptr) {
308        Type * pthreadTy = getSizeTy();
309        FunctionType * funVoidPtrVoidTy = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
310        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy->getPointerTo(), getVoidPtrTy(), funVoidPtrVoidTy->getPointerTo(), getVoidPtrTy()}, false);
311        pthreadCreateFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_create", mMod);
312        pthreadCreateFunc->setCallingConv(CallingConv::C);
313    }
314    return CreateCall(pthreadCreateFunc, {thread, attr, start_routine, arg});
315}
316
317Value * CBuilder::CreatePThreadExitCall(Value * value_ptr) {
318    Function * pthreadExitFunc = mMod->getFunction("pthread_exit");
319    if (pthreadExitFunc == nullptr) {
320        FunctionType * fty = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
321        pthreadExitFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_exit", mMod);
322        pthreadExitFunc->addFnAttr(Attribute::NoReturn);
323        pthreadExitFunc->setCallingConv(CallingConv::C);
324    }
325    CallInst * exitThread = CreateCall(pthreadExitFunc, {value_ptr});
326    exitThread->setDoesNotReturn();
327    return exitThread;
328}
329
330Value * CBuilder::CreatePThreadJoinCall(Value * thread, Value * value_ptr){
331    Function * pthreadJoinFunc = mMod->getFunction("pthread_join");
332    if (pthreadJoinFunc == nullptr) {
333        Type * pthreadTy = getSizeTy();
334        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy, getVoidPtrTy()->getPointerTo()}, false);
335        pthreadJoinFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_join", mMod);
336        pthreadJoinFunc->setCallingConv(CallingConv::C);
337    }
338    return CreateCall(pthreadJoinFunc, {thread, value_ptr});
339}
340
341void CBuilder::CreateAssert(Value * const assertion, StringRef failureMessage) {
342    if (codegen::EnableAsserts) {
343        Function * function = mMod->getFunction("__assert");
344        if (LLVM_UNLIKELY(function == nullptr)) {
345            auto ip = saveIP();
346            FunctionType * fty = FunctionType::get(getVoidTy(), { getInt1Ty(), getInt8PtrTy(), getSizeTy() }, false);
347            function = Function::Create(fty, Function::PrivateLinkage, "__assert", mMod);
348            function->setDoesNotThrow();
349            function->setDoesNotAlias(2);
350            BasicBlock * const entry = BasicBlock::Create(getContext(), "", function);
351            BasicBlock * const failure = BasicBlock::Create(getContext(), "", function);
352            BasicBlock * const success = BasicBlock::Create(getContext(), "", function);
353            auto arg = function->arg_begin();
354            arg->setName("assertion");
355            Value * e = &*arg++;
356            arg->setName("msg");
357            Value * msg = &*arg++;
358            arg->setName("sz");
359            Value * sz = &*arg;
360            SetInsertPoint(entry);
361            CreateCondBr(e, failure, success);
362            SetInsertPoint(failure);
363            Value * len = CreateAdd(sz, getSize(21));
364            ConstantInt * _11 = getSize(11);
365            Value * bytes = CreatePointerCast(CreateMalloc(len), getInt8PtrTy());
366            CreateMemCpy(bytes, CreateGlobalStringPtr("Assertion `"), _11, 1);
367            CreateMemCpy(CreateGEP(bytes, _11), msg, sz, 1);
368            CreateMemCpy(CreateGEP(bytes, CreateAdd(sz, _11)), CreateGlobalStringPtr("' failed.\n"), getSize(10), 1);
369            CreateWriteCall(getInt32(2), bytes, len);
370            CreateExit(-1);
371            CreateBr(success); // necessary to satisfy the LLVM verifier. this is not actually executed.
372            SetInsertPoint(success);
373            CreateRetVoid();
374            restoreIP(ip);
375        }
376        CreateCall(function, {CreateICmpEQ(assertion, Constant::getNullValue(assertion->getType())), CreateGlobalStringPtr(failureMessage), getSize(failureMessage.size())});
377    }
378}
379
380void CBuilder::CreateExit(const int exitCode) {
381    Function * exit = mMod->getFunction("exit");
382    if (LLVM_UNLIKELY(exit == nullptr)) {
383        FunctionType * fty = FunctionType::get(getVoidTy(), {getInt32Ty()}, false);
384        exit = Function::Create(fty, Function::ExternalLinkage, "exit", mMod);
385        exit->setDoesNotReturn();
386        exit->setDoesNotThrow();
387    }
388    CreateCall(exit, getInt32(exitCode));
389}
390
391BranchInst * CBuilder::CreateLikelyCondBr(Value * Cond, BasicBlock * True, BasicBlock * False, const int probability) {
392    MDBuilder mdb(getContext());
393    if (probability < 0 || probability > 100) {
394        report_fatal_error("branch weight probability must be in [0,100]");
395    }
396    return CreateCondBr(Cond, True, False, mdb.createBranchWeights(probability, 100 - probability));
397}
398
399Value * CBuilder::CreateCeilLog2(Value * const value) {
400    IntegerType * ty = cast<IntegerType>(value->getType());
401    CreateAssert(value, "CreateCeilLog2: value cannot be zero");
402    Value * v = CreateSub(value, ConstantInt::get(ty, 1));
403    Value * m = CreateCall(Intrinsic::getDeclaration(mMod, Intrinsic::ctlz, ty), {v, ConstantInt::getFalse(getContext())});
404    return CreateSub(ConstantInt::get(m->getType(), ty->getBitWidth()), m);
405}
406
407CBuilder::CBuilder(Module * const m, const unsigned GeneralRegisterWidthInBits, const bool SupportsIndirectBr, const unsigned CacheLineAlignmentInBytes)
408: IRBuilder<>(m->getContext())
409, mMod(m)
410, mCacheLineAlignment(CacheLineAlignmentInBytes)
411, mSizeType(getIntNTy(GeneralRegisterWidthInBits))
412, mFILEtype(nullptr)
413, mSupportsIndirectBr(SupportsIndirectBr) {
414}
Note: See TracBrowser for help on using the repository browser.