/*========================== begin_copyright_notice ============================

Copyright (C) 2017-2021 Intel Corporation

SPDX-License-Identifier: MIT

============================= end_copyright_notice ===========================*/

#ifndef _CISA_MEMOPT_H_
#define _CISA_MEMOPT_H_

#include "common/LLVMWarningsPush.hpp"
#include <llvm/ADT/ArrayRef.h>
#include "common/LLVMWarningsPop.hpp"
#include <stdint.h>

namespace llvm {
class FunctionPass;
class DataLayout;
class StructType;
class Type;
} // namespace llvm

namespace IGC {
class CodeGenContext;

llvm::FunctionPass *createMemOptPass(bool AllowNegativeSymPtrsForLoad, bool AllowVector8LoadStore);
llvm::FunctionPass *createLdStCombinePass();

// check both igc keys and internal flags
bool doLdStCombine(const CodeGenContext *CGC);
uint32_t getMaxStoreBytes(const CodeGenContext *CGC);
uint32_t getMaxLoadBytes(const CodeGenContext *CGC);

//
// Utility for struct manipulation
//

inline const char *getStructNameForSOALayout() { return "__StructSOALayout_"; }
inline const char *getStructNameForAOSLayout() { return "__StructAOSLayout_"; }

// If struct type is created by LdStCombine() for layout, return true.
bool isLayoutStructType(const StructType *StTy);
// If struct type is created by LdStCombine() in AOS layout, return true.
//   note: if a struct type is a layout struct, but not in AOS layout,
//         it must be in SOA layout.
bool isLayoutStructTypeAOS(const StructType *StTy);
bool isLayoutStructTypeSOA(const StructType *StTy);

// bitcastToUI64:
//   return C as ui64. C must fit into 64bits.
uint64_t bitcastToUI64(Constant *C, const DataLayout *DL);

// getStructMemberOffsetType_1:
//   Given a struct type 'StTy' and its 'Indices', return the type and
//   the byte offset of the member referred to by {StTy, Indices}.
//   This member must be at level 1.
//   The function checks to make sure 'Indices' has size of 1.
void getStructMemberByteOffsetAndType_1(const DataLayout *DL, StructType *StTy, const ArrayRef<unsigned> &Indices,
                                        Type *&Ty, uint32_t &ByteOffset);

// getStructMemberOffsetType_2:
//   Given a struct type 'StTy' and its 'Indices', return the types and
//   the byte offsets of the member referred to by {StTy, Indices}.
//   This member is at most at level 2. If it is at level 2, its enclosing
//   type at level 1 must be of struct type.
//   The returned results {Ty0, ByteOffset0} is for level 1 member; and
//   {Ty1, ByteOffset1} is for level 2 if it is at level 2 (Ty1 must not
//   be nullptr).
//   The function checks to maek sure 'Indices' has size of 2 at most.
void getStructMemberOffsetAndType_2(const DataLayout *DL, StructType *StTy, const ArrayRef<unsigned> &Indices,
                                    Type *&Ty0, uint32_t &ByteOffset0, Type *&Ty1, uint32_t &ByteOffset1);

// getAllDefinedMembers
//   Given a value 'V' of struct type, return all the indices of members
//   that have been defined (via insertValueInst), if not sure, all
//   indices of the struct type are returned.
// For the example,
//   Given struct = {i32, i32, i32, i32 }
//
//   %8 = insertvalue undef, i32 %3, 0
//   %9 = insertvalue %8,    i32 %4, 1
//  %10 = insertvalue %9,    i32 %5, 2
//
//  The value %9 will return {0, 1}, and %10 will return {0, 1, 2}.
void getAllDefinedMembers(const Value *IVI, SmallVectorImpl<std::vector<unsigned>> &fieldsTBC);
} // namespace IGC

#endif // _CISA_MEMOPT_H_
