diff --git a/lib/HLSL/DxilPreparePasses.cpp b/lib/HLSL/DxilPreparePasses.cpp index 9d56f57aa..cee26a2af 100644 --- a/lib/HLSL/DxilPreparePasses.cpp +++ b/lib/HLSL/DxilPreparePasses.cpp @@ -28,6 +28,7 @@ #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/Module.h" #include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/PassManager.h" #include "llvm/ADT/BitVector.h" #include "llvm/Pass.h" @@ -439,6 +440,9 @@ public: AddFunctionAnnotationForInitializers(M, DM); } + // Fix DIExpression fragments that cover whole variables + LegalizeDbgFragments(M); + return true; } @@ -481,6 +485,55 @@ private: } } + static bool BitPieceCoversEntireVar(DIExpression *expr, DILocalVariable *var, DITypeIdentifierMap &TypeIdentifierMap) { + if (expr->isBitPiece()) { + DIType *ty = var->getType().resolve(TypeIdentifierMap); + return expr->getBitPieceOffset() == 0 && expr->getBitPieceSize() == ty->getSizeInBits(); + } + return false; + } + + static void LegalizeDbgFragmentsForDbgIntrinsic(Function *f, DITypeIdentifierMap &TypeIdentifierMap) { + Intrinsic::ID intrinsic = f->getIntrinsicID(); + + DIBuilder dib(*f->getParent()); + if (intrinsic == Intrinsic::dbg_value) { + for (auto it = f->user_begin(), end = f->user_end(); it != end;) { + User *u = *(it++); + DbgValueInst *di = cast(u); + DIExpression *expr = di->getExpression(); + DILocalVariable *var = di->getVariable(); + if (BitPieceCoversEntireVar(expr, var, TypeIdentifierMap)) { + dib.insertDbgValueIntrinsic(di->getValue(), 0, var, DIExpression::get(di->getContext(), {}), di->getDebugLoc(), di); + di->eraseFromParent(); + } + } + } + else if (intrinsic == Intrinsic::dbg_declare) { + for (auto it = f->user_begin(), end = f->user_end(); it != end;) { + User *u = *(it++); + DbgDeclareInst *di = cast(u); + DIExpression *expr = di->getExpression(); + DILocalVariable *var = di->getVariable(); + if (BitPieceCoversEntireVar(expr, var, TypeIdentifierMap)) { + dib.insertDeclare(di->getAddress(), var, DIExpression::get(di->getContext(), {}), di->getDebugLoc(), di); + di->eraseFromParent(); + } + } + } + } + + static void LegalizeDbgFragments(Module &M) { + DITypeIdentifierMap TypeIdentifierMap; + + if (Function *f = M.getFunction(Intrinsic::getName(Intrinsic::dbg_value))) { + LegalizeDbgFragmentsForDbgIntrinsic(f, TypeIdentifierMap); + } + if (Function *f = M.getFunction(Intrinsic::getName(Intrinsic::dbg_declare))) { + LegalizeDbgFragmentsForDbgIntrinsic(f, TypeIdentifierMap); + } + } + void RemoveStoreUndefOutput(Module &M, hlsl::OP *hlslOP) { for (iplist::iterator F : M.getFunctionList()) { if (!hlslOP->IsDxilOpFunc(F)) diff --git a/tools/clang/test/HLSLFileCheck/dxil/debug/bitpiece_full_var.hlsl b/tools/clang/test/HLSLFileCheck/dxil/debug/bitpiece_full_var.hlsl new file mode 100644 index 000000000..f8e099e56 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxil/debug/bitpiece_full_var.hlsl @@ -0,0 +1,20 @@ +// RUN: %dxc -Zi -Od -E main -T ps_6_0 %s | FileCheck %s + +// Regression test for structs with just a single 32-bit member. + +// CHECK-DAG: call void @llvm.dbg.value(metadata float %{{.*}}, i64 0, metadata !{{[0-9]+}}, metadata !{{[0-9]+}}), !dbg !{{[0-9]+}} ; var:"my_s" !DIExpression() + +// Exclude quoted source file (see readme) +// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}} + +struct MyStruct { + float1 foo; +}; + +[RootSignature("")] +float main(float a : A) : SV_Target { + MyStruct my_s; + my_s.foo.x = a; + return my_s.foo.x; +} +