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

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

Progress on parenthesis matching example

File size: 18.6 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        FunctionType * fty = FunctionType::get(int32Ty, {int32Ty}, true);
61        closeFn = Function::Create(fty, Function::ExternalLinkage, "close", mMod);
62    }
63    return CreateCall(closeFn, {fildes});
64}
65
66Function * CBuilder::GetPrintf() {
67    Function * printf = mMod->getFunction("printf");
68    if (printf == nullptr) {
69        FunctionType * fty = FunctionType::get(getInt32Ty(), {getInt8PtrTy()}, true);
70        printf = Function::Create(fty, Function::ExternalLinkage, "printf", mMod);
71        printf->addAttribute(1, Attribute::NoAlias);
72    }
73    return printf;
74}
75
76void CBuilder::CallPrintInt(const std::string & name, Value * const value) {
77    Constant * printRegister = mMod->getFunction("PrintInt");
78    if (LLVM_UNLIKELY(printRegister == nullptr)) {
79        FunctionType *FT = FunctionType::get(getVoidTy(), { PointerType::get(getInt8Ty(), 0), getSizeTy() }, false);
80        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintInt", mMod);
81        auto arg = function->arg_begin();
82        std::string out = "%-40s = %" PRIx64 "\n";
83        BasicBlock * entry = BasicBlock::Create(mMod->getContext(), "entry", function);
84        IRBuilder<> builder(entry);
85        std::vector<Value *> args;
86        args.push_back(CreateGlobalStringPtr(out.c_str()));
87        Value * const name = &*(arg++);
88        name->setName("name");
89        args.push_back(name);
90        Value * value = &*arg;
91        value->setName("value");
92        args.push_back(value);
93        builder.CreateCall(GetPrintf(), args);
94        builder.CreateRetVoid();
95
96        printRegister = function;
97    }
98    Value * num = nullptr;
99    if (value->getType()->isPointerTy()) {
100        num = CreatePtrToInt(value, getSizeTy());
101    } else {
102        num = CreateZExtOrBitCast(value, getSizeTy());
103    }
104    assert (num->getType()->isIntegerTy());
105    CreateCall(printRegister, {CreateGlobalStringPtr(name.c_str()), num});
106}
107
108Value * CBuilder::CreateMalloc(Type * type, Value * size) {
109    DataLayout DL(getModule());
110    IntegerType * const intTy = getIntPtrTy(DL);
111    if (size->getType() != intTy) {
112        if (isa<Constant>(size)) {
113            size = ConstantExpr::getIntegerCast(cast<Constant>(size), intTy, false);
114        } else {
115            size = CreateZExtOrTrunc(size, intTy);
116        }
117    }   
118    Constant * width = ConstantExpr::getSizeOf(type);
119    if (LLVM_UNLIKELY(width->getType() != intTy)) {
120        width = ConstantExpr::getIntegerCast(width, intTy, false);
121    }
122    if (!width->isOneValue()) {
123        if (isa<Constant>(size)) {
124            size = ConstantExpr::getMul(cast<Constant>(size), width);
125        } else {
126            size = CreateMul(size, width);
127        }
128    }
129    Module * const m = getModule();
130    Function * malloc = m->getFunction("malloc");
131    if (malloc == nullptr) {
132        PointerType * const voidPtrTy = getVoidPtrTy();
133        FunctionType * fty = FunctionType::get(voidPtrTy, {intTy}, false);
134        malloc = Function::Create(fty, Function::ExternalLinkage, "malloc", mMod);
135        malloc->setCallingConv(CallingConv::C);
136        malloc->setDoesNotAlias(0);
137    }
138    assert (size->getType() == intTy);
139    CallInst * ci = CreateCall(malloc, size);
140    ci->setTailCall();
141    ci->setCallingConv(malloc->getCallingConv());
142    Value * ptr = CreateBitOrPointerCast(ci, type->getPointerTo());
143    CreateAssert(ptr, "FATAL ERROR: out of memory");
144    return ptr;
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        FunctionType * fty = FunctionType::get(getVoidTy(), {voidPtrTy}, false);
192        free = Function::Create(fty, Function::ExternalLinkage, "free", mMod);
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        FunctionType * fty = FunctionType::get(voidPtrTy, {voidPtrTy, intTy}, false);
255        realloc = Function::Create(fty, Function::ExternalLinkage, "realloc", mMod);
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        FunctionType * fty = FunctionType::get(getFILEptrTy(), {getInt8Ty()->getPointerTo(), getInt8Ty()->getPointerTo()}, false);
296        fOpenFunc = Function::Create(fty, Function::ExternalLinkage, "fopen", mMod);
297        fOpenFunc->setCallingConv(CallingConv::C);
298    }
299    return CreateCall(fOpenFunc, {filename, mode});
300}
301
302Value * CBuilder::CreateFReadCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
303    Function * fReadFunc = mMod->getFunction("fread");
304    if (fReadFunc == nullptr) {
305        FunctionType * fty = FunctionType::get(getSizeTy(), {getVoidPtrTy(), getSizeTy(), getSizeTy(), getFILEptrTy()}, false);
306        fReadFunc = Function::Create(fty, Function::ExternalLinkage, "fread", mMod);
307        fReadFunc->setCallingConv(CallingConv::C);
308    }
309    return CreateCall(fReadFunc, {ptr, size, nitems, stream});
310}
311
312Value * CBuilder::CreateFWriteCall(Value * ptr, Value * size, Value * nitems, Value * stream) {
313    Function * fWriteFunc = mMod->getFunction("fwrite");
314    if (fWriteFunc == nullptr) {
315        FunctionType * fty = FunctionType::get(getSizeTy(), {getVoidPtrTy(), getSizeTy(), getSizeTy(), getFILEptrTy()}, false);
316        fWriteFunc = Function::Create(fty, Function::ExternalLinkage, "fwrite", mMod);
317        fWriteFunc->setCallingConv(CallingConv::C);
318    }
319    return CreateCall(fWriteFunc, {ptr, size, nitems, stream});
320}
321
322Value * CBuilder::CreateFCloseCall(Value * stream) {
323    Function * fCloseFunc = mMod->getFunction("fclose");
324    if (fCloseFunc == nullptr) {
325        FunctionType * fty = FunctionType::get(getInt32Ty(), {getFILEptrTy()}, false);
326        fCloseFunc = Function::Create(fty, Function::ExternalLinkage, "fclose", mMod);
327        fCloseFunc->setCallingConv(CallingConv::C);
328    }
329    return CreateCall(fCloseFunc, {stream});
330}
331
332Value * CBuilder::CreatePThreadCreateCall(Value * thread, Value * attr, Function * start_routine, Value * arg) {
333    Function * pthreadCreateFunc = mMod->getFunction("pthread_create");
334    if (pthreadCreateFunc == nullptr) {
335        Type * pthreadTy = getSizeTy();
336        FunctionType * funVoidPtrVoidTy = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
337        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy->getPointerTo(), getVoidPtrTy(), funVoidPtrVoidTy->getPointerTo(), getVoidPtrTy()}, false);
338        pthreadCreateFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_create", mMod);
339        pthreadCreateFunc->setCallingConv(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        FunctionType * fty = FunctionType::get(getVoidTy(), {getVoidPtrTy()}, false);
348        pthreadExitFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_exit", mMod);
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    Function * pthreadJoinFunc = mMod->getFunction("pthread_join");
359    if (pthreadJoinFunc == nullptr) {
360        Type * pthreadTy = getSizeTy();
361        FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy, getVoidPtrTy()->getPointerTo()}, false);
362        pthreadJoinFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_join", mMod);
363        pthreadJoinFunc->setCallingConv(CallingConv::C);
364    }
365    return CreateCall(pthreadJoinFunc, {thread, value_ptr});
366}
367
368void CBuilder::CreateAssert(Value * const assertion, StringRef failureMessage) {
369    if (codegen::EnableAsserts) {
370        Function * function = mMod->getFunction("__assert");
371        if (LLVM_UNLIKELY(function == nullptr)) {
372            auto ip = saveIP();
373            FunctionType * fty = FunctionType::get(getVoidTy(), { getInt1Ty(), getInt8PtrTy(), getSizeTy() }, false);
374            function = Function::Create(fty, Function::PrivateLinkage, "__assert", mMod);
375            function->setDoesNotThrow();
376            function->setDoesNotAlias(2);
377            BasicBlock * const entry = BasicBlock::Create(getContext(), "", function);
378            BasicBlock * const failure = BasicBlock::Create(getContext(), "", function);
379            BasicBlock * const success = BasicBlock::Create(getContext(), "", function);
380            auto arg = function->arg_begin();
381            arg->setName("assertion");
382            Value * e = &*arg++;
383            arg->setName("msg");
384            Value * msg = &*arg++;
385            arg->setName("sz");
386            Value * sz = &*arg;
387            SetInsertPoint(entry);
388            CreateCondBr(e, failure, success);
389            SetInsertPoint(failure);
390            Value * len = CreateAdd(sz, getSize(21));
391            ConstantInt * _11 = getSize(11);
392            Value * bytes = CreateMalloc(getInt8Ty(), len);
393            CreateMemCpy(bytes, CreateGlobalStringPtr("Assertion `"), _11, 1);
394            CreateMemCpy(CreateGEP(bytes, _11), msg, sz, 1);
395            CreateMemCpy(CreateGEP(bytes, CreateAdd(sz, _11)), CreateGlobalStringPtr("' failed.\n"), getSize(10), 1);
396            CreateWriteCall(getInt32(2), bytes, len);
397            CreateExit(-1);
398            CreateBr(success); // necessary to satisfy the LLVM verifier. this is not actually executed.
399            SetInsertPoint(success);
400            CreateRetVoid();
401            restoreIP(ip);
402        }
403        CreateCall(function, {CreateICmpEQ(assertion, Constant::getNullValue(assertion->getType())), CreateGlobalStringPtr(failureMessage), getSize(failureMessage.size())});
404    }
405}
406
407void CBuilder::CreateExit(const int exitCode) {
408    Function * exit = mMod->getFunction("exit");
409    if (LLVM_UNLIKELY(exit == nullptr)) {
410        FunctionType * fty = FunctionType::get(getVoidTy(), {getInt32Ty()}, false);
411        exit = Function::Create(fty, Function::ExternalLinkage, "exit", mMod);
412        exit->setDoesNotReturn();
413        exit->setDoesNotThrow();
414    }
415    CreateCall(exit, getInt32(exitCode));
416}
417
418BranchInst * CBuilder::CreateLikelyCondBr(Value * Cond, BasicBlock * True, BasicBlock * False, const int probability) {
419    MDBuilder mdb(getContext());
420    if (probability < 0 || probability > 100) {
421        report_fatal_error("branch weight probability must be in [0,100]");
422    }
423    return CreateCondBr(Cond, True, False, mdb.createBranchWeights(probability, 100 - probability));
424}
425
426CBuilder::CBuilder(Module * const m, const unsigned GeneralRegisterWidthInBits, const bool SupportsIndirectBr, const unsigned CacheLineAlignmentInBytes)
427: IRBuilder<>(m->getContext())
428, mMod(m)
429, mCacheLineAlignment(CacheLineAlignmentInBytes)
430, mSizeType(getIntNTy(GeneralRegisterWidthInBits))
431, mFILEtype(nullptr)
432, mSupportsIndirectBr(SupportsIndirectBr) {
433}
Note: See TracBrowser for help on using the repository browser.