44#include " Lexer/Scanner.hpp"
55#include " Parser/Parser.hpp"
66
7+ #include " IRDec/ModuleLifter.hpp"
8+
9+ #include < llvm/IR/LLVMContext.h>
10+ #include < llvm/IRReader/IRReader.h>
11+
712namespace glu ::sema {
813
914// Import Search Path Priority:
1015// Example: import foo::bar::baz;
11- // 1. ./foo/bar/baz.glu (no selector)
12- // 2. ./foo/bar.glu (with selector baz)
13- // 3. <import paths>/foo/bar/baz.glu
14- // 4. <import paths>/foo/bar.glu (with selector baz)
15- // 5. <system import paths>/foo/bar/baz.glu
16- // 6. <system import paths>/foo/bar.glu (with selector baz)
17- // Note that the system import paths are added to the import paths by the
18- // compiler driver, so they are not explicitly handled here.
19- // With wildcards, multiple files are not searched:
16+ // 1. ./foo/bar/baz.glu (no selector) (Glu source file)
17+ // 2. ./foo/bar/baz.bc (no selector) (decompiling LLVM bitcode)
18+ // 3. ./foo/bar/baz.ll (no selector) (human-readable LLVM IR)
19+ // 4. ./foo/bar.glu (with selector baz) (Glu source file)
20+ // 5. ./foo/bar.bc (with selector baz) (decompiling LLVM bitcode)
21+ // 6. ./foo/bar.ll (with selector baz) (human-readable LLVM IR)
22+ // 7. <import paths>/foo/bar/baz.glu (no selector) (Glu source file)
23+ // 8. <import paths>/foo/bar/baz.bc (no selector) (decompiling LLVM bitcode)
24+ // 9. <import paths>/foo/bar/baz.ll (no selector) (human-readable LLVM IR)
25+ // 10. <import paths>/foo/bar.glu (with selector baz) (Glu source file)
26+ // 11. <import paths>/foo/bar.bc (with selector baz) (decompiling LLVM bitcode)
27+ // 12. <import paths>/foo/bar.ll (with selector baz) (human-readable LLVM IR)
28+ // Note that the system import paths are added at the end of the import paths by
29+ // the compiler driver, so they are not explicitly handled here. With wildcards,
30+ // files are not wildcard-expanded, the wildcard is treated as a selector.
2031// Example: import foo::bar::*;
2132// 1. ./foo/bar.glu (with selector *)
2233// 2. <import paths>/foo/bar.glu (with selector *)
2334// 3. <system import paths>/foo/bar.glu (with selector *)
2435// This may be changed in the future to support wildcard imports of multiple
25- // files.
36+ // files. Decompiling bitcode or LLVM IR with wildcards is also supported with
37+ // wildcards, but not shown here for brevity.
38+
39+ // MARK: - Import Resolution
2640
2741ImportManager::LocalImportResult ImportManager::findImport (
2842 SourceLocation importLoc, llvm::ArrayRef<llvm::StringRef> components,
@@ -99,13 +113,29 @@ bool ImportManager::trySelectPath(
99113 }
100114
101115 // Try with .bc extension (binary LLVM bitcode).
102- // fullPath = path;
103- // fullPath.append(".bc");
116+ fullPath = path;
117+ fullPath.append (" .bc" );
118+ if (auto fileOrErr = sm->loadIRFile (fullPath)) {
119+ // Found
120+ result = tryLoadingIRFile (importLoc, *fileOrErr, selector);
121+ return true ;
122+ }
123+
124+ // Try with .ll extension (human-readable LLVM IR).
125+ fullPath = path;
126+ fullPath.append (" .ll" );
127+ if (auto fileOrErr = sm->loadIRFile (fullPath)) {
128+ // Found
129+ result = tryLoadingIRFile (importLoc, *fileOrErr, selector);
130+ return true ;
131+ }
104132
105133 // No file found.
106134 return false ;
107135}
108136
137+ // MARK: - Import File Loading
138+
109139ImportManager::LocalImportResult ImportManager::tryLoadingFile (
110140 SourceLocation importLoc, FileID fid, llvm::StringRef selector
111141)
@@ -134,9 +164,27 @@ ImportManager::LocalImportResult ImportManager::tryLoadingFile(
134164 return std::tuple (_importedFiles[fid], selector);
135165}
136166
167+ ImportManager::LocalImportResult ImportManager::tryLoadingIRFile (
168+ SourceLocation importLoc, FileID fid, llvm::StringRef selector
169+ )
170+ {
171+ if (_failedImports.contains (fid)) {
172+ // Previous import failed, do not try again. Do not generate new errors.
173+ return std::nullopt ;
174+ }
175+ if (!_importedFiles[fid]) {
176+ // File has not been imported yet.
177+ if (!loadModuleFromIRFile (importLoc, fid)) {
178+ _failedImports.insert (fid);
179+ return std::nullopt ; // Import failed.
180+ }
181+ }
182+ // File has already been imported.
183+ return std::tuple (_importedFiles[fid], selector);
184+ }
185+
137186bool ImportManager::loadModuleFromFileID (FileID fid)
138187{
139- _importStack.push_back (fid);
140188 auto *sm = _context.getSourceManager ();
141189 glu::Scanner scanner (sm->getBuffer (fid));
142190 glu::Parser parser (scanner, _context, *sm, _diagManager);
@@ -147,12 +195,39 @@ bool ImportManager::loadModuleFromFileID(FileID fid)
147195 if (!ast) {
148196 return false ;
149197 }
198+ _importStack.push_back (fid);
150199 _importedFiles[fid] = sema::fastConstrainAST (ast, _diagManager, this );
151200 assert (_importStack.back () == fid);
152201 _importStack.pop_back ();
153202 return _importedFiles[fid] != nullptr ;
154203}
155204
205+ bool ImportManager::loadModuleFromIRFile (SourceLocation importLoc, FileID fid)
206+ {
207+ llvm::SMDiagnostic err;
208+ llvm::LLVMContext localContext;
209+ auto *sm = _context.getSourceManager ();
210+ auto llvmModule
211+ = llvm::parseIRFile (sm->getBufferName (fid), err, localContext);
212+
213+ if (!llvmModule) {
214+ _diagManager.error (
215+ importLoc, " Failed to parse LLVM module: " + err.getMessage ()
216+ );
217+ return false ;
218+ }
219+
220+ auto *ast = glu::irdec::liftModule (_context, llvmModule.get ());
221+
222+ _importStack.push_back (fid);
223+ _importedFiles[fid] = sema::fastConstrainAST (ast, _diagManager, this );
224+ assert (_importStack.back () == fid);
225+ _importStack.pop_back ();
226+ return _importedFiles[fid] != nullptr ;
227+ }
228+
229+ // MARK: - Module Copying
230+
156231static llvm::StringRef isOperatorOverload (llvm::StringRef name)
157232{
158233 return llvm::StringSwitch<bool >(name)
0 commit comments