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

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

Optimized Symbol Generation (and fixed potential bug that could allow duplicate names being constructed); made PabloKernel? extend PabloAST (temporarily removed PabloAST::getName() to avoid diamond problem); added an internal scalar to PabloKernel? struct for each Count to avoid InOut? output scalar variable problem; allowed CodeMotionPass? to move code within the same scope but across a branch statement. Began work on separating Kernels into either Block-Oriented or Segment-Oriented kernels.

File size: 14.7 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/Function.h>
12#include <llvm/IR/TypeBuilder.h>
13
14using namespace llvm;
15
16// ssize_t write(int fildes, const void *buf, size_t nbyte);
17Value * CBuilder::CreateWriteCall(Value * fildes, Value * buf, Value * nbyte) {
18    Function * write = mMod->getFunction("write");
19    if (write == nullptr) {
20        IntegerType * sizeTy = getSizeTy();
21        IntegerType * int32Ty = getInt32Ty();
22        PointerType * int8PtrTy = getInt8PtrTy();
23        write = cast<Function>(mMod->getOrInsertFunction("write",
24                                                        AttributeSet().addAttribute(mMod->getContext(), 2U, Attribute::NoAlias),
25                                                        sizeTy, int32Ty, int8PtrTy, sizeTy, nullptr));
26    }
27    return CreateCall(write, {fildes, buf, nbyte});
28}
29
30Value * CBuilder::CreateReadCall(Value * fildes, Value * buf, Value * nbyte) {
31    Function * readFn = mMod->getFunction("read");
32    if (readFn == nullptr) {
33        IntegerType * sizeTy = getSizeTy();
34        IntegerType * int32Ty = getInt32Ty();
35        PointerType * int8PtrTy = getInt8PtrTy();
36        readFn = cast<Function>(mMod->getOrInsertFunction("read",
37                                                         AttributeSet().addAttribute(mMod->getContext(), 2U, Attribute::NoAlias),
38                                                         sizeTy, int32Ty, int8PtrTy, sizeTy, nullptr));
39    }
40    return CreateCall(readFn, {fildes, buf, nbyte});
41}
42
43Function * CBuilder::GetPrintf() {
44    Function * printf = mMod->getFunction("printf");
45    if (printf == nullptr) {
46        printf = cast<Function>(mMod->getOrInsertFunction("printf"
47                                , FunctionType::get(getInt32Ty(), {getInt8PtrTy()}, true)
48                                , AttributeSet().addAttribute(getContext(), 1U, Attribute::NoAlias)));
49
50    }
51    return printf;
52}
53
54void CBuilder::CallPrintInt(const std::string & name, Value * const value) {
55    Constant * printRegister = mMod->getFunction("PrintInt");
56    if (LLVM_UNLIKELY(printRegister == nullptr)) {
57        FunctionType *FT = FunctionType::get(getVoidTy(), { PointerType::get(getInt8Ty(), 0), getSizeTy() }, false);
58        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintInt", mMod);
59        auto arg = function->arg_begin();
60        std::string out = "%-40s = %" PRIx64 "\n";
61        BasicBlock * entry = BasicBlock::Create(mMod->getContext(), "entry", function);
62        IRBuilder<> builder(entry);
63        std::vector<Value *> args;
64        args.push_back(CreateGlobalStringPtr(out.c_str()));
65        Value * const name = &*(arg++);
66        name->setName("name");
67        args.push_back(name);
68        Value * value = &*arg;
69        value->setName("value");
70        args.push_back(value);
71        builder.CreateCall(GetPrintf(), args);
72        builder.CreateRetVoid();
73
74        printRegister = function;
75    }
76    Value * num = nullptr;
77    if (value->getType()->isPointerTy()) {
78        num = CreatePtrToInt(value, getSizeTy());
79    } else {
80        num = CreateZExtOrBitCast(value, getSizeTy());
81    }
82    assert (num->getType()->isIntegerTy());
83    CreateCall(printRegister, {CreateGlobalStringPtr(name.c_str()), num});
84}
85
86Value * CBuilder::CreateMalloc(Type * type, Value * size) {
87    DataLayout DL(getModule());
88    Type * const intTy = getIntPtrTy(DL);
89    Constant * const width = ConstantExpr::getSizeOf(type);
90    if (size->getType() != intTy) {
91        if (isa<Constant>(size)) {
92            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
93        } else {
94            size = CreateTruncOrBitCast(size, intTy);
95        }
96    }
97    if (!width->isOneValue()) {
98        if (isa<Constant>(size)) {
99            size = ConstantExpr::getMul(cast<Constant>(size), width);
100        } else {
101            size = CreateMul(size, width);
102        }
103    }
104    Module * const m = getModule();
105    Function * malloc = m->getFunction("malloc");
106    if (malloc == nullptr) {
107        PointerType * const voidPtrTy = getVoidPtrTy();
108        malloc = cast<Function>(m->getOrInsertFunction("malloc", voidPtrTy, intTy, nullptr));
109        malloc->setCallingConv(CallingConv::C);
110        malloc->setDoesNotAlias(0);
111    }
112    CallInst * ci = CreateCall(malloc, size);
113    ci->setTailCall();
114    ci->setCallingConv(malloc->getCallingConv());
115    return CreateBitOrPointerCast(ci, type->getPointerTo());
116}
117
118Value * CBuilder::CreateAlignedMalloc(Type * type, Value * size, const unsigned alignment) {
119    assert ((alignment & (alignment - 1)) == 0); // is power of 2
120    DataLayout DL(getModule());
121    IntegerType * const intTy = getIntPtrTy(DL);
122    const auto byteWidth = (intTy->getBitWidth() / 8);
123    Constant * const offset = ConstantInt::get(intTy, alignment + byteWidth - 1);
124    Constant * const width = ConstantExpr::getSizeOf(type);
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    if (size->getType() != intTy) {
133        if (isa<Constant>(size)) {
134            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
135        } else {
136            size = CreateTruncOrBitCast(size, intTy);
137        }
138    }
139    if (isa<Constant>(size)) {
140        size = ConstantExpr::getAdd(cast<Constant>(size), offset);
141    } else {
142        size = CreateAdd(size, offset);
143    }
144    Value * unaligned = CreatePtrToInt(CreateMalloc(getInt8Ty(), size), intTy);
145    Value * aligned = CreateAnd(CreateAdd(unaligned, offset), ConstantExpr::getNot(ConstantInt::get(intTy, alignment - 1)));
146    Value * prefix = CreateIntToPtr(CreateSub(aligned, ConstantInt::get(intTy, byteWidth)), intTy->getPointerTo());
147    assert (unaligned->getType() == prefix->getType()->getPointerElementType());
148    CreateAlignedStore(unaligned, prefix, byteWidth);
149    return CreateIntToPtr(aligned, type->getPointerTo());
150}
151
152void CBuilder::CreateFree(Value * const ptr) {
153    assert (ptr->getType()->isPointerTy());
154    Module * const m = getModule();
155    PointerType * const voidPtrTy = getVoidPtrTy();
156    Function * free = m->getFunction("free");
157    if (free == nullptr) {
158        free = cast<Function>(getModule()->getOrInsertFunction("free", getVoidTy(), voidPtrTy, nullptr));
159        free->setCallingConv(CallingConv::C);
160    }
161    CallInst * const ci = CreateCall(free, CreatePointerCast(ptr, voidPtrTy));
162    ci->setTailCall();
163    ci->setCallingConv(free->getCallingConv());
164}
165
166void CBuilder::CreateAlignedFree(Value * const ptr, const bool testForNullAddress) {
167    // WARNING: this will segfault if the value of the ptr at runtime is null but testForNullAddress was not set
168    PointerType * type = cast<PointerType>(ptr->getType());
169    BasicBlock * exit = nullptr;
170    if (testForNullAddress) {
171        LLVMContext & C = getContext();
172        BasicBlock * bb = GetInsertBlock();
173        Function * f = bb->getParent();
174        exit = BasicBlock::Create(C, "", f, bb);
175        BasicBlock * entry = BasicBlock::Create(C, "", f, exit);
176        Value * cond = CreateICmpEQ(ptr, ConstantPointerNull::get(type));
177        CreateCondBr(cond, exit, entry);
178        SetInsertPoint(entry);
179    }
180    DataLayout DL(getModule());
181    IntegerType * const intTy = getIntPtrTy(DL);
182    const auto byteWidth = (intTy->getBitWidth() / 8);
183    Value * prefix = CreatePtrToInt(ptr, intTy);
184    prefix = CreateSub(prefix, ConstantInt::get(intTy, byteWidth));
185    prefix = CreateIntToPtr(prefix, intTy->getPointerTo());
186    prefix = CreateIntToPtr(CreateAlignedLoad(prefix, byteWidth), type);
187    CreateFree(prefix);
188    if (testForNullAddress) {
189        CreateBr(exit);
190        SetInsertPoint(exit);
191    }
192}
193
194Value * CBuilder::CreateRealloc(Value * ptr, Value * size) {
195    DataLayout DL(getModule());
196    Type * const intTy = getIntPtrTy(DL);
197    PointerType * type = cast<PointerType>(ptr->getType());
198    Constant * const width = ConstantExpr::getSizeOf(type->getPointerElementType());
199    if (size->getType() != intTy) {
200        if (isa<Constant>(size)) {
201            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
202        } else {
203            size = CreateTruncOrBitCast(size, intTy);
204        }
205    }
206    if (!width->isOneValue()) {
207        if (isa<Constant>(size)) {
208            size = ConstantExpr::getMul(cast<Constant>(size), width);
209        } else {
210            size = CreateMul(size, width);
211        }
212    }
213    Module * const m = getModule();
214    Function * realloc = m->getFunction("realloc");
215    if (realloc == nullptr) {
216        PointerType * const voidPtrTy = getVoidPtrTy();
217        realloc = cast<Function>(m->getOrInsertFunction("realloc", voidPtrTy, voidPtrTy, intTy, nullptr));
218        realloc->setCallingConv(CallingConv::C);
219        realloc->setDoesNotAlias(1);
220    }
221    CallInst * ci = CreateCall(realloc, {ptr, size});
222    ci->setTailCall();
223    ci->setCallingConv(realloc->getCallingConv());
224    return CreateBitOrPointerCast(ci, type);
225}
226
227void CBuilder::CreateMemZero(Value * ptr, Value * size, const unsigned alignment) {
228    assert (ptr->getType()->isPointerTy() && size->getType()->isIntegerTy());
229    Type * const type = ptr->getType();
230    Constant * const width = ConstantExpr::getSizeOf(type->getPointerElementType());
231    if (isa<Constant>(size)) {
232        size = ConstantExpr::getMul(cast<Constant>(size), width);
233    } else {
234        size = CreateMul(size, width);
235    }
236    CreateMemSet(CreatePointerCast(ptr, getInt8PtrTy()), getInt8(0), size, alignment);
237}
238
239PointerType * CBuilder::getVoidPtrTy() const {
240    return TypeBuilder<void *, false>::get(getContext());
241}
242
243LoadInst * CBuilder::CreateAtomicLoadAcquire(Value * ptr) {
244    unsigned alignment = cast<PointerType>(ptr->getType())->getElementType()->getPrimitiveSizeInBits() / 8;
245    LoadInst * inst = CreateAlignedLoad(ptr, alignment);
246    inst->setOrdering(AtomicOrdering::Acquire);
247    return inst;
248   
249}
250StoreInst * CBuilder::CreateAtomicStoreRelease(Value * val, Value * ptr) {
251    unsigned alignment = cast<PointerType>(ptr->getType())->getElementType()->getPrimitiveSizeInBits() / 8;
252    StoreInst * inst = CreateAlignedStore(val, ptr, alignment);
253    inst->setOrdering(AtomicOrdering::Release);
254    return inst;
255}
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        fOpenFunc = cast<Function>(mMod->getOrInsertFunction("fopen", getFILEptrTy(), getInt8Ty()->getPointerTo(), getInt8Ty()->getPointerTo(), nullptr));
269        fOpenFunc->setCallingConv(llvm::CallingConv::C);
270    }
271    return CreateCall(fOpenFunc, {filename, mode});
272}
273
274Value * CBuilder::CreateFReadCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
275    Function * fReadFunc = mMod->getFunction("fread");
276    if (fReadFunc == nullptr) {
277        fReadFunc = cast<Function>(mMod->getOrInsertFunction("fread", getSizeTy(), getVoidPtrTy(), getSizeTy(), getSizeTy(), getFILEptrTy(), nullptr));
278        fReadFunc->setCallingConv(llvm::CallingConv::C);
279    }
280    return CreateCall(fReadFunc, {ptr, size, nitems, stream});
281}
282
283Value * CBuilder::CreateFWriteCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
284    Function * fWriteFunc = mMod->getFunction("fwrite");
285    if (fWriteFunc == nullptr) {
286        fWriteFunc = cast<Function>(mMod->getOrInsertFunction("fwrite", getSizeTy(), getVoidPtrTy(), getSizeTy(), getSizeTy(), getFILEptrTy(), nullptr));
287        fWriteFunc->setCallingConv(llvm::CallingConv::C);
288    }
289    return CreateCall(fWriteFunc, {ptr, size, nitems, stream});
290}
291
292Value * CBuilder::CreateFCloseCall(Value * stream) {
293    Function * fCloseFunc = mMod->getFunction("fclose");
294    if (fCloseFunc == nullptr) {
295        fCloseFunc = cast<Function>(mMod->getOrInsertFunction("fclose", getInt32Ty(), getFILEptrTy(), nullptr));
296        fCloseFunc->setCallingConv(llvm::CallingConv::C);
297    }
298    return CreateCall(fCloseFunc, {stream});
299}
300
301Value * CBuilder::CreatePThreadCreateCall(Value * thread, Value * attr, Function * start_routine, Value * arg) {
302    Function * pthreadCreateFunc = mMod->getFunction("pthread_create");
303    if (pthreadCreateFunc == nullptr) {
304        Type * pthreadTy = getSizeTy();
305        FunctionType * funVoidPtrVoidTy = FunctionType::get(getVoidTy(), getVoidPtrTy(), false);
306
307        pthreadCreateFunc = cast<Function>(mMod->getOrInsertFunction("pthread_create",
308                                                                     getInt32Ty(),
309                                                                     pthreadTy->getPointerTo(),
310                                                                     getVoidPtrTy(),
311                                                                     static_cast<Type *>(funVoidPtrVoidTy)->getPointerTo(),
312                                                                     getVoidPtrTy(), nullptr));
313        pthreadCreateFunc->setCallingConv(llvm::CallingConv::C);
314    }
315    return CreateCall(pthreadCreateFunc, {thread, attr, start_routine, arg});
316}
317
318Value * CBuilder::CreatePThreadExitCall(Value * value_ptr) {
319    Function * pthreadExitFunc = mMod->getFunction("pthread_exit");
320    if (pthreadExitFunc == nullptr) {
321        pthreadExitFunc = cast<Function>(mMod->getOrInsertFunction("pthread_exit", getVoidTy(), getVoidPtrTy(), nullptr));
322        pthreadExitFunc->addFnAttr(llvm::Attribute::NoReturn);
323        pthreadExitFunc->setCallingConv(llvm::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    Type * pthreadTy = getSizeTy();
332    Function * pthreadJoinFunc = cast<Function>(mMod->getOrInsertFunction("pthread_join",
333                                                                       getInt32Ty(),
334                                                                       pthreadTy,
335                                                                       getVoidPtrTy()->getPointerTo(), nullptr));
336    pthreadJoinFunc->setCallingConv(llvm::CallingConv::C);
337    return CreateCall(pthreadJoinFunc, {thread, value_ptr});
338}
339
340CBuilder::CBuilder(llvm::Module * m, unsigned GeneralRegisterWidthInBits, unsigned CacheLineAlignmentInBytes)
341: IRBuilder<>(m->getContext())
342, mMod(m)
343, mCacheLineAlignment(CacheLineAlignmentInBytes)
344, mSizeType(getIntNTy(GeneralRegisterWidthInBits))
345, mFILEtype(nullptr) {
346}
Note: See TracBrowser for help on using the repository browser.