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

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

Added enable asserts (-ea) command line flag + restructured BlockOrientedKernels? to allow for inlined code.

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