#pragma once #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/MapVector.h" #include "dxc/DXIL/DxilCBuffer.h" #include #include namespace clang { class HLSLPatchConstantFuncAttr; namespace CodeGen { class CodeGenModule; } } namespace llvm { class Function; class Module; class Value; class DebugLoc; class Constant; class GlobalVariable; class CallInst; class Instruction; template class SmallVector; } namespace hlsl { class HLModule; struct DxilResourceProperties; struct DxilFunctionProps; class DxilFieldAnnotation; enum class IntrinsicOp; namespace dxilutil { class ExportMap; } } namespace CGHLSLMSHelper { struct EntryFunctionInfo { clang::SourceLocation SL = clang::SourceLocation(); llvm::Function *Func = nullptr; }; // Map to save patch constant functions struct PatchConstantInfo { clang::SourceLocation SL = clang::SourceLocation(); llvm::Function *Func = nullptr; std::uint32_t NumOverloads = 0; }; /// Use this class to represent HLSL cbuffer in high-level DXIL. class HLCBuffer : public hlsl::DxilCBuffer { public: HLCBuffer(bool bIsView, bool bIsTBuf) : bIsView(bIsView), bIsTBuf(bIsTBuf), bIsArray(false), ResultTy(nullptr) {} virtual ~HLCBuffer() = default; void AddConst(std::unique_ptr &pItem) { pItem->SetID(constants.size()); constants.push_back(std::move(pItem)); } std::vector> &GetConstants() { return constants; } bool IsView() { return bIsView; } bool IsTBuf() { return bIsTBuf; } bool IsArray() { return bIsArray; } void SetIsArray() { bIsArray = true; } llvm::Type *GetResultType() { return ResultTy; } void SetResultType(llvm::Type *Ty) { ResultTy = Ty; } private: std::vector> constants; // constants inside const buffer bool bIsView; bool bIsTBuf; bool bIsArray; llvm::Type *ResultTy; }; // Scope to help transform multiple returns. struct Scope { enum class ScopeKind { IfScope, SwitchScope, LoopScope, ReturnScope, FunctionScope, }; ScopeKind kind; llvm::BasicBlock *EndScopeBB; // Save loopContinueBB to create dxBreak. llvm::BasicBlock *loopContinueBB; // For case like // if () { // ... // return; // } else { // ... // return; // } // // both path is returned. // When whole scope is returned, go to parent scope directly. // Anything after it is unreachable. bool bWholeScopeReturned; unsigned parentScopeIndex; }; class ScopeInfo { public: ScopeInfo(){} ScopeInfo(llvm::Function *F); void AddIf(llvm::BasicBlock *endIfBB); void AddSwitch(llvm::BasicBlock *endSwitchBB); void AddLoop(llvm::BasicBlock *loopContinue, llvm::BasicBlock *endLoopBB); void AddRet(llvm::BasicBlock *bbWithRet); void EndScope(bool bScopeFinishedWithRet); Scope &GetScope(unsigned i); const llvm::SmallVector &GetRetScopes() { return rets; } void LegalizeWholeReturnedScope(); llvm::SmallVector &GetScopes() { return scopes; } bool CanSkipStructurize(); private: void AddScope(Scope::ScopeKind k, llvm::BasicBlock *endScopeBB); llvm::SmallVector rets; unsigned maxRetLevel; bool bAllReturnsInIf; llvm::SmallVector scopeStack; // save all scopes. llvm::SmallVector scopes; }; // Map from value to resource properties. // This only collect object variables(global/local/parameter), not object fields inside struct. // Object fields inside struct is saved by TypeAnnotation. struct DxilObjectProperties { bool AddResource(llvm::Value *V, const hlsl::DxilResourceProperties &RP); bool IsResource(llvm::Value *V); hlsl::DxilResourceProperties GetResource(llvm::Value *V); // MapVector for deterministic iteration order. llvm::MapVector resMap; }; // Align cbuffer offset in legacy mode (16 bytes per row). unsigned AlignBufferOffsetInLegacy(unsigned offset, unsigned size, unsigned scalarSizeInBytes, bool bNeedNewRow); void FinishEntries(hlsl::HLModule &HLM, const EntryFunctionInfo &Entry, clang::CodeGen::CodeGenModule &CGM, llvm::StringMap &entryFunctionMap, std::unordered_map &HSEntryPatchConstantFuncAttr, llvm::StringMap &patchConstantFunctionMap, std::unordered_map> &patchConstantFunctionPropsMap); void FinishIntrinsics( hlsl::HLModule &HLM, std::vector> &intrinsicMap, DxilObjectProperties &valToResPropertiesMap); void AddDxBreak(llvm::Module &M, const llvm::SmallVector &DxBreaks); void ReplaceConstStaticGlobals( std::unordered_map> &staticConstGlobalInitListMap, std::unordered_map &staticConstGlobalCtorMap); void FinishClipPlane(hlsl::HLModule &HLM, std::vector &clipPlaneFuncList, std::unordered_map &debugInfoMap, clang::CodeGen::CodeGenModule &CGM); void AddRegBindingsForResourceInConstantBuffer( hlsl::HLModule &HLM, llvm::DenseMap, 1>> &constantRegBindingMap); void FinishCBuffer( hlsl::HLModule &HLM, llvm::Type *CBufferType, std::unordered_map &AnnotationMap); void ProcessCtorFunctions(llvm::Module &M, llvm::SmallVector &Ctors, llvm::Function *Entry, llvm::Function *PatchConstantFn); void CollectCtorFunctions(llvm::Module &M, llvm::StringRef globalName, llvm::SmallVector &Ctors, clang::CodeGen::CodeGenModule &CGM); void TranslateRayQueryConstructor(hlsl::HLModule &HLM); void UpdateLinkage( hlsl::HLModule &HLM, clang::CodeGen::CodeGenModule &CGM, hlsl::dxilutil::ExportMap &exportMap, llvm::StringMap &entryFunctionMap, llvm::StringMap &patchConstantFunctionMap); void StructurizeMultiRet(llvm::Module &M, clang::CodeGen::CodeGenModule &CGM, llvm::DenseMap &ScopeMap, bool bWaveEnabledStage, llvm::SmallVector &DxBreaks); llvm::Value *TryEvalIntrinsic(llvm::CallInst *CI, hlsl::IntrinsicOp intriOp, unsigned hlslVersion); void SimpleTransformForHLDXIR(llvm::Module *pM); void ExtensionCodeGen(hlsl::HLModule &HLM, clang::CodeGen::CodeGenModule &CGM); } // namespace CGHLSLMSHelper