1818#include " llvm/ADT/StringRef.h"
1919#include " llvm/Analysis/ModuleSummaryAnalysis.h"
2020#include " llvm/IR/Constants.h"
21+ #include " llvm/IR/DebugInfo.h"
2122#include " llvm/IR/DerivedTypes.h"
2223#include " llvm/IR/GlobalVariable.h"
2324#include " llvm/IR/IntrinsicInst.h"
2829#include " llvm/InitializePasses.h"
2930#include " llvm/Pass.h"
3031#include " llvm/Support/Alignment.h"
32+ #include " llvm/Transforms/Utils/Cloning.h"
3133#include " llvm/Transforms/Utils/ModuleUtils.h"
3234
3335using namespace llvm ;
@@ -138,7 +140,75 @@ static void removeLifetimeIntrinsics(Module &M) {
138140 }
139141}
140142
143+ static void replaceNamedMetadataArray (Module &M, StringRef Name,
144+ ArrayRef<Metadata *> NewOps) {
145+ NamedMDNode *NMD = M.getNamedMetadata (Name);
146+ if (!NMD)
147+ return ;
148+ NMD->eraseFromParent ();
149+ M.getOrInsertNamedMetadata (Name)->addOperand (
150+ MDTuple::get (M.getContext (), NewOps));
151+ }
152+
141153class EmbedDXILPass : public llvm ::ModulePass {
154+ std::string writeModule (Module &M, bool HasDebugInfo, bool IsDebug) {
155+ std::string Data;
156+ llvm::raw_string_ostream OS (Data);
157+
158+ if (HasDebugInfo) {
159+ if (IsDebug) {
160+ // Replace dx.source metadata nodes with stubs.
161+ // TODO: Add /Qsource_in_debug_module flag to enable/disable this.
162+ LLVMContext &Ctx = M.getContext ();
163+ MDString *EmptyString = MDString::get (Ctx, " " );
164+ replaceNamedMetadataArray (M, " dx.source.contents" ,
165+ {EmptyString, EmptyString});
166+ replaceNamedMetadataArray (M, " dx.source.defines" , {});
167+ replaceNamedMetadataArray (M, " dx.source.mainFileName" , {EmptyString});
168+ replaceNamedMetadataArray (M, " dx.source.args" , {});
169+ } else {
170+ // If we have an ILDB part, strip DXIL from all debug info.
171+ StripDebugInfo (M);
172+
173+ // Also, manually remove debug version flags and dx.source nodes.
174+ if (NamedMDNode *Flags = M.getModuleFlagsMetadata ()) {
175+ SmallVector<llvm::Module::ModuleFlagEntry, 4 > FlagEntries;
176+ M.getModuleFlagsMetadata (FlagEntries);
177+ Flags->eraseFromParent ();
178+ for (unsigned I : seq (FlagEntries.size ())) {
179+ llvm::Module::ModuleFlagEntry &Entry = FlagEntries[I];
180+ if (Entry.Key ->getString () == " Dwarf Version" ||
181+ Entry.Key ->getString () == " Debug Info Version" ) {
182+ continue ;
183+ }
184+ M.addModuleFlag (Entry.Behavior , Entry.Key ->getString (),
185+ cast<ConstantAsMetadata>(Entry.Val )->getValue ());
186+ }
187+ }
188+ for (NamedMDNode &NMD : llvm::make_early_inc_range (M.named_metadata ()))
189+ if (NMD.getName ().starts_with (" dx.source" ))
190+ NMD.eraseFromParent ();
191+ }
192+ }
193+
194+ const auto DIMap = DXILDebugInfoPass::run (M);
195+ WriteDXILToFile (M, OS, DIMap);
196+ return Data;
197+ }
198+
199+ GlobalVariable *createSectionGlobal (Module &M, StringRef Data,
200+ StringRef GlobalName,
201+ StringRef SectionName) {
202+ Constant *ModuleConstant =
203+ ConstantDataArray::get (M.getContext (), arrayRefFromStringRef (Data));
204+ auto *GV = new llvm::GlobalVariable (M, ModuleConstant->getType (), true ,
205+ GlobalValue::PrivateLinkage,
206+ ModuleConstant, GlobalName);
207+ GV->setSection (SectionName);
208+ GV->setAlignment (Align (4 ));
209+ return GV;
210+ }
211+
142212public:
143213 static char ID; // Pass identification, replacement for typeid
144214 EmbedDXILPass () : ModulePass(ID) {
@@ -148,29 +218,38 @@ class EmbedDXILPass : public llvm::ModulePass {
148218 StringRef getPassName () const override { return " DXIL Embedder" ; }
149219
150220 bool runOnModule (Module &M) override {
151- std::string Data;
152- llvm::raw_string_ostream OS (Data);
153-
154221 // Perform late legalization of lifetime intrinsics that would otherwise
155222 // fail the Module Verifier if performed in an earlier pass
156223 legalizeLifetimeIntrinsics (M);
157224
158- const auto DIMap = DXILDebugInfoPass::run (M);
159- WriteDXILToFile (M, OS, DIMap);
225+ bool HasDebugInfo = !M.debug_compile_units ().empty ();
226+ std::string ILDBData;
227+ if (HasDebugInfo) {
228+ // Write DXIL with debug info to ILDB part.
229+ // Clone the module to avoid alternating it with DebugInfoPass
230+ // before stripping the debug info later.
231+ ILDBData =
232+ writeModule (*llvm::CloneModule (M), HasDebugInfo, /* IsDebug=*/ true );
233+ }
234+
235+ // Clone the module to save dx.source metadata nodes from stripping, as they
236+ // are needed for DXILMetadataAnalysisWrapperPass.
237+ std::string DXILData =
238+ writeModule (*llvm::CloneModule (M), HasDebugInfo, /* IsDebug=*/ false );
160239
161240 // We no longer need lifetime intrinsics after bitcode serialization, so we
162241 // simply remove them to keep the Module Verifier happy after our
163242 // not-so-legal legalizations
164243 removeLifetimeIntrinsics (M);
165244
166- Constant *ModuleConstant =
167- ConstantDataArray::get (M. getContext (), arrayRefFromStringRef (Data));
168- auto * GV = new llvm::GlobalVariable (M, ModuleConstant-> getType (), true ,
169- GlobalValue::PrivateLinkage,
170- ModuleConstant , " dx.dxil " );
171- GV-> setSection ( " DXIL " );
172- GV-> setAlignment ( Align ( 4 ));
173- appendToCompilerUsed (M, {GV} );
245+ SmallVector<GlobalValue *, 2 > Globals;
246+ if (HasDebugInfo) {
247+ // Create a GV after both parts are written, otherwise it gets
248+ // added to DXIL when `writeModule` is called the second time.
249+ Globals. emplace_back ( createSectionGlobal (M, ILDBData , " dx.ildb " , " ILDB " ) );
250+ }
251+ Globals. emplace_back ( createSectionGlobal (M, DXILData, " dx.dxil " , " DXIL " ));
252+ appendToCompilerUsed (M, Globals );
174253 return true ;
175254 }
176255
0 commit comments