[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / flang / tools / bbc / bbc.cpp
blob378216bd1e51f8f363a83a9c4408e77db0335a39
1 //===- bbc.cpp - Burnside Bridge Compiler -----------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
11 //===----------------------------------------------------------------------===//
12 ///
13 /// This is a tool for translating Fortran sources to the FIR dialect of MLIR.
14 ///
15 //===----------------------------------------------------------------------===//
17 #include "flang/Common/Fortran-features.h"
18 #include "flang/Common/OpenMP-features.h"
19 #include "flang/Common/default-kinds.h"
20 #include "flang/Lower/Bridge.h"
21 #include "flang/Lower/PFTBuilder.h"
22 #include "flang/Lower/Support/Verifier.h"
23 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
24 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
25 #include "flang/Optimizer/Support/InitFIR.h"
26 #include "flang/Optimizer/Support/InternalNames.h"
27 #include "flang/Optimizer/Support/Utils.h"
28 #include "flang/Optimizer/Transforms/Passes.h"
29 #include "flang/Parser/characters.h"
30 #include "flang/Parser/dump-parse-tree.h"
31 #include "flang/Parser/message.h"
32 #include "flang/Parser/parse-tree-visitor.h"
33 #include "flang/Parser/parse-tree.h"
34 #include "flang/Parser/parsing.h"
35 #include "flang/Parser/provenance.h"
36 #include "flang/Parser/unparse.h"
37 #include "flang/Semantics/expression.h"
38 #include "flang/Semantics/runtime-type-info.h"
39 #include "flang/Semantics/semantics.h"
40 #include "flang/Semantics/unparse-with-symbols.h"
41 #include "flang/Tools/CrossToolHelpers.h"
42 #include "flang/Version.inc"
43 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
44 #include "mlir/IR/AsmState.h"
45 #include "mlir/IR/BuiltinOps.h"
46 #include "mlir/IR/MLIRContext.h"
47 #include "mlir/Parser/Parser.h"
48 #include "mlir/Pass/Pass.h"
49 #include "mlir/Pass/PassManager.h"
50 #include "mlir/Pass/PassRegistry.h"
51 #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
52 #include "mlir/Transforms/Passes.h"
53 #include "llvm/Passes/OptimizationLevel.h"
54 #include "llvm/Support/CommandLine.h"
55 #include "llvm/Support/ErrorOr.h"
56 #include "llvm/Support/FileSystem.h"
57 #include "llvm/Support/InitLLVM.h"
58 #include "llvm/Support/MemoryBuffer.h"
59 #include "llvm/Support/Path.h"
60 #include "llvm/Support/SourceMgr.h"
61 #include "llvm/Support/TargetSelect.h"
62 #include "llvm/Support/ToolOutputFile.h"
63 #include "llvm/Support/raw_ostream.h"
64 #include "llvm/TargetParser/Host.h"
65 #include "llvm/TargetParser/Triple.h"
67 //===----------------------------------------------------------------------===//
68 // Some basic command-line options
69 //===----------------------------------------------------------------------===//
71 static llvm::cl::opt<std::string> inputFilename(llvm::cl::Positional,
72 llvm::cl::Required,
73 llvm::cl::desc("<input file>"));
75 static llvm::cl::opt<std::string>
76 outputFilename("o", llvm::cl::desc("Specify the output filename"),
77 llvm::cl::value_desc("filename"));
79 static llvm::cl::list<std::string>
80 includeDirs("I", llvm::cl::desc("include module search paths"));
82 static llvm::cl::alias includeAlias("module-directory",
83 llvm::cl::desc("module search directory"),
84 llvm::cl::aliasopt(includeDirs));
86 static llvm::cl::list<std::string>
87 intrinsicIncludeDirs("J", llvm::cl::desc("intrinsic module search paths"));
89 static llvm::cl::alias
90 intrinsicIncludeAlias("intrinsic-module-directory",
91 llvm::cl::desc("intrinsic module directory"),
92 llvm::cl::aliasopt(intrinsicIncludeDirs));
94 static llvm::cl::opt<std::string>
95 moduleDir("module", llvm::cl::desc("module output directory (default .)"),
96 llvm::cl::init("."));
98 static llvm::cl::opt<std::string>
99 moduleSuffix("module-suffix", llvm::cl::desc("module file suffix override"),
100 llvm::cl::init(".mod"));
102 static llvm::cl::opt<bool>
103 emitFIR("emit-fir",
104 llvm::cl::desc("Dump the FIR created by lowering and exit"),
105 llvm::cl::init(false));
107 static llvm::cl::opt<bool>
108 emitHLFIR("emit-hlfir",
109 llvm::cl::desc("Dump the HLFIR created by lowering and exit"),
110 llvm::cl::init(false));
112 static llvm::cl::opt<bool> warnStdViolation("Mstandard",
113 llvm::cl::desc("emit warnings"),
114 llvm::cl::init(false));
116 static llvm::cl::opt<bool> warnIsError("Werror",
117 llvm::cl::desc("warnings are errors"),
118 llvm::cl::init(false));
120 static llvm::cl::opt<bool> dumpSymbols("dump-symbols",
121 llvm::cl::desc("dump the symbol table"),
122 llvm::cl::init(false));
124 static llvm::cl::opt<bool> pftDumpTest(
125 "pft-test",
126 llvm::cl::desc("parse the input, create a PFT, dump it, and exit"),
127 llvm::cl::init(false));
129 static llvm::cl::opt<bool> enableOpenMP("fopenmp",
130 llvm::cl::desc("enable openmp"),
131 llvm::cl::init(false));
133 static llvm::cl::opt<bool>
134 enableOpenMPDevice("fopenmp-is-target-device",
135 llvm::cl::desc("enable openmp device compilation"),
136 llvm::cl::init(false));
138 static llvm::cl::opt<bool>
139 enableOpenMPGPU("fopenmp-is-gpu",
140 llvm::cl::desc("enable openmp GPU target codegen"),
141 llvm::cl::init(false));
143 // A simplified subset of the OpenMP RTL Flags from Flang, only the primary
144 // positive options are available, no negative options e.g. fopen_assume* vs
145 // fno_open_assume*
146 static llvm::cl::opt<uint32_t>
147 setOpenMPVersion("fopenmp-version",
148 llvm::cl::desc("OpenMP standard version"),
149 llvm::cl::init(11));
151 static llvm::cl::opt<uint32_t> setOpenMPTargetDebug(
152 "fopenmp-target-debug",
153 llvm::cl::desc("Enable debugging in the OpenMP offloading device RTL"),
154 llvm::cl::init(0));
156 static llvm::cl::opt<bool> setOpenMPThreadSubscription(
157 "fopenmp-assume-threads-oversubscription",
158 llvm::cl::desc("Assume work-shared loops do not have more "
159 "iterations than participating threads."),
160 llvm::cl::init(false));
162 static llvm::cl::opt<bool> setOpenMPTeamSubscription(
163 "fopenmp-assume-teams-oversubscription",
164 llvm::cl::desc("Assume distributed loops do not have more iterations than "
165 "participating teams."),
166 llvm::cl::init(false));
168 static llvm::cl::opt<bool> setOpenMPNoThreadState(
169 "fopenmp-assume-no-thread-state",
170 llvm::cl::desc(
171 "Assume that no thread in a parallel region will modify an ICV."),
172 llvm::cl::init(false));
174 static llvm::cl::opt<bool> setOpenMPNoNestedParallelism(
175 "fopenmp-assume-no-nested-parallelism",
176 llvm::cl::desc("Assume that no thread in a parallel region will encounter "
177 "a parallel region."),
178 llvm::cl::init(false));
180 static llvm::cl::opt<bool> enableOpenACC("fopenacc",
181 llvm::cl::desc("enable openacc"),
182 llvm::cl::init(false));
184 static llvm::cl::opt<bool> enablePolymorphic(
185 "polymorphic-type",
186 llvm::cl::desc("enable polymorphic type lowering (experimental)"),
187 llvm::cl::init(false));
189 static llvm::cl::opt<bool> enableNoPPCNativeVecElemOrder(
190 "fno-ppc-native-vector-element-order",
191 llvm::cl::desc("no PowerPC native vector element order."),
192 llvm::cl::init(false));
194 static llvm::cl::opt<bool> useHLFIR("hlfir",
195 llvm::cl::desc("Lower to high level FIR"),
196 llvm::cl::init(false));
198 static llvm::cl::opt<bool> enableCUDA("fcuda",
199 llvm::cl::desc("enable CUDA Fortran"),
200 llvm::cl::init(false));
202 static llvm::cl::opt<bool> fixedForm("ffixed-form",
203 llvm::cl::desc("enable fixed form"),
204 llvm::cl::init(false));
206 #define FLANG_EXCLUDE_CODEGEN
207 #include "flang/Tools/CLOptions.inc"
209 //===----------------------------------------------------------------------===//
211 using ProgramName = std::string;
213 // Print the module with the "module { ... }" wrapper, preventing
214 // information loss from attribute information appended to the module
215 static void printModule(mlir::ModuleOp mlirModule, llvm::raw_ostream &out) {
216 out << mlirModule << '\n';
219 static void registerAllPasses() {
220 fir::support::registerMLIRPassesForFortranTools();
221 fir::registerOptTransformPasses();
224 //===----------------------------------------------------------------------===//
225 // Translate Fortran input to FIR, a dialect of MLIR.
226 //===----------------------------------------------------------------------===//
228 static mlir::LogicalResult convertFortranSourceToMLIR(
229 std::string path, Fortran::parser::Options options,
230 const ProgramName &programPrefix,
231 Fortran::semantics::SemanticsContext &semanticsContext,
232 const mlir::PassPipelineCLParser &passPipeline) {
234 // prep for prescan and parse
235 Fortran::parser::Parsing parsing{semanticsContext.allCookedSources()};
236 parsing.Prescan(path, options);
237 if (!parsing.messages().empty() && (parsing.messages().AnyFatalError())) {
238 llvm::errs() << programPrefix << "could not scan " << path << '\n';
239 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
240 return mlir::failure();
243 // parse the input Fortran
244 parsing.Parse(llvm::outs());
245 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
246 if (!parsing.consumedWholeFile()) {
247 parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),
248 "parser FAIL (final position)",
249 "error: ", llvm::raw_ostream::RED);
250 return mlir::failure();
252 if ((!parsing.messages().empty() && (parsing.messages().AnyFatalError())) ||
253 !parsing.parseTree().has_value()) {
254 llvm::errs() << programPrefix << "could not parse " << path << '\n';
255 return mlir::failure();
258 // run semantics
259 auto &parseTree = *parsing.parseTree();
260 Fortran::semantics::Semantics semantics(semanticsContext, parseTree);
261 semantics.Perform();
262 semantics.EmitMessages(llvm::errs());
263 if (semantics.AnyFatalError()) {
264 llvm::errs() << programPrefix << "semantic errors in " << path << '\n';
265 return mlir::failure();
267 Fortran::semantics::RuntimeDerivedTypeTables tables;
268 if (!semantics.AnyFatalError()) {
269 tables =
270 Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext);
271 if (!tables.schemata)
272 llvm::errs() << programPrefix
273 << "could not find module file for __fortran_type_info\n";
276 if (dumpSymbols) {
277 semantics.DumpSymbols(llvm::outs());
278 return mlir::success();
281 if (pftDumpTest) {
282 if (auto ast = Fortran::lower::createPFT(parseTree, semanticsContext)) {
283 Fortran::lower::dumpPFT(llvm::outs(), *ast);
284 return mlir::success();
286 llvm::errs() << "Pre FIR Tree is NULL.\n";
287 return mlir::failure();
290 // translate to FIR dialect of MLIR
291 mlir::DialectRegistry registry;
292 fir::support::registerNonCodegenDialects(registry);
293 mlir::MLIRContext ctx(registry);
294 fir::support::loadNonCodegenDialects(ctx);
295 auto &defKinds = semanticsContext.defaultKinds();
296 fir::KindMapping kindMap(
297 &ctx, llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)});
298 // Use default lowering options for bbc.
299 Fortran::lower::LoweringOptions loweringOptions{};
300 loweringOptions.setPolymorphicTypeImpl(enablePolymorphic);
301 loweringOptions.setNoPPCNativeVecElemOrder(enableNoPPCNativeVecElemOrder);
302 loweringOptions.setLowerToHighLevelFIR(useHLFIR || emitHLFIR);
303 auto burnside = Fortran::lower::LoweringBridge::create(
304 ctx, semanticsContext, defKinds, semanticsContext.intrinsics(),
305 semanticsContext.targetCharacteristics(), parsing.allCooked(), "",
306 kindMap, loweringOptions, {});
307 burnside.lower(parseTree, semanticsContext);
308 mlir::ModuleOp mlirModule = burnside.getModule();
309 if (enableOpenMP) {
310 if (enableOpenMPGPU && !enableOpenMPDevice) {
311 llvm::errs() << "FATAL: -fopenmp-is-gpu can only be set if "
312 "-fopenmp-is-target-device is also set";
313 return mlir::failure();
315 auto offloadModuleOpts =
316 OffloadModuleOpts(setOpenMPTargetDebug, setOpenMPTeamSubscription,
317 setOpenMPThreadSubscription, setOpenMPNoThreadState,
318 setOpenMPNoNestedParallelism, enableOpenMPDevice,
319 enableOpenMPGPU, setOpenMPVersion);
320 setOffloadModuleInterfaceAttributes(mlirModule, offloadModuleOpts);
321 setOpenMPVersionAttribute(mlirModule, setOpenMPVersion);
323 std::error_code ec;
324 std::string outputName = outputFilename;
325 if (!outputName.size())
326 outputName = llvm::sys::path::stem(inputFilename).str().append(".mlir");
327 llvm::raw_fd_ostream out(outputName, ec);
328 if (ec)
329 return mlir::emitError(mlir::UnknownLoc::get(&ctx),
330 "could not open output file ")
331 << outputName;
333 // Otherwise run the default passes.
334 mlir::PassManager pm(mlirModule->getName(),
335 mlir::OpPassManager::Nesting::Implicit);
336 if (enableOpenMP)
337 // WARNING: This pipeline must be run immediately after the lowering to
338 // ensure that the FIR is correct with respect to OpenMP operations/
339 // attributes.
340 fir::createOpenMPFIRPassPipeline(pm, enableOpenMPDevice);
341 pm.enableVerifier(/*verifyPasses=*/true);
342 (void)mlir::applyPassManagerCLOptions(pm);
343 if (passPipeline.hasAnyOccurrences()) {
344 // run the command-line specified pipeline
345 hlfir::registerHLFIRPasses();
346 (void)passPipeline.addToPipeline(pm, [&](const llvm::Twine &msg) {
347 mlir::emitError(mlir::UnknownLoc::get(&ctx)) << msg;
348 return mlir::failure();
350 } else if (emitFIR || emitHLFIR) {
351 // --emit-fir: Build the IR, verify it, and dump the IR if the IR passes
352 // verification. Use --dump-module-on-failure to dump invalid IR.
353 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
354 if (mlir::failed(pm.run(mlirModule))) {
355 llvm::errs() << "FATAL: verification of lowering to FIR failed";
356 return mlir::failure();
359 if (emitFIR && useHLFIR) {
360 // lower HLFIR to FIR
361 fir::createHLFIRToFIRPassPipeline(pm, llvm::OptimizationLevel::O2);
362 if (mlir::failed(pm.run(mlirModule))) {
363 llvm::errs() << "FATAL: lowering from HLFIR to FIR failed";
364 return mlir::failure();
368 printModule(mlirModule, out);
369 return mlir::success();
370 } else {
371 // run the default canned pipeline
372 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
374 // Add O2 optimizer pass pipeline.
375 fir::createDefaultFIROptimizerPassPipeline(
376 pm, MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel::O2));
379 if (mlir::succeeded(pm.run(mlirModule))) {
380 // Emit MLIR and do not lower to LLVM IR.
381 printModule(mlirModule, out);
382 return mlir::success();
384 // Something went wrong. Try to dump the MLIR module.
385 llvm::errs() << "oops, pass manager reported failure\n";
386 return mlir::failure();
389 int main(int argc, char **argv) {
390 [[maybe_unused]] llvm::InitLLVM y(argc, argv);
391 registerAllPasses();
393 mlir::registerMLIRContextCLOptions();
394 mlir::registerAsmPrinterCLOptions();
395 mlir::registerPassManagerCLOptions();
396 mlir::PassPipelineCLParser passPipe("", "Compiler passes to run");
397 llvm::cl::ParseCommandLineOptions(argc, argv, "Burnside Bridge Compiler\n");
399 ProgramName programPrefix;
400 programPrefix = argv[0] + ": "s;
402 if (includeDirs.size() == 0) {
403 includeDirs.push_back(".");
404 // Default Fortran modules should be installed in include/flang (a sibling
405 // to the bin) directory.
406 intrinsicIncludeDirs.push_back(
407 llvm::sys::path::parent_path(
408 llvm::sys::path::parent_path(
409 llvm::sys::fs::getMainExecutable(argv[0], nullptr)))
410 .str() +
411 "/include/flang");
414 Fortran::parser::Options options;
415 options.predefinitions.emplace_back("__flang__"s, "1"s);
416 options.predefinitions.emplace_back("__flang_major__"s,
417 std::string{FLANG_VERSION_MAJOR_STRING});
418 options.predefinitions.emplace_back("__flang_minor__"s,
419 std::string{FLANG_VERSION_MINOR_STRING});
420 options.predefinitions.emplace_back(
421 "__flang_patchlevel__"s, std::string{FLANG_VERSION_PATCHLEVEL_STRING});
423 // enable parsing of OpenMP
424 if (enableOpenMP) {
425 options.features.Enable(Fortran::common::LanguageFeature::OpenMP);
426 Fortran::common::setOpenMPMacro(setOpenMPVersion, options.predefinitions);
429 // enable parsing of OpenACC
430 if (enableOpenACC) {
431 options.features.Enable(Fortran::common::LanguageFeature::OpenACC);
432 options.predefinitions.emplace_back("_OPENACC", "202211");
435 // enable parsing of CUDA Fortran
436 if (enableCUDA) {
437 options.features.Enable(Fortran::common::LanguageFeature::CUDA);
440 if (fixedForm) {
441 options.isFixedForm = fixedForm;
444 Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;
445 Fortran::parser::AllSources allSources;
446 Fortran::parser::AllCookedSources allCookedSources(allSources);
447 Fortran::semantics::SemanticsContext semanticsContext{
448 defaultKinds, options.features, allCookedSources};
449 semanticsContext.set_moduleDirectory(moduleDir)
450 .set_moduleFileSuffix(moduleSuffix)
451 .set_searchDirectories(includeDirs)
452 .set_intrinsicModuleDirectories(intrinsicIncludeDirs)
453 .set_warnOnNonstandardUsage(warnStdViolation)
454 .set_warningsAreErrors(warnIsError);
456 llvm::Triple targetTriple{llvm::Triple(
457 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))};
458 // FIXME: Handle real(3) ?
459 if (targetTriple.getArch() != llvm::Triple::ArchType::x86 &&
460 targetTriple.getArch() != llvm::Triple::ArchType::x86_64) {
461 semanticsContext.targetCharacteristics().DisableType(
462 Fortran::common::TypeCategory::Real, /*kind=*/10);
464 if (targetTriple.isPPC())
465 semanticsContext.targetCharacteristics().set_isPPC(true);
467 return mlir::failed(convertFortranSourceToMLIR(
468 inputFilename, options, programPrefix, semanticsContext, passPipe));