1/****************************************************************************
2 * Copyright (C) 2014-2015 Intel Corporation.   All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * @file builder.h
24 *
25 * @brief Includes all the builder related functionality
26 *
27 * Notes:
28 *
29 ******************************************************************************/
30
31#include "jit_pch.hpp"
32#include "builder.h"
33
34namespace SwrJit
35{
36    using namespace llvm;
37
38    //////////////////////////////////////////////////////////////////////////
39    /// @brief Contructor for Builder.
40    /// @param pJitMgr - JitManager which contains modules, function passes, etc.
41    Builder::Builder(JitManager* pJitMgr) : mpJitMgr(pJitMgr), mpPrivateContext(nullptr)
42    {
43        mVWidth   = pJitMgr->mVWidth;
44        mVWidth16 = 16;
45
46        mpIRBuilder = &pJitMgr->mBuilder;
47
48        // Built in types: scalar
49
50        mVoidTy     = Type::getVoidTy(pJitMgr->mContext);
51        mFP16Ty     = Type::getHalfTy(pJitMgr->mContext);
52        mFP32Ty     = Type::getFloatTy(pJitMgr->mContext);
53        mFP32PtrTy  = PointerType::get(mFP32Ty, 0);
54        mDoubleTy   = Type::getDoubleTy(pJitMgr->mContext);
55        mInt1Ty     = Type::getInt1Ty(pJitMgr->mContext);
56        mInt8Ty     = Type::getInt8Ty(pJitMgr->mContext);
57        mInt16Ty    = Type::getInt16Ty(pJitMgr->mContext);
58        mInt32Ty    = Type::getInt32Ty(pJitMgr->mContext);
59        mInt64Ty    = Type::getInt64Ty(pJitMgr->mContext);
60        mInt8PtrTy  = PointerType::get(mInt8Ty, 0);
61        mInt16PtrTy = PointerType::get(mInt16Ty, 0);
62        mInt32PtrTy = PointerType::get(mInt32Ty, 0);
63        mInt64PtrTy = PointerType::get(mInt64Ty, 0);
64        mHandleTy   = mInt8PtrTy;
65
66        mSimd4FP64Ty = getVectorType(mDoubleTy, 4);
67
68        // Built in types: target simd
69        SetTargetWidth(pJitMgr->mVWidth);
70
71        // Built in types: simd16
72
73        mSimd16Int1Ty     = getVectorType(mInt1Ty, mVWidth16);
74        mSimd16Int16Ty    = getVectorType(mInt16Ty, mVWidth16);
75        mSimd16Int32Ty    = getVectorType(mInt32Ty, mVWidth16);
76        mSimd16Int64Ty    = getVectorType(mInt64Ty, mVWidth16);
77        mSimd16FP16Ty     = getVectorType(mFP16Ty, mVWidth16);
78        mSimd16FP32Ty     = getVectorType(mFP32Ty, mVWidth16);
79        mSimd16VectorTy   = ArrayType::get(mSimd16FP32Ty, 4);
80        mSimd16VectorTRTy = ArrayType::get(mSimd16FP32Ty, 5);
81
82        mSimd32Int8Ty = getVectorType(mInt8Ty, 32);
83
84        if (sizeof(uint32_t*) == 4)
85        {
86            mIntPtrTy       = mInt32Ty;
87            mSimdIntPtrTy   = mSimdInt32Ty;
88            mSimd16IntPtrTy = mSimd16Int32Ty;
89        }
90        else
91        {
92            SWR_ASSERT(sizeof(uint32_t*) == 8);
93
94            mIntPtrTy       = mInt64Ty;
95            mSimdIntPtrTy   = mSimdInt64Ty;
96            mSimd16IntPtrTy = mSimd16Int64Ty;
97        }
98    }
99
100    void Builder::SetTargetWidth(uint32_t width)
101    {
102        mVWidth = width;
103
104        mSimdInt1Ty      = getVectorType(mInt1Ty, mVWidth);
105        mSimdInt16Ty     = getVectorType(mInt16Ty, mVWidth);
106        mSimdInt32Ty     = getVectorType(mInt32Ty, mVWidth);
107        mSimdInt64Ty     = getVectorType(mInt64Ty, mVWidth);
108        mSimdFP16Ty      = getVectorType(mFP16Ty, mVWidth);
109        mSimdFP32Ty      = getVectorType(mFP32Ty, mVWidth);
110        mSimdVectorTy    = ArrayType::get(mSimdFP32Ty, 4);
111        mSimdVectorIntTy = ArrayType::get(mSimdInt32Ty, 4);
112        mSimdVectorTRTy  = ArrayType::get(mSimdFP32Ty, 5);
113        mSimdVectorTRIntTy  = ArrayType::get(mSimdInt32Ty, 5);
114    }
115
116    /// @brief Mark this alloca as temporary to avoid hoisting later on
117    void Builder::SetTempAlloca(Value* inst)
118    {
119        AllocaInst* pAlloca = dyn_cast<AllocaInst>(inst);
120        SWR_ASSERT(pAlloca, "Unexpected non-alloca instruction");
121        MDNode* N = MDNode::get(JM()->mContext, MDString::get(JM()->mContext, "is_temp_alloca"));
122        pAlloca->setMetadata("is_temp_alloca", N);
123    }
124
125    bool Builder::IsTempAlloca(Value* inst)
126    {
127        AllocaInst* pAlloca = dyn_cast<AllocaInst>(inst);
128        SWR_ASSERT(pAlloca, "Unexpected non-alloca instruction");
129
130        return (pAlloca->getMetadata("is_temp_alloca") != nullptr);
131    }
132
133    // Returns true if able to find a call instruction to mark
134    bool Builder::SetNamedMetaDataOnCallInstr(Instruction* inst, StringRef mdName)
135    {
136        CallInst* pCallInstr = dyn_cast<CallInst>(inst);
137        if (pCallInstr)
138        {
139            MDNode* N = MDNode::get(JM()->mContext, MDString::get(JM()->mContext, mdName));
140            pCallInstr->setMetadata(mdName, N);
141            return true;
142        }
143        else
144        {
145            // Follow use def chain back up
146            for (Use& u : inst->operands())
147            {
148                Instruction* srcInst = dyn_cast<Instruction>(u.get());
149                if (srcInst)
150                {
151                    if (SetNamedMetaDataOnCallInstr(srcInst, mdName))
152                    {
153                        return true;
154                    }
155                }
156            }
157        }
158
159        return false;
160    }
161
162    bool Builder::HasNamedMetaDataOnCallInstr(Instruction* inst, StringRef mdName)
163    {
164        CallInst* pCallInstr = dyn_cast<CallInst>(inst);
165
166        if (!pCallInstr)
167        {
168            return false;
169        }
170
171        return (pCallInstr->getMetadata(mdName) != nullptr);
172    }
173
174    //////////////////////////////////////////////////////////////////////////
175    /// @brief Packetizes the type. Assumes SOA conversion.
176    Type* Builder::GetVectorType(Type* pType)
177    {
178        if (pType->isVectorTy())
179        {
180            return pType;
181        }
182
183        // [N x float] should packetize to [N x <8 x float>]
184        if (pType->isArrayTy())
185        {
186            uint32_t arraySize     = pType->getArrayNumElements();
187            Type*    pArrayType    = pType->getArrayElementType();
188            Type*    pVecArrayType = GetVectorType(pArrayType);
189            Type*    pVecType      = ArrayType::get(pVecArrayType, arraySize);
190            return pVecType;
191        }
192
193        // {float,int} should packetize to {<8 x float>, <8 x int>}
194        if (pType->isAggregateType())
195        {
196            uint32_t              numElems = pType->getStructNumElements();
197            SmallVector<Type*, 8> vecTypes;
198            for (uint32_t i = 0; i < numElems; ++i)
199            {
200                Type* pElemType    = pType->getStructElementType(i);
201                Type* pVecElemType = GetVectorType(pElemType);
202                vecTypes.push_back(pVecElemType);
203            }
204            Type* pVecType = StructType::get(JM()->mContext, vecTypes);
205            return pVecType;
206        }
207
208        // [N x float]* should packetize to [N x <8 x float>]*
209        if (pType->isPointerTy() && pType->getPointerElementType()->isArrayTy())
210        {
211            return PointerType::get(GetVectorType(pType->getPointerElementType()),
212                                    pType->getPointerAddressSpace());
213        }
214
215        // <ty> should packetize to <8 x <ty>>
216        Type* vecType = getVectorType(pType, JM()->mVWidth);
217        return vecType;
218    }
219} // namespace SwrJit
220