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

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

Changes working towards simplifying accessing stream elements + some modifications to simplify include / forward declarations within the CodeGen? library.

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