| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // DxilUtil.h // |
| // Copyright (C) Microsoft Corporation. All rights reserved. // |
| // This file is distributed under the University of Illinois Open Source // |
| // License. See LICENSE.TXT for details. // |
| // // |
| // DXIL helper functions. // |
| // // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #pragma once |
| #include <memory> |
| #include <string> |
| #include <unordered_set> |
| |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/GetElementPtrTypeIterator.h" |
| #include "llvm/IR/IRBuilder.h" |
| |
| #include "dxc/DXIL/DxilConstants.h" |
| #include "dxc/DXIL/DxilResourceProperties.h" |
| |
| namespace llvm { |
| class Type; |
| class GlobalVariable; |
| class Function; |
| class Module; |
| class MemoryBuffer; |
| class LLVMContext; |
| class DiagnosticInfo; |
| class Value; |
| class Instruction; |
| class CallInst; |
| class BasicBlock; |
| class raw_ostream; |
| class ModulePass; |
| class PassRegistry; |
| class DebugInfoFinder; |
| class DebugLoc; |
| class DIGlobalVariable; |
| class ConstantInt; |
| class SwitchInst; |
| class GEPOperator; |
| |
| ModulePass *createDxilLoadMetadataPass(); |
| void initializeDxilLoadMetadataPass(llvm::PassRegistry &); |
| } // namespace llvm |
| |
| namespace hlsl { |
| |
| class DxilFieldAnnotation; |
| class DxilModule; |
| class DxilTypeSystem; |
| class OP; |
| |
| namespace dxilutil { |
| extern const char ManglingPrefix[]; |
| extern const char EntryPrefix[]; |
| extern const char *kResourceMapErrorMsg; |
| |
| unsigned GetLegacyCBufferFieldElementSize(DxilFieldAnnotation &fieldAnnotation, |
| llvm::Type *Ty, |
| DxilTypeSystem &typeSys); |
| llvm::Type *GetArrayEltTy(llvm::Type *Ty); |
| bool HasDynamicIndexing(llvm::Value *V); |
| |
| // Cleans up unnecessary chains of GEPs and bitcasts left over from certain |
| // optimizations. This function is NOT safe to call while iterating |
| // instructions either forward or backward. If V happens to be a GEP or |
| // bitcast, the function may delete V, instructions preceding V it, and |
| // instructions following V. |
| bool MergeGepUse(llvm::Value *V); |
| |
| // Find alloca insertion point, given instruction |
| llvm::Instruction * |
| FindAllocaInsertionPt(llvm::Instruction *I); // Considers entire parent function |
| llvm::Instruction * |
| FindAllocaInsertionPt(llvm::BasicBlock *BB); // Only considers provided block |
| llvm::Instruction *FindAllocaInsertionPt(llvm::Function *F); |
| llvm::Instruction *SkipAllocas(llvm::Instruction *I); |
| // Get first non-alloca insertion point, to avoid inserting non-allocas before |
| // alloca |
| llvm::Instruction *FirstNonAllocaInsertionPt( |
| llvm::Instruction *I); // Considers entire parent function |
| llvm::Instruction *FirstNonAllocaInsertionPt( |
| llvm::BasicBlock *BB); // Only considers provided block |
| llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Function *F); |
| |
| bool IsStaticGlobal(llvm::GlobalVariable *GV); |
| bool IsSharedMemoryGlobal(llvm::GlobalVariable *GV); |
| bool RemoveUnusedFunctions(llvm::Module &M, llvm::Function *EntryFunc, |
| llvm::Function *PatchConstantFunc, bool IsLib); |
| |
| llvm::DIGlobalVariable * |
| FindGlobalVariableDebugInfo(llvm::GlobalVariable *GV, |
| llvm::DebugInfoFinder &DbgInfoFinder); |
| |
| void EmitErrorOnInstruction(llvm::Instruction *I, llvm::Twine Msg); |
| void EmitWarningOnInstruction(llvm::Instruction *I, llvm::Twine Msg); |
| void EmitErrorOnFunction(llvm::LLVMContext &Ctx, llvm::Function *F, |
| llvm::Twine Msg); |
| void EmitWarningOnFunction(llvm::LLVMContext &Ctx, llvm::Function *F, |
| llvm::Twine Msg); |
| void EmitErrorOnGlobalVariable(llvm::LLVMContext &Ctx, llvm::GlobalVariable *GV, |
| llvm::Twine Msg); |
| void EmitWarningOnGlobalVariable(llvm::LLVMContext &Ctx, |
| llvm::GlobalVariable *GV, llvm::Twine Msg); |
| void EmitErrorOnContext(llvm::LLVMContext &Ctx, llvm::Twine Msg); |
| void EmitWarningOnContext(llvm::LLVMContext &Ctx, llvm::Twine Msg); |
| void EmitNoteOnContext(llvm::LLVMContext &Ctx, llvm::Twine Msg); |
| |
| void EmitResMappingError(llvm::Instruction *Res); |
| // Simple demangle just support case "\01?name@" pattern. |
| llvm::StringRef DemangleFunctionName(llvm::StringRef name); |
| // ReplaceFunctionName replaces the undecorated portion of originalName with |
| // undecorated newName |
| std::string ReplaceFunctionName(llvm::StringRef originalName, |
| llvm::StringRef newName); |
| void PrintEscapedString(llvm::StringRef Name, llvm::raw_ostream &Out); |
| void PrintUnescapedString(llvm::StringRef Name, llvm::raw_ostream &Out); |
| // Change select/phi on operands into select/phi on operation. |
| // phi0 = phi a0, b0, c0 |
| // phi1 = phi a1, b1, c1 |
| // Inst = Add(phi0, phi1); |
| // into |
| // A = Add(a0, a1); |
| // B = Add(b0, b1); |
| // C = Add(c0, c1); |
| // NewInst = phi A, B, C |
| // Only support 1 operand now, other oerands should be Constant. |
| llvm::Value *SelectOnOperation(llvm::Instruction *Inst, unsigned operandIdx); |
| // Collect all select operand used by Inst. |
| void CollectSelect(llvm::Instruction *Inst, |
| std::unordered_set<llvm::Instruction *> &selectSet); |
| // If all operands are the same for a select inst, replace it with the operand. |
| // Returns replacement value if successful |
| llvm::Value *MergeSelectOnSameValue(llvm::Instruction *SelInst, |
| unsigned startOpIdx, unsigned numOperands); |
| bool SimplifyTrivialPHIs(llvm::BasicBlock *BB); |
| llvm::BasicBlock *GetSwitchSuccessorForCond(llvm::SwitchInst *Switch, |
| llvm::ConstantInt *Cond); |
| void MigrateDebugValue(llvm::Value *Old, llvm::Value *New); |
| void TryScatterDebugValueToVectorElements(llvm::Value *Val); |
| std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::StringRef BC, |
| llvm::LLVMContext &Ctx, |
| std::string &DiagStr); |
| std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::MemoryBuffer *MB, |
| llvm::LLVMContext &Ctx, |
| std::string &DiagStr); |
| std::unique_ptr<llvm::Module> |
| LoadModuleFromBitcodeLazy(std::unique_ptr<llvm::MemoryBuffer> &&MB, |
| llvm::LLVMContext &Ctx, std::string &DiagStr); |
| void PrintDiagnosticHandler(const llvm::DiagnosticInfo &DI, void *Context); |
| bool IsIntegerOrFloatingPointType(llvm::Type *Ty); |
| // Returns true if type contains HLSL Object type (resource) |
| bool ContainsHLSLObjectType(llvm::Type *Ty); |
| std::pair<bool, DxilResourceProperties> |
| GetHLSLResourceProperties(llvm::Type *Ty); |
| bool IsHLSLResourceType(llvm::Type *Ty); |
| bool IsHLSLObjectType(llvm::Type *Ty); |
| bool IsHLSLRayQueryType(llvm::Type *Ty); |
| bool IsHLSLWaveMatrixType(llvm::Type *Ty, |
| DXIL::WaveMatrixKind *pKind = nullptr); |
| bool IsHLSLResourceDescType(llvm::Type *Ty); |
| bool IsResourceSingleComponent(llvm::Type *Ty); |
| uint8_t GetResourceComponentCount(llvm::Type *Ty); |
| bool IsSplat(llvm::ConstantDataVector *cdv); |
| bool IsHLSLNodeIOType(llvm::Type *Ty); |
| bool IsHLSLNodeOutputType(llvm::Type *Ty); |
| bool IsHLSLNodeOutputArrayType(llvm::Type *Ty); |
| bool IsHLSLEmptyNodeOutputType(llvm::Type *Ty); |
| bool IsHLSLEmptyNodeOutputArrayType(llvm::Type *Ty); |
| bool IsHLSLNodeInputRecordType(llvm::Type *Ty); |
| bool IsHLSLRWNodeInputRecordType(llvm::Type *Ty); |
| bool IsHLSLNodeOutputRecordType(llvm::Type *Ty); |
| bool IsHLSLGSNodeOutputRecordType(llvm::Type *Ty); |
| bool IsHLSLNodeRecordType(llvm::Type *Ty); |
| bool IsHLSLNodeInputOutputType(llvm::Type *Ty); |
| |
| llvm::Type * |
| StripArrayTypes(llvm::Type *Ty, |
| llvm::SmallVectorImpl<unsigned> *OuterToInnerLengths = nullptr); |
| llvm::Type *WrapInArrayTypes(llvm::Type *Ty, |
| llvm::ArrayRef<unsigned> OuterToInnerLengths); |
| llvm::Value *MirrorGEP(llvm::GEPOperator *GEP, llvm::Value *NewBasePtr); |
| |
| llvm::CallInst *TranslateCallRawBufferLoadToBufferLoad( |
| llvm::CallInst *CI, llvm::Function *newFunction, hlsl::OP *op); |
| void ReplaceRawBufferLoadWithBufferLoad(llvm::Function *F, hlsl::OP *op); |
| |
| llvm::CallInst *TranslateCallRawBufferStoreToBufferStore( |
| llvm::CallInst *CI, llvm::Function *newFunction, hlsl::OP *op); |
| void ReplaceRawBufferStoreWithBufferStore(llvm::Function *F, hlsl::OP *op); |
| |
| void ReplaceRawBufferLoad64Bit(llvm::Function *F, llvm::Type *EltTy, |
| hlsl::OP *hlslOP); |
| void ReplaceRawBufferStore64Bit(llvm::Function *F, llvm::Type *ETy, |
| hlsl::OP *hlslOP); |
| |
| bool IsConvergentMarker(llvm::Value *V); |
| llvm::Value *GetConvergentSource(llvm::Value *V); |
| |
| /// If value is a bitcast to base class pattern, equivalent |
| /// to a getelementptr X, 0, 0, 0... turn it into the appropriate gep. |
| /// This can enhance SROA and other transforms that want type-safe pointers, |
| /// and enables merging with other getelementptr's. |
| llvm::Value *TryReplaceBaseCastWithGep(llvm::Value *V); |
| bool FunctionHasNoSideEffects(llvm::Instruction *I); |
| llvm::Value::user_iterator mdv_users_end(llvm::Value *V); |
| llvm::Value::user_iterator mdv_users_begin(llvm::Value *V); |
| inline bool mdv_user_empty(llvm::Value *V) { |
| return mdv_users_begin(V) == mdv_users_end(V); |
| } |
| |
| /// Finds all allocas that only have stores and delete them. |
| /// These allocas hold on to values that do not contribute to the |
| /// shader's results. |
| bool DeleteDeadAllocas(llvm::Function &F); |
| |
| llvm::Value *GEPIdxToOffset(llvm::GetElementPtrInst *GEP, |
| llvm::IRBuilder<> &Builder, hlsl::OP *OP, |
| const llvm::DataLayout &DL); |
| } // namespace dxilutil |
| |
| } // namespace hlsl |