This change drops the use of the "Layout" type and instead uses explicit padding throughout the compiler to represent types in HLSL buffers. There are a few parts to this, though it's difficult to split them up as they're very interdependent: 1. Refactor HLSLBufferLayoutBuilder to allow us to calculate the padding of arbitrary types. 2. Teach Clang CodeGen to use HLSL specific paths for cbuffers when generating aggregate copies, array accesses, and structure accesses. 3. Simplify DXILCBufferAccesses such that it directly replaces accesses with dx.resource.getpointer rather than recalculating the layout. 4. Basic infrastructure for SPIR-V handling, but the implementation itself will need work in follow ups. Fixes several issues, including #138996, #144573, and #156084. Resolves #147352.
111 lines
3.9 KiB
C++
111 lines
3.9 KiB
C++
//===- DirectX.cpp---------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ABIInfoImpl.h"
|
|
#include "CodeGenModule.h"
|
|
#include "HLSLBufferLayoutBuilder.h"
|
|
#include "TargetInfo.h"
|
|
#include "clang/AST/Type.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
#include "llvm/IR/Type.h"
|
|
|
|
using namespace clang;
|
|
using namespace clang::CodeGen;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Target codegen info implementation for DirectX.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
|
|
public:
|
|
DirectXTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
|
|
: TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
|
|
|
|
llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *T,
|
|
const CGHLSLOffsetInfo &OffsetInfo) const override;
|
|
|
|
llvm::Type *getHLSLPadding(CodeGenModule &CGM,
|
|
CharUnits NumBytes) const override {
|
|
unsigned Size = NumBytes.getQuantity();
|
|
return llvm::TargetExtType::get(CGM.getLLVMContext(), "dx.Padding", {},
|
|
{Size});
|
|
}
|
|
|
|
bool isHLSLPadding(llvm::Type *Ty) const override {
|
|
if (auto *TET = dyn_cast<llvm::TargetExtType>(Ty))
|
|
return TET->getName() == "dx.Padding";
|
|
return false;
|
|
}
|
|
};
|
|
|
|
llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
|
|
CodeGenModule &CGM, const Type *Ty,
|
|
const CGHLSLOffsetInfo &OffsetInfo) const {
|
|
auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
|
|
if (!ResType)
|
|
return nullptr;
|
|
|
|
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
|
|
const HLSLAttributedResourceType::Attributes &ResAttrs = ResType->getAttrs();
|
|
switch (ResAttrs.ResourceClass) {
|
|
case llvm::dxil::ResourceClass::UAV:
|
|
case llvm::dxil::ResourceClass::SRV: {
|
|
// TypedBuffer and RawBuffer both need element type
|
|
QualType ContainedTy = ResType->getContainedType();
|
|
if (ContainedTy.isNull())
|
|
return nullptr;
|
|
|
|
// convert element type
|
|
llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
|
|
|
|
llvm::StringRef TypeName =
|
|
ResAttrs.RawBuffer ? "dx.RawBuffer" : "dx.TypedBuffer";
|
|
SmallVector<unsigned, 3> Ints = {/*IsWriteable*/ ResAttrs.ResourceClass ==
|
|
llvm::dxil::ResourceClass::UAV,
|
|
/*IsROV*/ ResAttrs.IsROV};
|
|
if (!ResAttrs.RawBuffer) {
|
|
const clang::Type *ElemType = ContainedTy->getUnqualifiedDesugaredType();
|
|
if (ElemType->isVectorType())
|
|
ElemType = cast<clang::VectorType>(ElemType)
|
|
->getElementType()
|
|
->getUnqualifiedDesugaredType();
|
|
Ints.push_back(/*IsSigned*/ ElemType->isSignedIntegerType());
|
|
}
|
|
|
|
return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
|
|
}
|
|
case llvm::dxil::ResourceClass::CBuffer: {
|
|
QualType ContainedTy = ResType->getContainedType();
|
|
if (ContainedTy.isNull() || !ContainedTy->isStructureType())
|
|
return nullptr;
|
|
|
|
llvm::StructType *BufferLayoutTy =
|
|
HLSLBufferLayoutBuilder(CGM).layOutStruct(
|
|
ContainedTy->getAsCanonical<RecordType>(), OffsetInfo);
|
|
if (!BufferLayoutTy)
|
|
return nullptr;
|
|
|
|
return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {BufferLayoutTy});
|
|
}
|
|
case llvm::dxil::ResourceClass::Sampler:
|
|
llvm_unreachable("dx.Sampler handles are not implemented yet");
|
|
break;
|
|
}
|
|
llvm_unreachable("Unknown llvm::dxil::ResourceClass enum");
|
|
}
|
|
|
|
} // namespace
|
|
|
|
std::unique_ptr<TargetCodeGenInfo>
|
|
CodeGen::createDirectXTargetCodeGenInfo(CodeGenModule &CGM) {
|
|
return std::make_unique<DirectXTargetCodeGenInfo>(CGM.getTypes());
|
|
}
|