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

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

First attempt at inlining all DoBlock? and FinalBlock? functions by using indirect jumps. Disabled for NVPTX until Linda can check whether they're supported by the LLVM NVPTX library.

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