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

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

Added a simple CreateAssert? function in CBuilder and ReadOnly? flag for getStreamSetBufferPtr method to prevent expanding input stream sets. Begun work on CarryManager? to preallocate variable-length carry data slots.

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