From d5f48a217f404c3462537527f4169bb45eed3904 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Sat, 7 Apr 2018 03:30:07 +0000 Subject: [PATCH 01/10] Merging r327099: ------------------------------------------------------------------------ r327099 | rsmith | 2018-03-08 18:00:01 -0800 (Thu, 08 Mar 2018) | 3 lines PR36645: Go looking for an appropriate array bound when constant-evaluating a name of an array object. ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_60@329478 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ExprConstant.cpp | 16 ++++++++++++---- test/SemaCXX/constant-expression-cxx11.cpp | 4 ++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8d9b3c3bebc0..5c9744f4e89c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -61,14 +61,22 @@ namespace { static QualType getType(APValue::LValueBase B) { if (!B) return QualType(); - if (const ValueDecl *D = B.dyn_cast()) + if (const ValueDecl *D = B.dyn_cast()) { // FIXME: It's unclear where we're supposed to take the type from, and - // this actually matters for arrays of unknown bound. Using the type of - // the most recent declaration isn't clearly correct in general. Eg: + // this actually matters for arrays of unknown bound. Eg: // // extern int arr[]; void f() { extern int arr[3]; }; // constexpr int *p = &arr[1]; // valid? - return cast(D->getMostRecentDecl())->getType(); + // + // For now, we take the array bound from the most recent declaration. + for (auto *Redecl = cast(D->getMostRecentDecl()); Redecl; + Redecl = cast_or_null(Redecl->getPreviousDecl())) { + QualType T = Redecl->getType(); + if (!T->isIncompleteArrayType()) + return T; + } + return D->getType(); + } const Expr *Base = B.get(); diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 51dd6199e63a..fe4c54e7e6f2 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -629,6 +629,10 @@ namespace ArrayOfUnknownBound { extern const int carr[]; // expected-note {{here}} constexpr int n = carr[0]; // expected-error {{constant}} expected-note {{non-constexpr variable}} + + constexpr int local_extern[] = {1, 2, 3}; + void f() { extern const int local_extern[]; } + static_assert(local_extern[1] == 2, ""); } namespace DependentValues { From 4cea2510abec0e5f6863c925a784948e3fd78d00 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Mon, 9 Apr 2018 21:20:06 +0000 Subject: [PATCH 02/10] Merging r328708: ------------------------------------------------------------------------ r328708 | hans | 2018-03-28 07:57:49 -0700 (Wed, 28 Mar 2018) | 1 line clang-cl: s/Enable/Disable/ in help text for /GX- ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_60@329624 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/CLCompatOptions.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td index c1f0a89b5dc8..e417f6cbbec6 100644 --- a/include/clang/Driver/CLCompatOptions.td +++ b/include/clang/Driver/CLCompatOptions.td @@ -238,7 +238,7 @@ def _SLASH_Fo : CLCompileJoined<"Fo">, def _SLASH_GX : CLFlag<"GX">, HelpText<"Enable exception handling">; def _SLASH_GX_ : CLFlag<"GX-">, - HelpText<"Enable exception handling">; + HelpText<"Disable exception handling">; def _SLASH_imsvc : CLJoinedOrSeparate<"imsvc">, HelpText<"Add directory to system include search path, as if part of %INCLUDE%">, MetaVarName<"">; From ab474c24e0576eae923f25bb7f6aaddcd853daeb Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Mon, 9 Apr 2018 21:30:20 +0000 Subject: [PATCH 03/10] Merging r329052: ------------------------------------------------------------------------ r329052 | hans | 2018-04-03 02:28:21 -0700 (Tue, 03 Apr 2018) | 1 line UsersManual.rst: update text for /GX- to match r328708 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_60@329625 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/UsersManual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst index 11f77e58798e..fb6112d0298e 100644 --- a/docs/UsersManual.rst +++ b/docs/UsersManual.rst @@ -2741,7 +2741,7 @@ Execute ``clang-cl /?`` to see a list of supported options: /Gv Set __vectorcall as a default calling convention /Gw- Don't put each data item in its own section /Gw Put each data item in its own section - /GX- Enable exception handling + /GX- Disable exception handling /GX Enable exception handling /Gy- Don't put each function in its own section /Gy Put each function in its own section From 31f349d884b2007b6328de58832478a738759c73 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Tue, 10 Apr 2018 04:22:41 +0000 Subject: [PATCH 04/10] Merging r328829: ------------------------------------------------------------------------ r328829 | manojgupta | 2018-03-29 14:11:15 -0700 (Thu, 29 Mar 2018) | 23 lines [AArch64]: Add support for parsing rN registers. Summary: Allow rN registers to be simply parsed as correspoing xN registers. The "register ... asm("rN")" is an command to the compiler's register allocator, not an operand to any individual assembly instruction. GCC documents this syntax as "...the name of the register that should be used." This is needed to support the changes in Linux kernel (see https://lkml.org/lkml/2018/3/1/268 ) Note: This will add support only for the limited use case of register ... asm("rN"). Any other uses that make rN leak into assembly are not supported. Reviewers: kristof.beyls, rengolin, peter.smith, t.p.northover Reviewed By: peter.smith Subscribers: javed.absar, eraman, cfe-commits, srhines Differential Revision: https://reviews.llvm.org/D44815 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_60@329669 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Basic/Targets/AArch64.cpp | 35 ++++++++++++++++++++++++++++++- test/CodeGen/aarch64-inline-asm.c | 20 ++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/Basic/Targets/AArch64.cpp b/lib/Basic/Targets/AArch64.cpp index 4d3cd121f705..8762ef691700 100644 --- a/lib/Basic/Targets/AArch64.cpp +++ b/lib/Basic/Targets/AArch64.cpp @@ -299,7 +299,40 @@ ArrayRef AArch64TargetInfo::getGCCRegNames() const { } const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { - {{"w31"}, "wsp"}, {{"x29"}, "fp"}, {{"x30"}, "lr"}, {{"x31"}, "sp"}, + {{"w31"}, "wsp"}, + {{"x31"}, "sp"}, + // GCC rN registers are aliases of xN registers. + {{"r0"}, "x0"}, + {{"r1"}, "x1"}, + {{"r2"}, "x2"}, + {{"r3"}, "x3"}, + {{"r4"}, "x4"}, + {{"r5"}, "x5"}, + {{"r6"}, "x6"}, + {{"r7"}, "x7"}, + {{"r8"}, "x8"}, + {{"r9"}, "x9"}, + {{"r10"}, "x10"}, + {{"r11"}, "x11"}, + {{"r12"}, "x12"}, + {{"r13"}, "x13"}, + {{"r14"}, "x14"}, + {{"r15"}, "x15"}, + {{"r16"}, "x16"}, + {{"r17"}, "x17"}, + {{"r18"}, "x18"}, + {{"r19"}, "x19"}, + {{"r20"}, "x20"}, + {{"r21"}, "x21"}, + {{"r22"}, "x22"}, + {{"r23"}, "x23"}, + {{"r24"}, "x24"}, + {{"r25"}, "x25"}, + {{"r26"}, "x26"}, + {{"r27"}, "x27"}, + {{"r28"}, "x28"}, + {{"r29", "x29"}, "fp"}, + {{"r30", "x30"}, "lr"}, // The S/D/Q and W/X registers overlap, but aren't really aliases; we // don't want to substitute one of these for a different-sized one. }; diff --git a/test/CodeGen/aarch64-inline-asm.c b/test/CodeGen/aarch64-inline-asm.c index a1078f1bab83..264df9d5fc03 100644 --- a/test/CodeGen/aarch64-inline-asm.c +++ b/test/CodeGen/aarch64-inline-asm.c @@ -54,3 +54,23 @@ void test_constraint_Q(void) { asm("ldxr %0, %1" : "=r"(val) : "Q"(var)); // CHECK: call i32 asm "ldxr $0, $1", "=r,*Q"(i64* @var) } + +void test_gcc_registers(void) { + register unsigned long reg0 asm("r0") = 0; + register unsigned long reg1 asm("r1") = 1; + register unsigned int reg29 asm("r29") = 2; + register unsigned int reg30 asm("r30") = 3; + + // Test remapping register names in register ... asm("rN") statments. + // rN register operands in these two inline assembly lines + // should get renamed to valid AArch64 registers. + asm volatile("hvc #0" : : "r" (reg0), "r" (reg1)); + // CHECK: call void asm sideeffect "hvc #0", "{x0},{x1}" + asm volatile("hvc #0" : : "r" (reg29), "r" (reg30)); + // CHECK: call void asm sideeffect "hvc #0", "{fp},{lr}" + + // rN registers when used without register ... asm("rN") syntax + // should not be remapped. + asm volatile("mov r0, r1\n"); + // CHECK: call void asm sideeffect "mov r0, r1\0A", ""() +} From 0e746072ed897a85b4f533ab050b9f506941a097 Mon Sep 17 00:00:00 2001 From: Simon Dardis Date: Wed, 11 Apr 2018 12:58:50 +0000 Subject: [PATCH 05/10] Merging r325651: ------------------------------------------------------------------------ r325651 | sdardis | 2018-02-21 00:05:05 +0000 (Wed, 21 Feb 2018) | 34 lines [mips] Spectre variant two mitigation for MIPSR2 This patch provides mitigation for CVE-2017-5715, Spectre variant two, which affects the P5600 and P6600. It provides the option -mindirect-jump=hazard, which instructs the LLVM backend to replace indirect branches with their hazard barrier variants. This option is accepted when targeting MIPS revision two or later. The migitation strategy suggested by MIPS for these processors is to use two hazard barrier instructions. 'jalr.hb' and 'jr.hb' are hazard barrier variants of the 'jalr' and 'jr' instructions respectively. These instructions impede the execution of instruction stream until architecturally defined hazards (changes to the instruction stream, privileged registers which may affect execution) are cleared. These instructions in MIPS' designs are not speculated past. These instructions are used with the option -mindirect-jump=hazard when branching indirectly and for indirect function calls. These instructions are defined by the MIPS32R2 ISA, so this mitigation method is not compatible with processors which implement an earlier revision of the MIPS ISA. Implementation note: I've opted to provide this as an -mindirect-jump={hazard,...} style option in case alternative mitigation methods are required for other implementations of the MIPS ISA in future, e.g. retpoline style solutions. Reviewers: atanasyan Differential Revision: https://reviews.llvm.org/D43487 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_60@329799 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticDriverKinds.td | 4 ++ include/clang/Driver/Options.td | 3 ++ lib/Basic/Targets/Mips.h | 6 ++- lib/Driver/ToolChains/Arch/Mips.cpp | 39 ++++++++++++++++++++ lib/Driver/ToolChains/Arch/Mips.h | 1 + test/Driver/mips-features.c | 6 +++ test/Driver/mips-indirect-branch.c | 23 ++++++++++++ 7 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 test/Driver/mips-indirect-branch.c diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 28aead0cdb99..69c20ea7806c 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -326,6 +326,10 @@ def warn_drv_unsupported_abicalls : Warning< "ignoring '-mabicalls' option as it cannot be used with " "non position-independent code and the N64 ABI">, InGroup; +def err_drv_unsupported_indirect_jump_opt : Error< + "'-mindirect-jump=%0' is unsupported with the '%1' architecture">; +def err_drv_unknown_indirect_jump_opt : Error< + "unknown '-mindirect-jump=' option '%0'">; def warn_drv_unable_to_find_directory_expected : Warning< "unable to find %0 directory, expected to be in '%1'">, diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index ad72aef3fc94..288bd482bb97 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -1992,6 +1992,9 @@ def mbranch_likely : Flag<["-"], "mbranch-likely">, Group, IgnoredGCCCompat; def mno_branch_likely : Flag<["-"], "mno-branch-likely">, Group, IgnoredGCCCompat; +def mindirect_jump_EQ : Joined<["-"], "mindirect-jump=">, + Group, + HelpText<"Change indirect jump instructions to inhibit speculation">; def mdsp : Flag<["-"], "mdsp">, Group; def mno_dsp : Flag<["-"], "mno-dsp">, Group; def mdspr2 : Flag<["-"], "mdspr2">, Group; diff --git a/lib/Basic/Targets/Mips.h b/lib/Basic/Targets/Mips.h index 28900f21f86b..4b61116a3256 100644 --- a/lib/Basic/Targets/Mips.h +++ b/lib/Basic/Targets/Mips.h @@ -54,6 +54,7 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { enum DspRevEnum { NoDSP, DSP1, DSP2 } DspRev; bool HasMSA; bool DisableMadd4; + bool UseIndirectJumpHazard; protected: bool HasFP64; @@ -64,7 +65,8 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { : TargetInfo(Triple), IsMips16(false), IsMicromips(false), IsNan2008(false), IsAbs2008(false), IsSingleFloat(false), IsNoABICalls(false), CanUseBSDABICalls(false), FloatABI(HardFloat), - DspRev(NoDSP), HasMSA(false), DisableMadd4(false), HasFP64(false) { + DspRev(NoDSP), HasMSA(false), DisableMadd4(false), + UseIndirectJumpHazard(false), HasFP64(false) { TheCXXABI.set(TargetCXXABI::GenericMIPS); setABI((getTriple().getArch() == llvm::Triple::mips || @@ -338,6 +340,8 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { IsAbs2008 = false; else if (Feature == "+noabicalls") IsNoABICalls = true; + else if (Feature == "+use-indirect-jump-hazard") + UseIndirectJumpHazard = true; } setDataLayout(); diff --git a/lib/Driver/ToolChains/Arch/Mips.cpp b/lib/Driver/ToolChains/Arch/Mips.cpp index 61481a92d0b7..e72754d5ad53 100644 --- a/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/lib/Driver/ToolChains/Arch/Mips.cpp @@ -343,6 +343,28 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4, "nomadd4"); AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt, "mt"); + + if (Arg *A = Args.getLastArg(options::OPT_mindirect_jump_EQ)) { + StringRef Val = StringRef(A->getValue()); + if (Val == "hazard") { + Arg *B = + Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); + Arg *C = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16); + + if (B && B->getOption().matches(options::OPT_mmicromips)) + D.Diag(diag::err_drv_unsupported_indirect_jump_opt) + << "hazard" << "micromips"; + else if (C && C->getOption().matches(options::OPT_mips16)) + D.Diag(diag::err_drv_unsupported_indirect_jump_opt) + << "hazard" << "mips16"; + else if (mips::supportsIndirectJumpHazardBarrier(CPUName)) + Features.push_back("+use-indirect-jump-hazard"); + else + D.Diag(diag::err_drv_unsupported_indirect_jump_opt) + << "hazard" << CPUName; + } else + D.Diag(diag::err_drv_unknown_indirect_jump_opt) << Val; + } } mips::IEEE754Standard mips::getIEEE754Standard(StringRef &CPU) { @@ -447,3 +469,20 @@ bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple, return UseFPXX; } + +bool mips::supportsIndirectJumpHazardBarrier(StringRef &CPU) { + // Supporting the hazard barrier method of dealing with indirect + // jumps requires MIPSR2 support. + return llvm::StringSwitch(CPU) + .Case("mips32r2", true) + .Case("mips32r3", true) + .Case("mips32r5", true) + .Case("mips32r6", true) + .Case("mips64r2", true) + .Case("mips64r3", true) + .Case("mips64r5", true) + .Case("mips64r6", true) + .Case("octeon", true) + .Case("p5600", true) + .Default(false); +} diff --git a/lib/Driver/ToolChains/Arch/Mips.h b/lib/Driver/ToolChains/Arch/Mips.h index 89eea9a1514c..7e90488363a5 100644 --- a/lib/Driver/ToolChains/Arch/Mips.h +++ b/lib/Driver/ToolChains/Arch/Mips.h @@ -53,6 +53,7 @@ bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI); +bool supportsIndirectJumpHazardBarrier(StringRef &CPU); } // end namespace mips } // end namespace target diff --git a/test/Driver/mips-features.c b/test/Driver/mips-features.c index a9db0f101700..d9bde7ded6f0 100644 --- a/test/Driver/mips-features.c +++ b/test/Driver/mips-features.c @@ -402,3 +402,9 @@ // RUN: %clang -target -mips-mti-linux-gnu -### -c %s -mno-branch-likely 2>&1 \ // RUN: | FileCheck --check-prefix=NO-BRANCH-LIKELY %s // NO-BRANCH-LIKELY: argument unused during compilation: '-mno-branch-likely' + +// -mindirect-jump=hazard +// RUN: %clang -target mips-unknown-linux-gnu -### -c %s \ +// RUN: -mindirect-jump=hazard 2>&1 \ +// RUN: | FileCheck --check-prefix=INDIRECT-BH %s +// INDIRECT-BH: "-target-feature" "+use-indirect-jump-hazard" diff --git a/test/Driver/mips-indirect-branch.c b/test/Driver/mips-indirect-branch.c new file mode 100644 index 000000000000..64e85d5dc5a1 --- /dev/null +++ b/test/Driver/mips-indirect-branch.c @@ -0,0 +1,23 @@ +// REQUIRES: mips-registered-target +// -mindirect-jump=hazard -mips32 +// RUN: %clang -target mips-unknown-linux-gnu -mips32 -### -c %s \ +// RUN: -mindirect-jump=hazard 2>&1 | FileCheck %s --check-prefix=MIPS32 +// MIPS32: error: '-mindirect-jump=hazard' is unsupported with the 'mips32' architecture + +// -mindirect-jump=hazard -mmicromips +// RUN: %clang -target mips-unknown-linux-gnu -mmicromips -### -c %s \ +// RUN: -mindirect-jump=hazard 2>&1 | FileCheck %s --check-prefix=MICROMIPS +// MICROMIPS: error: '-mindirect-jump=hazard' is unsupported with the 'micromips' architecture + +// -mindirect-jump=hazard -mips16 +// RUN: %clang -target mips-unknown-linux-gnu -mips16 -### -c %s \ +// RUN: -mindirect-jump=hazard 2>&1 | FileCheck %s --check-prefix=MIPS16 +// MIPS16: error: '-mindirect-jump=hazard' is unsupported with the 'mips16' architecture + +// RUN: %clang -target mips-unknown-linux-gnu -### -c %s \ +// RUN: -mindirect-jump=retopline 2>&1 | FileCheck %s --check-prefix=RETOPLINE +// RETOPLINE: error: unknown '-mindirect-jump=' option 'retopline' + +// RUN: %clang -target mips-unknown-linux-gnu -### -mips32 -c %s \ +// RUN: -mindirect-jump=retopline 2>&1 | FileCheck %s --check-prefix=MIXED +// MIXED: error: unknown '-mindirect-jump=' option 'retopline' From 6451be62d3fb05e230cccd5a46074e8694270999 Mon Sep 17 00:00:00 2001 From: Eric Schweitz Date: Mon, 8 Jan 2018 14:06:45 -0800 Subject: [PATCH 06/10] Porting Flang driver changes to release_60 --- include/clang/Basic/DiagnosticDriverKinds.td | 4 + include/clang/Driver/Action.h | 11 + include/clang/Driver/Driver.h | 6 +- include/clang/Driver/Options.td | 157 +++- include/clang/Driver/Phases.h | 1 + include/clang/Driver/ToolChain.h | 15 + include/clang/Driver/Types.def | 8 +- include/clang/Driver/Types.h | 9 + lib/Driver/Action.cpp | 7 + lib/Driver/CMakeLists.txt | 1 + lib/Driver/Driver.cpp | 12 + lib/Driver/Phases.cpp | 1 + lib/Driver/ToolChain.cpp | 54 ++ lib/Driver/ToolChains/CommonArgs.cpp | 35 + lib/Driver/ToolChains/CommonArgs.h | 2 + lib/Driver/ToolChains/Flang.cpp | 851 +++++++++++++++++++ lib/Driver/ToolChains/Flang.h | 50 ++ lib/Driver/ToolChains/Gnu.cpp | 10 + lib/Driver/ToolChains/Linux.cpp | 188 ++++ lib/Driver/ToolChains/Linux.h | 3 + lib/Driver/Types.cpp | 60 +- tools/driver/CMakeLists.txt | 2 +- 22 files changed, 1462 insertions(+), 25 deletions(-) create mode 100644 lib/Driver/ToolChains/Flang.cpp create mode 100644 lib/Driver/ToolChains/Flang.h mode change 100644 => 100755 lib/Driver/Types.cpp diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 69c20ea7806c..0a92894ab850 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -43,6 +43,10 @@ def err_drv_invalid_pgo_instrumentor : Error< "invalid PGO instrumentor in argument '%0'">; def err_drv_invalid_rtlib_name : Error< "invalid runtime library name in argument '%0'">; +def err_drv_invalid_allocatable_mode : Error< + "invalid semantic mode for assignments to allocatables in argument '%0'">; +def err_drv_unsupported_fixed_line_length : Error< + "unsupported fixed-format line length in argument '%0'">; def err_drv_unsupported_rtlib_for_platform : Error< "unsupported runtime library '%0' for platform '%1'">; def err_drv_invalid_stdlib_name : Error< diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h index 72456d34a0d9..1e182d88f11a 100644 --- a/include/clang/Driver/Action.h +++ b/include/clang/Driver/Action.h @@ -59,6 +59,7 @@ class Action { AnalyzeJobClass, MigrateJobClass, CompileJobClass, + FortranFrontendJobClass, BackendJobClass, AssembleJobClass, LinkJobClass, @@ -400,6 +401,16 @@ class MigrateJobAction : public JobAction { } }; +class FortranFrontendJobAction : public JobAction { + void anchor() override; +public: + FortranFrontendJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == FortranFrontendJobClass; + } +}; + class CompileJobAction : public JobAction { void anchor() override; public: diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 07134309835e..8328b871a31a 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -67,7 +67,8 @@ class Driver { GCCMode, GXXMode, CPPMode, - CLMode + CLMode, + FortranMode } Mode; enum SaveTempsMode { @@ -182,6 +183,9 @@ class Driver { /// Whether the driver should follow cl.exe like behavior. bool IsCLMode() const { return Mode == CLMode; } + /// Whether the driver should follow gfortran like behavior. + bool IsFortranMode() const { return Mode == FortranMode; } + /// Only print tool bindings, don't build any jobs. unsigned CCCPrintBindings : 1; diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 288bd482bb97..1f1792099d24 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -247,7 +247,7 @@ class InternalDriverOpt : Group, Flags<[DriverOption, HelpHidden]>; def driver_mode : Joined<["--"], "driver-mode=">, Group, Flags<[CoreOption, DriverOption, HelpHidden]>, - HelpText<"Set the driver mode to either 'gcc', 'g++', 'cpp', or 'cl'">; + HelpText<"Set the driver mode to either 'gcc', 'g++', 'cpp', 'cl', or 'fortran'">; def rsp_quoting : Joined<["--"], "rsp-quoting=">, Group, Flags<[CoreOption, DriverOption, HelpHidden]>, HelpText<"Set the rsp quoting to either 'posix', or 'windows'">; @@ -2719,11 +2719,19 @@ defm devirtualize : BooleanFFlag<"devirtualize">, Group, Group; +// gfortran options that we recognize in the driver and pass along when +// invoking GCC to compile Fortran code. +def flang_rt_Group : OptionGroup<"Flang runtime library Group">; +def pgi_fortran_Group : OptionGroup<"PGI Fortran compatibility Group">, + Flags<[HelpHidden]>; + // Generic gfortran options. def A_DASH : Joined<["-"], "A-">, Group; def J : JoinedOrSeparate<["-"], "J">, Flags<[RenderJoined]>, Group; -def cpp : Flag<["-"], "cpp">, Group; -def nocpp : Flag<["-"], "nocpp">, Group; +def cpp : Flag<["-"], "cpp">, Group, + HelpText<"Preprocess Fortran files">; +def nocpp : Flag<["-"], "nocpp">, Group, + HelpText<"Don't preprocess Fortran files">; def static_libgfortran : Flag<["-"], "static-libgfortran">, Group; // "f" options with values for gfortran. @@ -2731,7 +2739,8 @@ def fblas_matmul_limit_EQ : Joined<["-"], "fblas-matmul-limit=">, Group, Group; +def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Group, + HelpText<"Set line length in fixed-form format Fortran, current supporting only 72 and 132 characters">; def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group; def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group; def finit_character_EQ : Joined<["-"], "finit-character=">, Group; @@ -2744,12 +2753,17 @@ def fmax_stack_var_size_EQ : Joined<["-"], "fmax-stack-var-size=">, Group, Group; // "f" flags for gfortran. defm aggressive_function_elimination : BooleanFFlag<"aggressive-function-elimination">, Group; defm align_commons : BooleanFFlag<"align-commons">, Group; defm all_intrinsics : BooleanFFlag<"all-intrinsics">, Group; defm automatic : BooleanFFlag<"automatic">, Group; -defm backslash : BooleanFFlag<"backslash">, Group; +def fbackslash: Flag<["-"], "fbackslash">, Group, + HelpText<"Treat backslash as C-style escape character">; +def fnobackslash: Flag<["-"], "fno-backslash">, Group, + HelpText<"Treat backslash like any other character in character strings">; defm backtrace : BooleanFFlag<"backtrace">, Group; defm bounds_check : BooleanFFlag<"bounds-check">, Group; defm check_array_temporaries : BooleanFFlag<"check-array-temporaries">, Group; @@ -2757,17 +2771,27 @@ defm cray_pointer : BooleanFFlag<"cray-pointer">, Group; defm d_lines_as_code : BooleanFFlag<"d-lines-as-code">, Group; defm d_lines_as_comments : BooleanFFlag<"d-lines-as-comments">, Group; defm default_double_8 : BooleanFFlag<"default-double-8">, Group; -defm default_integer_8 : BooleanFFlag<"default-integer-8">, Group; -defm default_real_8 : BooleanFFlag<"default-real-8">, Group; +def default_integer_8_f : Flag<["-"], "fdefault-integer-8">, Group, + HelpText<"Treat INTEGER and LOGICAL as INTEGER*8 and LOGICAL*8">; +def default_integer_8_fno : Flag<["-"], "fno-default-integer-8">, Group; +def default_real_8_f : Flag<["-"], "fdefault-real-8">, Group, + HelpText<"Treat REAL as REAL*8">; +def default_real_8_fno : Flag<["-"], "fno-default-real-8">, Group; defm dollar_ok : BooleanFFlag<"dollar-ok">, Group; defm dump_fortran_optimized : BooleanFFlag<"dump-fortran-optimized">, Group; defm dump_fortran_original : BooleanFFlag<"dump-fortran-original">, Group; defm dump_parse_tree : BooleanFFlag<"dump-parse-tree">, Group; defm external_blas : BooleanFFlag<"external-blas">, Group; defm f2c : BooleanFFlag<"f2c">, Group; -defm fixed_form : BooleanFFlag<"fixed-form">, Group; -defm free_form : BooleanFFlag<"free-form">, Group; -defm frontend_optimize : BooleanFFlag<"frontend-optimize">, Group; +def fixed_form_on : Flag<["-"], "ffixed-form">, Group, + HelpText<"Enable fixed-form format for Fortran">; +def fixed_form_off : Flag<["-"], "fno-fixed-form">, Group, + HelpText<"Disable fixed-form format for Fortran">; +def free_form_on : Flag<["-"], "ffree-form">, Group, + HelpText<"Enable free-form format for Fortran">; +def free_form_off : Flag<["-"], "fno-free-form">, Group, + HelpText<"Disable free-form format for Fortran">; +defm frontend_optimize : BooleanFFlag<"frontend-optimize">, Group; defm implicit_none : BooleanFFlag<"implicit-none">, Group; defm init_local_zero : BooleanFFlag<"init-local-zero">, Group; defm integer_4_integer_8 : BooleanFFlag<"integer-4-integer-8">, Group; @@ -2792,6 +2816,119 @@ defm stack_arrays : BooleanFFlag<"stack-arrays">, Group; defm underscoring : BooleanFFlag<"underscoring">, Group; defm whole_file : BooleanFFlag<"whole-file">, Group; +// Flang-specific options +multiclass BooleanKFlag { + def _on : Flag<["-"], "K"#name>; + def _off : Flag<["-"], "Kno"#name>; +} + +multiclass BooleanMFlag { + def _on : Flag<["-"], "M"#name>; + def _off : Flag<["-"], "Mno"#name>; +} + +def Mfixed : Flag<["-"], "Mfixed">, Group, + HelpText<"Force fixed-form format Fortran">, + Flags<[HelpHidden]>; +def Mfree_on: Flag<["-"], "Mfree">, Group, + HelpText<"Enable free-form format for Fortran">, + Flags<[HelpHidden]>; +def Mfree_off: Flag<["-"], "Mnofree">, Group, + HelpText<"Disable free-form format for Fortran">, + Flags<[HelpHidden]>; +def Mfreeform_on: Flag<["-"], "Mfreeform">, Group, + HelpText<"Enable free-form format for Fortran">, + Flags<[HelpHidden]>; +def Mfreeform_off: Flag<["-"], "Mnofreeform">, Group, + HelpText<"Disable free-form format for Fortran">, + Flags<[HelpHidden]>; + +def Mipa: Joined<["-"], "Mipa">, Group; +def Mstackarrays: Joined<["-"], "Mstack_arrays">, Group; +def pc: JoinedOrSeparate<["-"], "pc">, Group; +def Mfprelaxed: Joined<["-"], "Mfprelaxed">, Group; +def Mnofprelaxed: Joined<["-"], "Mnofprelaxed">, Group; +defm Mstride0: BooleanMFlag<"stride0">, Group; +defm Mrecursive: BooleanMFlag<"recursive">, Group; +defm Mreentrant: BooleanMFlag<"reentrant">, Group; +defm Mbounds: BooleanMFlag<"bounds">, Group; +def Mdaz_on: Flag<["-"], "Mdaz">, Group, + HelpText<"Treat denormalized numbers as zero">; +def Mdaz_off: Flag<["-"], "Mnodaz">, Group, + HelpText<"Disable treating denormalized numbers as zero">; +def Kieee_on : Flag<["-"], "Kieee">, Group, + HelpText<"Enable IEEE division">; +def Kieee_off : Flag<["-"], "Knoieee">, Group, + HelpText<"Disable IEEE division">; +def Mextend : Flag<["-"], "Mextend">, Group, + HelpText<"Allow lines up to 132 characters in Fortran sources">; +def Mpreprocess : Flag<["-"], "Mpreprocess">, Group, + HelpText<"Preprocess Fortran files">; +def Mstandard: Flag<["-"], "Mstandard">, Group, + HelpText<"Check Fortran standard conformance">; +def Mchkptr: Flag<["-"], "Mchkptr">, Group; +defm Minline: BooleanMFlag<"inline">, Group; +def fma: Flag<["-"], "fma">, Group, + HelpText<"Enable generation of FMA instructions">; +def nofma: Flag<["-"], "nofma">, Group, + HelpText<"Disable generation of FMA instructions">; +defm Mfma: BooleanMFlag<"fma">, Group, + HelpText<"Enable generation of FMA instructions">; +def mp: Flag<["-"], "mp">, Group, + HelpText<"Enable OpenMP">; +def nomp: Flag<["-"], "nomp">, Group, + HelpText<"Do not link with OpenMP library libomp">; +def Mflushz_on: Flag<["-"], "Mflushz">, Group, + HelpText<"Set SSE to flush-to-zero mode">; +def Mflushz_off: Flag<["-"], "Mnoflushz">, Group, + HelpText<"Disabling setting SSE to flush-to-zero mode">; +def Msave_on: Flag<["-"], "Msave">, Group, + HelpText<"Assume all Fortran variables have SAVE attribute">; +def Msave_off: Flag<["-"], "Mnosave">, Group, + HelpText<"Assume no Fortran variables have SAVE attribute">; +def Mcache_align_on: Flag<["-"], "Mcache_align">, Group, + HelpText<"Align large objects on cache-line boundaries">; +def Mcache_align_off: Flag<["-"], "Mnocache_align">, Group, + HelpText<"Disable aligning large objects on cache-line boundaries">; +def ModuleDir : Separate<["-"], "module">, Group, + HelpText<"Fortran module path">; +def Minform_EQ : Joined<["-"], "Minform=">, + HelpText<"Set error level of messages to display">; +def Mallocatable_EQ : Joined<["-"], "Mallocatable=">, + HelpText<"Select semantics for assignments to allocatables (F03 or F95)">; +def Mbyteswapio: Flag<["-"], "Mbyteswapio">, Group, + HelpText<"Swap byte-order for unformatted input/output">; +def byteswapio: Flag<["-"], "byteswapio">, Group, + HelpText<"Swap byte-order for unformatted input/output">; +def Mbackslash: Flag<["-"], "Mbackslash">, Group, + HelpText<"Treat backslash like any other character in character strings">; +def Mnobackslash: Flag<["-"], "Mnobackslash">, Group, + HelpText<"Treat backslash as C-style escape character">; +def staticFlangLibs: Flag<["-"], "static-flang-libs">, Group, + HelpText<"Link using static Flang libraries">; +def noFlangLibs: Flag<["-"], "no-flang-libs">, Group, + HelpText<"Do not link against Flang libraries">; +def r8: Flag<["-"], "r8">, Group, + HelpText<"Treat REAL as REAL*8">; +def i8: Flag<["-"], "i8">, Group, + HelpText<"Treat INTEGER and LOGICAL as INTEGER*8 and LOGICAL*8">; +def no_fortran_main: Flag<["-"], "fno-fortran-main">, Group, + HelpText<"Don't link in Fortran main">; +def Mnomain: Flag<["-"], "Mnomain">, Group, + HelpText<"Don't link in Fortran main">; + +// Flang internal debug options +def Mx_EQ : Joined<["-"], "Mx,">, Group; +def My_EQ : Joined<["-"], "My,">, Group; +def Hx_EQ : Joined<["-"], "Hx,">, Group; +def Hy_EQ : Joined<["-"], "Hy,">, Group; +def Wm_EQ : Joined<["-"], "Wm,">, Group; + +def Mq_EQ : Joined<["-"], "Mq,">, Group; +def Hq_EQ : Joined<["-"], "Hq,">, Group; +def Mqq_EQ : Joined<["-"], "Mqq,">, Group; +def Hqq_EQ : Joined<["-"], "Hqq,">, Group; +def Wh_EQ : Joined<["-"], "Wh,">, Group; include "CC1Options.td" diff --git a/include/clang/Driver/Phases.h b/include/clang/Driver/Phases.h index cd6b5b5c9f05..fe96caaaf800 100644 --- a/include/clang/Driver/Phases.h +++ b/include/clang/Driver/Phases.h @@ -18,6 +18,7 @@ namespace phases { enum ID { Preprocess, Precompile, + FortranFrontend, Compile, Backend, Assemble, diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index 13f54d3718b4..9bcec45e6c90 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -107,11 +107,13 @@ class ToolChain { /// programs. path_list ProgramPaths; + mutable std::unique_ptr FlangFrontend; mutable std::unique_ptr Clang; mutable std::unique_ptr Assemble; mutable std::unique_ptr Link; mutable std::unique_ptr OffloadBundler; Tool *getClang() const; + Tool *getFlangFrontend() const; Tool *getAssemble() const; Tool *getLink() const; Tool *getClangAs() const; @@ -450,6 +452,14 @@ class ToolChain { AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; + /// \brief Add the flang arguments for system include paths. + /// + /// This routine is responsible for adding the -stdinc argument to + /// include headers and module files from standard system header directories. + virtual void + AddFlangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &Flang1Args) const { } + /// \brief Add options that need to be passed to cc1 for this target. virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, @@ -514,6 +524,11 @@ class ToolChain { virtual VersionTuple computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const; + /// AddFortranStdlibLibArgs - Add the system specific linker arguments to use + /// for the given Fortran runtime library type. + virtual void AddFortranStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + /// \brief Return sanitizers which are available in this toolchain. virtual SanitizerMask getSupportedSanitizers() const; diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def index 2430b5b924c3..0fd9c2779cf4 100644 --- a/include/clang/Driver/Types.def +++ b/include/clang/Driver/Types.def @@ -69,12 +69,16 @@ TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, "h", "pu") TYPE("c++-module", CXXModule, PP_CXXModule, "cppm", "mu") TYPE("c++-module-cpp-output", PP_CXXModule, INVALID, "iim", "m") +// Fortran +TYPE("f77", PP_F_FixedForm, INVALID, "f", "u") +TYPE("f77-cpp-input", F_FixedForm, PP_F_FixedForm, "F", "u") +TYPE("f95", PP_F_FreeForm, INVALID, "f95", "u") +TYPE("f95-cpp-input", F_FreeForm, PP_F_FreeForm, "F95", "u") + // Other languages. TYPE("ada", Ada, INVALID, nullptr, "u") TYPE("assembler", PP_Asm, INVALID, "s", "au") TYPE("assembler-with-cpp", Asm, PP_Asm, "S", "au") -TYPE("f95", PP_Fortran, INVALID, nullptr, "u") -TYPE("f95-cpp-input", Fortran, PP_Fortran, nullptr, "u") TYPE("java", Java, INVALID, nullptr, "u") // LLVM IR/LTO types. We define separate types for IR and LTO because LTO diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h index 22a26ae46a0b..ae3fa36231b5 100644 --- a/include/clang/Driver/Types.h +++ b/include/clang/Driver/Types.h @@ -107,6 +107,15 @@ namespace types { /// source file type (used for clang-cl emulation of \Yc). ID lookupHeaderTypeForSourceType(ID Id); + /// isFortran -- is it a Fortran input + bool isFortran(ID Id); + + /// isFreeFormFortran -- is it a free form layout Fortran input + bool isFreeFormFortran(ID Id); + + /// isFixedFormFortran -- is it a fixed form layout Fortran input + bool isFixedFormFortran(ID Id); + } // end namespace types } // end namespace driver } // end namespace clang diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 85e466a4409d..70ff131d7820 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -29,6 +29,7 @@ const char *Action::getClassName(ActionClass AC) { case PrecompileJobClass: return "precompiler"; case AnalyzeJobClass: return "analyzer"; case MigrateJobClass: return "migrator"; + case FortranFrontendJobClass: return "fortran-frontend"; case CompileJobClass: return "compiler"; case BackendJobClass: return "backend"; case AssembleJobClass: return "assembler"; @@ -323,6 +324,12 @@ void MigrateJobAction::anchor() {} MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType) : JobAction(MigrateJobClass, Input, OutputType) {} +void FortranFrontendJobAction::anchor() {} + +FortranFrontendJobAction::FortranFrontendJobAction(Action *Input, + types::ID OutputType) + : JobAction(FortranFrontendJobClass, Input, OutputType) {} + void CompileJobAction::anchor() {} CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType) diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 5bf91f2be981..fb560d418b03 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -40,6 +40,7 @@ add_clang_library(clangDriver ToolChains/Cuda.cpp ToolChains/Darwin.cpp ToolChains/DragonFly.cpp + ToolChains/Flang.cpp ToolChains/FreeBSD.cpp ToolChains/Fuchsia.cpp ToolChains/Gnu.cpp diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 325b233ac5ec..5205ea98c1ae 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -153,6 +153,7 @@ void Driver::setDriverModeFromOption(StringRef Opt) { .Case("g++", GXXMode) .Case("cpp", CPPMode) .Case("cl", CLMode) + .Case("fortran", FortranMode) .Default(~0U); if (M != ~0U) @@ -231,6 +232,10 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) { FinalPhase = phases::Preprocess; + // -fsyntax-only stops Fortran compilation after FortranFrontend + } else if (IsFortranMode() && (PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only))) { + FinalPhase = phases::FortranFrontend; + // --precompile only runs up to precompilation. } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) { FinalPhase = phases::Precompile; @@ -3023,6 +3028,13 @@ Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args, } return C.MakeAction(Input, OutputTy); } + case phases::FortranFrontend: { + if (Args.hasArg(options::OPT_fsyntax_only)) + return C.MakeAction(Input, + types::TY_Nothing); + return C.MakeAction(Input, + types::TY_LLVM_IR); + } case phases::Compile: { if (Args.hasArg(options::OPT_fsyntax_only)) return C.MakeAction(Input, types::TY_Nothing); diff --git a/lib/Driver/Phases.cpp b/lib/Driver/Phases.cpp index 7ae270857f4d..5f5e206f7d98 100644 --- a/lib/Driver/Phases.cpp +++ b/lib/Driver/Phases.cpp @@ -17,6 +17,7 @@ const char *phases::getPhaseName(ID Id) { switch (Id) { case Preprocess: return "preprocessor"; case Precompile: return "precompiler"; + case FortranFrontend: return "fortran-frontend"; case Compile: return "compiler"; case Backend: return "backend"; case Assemble: return "assembler"; diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index f96a1182e3ca..eab990e236ae 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -11,6 +11,7 @@ #include "ToolChains/CommonArgs.h" #include "ToolChains/Arch/ARM.h" #include "ToolChains/Clang.h" +#include "ToolChains/Flang.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" @@ -137,6 +138,7 @@ const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { {"cpp", "--driver-mode=cpp"}, {"cl", "--driver-mode=cl"}, {"++", "--driver-mode=g++"}, + {"flang", "--driver-mode=fortran"}, }; for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) { @@ -255,6 +257,12 @@ Tool *ToolChain::getAssemble() const { return Assemble.get(); } +Tool *ToolChain::getFlangFrontend() const { + if (!FlangFrontend) + FlangFrontend.reset(new tools::FlangFrontend(*this)); + return FlangFrontend.get(); +} + Tool *ToolChain::getClangAs() const { if (!Assemble) Assemble.reset(new tools::ClangAs(*this)); @@ -301,6 +309,9 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::OffloadBundlingJobClass: case Action::OffloadUnbundlingJobClass: return getOffloadBundler(); + + case Action::FortranFrontendJobClass: + return getFlangFrontend(); } llvm_unreachable("Invalid tool kind."); @@ -749,6 +760,49 @@ void ToolChain::AddCCKextLibArgs(const ArgList &Args, CmdArgs.push_back("-lcc_kext"); } +void ToolChain::AddFortranStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + bool staticFlangLibs = false; + bool useOpenMP = false; + + if (Args.hasArg(options::OPT_staticFlangLibs)) { + for (auto *A: Args.filtered(options::OPT_staticFlangLibs)) { + A->claim(); + staticFlangLibs = true; + } + } + + Arg *A = Args.getLastArg(options::OPT_mp, options::OPT_nomp, + options::OPT_fopenmp, options::OPT_fno_openmp); + if (A && + (A->getOption().matches(options::OPT_mp) || + A->getOption().matches(options::OPT_fopenmp))) { + useOpenMP = true; + } + + if (staticFlangLibs) { + CmdArgs.push_back("-Bstatic"); + } + CmdArgs.push_back("-lflang"); + CmdArgs.push_back("-lflangrti"); + if( useOpenMP ) { + CmdArgs.push_back("-lomp"); + } + else { + CmdArgs.push_back("-lompstub"); + } + if( staticFlangLibs ) { + CmdArgs.push_back("-Bdynamic"); + } + + CmdArgs.push_back("-lm"); + CmdArgs.push_back("-lrt"); + + // Allways link Fortran executables with Pthreads + CmdArgs.push_back("-lpthread"); + +} + bool ToolChain::AddFastMathRuntimeIfAvailable(const ArgList &Args, ArgStringList &CmdArgs) const { // Do not check for -fno-fast-math or -fno-unsafe-math when -Ofast passed diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp index f26880123d8c..535ae12193a5 100644 --- a/lib/Driver/ToolChains/CommonArgs.cpp +++ b/lib/Driver/ToolChains/CommonArgs.cpp @@ -56,6 +56,23 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +/// \brief Determine if Fortran link libraies are needed +bool tools::needFortranLibs(const Driver &D, const ArgList &Args) { + if (D.IsFortranMode() && !Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_noFlangLibs)) { + return true; + } + + return false; +} + +/// \brief Determine if Fortran "main" object is needed +static bool needFortranMain(const Driver &D, const ArgList &Args) { + return (needFortranLibs(D, Args) + && (!Args.hasArg(options::OPT_Mnomain) || + !Args.hasArg(options::OPT_no_fortran_main))); +} + void tools::addPathIfExists(const Driver &D, const Twine &Path, ToolChain::path_list &Paths) { if (D.getVFS().exists(Path)) @@ -138,6 +155,7 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs, const JobAction &JA) { const Driver &D = TC.getDriver(); + bool SeenFirstLinkerInput = false; // Add extra linker input arguments which are not treated as inputs // (constructed via -Xarch_). @@ -162,6 +180,14 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, continue; } + // Add Fortan "main" before the first linker input + if (!SeenFirstLinkerInput) { + if (needFortranMain(D, Args)) { + CmdArgs.push_back("-lflangmain"); + } + SeenFirstLinkerInput = true; + } + // Otherwise, this is a linker input argument. const Arg &A = II.getInputArg(); @@ -179,6 +205,15 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, } } + if (!SeenFirstLinkerInput && needFortranMain(D, Args)) { + CmdArgs.push_back("-lflangmain"); + } + + // Claim "no Fortran main" arguments + for (auto Arg : Args.filtered(options::OPT_no_fortran_main, options::OPT_Mnomain)) { + Arg->claim(); + } + // LIBRARY_PATH - included following the user specified library paths. // and only supported on native toolchains. if (!TC.isCrossCompiling()) { diff --git a/lib/Driver/ToolChains/CommonArgs.h b/lib/Driver/ToolChains/CommonArgs.h index 012f5b9f87ae..6e1ed090611e 100644 --- a/lib/Driver/ToolChains/CommonArgs.h +++ b/lib/Driver/ToolChains/CommonArgs.h @@ -20,6 +20,8 @@ namespace clang { namespace driver { namespace tools { +bool needFortranLibs(const Driver &D, const llvm::opt::ArgList &Args); + void addPathIfExists(const Driver &D, const Twine &Path, ToolChain::path_list &Paths); diff --git a/lib/Driver/ToolChains/Flang.cpp b/lib/Driver/ToolChains/Flang.cpp new file mode 100644 index 000000000000..eb619a860e93 --- /dev/null +++ b/lib/Driver/ToolChains/Flang.cpp @@ -0,0 +1,851 @@ +//===--- Flang.cpp - Flang+LLVM ToolChain Implementations -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Flang.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/XRayArgs.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/YAMLParser.h" + +#ifdef LLVM_ON_UNIX +#include // For getuid(). +#endif + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +void FlangFrontend::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, const char *LinkingOutput) const { + ArgStringList CommonCmdArgs; + ArgStringList UpperCmdArgs; + ArgStringList LowerCmdArgs; + SmallString<256> Stem; + std::string OutFile; + bool NeedIEEE = true; + + // Check number of inputs for sanity. We need at least one input. + assert(Inputs.size() >= 1 && "Must have at least one input."); + + /***** Process file arguments to both parts *****/ + const InputInfo &Input = Inputs[0]; + types::ID InputType = Input.getType(); + // Check file type sanity + assert(types::isFortran(InputType) && "Can only accept Fortran"); + + if (Args.hasArg(options::OPT_fsyntax_only)) { + // For -fsyntax-only produce temp files only + Stem = C.getDriver().GetTemporaryPath("", ""); + } else { + OutFile = Output.getFilename(); + Stem = llvm::sys::path::filename(OutFile); + llvm::sys::path::replace_extension(Stem, ""); + } + + // Add input file name to the compilation line + UpperCmdArgs.push_back(Input.getBaseInput()); + + // Add temporary output for ILM + const char * ILMFile = Args.MakeArgString(Stem + ".ilm"); + LowerCmdArgs.push_back(ILMFile); + C.addTempFile(ILMFile); + + /***** Process common args *****/ + + // Override IEEE mode if needed + if (Args.hasArg(options::OPT_Ofast) || + Args.hasArg(options::OPT_ffast_math) || + Args.hasArg(options::OPT_fno_fast_math) || + Args.hasArg(options::OPT_Kieee_on) || + Args.hasArg(options::OPT_Kieee_off)) { + auto A = Args.getLastArg(options::OPT_Ofast, + options::OPT_ffast_math, + options::OPT_fno_fast_math, + options::OPT_Kieee_on, + options::OPT_Kieee_off); + auto Opt = A->getOption(); + if (Opt.matches(options::OPT_Ofast) || + Opt.matches(options::OPT_ffast_math) || + Opt.matches(options::OPT_Kieee_off)) { + NeedIEEE = false; + } + } + + // -Kieee is on by default + if (!Args.hasArg(options::OPT_Kieee_off)) { + CommonCmdArgs.push_back("-y"); // Common: -y 129 2 + CommonCmdArgs.push_back("129"); + CommonCmdArgs.push_back("2"); + // Lower: -x 6 0x100 + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("6"); + LowerCmdArgs.push_back("0x100"); + // -x 42 0x400000 + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("42"); + LowerCmdArgs.push_back("0x400000"); + // -y 129 4 + LowerCmdArgs.push_back("-y"); + LowerCmdArgs.push_back("129"); + LowerCmdArgs.push_back("4"); + // -x 129 0x400 + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("129"); + LowerCmdArgs.push_back("0x400"); + for (auto Arg : Args.filtered(options::OPT_Kieee_on)) { + Arg->claim(); + } + } else { + for (auto Arg : Args.filtered(options::OPT_Kieee_off)) { + Arg->claim(); + } + } + + // Add "inform level" flag + if (Args.hasArg(options::OPT_Minform_EQ)) { + // Parse arguments to set its value + for (Arg *A : Args.filtered(options::OPT_Minform_EQ)) { + A->claim(); + CommonCmdArgs.push_back("-inform"); + CommonCmdArgs.push_back(A->getValue(0)); + } + } else { + // Default value + CommonCmdArgs.push_back("-inform"); + CommonCmdArgs.push_back("warn"); + } + + for (auto Arg : Args.filtered(options::OPT_Msave_on)) { + Arg->claim(); + CommonCmdArgs.push_back("-save"); + } + + for (auto Arg : Args.filtered(options::OPT_Msave_off)) { + Arg->claim(); + CommonCmdArgs.push_back("-nosave"); + } + + // Treat denormalized numbers as zero: On + for (auto Arg : Args.filtered(options::OPT_Mdaz_on)) { + Arg->claim(); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("129"); + CommonCmdArgs.push_back("4"); + CommonCmdArgs.push_back("-y"); + CommonCmdArgs.push_back("129"); + CommonCmdArgs.push_back("0x400"); + } + + // Treat denormalized numbers as zero: Off + for (auto Arg : Args.filtered(options::OPT_Mdaz_off)) { + Arg->claim(); + CommonCmdArgs.push_back("-y"); + CommonCmdArgs.push_back("129"); + CommonCmdArgs.push_back("4"); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("129"); + CommonCmdArgs.push_back("0x400"); + } + + // Bounds checking: On + for (auto Arg : Args.filtered(options::OPT_Mbounds_on)) { + Arg->claim(); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("70"); + CommonCmdArgs.push_back("2"); + } + + // Bounds checking: Off + for (auto Arg : Args.filtered(options::OPT_Mbounds_off)) { + Arg->claim(); + CommonCmdArgs.push_back("-y"); + CommonCmdArgs.push_back("70"); + CommonCmdArgs.push_back("2"); + } + + // Generate code allowing recursive subprograms + for (auto Arg : Args.filtered(options::OPT_Mrecursive_on)) { + Arg->claim(); + CommonCmdArgs.push_back("-recursive"); + } + + // Disable recursive subprograms + for (auto Arg : Args.filtered(options::OPT_Mrecursive_off)) { + Arg->claim(); + CommonCmdArgs.push_back("-norecursive"); + } + + // Enable generating reentrant code (disable optimizations that inhibit it) + for (auto Arg : Args.filtered(options::OPT_Mreentrant_on)) { + Arg->claim(); + CommonCmdArgs.push_back("-reentrant"); + } + + // Allow optimizations inhibiting reentrancy + for (auto Arg : Args.filtered(options::OPT_Mreentrant_off)) { + Arg->claim(); + CommonCmdArgs.push_back("-noreentrant"); + } + + // Swap byte order for unformatted IO + for (auto Arg : Args.filtered(options::OPT_Mbyteswapio, options::OPT_byteswapio)) { + Arg->claim(); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("125"); + CommonCmdArgs.push_back("2"); + } + + // Treat backslashes as regular characters + for (auto Arg : Args.filtered(options::OPT_fnobackslash, options::OPT_Mbackslash)) { + Arg->claim(); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("124"); + CommonCmdArgs.push_back("0x40"); + } + + // Treat backslashes as C-style escape characters + for (auto Arg : Args.filtered(options::OPT_fbackslash, options::OPT_Mnobackslash)) { + Arg->claim(); + CommonCmdArgs.push_back("-y"); + CommonCmdArgs.push_back("124"); + CommonCmdArgs.push_back("0x40"); + } + + // handle OpemMP options + if (auto *A = Args.getLastArg(options::OPT_mp, options::OPT_nomp, + options::OPT_fopenmp, options::OPT_fno_openmp)) { + for (auto Arg : Args.filtered(options::OPT_mp, options::OPT_nomp)) { + Arg->claim(); + } + for (auto Arg : Args.filtered(options::OPT_fopenmp, + options::OPT_fno_openmp)) { + Arg->claim(); + } + + if (A->getOption().matches(options::OPT_mp) || + A->getOption().matches(options::OPT_fopenmp)) { + + CommonCmdArgs.push_back("-mp"); + + // Allocate threadprivate data local to the thread + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("69"); + CommonCmdArgs.push_back("0x200"); + + // Use the 'fair' schedule as the default static schedule + // for parallel do loops + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("69"); + CommonCmdArgs.push_back("0x400"); + } + } + + // Align large objects on cache lines + for (auto Arg : Args.filtered(options::OPT_Mcache_align_on)) { + Arg->claim(); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("119"); + CommonCmdArgs.push_back("0x10000000"); + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("129"); + LowerCmdArgs.push_back("0x40000000"); + } + + // Disable special alignment of large objects + for (auto Arg : Args.filtered(options::OPT_Mcache_align_off)) { + Arg->claim(); + CommonCmdArgs.push_back("-y"); + CommonCmdArgs.push_back("119"); + CommonCmdArgs.push_back("0x10000000"); + LowerCmdArgs.push_back("-y"); + LowerCmdArgs.push_back("129"); + LowerCmdArgs.push_back("0x40000000"); + } + + // -Mstack_arrays + for (auto Arg : Args.filtered(options::OPT_Mstackarrays)) { + Arg->claim(); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("54"); + CommonCmdArgs.push_back("8"); + } + + // -g should produce DWARFv2 + for (auto Arg : Args.filtered(options::OPT_g_Flag)) { + Arg->claim(); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("120"); + CommonCmdArgs.push_back("0x200"); + } + + // -gdwarf-2 + for (auto Arg : Args.filtered(options::OPT_gdwarf_2)) { + Arg->claim(); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("120"); + CommonCmdArgs.push_back("0x200"); + } + + // -gdwarf-3 + for (auto Arg : Args.filtered(options::OPT_gdwarf_3)) { + Arg->claim(); + CommonCmdArgs.push_back("-x"); + CommonCmdArgs.push_back("120"); + CommonCmdArgs.push_back("0x4000"); + } + + // -Mipa has no effect + if (Arg *A = Args.getLastArg(options::OPT_Mipa)) { + getToolChain().getDriver().Diag(diag::warn_drv_clang_unsupported) + << A->getAsString(Args); + } + + // -Minline has no effect + if (Arg *A = Args.getLastArg(options::OPT_Minline_on)) { + getToolChain().getDriver().Diag(diag::warn_drv_clang_unsupported) + << A->getAsString(Args); + } + + // Handle -fdefault-real-8 (and its alias, -r8) and -fno-default-real-8 + if (Arg *A = Args.getLastArg(options::OPT_r8, + options::OPT_default_real_8_f, + options::OPT_default_real_8_fno)) { + const char * fl; + // For -f version add -x flag, for -fno add -y + if (A->getOption().matches(options::OPT_default_real_8_fno)) { + fl = "-y"; + } else { + fl = "-x"; + } + + for (Arg *A : Args.filtered(options::OPT_r8, + options::OPT_default_real_8_f, + options::OPT_default_real_8_fno)) { + A->claim(); + } + + UpperCmdArgs.push_back(fl); + UpperCmdArgs.push_back("124"); + UpperCmdArgs.push_back("0x8"); + UpperCmdArgs.push_back(fl); + UpperCmdArgs.push_back("124"); + UpperCmdArgs.push_back("0x80000"); + } + + // Process and claim -i8/-fdefault-integer-8/-fno-default-integer-8 argument + if (Arg *A = Args.getLastArg(options::OPT_i8, + options::OPT_default_integer_8_f, + options::OPT_default_integer_8_fno)) { + const char * fl; + + if (A->getOption().matches(options::OPT_default_integer_8_fno)) { + fl = "-y"; + } else { + fl = "-x"; + } + + for (Arg *A : Args.filtered(options::OPT_i8, + options::OPT_default_integer_8_f, + options::OPT_default_integer_8_fno)) { + A->claim(); + } + + UpperCmdArgs.push_back(fl); + UpperCmdArgs.push_back("124"); + UpperCmdArgs.push_back("0x10"); + } + + // Set a -x flag for first part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_Hx_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + auto XFlag = Value.split(","); + UpperCmdArgs.push_back("-x"); + UpperCmdArgs.push_back(Args.MakeArgString(XFlag.first)); + UpperCmdArgs.push_back(Args.MakeArgString(XFlag.second)); + } + + // Set a -y flag for first part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_Hy_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + auto XFlag = Value.split(","); + UpperCmdArgs.push_back("-y"); + UpperCmdArgs.push_back(Args.MakeArgString(XFlag.first)); + UpperCmdArgs.push_back(Args.MakeArgString(XFlag.second)); + } + + // Set a -q (debug) flag for first part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_Hq_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + auto XFlag = Value.split(","); + UpperCmdArgs.push_back("-q"); + UpperCmdArgs.push_back(Args.MakeArgString(XFlag.first)); + UpperCmdArgs.push_back(Args.MakeArgString(XFlag.second)); + } + + // Set a -qq (debug) flag for first part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_Hqq_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + auto XFlag = Value.split(","); + UpperCmdArgs.push_back("-qq"); + UpperCmdArgs.push_back(Args.MakeArgString(XFlag.first)); + UpperCmdArgs.push_back(Args.MakeArgString(XFlag.second)); + } + + // Pass an arbitrary flag for first part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_Wh_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + SmallVector PassArgs; + Value.split(PassArgs, StringRef(",")); + for (StringRef PassArg : PassArgs) { + UpperCmdArgs.push_back(Args.MakeArgString(PassArg)); + } + } + + // Flush to zero mode + // Disabled by default, but can be enabled by a switch + if (Args.hasArg(options::OPT_Mflushz_on)) { + // For -Mflushz set -x 129 2 for second part of Fortran frontend + for (Arg *A: Args.filtered(options::OPT_Mflushz_on)) { + A->claim(); + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("129"); + LowerCmdArgs.push_back("2"); + } + } else { + LowerCmdArgs.push_back("-y"); + LowerCmdArgs.push_back("129"); + LowerCmdArgs.push_back("2"); + for (Arg *A: Args.filtered(options::OPT_Mflushz_off)) { + A->claim(); + } + } + + // Enable FMA + for (Arg *A: Args.filtered(options::OPT_Mfma_on, options::OPT_fma)) { + A->claim(); + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("172"); + LowerCmdArgs.push_back("0x40000000"); + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("179"); + LowerCmdArgs.push_back("1"); + } + + // Disable FMA + for (Arg *A: Args.filtered(options::OPT_Mfma_off, options::OPT_nofma)) { + A->claim(); + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("171"); + LowerCmdArgs.push_back("0x40000000"); + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("178"); + LowerCmdArgs.push_back("1"); + } + + // For -fPIC set -x 62 8 for second part of Fortran frontend + for (Arg *A: Args.filtered(options::OPT_fPIC)) { + A->claim(); + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("62"); + LowerCmdArgs.push_back("8"); + } + + StringRef OptOStr("0"); + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O4)) { + OptOStr = "4"; // FIXME what should this be? + } else if (A->getOption().matches(options::OPT_Ofast)) { + OptOStr = "2"; // FIXME what should this be? + } else if (A->getOption().matches(options::OPT_O0)) { + // intentionally do nothing + } else { + assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag"); + StringRef S(A->getValue()); + if ((S == "s") || (S == "z")) { + // -Os = size; -Oz = more size + OptOStr = "2"; // FIXME -Os|-Oz => -opt ? + } else if ((S == "1") || (S == "2") || (S == "3")) { + OptOStr = S; + } else { + OptOStr = "4"; + } + } + } + unsigned OptLevel = std::stoi(OptOStr.str()); + + if (Args.hasArg(options::OPT_g_Group)) { + // pass -g to lower + LowerCmdArgs.push_back("-debug"); + } + + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math)) { + if (A->getOption().matches(options::OPT_ffast_math)) { + LowerCmdArgs.push_back("-x"); + } else { + LowerCmdArgs.push_back("-y"); + } + LowerCmdArgs.push_back("216"); + LowerCmdArgs.push_back("1"); + } + + // IEEE compatibility mode + LowerCmdArgs.push_back("-ieee"); + if (NeedIEEE) { + LowerCmdArgs.push_back("1"); + } else { + LowerCmdArgs.push_back("0"); + } + + /***** Upper part of the Fortran frontend *****/ + + // TODO do we need to invoke this under GDB sometimes? + const char *UpperExec = Args.MakeArgString(getToolChain().GetProgramPath("flang1")); + + UpperCmdArgs.push_back("-opt"); UpperCmdArgs.push_back(Args.MakeArgString(OptOStr)); + UpperCmdArgs.push_back("-terse"); UpperCmdArgs.push_back("1"); + UpperCmdArgs.push_back("-inform"); UpperCmdArgs.push_back("warn"); + UpperCmdArgs.push_back("-nohpf"); + UpperCmdArgs.push_back("-nostatic"); + UpperCmdArgs.append(CommonCmdArgs.begin(), CommonCmdArgs.end()); // Append common arguments + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("19"); UpperCmdArgs.push_back("0x400000"); + UpperCmdArgs.push_back("-quad"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("59"); UpperCmdArgs.push_back("4"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("15"); UpperCmdArgs.push_back("2"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("49"); UpperCmdArgs.push_back("0x400004"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("51"); UpperCmdArgs.push_back("0x20"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("57"); UpperCmdArgs.push_back("0x4c"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("58"); UpperCmdArgs.push_back("0x10000"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("124"); UpperCmdArgs.push_back("0x1000"); + UpperCmdArgs.push_back("-tp"); UpperCmdArgs.push_back("px"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("57"); UpperCmdArgs.push_back("0xfb0000"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("58"); UpperCmdArgs.push_back("0x78031040"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("47"); UpperCmdArgs.push_back("0x08"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("48"); UpperCmdArgs.push_back("4608"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("49"); UpperCmdArgs.push_back("0x100"); + if (OptLevel >= 2) { + UpperCmdArgs.push_back("-x"); + UpperCmdArgs.push_back("70"); + UpperCmdArgs.push_back("0x6c00"); + UpperCmdArgs.push_back("-x"); + UpperCmdArgs.push_back("119"); + UpperCmdArgs.push_back("0x10000000"); + UpperCmdArgs.push_back("-x"); + UpperCmdArgs.push_back("129"); + UpperCmdArgs.push_back("2"); + UpperCmdArgs.push_back("-x"); + UpperCmdArgs.push_back("47"); + UpperCmdArgs.push_back("0x400000"); + UpperCmdArgs.push_back("-x"); + UpperCmdArgs.push_back("52"); + UpperCmdArgs.push_back("2"); + } + + // Add system include arguments. + getToolChain().AddFlangSystemIncludeArgs(Args, UpperCmdArgs); + + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("unix"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__unix"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__unix__"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("linux"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__linux"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__linux__"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__NO_MATH_INLINES"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__LP64__"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__x86_64"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__x86_64__"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__LONG_MAX__=9223372036854775807L"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__SIZE_TYPE__=unsigned long int"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__PTRDIFF_TYPE__=long int"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__THROW="); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__extension__="); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__amd_64__amd64__"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__k8"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__k8__"); + UpperCmdArgs.push_back("-def"); UpperCmdArgs.push_back("__PGLLVM__"); + + // Enable preprocessor + if (Args.hasArg(options::OPT_Mpreprocess) || + Args.hasArg(options::OPT_cpp) || + types::getPreprocessedType(InputType) != types::TY_INVALID) { + UpperCmdArgs.push_back("-preprocess"); + for (auto Arg : Args.filtered(options::OPT_Mpreprocess, options::OPT_cpp)) { + Arg->claim(); + } + } + + // Enable standards checking + if (Args.hasArg(options::OPT_Mstandard)) { + UpperCmdArgs.push_back("-standard"); + for (auto Arg : Args.filtered(options::OPT_Mstandard)) { + Arg->claim(); + } + } + + // Free or fixed form file + if (Args.hasArg(options::OPT_fortran_format_Group)) { + // Override file name suffix, scan arguments for that + for (Arg *A : Args.filtered(options::OPT_fortran_format_Group)) { + A->claim(); + switch (A->getOption().getID()) { + default: + llvm_unreachable("missed a case"); + case options::OPT_fixed_form_on: + case options::OPT_free_form_off: + case options::OPT_Mfixed: + case options::OPT_Mfree_off: + case options::OPT_Mfreeform_off: + UpperCmdArgs.push_back("-nofreeform"); + break; + case options::OPT_free_form_on: + case options::OPT_fixed_form_off: + case options::OPT_Mfree_on: + case options::OPT_Mfreeform_on: + UpperCmdArgs.push_back("-freeform"); + break; + } + } + } else { + // Deduce format from file name suffix + if (types::isFreeFormFortran(InputType)) { + UpperCmdArgs.push_back("-freeform"); + } else { + UpperCmdArgs.push_back("-nofreeform"); + } + } + + // Extend lines to 132 characters + for (auto Arg : Args.filtered(options::OPT_Mextend)) { + Arg->claim(); + UpperCmdArgs.push_back("-extend"); + } + + for (auto Arg : Args.filtered(options::OPT_ffixed_line_length_VALUE)) { + StringRef Value = Arg->getValue(); + if (Value == "72") { + Arg->claim(); + } else if (Value == "132") { + Arg->claim(); + UpperCmdArgs.push_back("-extend"); + } else { + getToolChain().getDriver().Diag(diag::err_drv_unsupported_fixed_line_length) + << Arg->getAsString(Args); + } + } + + // Add user-defined include directories + for (auto Arg : Args.filtered(options::OPT_I)) { + Arg->claim(); + UpperCmdArgs.push_back("-idir"); + UpperCmdArgs.push_back(Arg->getValue(0)); + } + + // Add user-defined module directories + for (auto Arg : Args.filtered(options::OPT_ModuleDir, options::OPT_J)) { + Arg->claim(); + UpperCmdArgs.push_back("-moddir"); + UpperCmdArgs.push_back(Arg->getValue(0)); + } + + // "Define" preprocessor flags + for (auto Arg : Args.filtered(options::OPT_D)) { + Arg->claim(); + UpperCmdArgs.push_back("-def"); + UpperCmdArgs.push_back(Arg->getValue(0)); + } + + // "Define" preprocessor flags + for (auto Arg : Args.filtered(options::OPT_U)) { + Arg->claim(); + UpperCmdArgs.push_back("-undef"); + UpperCmdArgs.push_back(Arg->getValue(0)); + } + + UpperCmdArgs.push_back("-vect"); UpperCmdArgs.push_back("48"); + + // Semantics for assignments to allocatables + if (Arg *A = Args.getLastArg(options::OPT_Mallocatable_EQ)) { + // Argument is passed explicitly + StringRef Value = A->getValue(); + if (Value == "03") { // Enable Fortran 2003 semantics + UpperCmdArgs.push_back("-x"); // Set XBIT + } else if (Value == "95") { // Enable Fortran 2003 semantics + UpperCmdArgs.push_back("-y"); // Unset XBIT + } else { + getToolChain().getDriver().Diag(diag::err_drv_invalid_allocatable_mode) + << A->getAsString(Args); + } + } else { // No argument passed + UpperCmdArgs.push_back("-y"); // Default is 1995 + } + UpperCmdArgs.push_back("54"); UpperCmdArgs.push_back("1"); // XBIT value + + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("70"); UpperCmdArgs.push_back("0x40000000"); + UpperCmdArgs.push_back("-y"); UpperCmdArgs.push_back("163"); UpperCmdArgs.push_back("0xc0000000"); + UpperCmdArgs.push_back("-x"); UpperCmdArgs.push_back("189"); UpperCmdArgs.push_back("0x10"); + + // Enable NULL pointer checking + if (Args.hasArg(options::OPT_Mchkptr)) { + UpperCmdArgs.push_back("-x"); + UpperCmdArgs.push_back("70"); + UpperCmdArgs.push_back("4"); + for (auto Arg : Args.filtered(options::OPT_Mchkptr)) { + Arg->claim(); + } + } + + const char * STBFile = Args.MakeArgString(Stem + ".stb"); + C.addTempFile(STBFile); + UpperCmdArgs.push_back("-stbfile"); + UpperCmdArgs.push_back(STBFile); + + const char * ModuleExportFile = Args.MakeArgString(Stem + ".cmod"); + C.addTempFile(ModuleExportFile); + UpperCmdArgs.push_back("-modexport"); + UpperCmdArgs.push_back(ModuleExportFile); + + const char * ModuleIndexFile = Args.MakeArgString(Stem + ".cmdx"); + C.addTempFile(ModuleIndexFile); + UpperCmdArgs.push_back("-modindex"); + UpperCmdArgs.push_back(ModuleIndexFile); + + UpperCmdArgs.push_back("-output"); + UpperCmdArgs.push_back(ILMFile); + + C.addCommand(llvm::make_unique(JA, *this, UpperExec, UpperCmdArgs, Inputs)); + + // For -fsyntax-only that is it + if (Args.hasArg(options::OPT_fsyntax_only)) return; + + /***** Lower part of Fortran frontend *****/ + + const char *LowerExec = Args.MakeArgString(getToolChain().GetProgramPath("flang2")); + + // TODO FLANG arg handling + LowerCmdArgs.push_back("-fn"); LowerCmdArgs.push_back(Input.getBaseInput()); + LowerCmdArgs.push_back("-opt"); LowerCmdArgs.push_back(Args.MakeArgString(OptOStr)); + LowerCmdArgs.push_back("-terse"); LowerCmdArgs.push_back("1"); + LowerCmdArgs.push_back("-inform"); LowerCmdArgs.push_back("warn"); + LowerCmdArgs.append(CommonCmdArgs.begin(), CommonCmdArgs.end()); // Append common arguments + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("51"); LowerCmdArgs.push_back("0x20"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("119"); LowerCmdArgs.push_back("0xa10000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("122"); LowerCmdArgs.push_back("0x40"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("123"); LowerCmdArgs.push_back("0x1000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("127"); LowerCmdArgs.push_back("4"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("127"); LowerCmdArgs.push_back("17"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("19"); LowerCmdArgs.push_back("0x400000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("28"); LowerCmdArgs.push_back("0x40000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("120"); LowerCmdArgs.push_back("0x10000000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("70"); LowerCmdArgs.push_back("0x8000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("122"); LowerCmdArgs.push_back("1"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("125"); LowerCmdArgs.push_back("0x20000"); + LowerCmdArgs.push_back("-quad"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("59"); LowerCmdArgs.push_back("4"); + LowerCmdArgs.push_back("-tp"); LowerCmdArgs.push_back("px"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("120"); LowerCmdArgs.push_back("0x1000"); // debug lite + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("124"); LowerCmdArgs.push_back("0x1400"); + LowerCmdArgs.push_back("-y"); LowerCmdArgs.push_back("15"); LowerCmdArgs.push_back("2"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("57"); LowerCmdArgs.push_back("0x3b0000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("58"); LowerCmdArgs.push_back("0x48000000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("49"); LowerCmdArgs.push_back("0x100"); + LowerCmdArgs.push_back("-astype"); LowerCmdArgs.push_back("0"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("183"); LowerCmdArgs.push_back("4"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("121"); LowerCmdArgs.push_back("0x800"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("54"); LowerCmdArgs.push_back("0x10"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("70"); LowerCmdArgs.push_back("0x40000000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("249"); LowerCmdArgs.push_back("50"); // LLVM version + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("124"); LowerCmdArgs.push_back("1"); + LowerCmdArgs.push_back("-y"); LowerCmdArgs.push_back("163"); LowerCmdArgs.push_back("0xc0000000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("189"); LowerCmdArgs.push_back("0x10"); + LowerCmdArgs.push_back("-y"); LowerCmdArgs.push_back("189"); LowerCmdArgs.push_back("0x4000000"); + + // Remove "noinline" attriblute + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("183"); LowerCmdArgs.push_back("0x10"); + + // Set a -x flag for second part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_Mx_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + auto XFlag = Value.split(","); + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back(Args.MakeArgString(XFlag.first)); + LowerCmdArgs.push_back(Args.MakeArgString(XFlag.second)); + } + + // Set a -y flag for second part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_My_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + auto XFlag = Value.split(","); + LowerCmdArgs.push_back("-y"); + LowerCmdArgs.push_back(Args.MakeArgString(XFlag.first)); + LowerCmdArgs.push_back(Args.MakeArgString(XFlag.second)); + } + + // Set a -q (debug) flag for second part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_Mq_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + auto XFlag = Value.split(","); + LowerCmdArgs.push_back("-q"); + LowerCmdArgs.push_back(Args.MakeArgString(XFlag.first)); + LowerCmdArgs.push_back(Args.MakeArgString(XFlag.second)); + } + + // Set a -qq (debug) flag for second part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_Mqq_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + auto XFlag = Value.split(","); + LowerCmdArgs.push_back("-qq"); + LowerCmdArgs.push_back(Args.MakeArgString(XFlag.first)); + LowerCmdArgs.push_back(Args.MakeArgString(XFlag.second)); + } + + // Pass an arbitrary flag for second part of Fortran frontend + for (Arg *A : Args.filtered(options::OPT_Wm_EQ)) { + A->claim(); + StringRef Value = A->getValue(); + SmallVector PassArgs; + Value.split(PassArgs, StringRef(",")); + for (StringRef PassArg : PassArgs) { + LowerCmdArgs.push_back(Args.MakeArgString(PassArg)); + } + } + + LowerCmdArgs.push_back("-stbfile"); + LowerCmdArgs.push_back(STBFile); + + LowerCmdArgs.push_back("-asm"); LowerCmdArgs.push_back(Args.MakeArgString(OutFile)); + + C.addCommand(llvm::make_unique(JA, *this, LowerExec, LowerCmdArgs, Inputs)); +} + diff --git a/lib/Driver/ToolChains/Flang.h b/lib/Driver/ToolChains/Flang.h new file mode 100644 index 000000000000..2c3eb7c895a0 --- /dev/null +++ b/lib/Driver/ToolChains/Flang.h @@ -0,0 +1,50 @@ +//===--- Flang.h - Flang Tool and ToolChain Implementations ====-*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Flang_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Flang_H + +#include "MSVC.h" +#include "clang/Basic/DebugInfoOptions.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/Types.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace driver { + +namespace tools { + +/// \brief Flang Fortran frontend +class LLVM_LIBRARY_VISIBILITY FlangFrontend : public Tool { +public: + FlangFrontend(const ToolChain &TC) + : Tool("flang:frontend", + "Fortran frontend to LLVM", TC, + RF_Full) {} + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedAssembler() const override { return false; } + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace tools + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index 7845781f12c4..b391ba27ffa9 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -465,6 +465,16 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); + // Add Fortran runtime libraries + if (needFortranLibs(D, Args)) { + ToolChain.AddFortranStdlibLibArgs(Args, CmdArgs); + } else { + // Claim "no Flang libraries" arguments if any + for (auto Arg : Args.filtered(options::OPT_noFlangLibs)) { + Arg->claim(); + } + } + if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) { diff --git a/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp index 1301cdf114ae..504c29502ac1 100644 --- a/lib/Driver/ToolChains/Linux.cpp +++ b/lib/Driver/ToolChains/Linux.cpp @@ -543,6 +543,194 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { return "/" + LibDir + "/" + Loader; } +/// Convert path list to Fortran frontend argument +static void AddFlangSysIncludeArg(const ArgList &DriverArgs, + ArgStringList &Flang1Args, + ToolChain::path_list IncludePathList) { + std::string ArgValue; // Path argument value + + // Make up argument value consisting of paths separated by colons + bool first = true; + for (auto P : IncludePathList) { + if (first) { + first = false; + } else { + ArgValue += ":"; + } + ArgValue += P; + } + + // Add the argument + Flang1Args.push_back("-stdinc"); + Flang1Args.push_back(DriverArgs.MakeArgString(ArgValue)); +} + +void Linux::AddFlangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &Flang1Args) const { + path_list IncludePathList; + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + { + SmallString<128> P(D.InstalledDir); + llvm::sys::path::append(P, "../include"); + IncludePathList.push_back(P.str()); + } + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) + IncludePathList.push_back(SysRoot + "/usr/local/include"); + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + IncludePathList.push_back(P.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) { + AddFlangSysIncludeArg(DriverArgs, Flang1Args, IncludePathList); + return; + } + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : ""; + IncludePathList.push_back(Prefix.str() + dir.str()); + } + AddFlangSysIncludeArg(DriverArgs, Flang1Args, IncludePathList); + return; + } + + // Lacking those, try to detect the correct set of system includes for the + // target triple. + + // Add include directories specific to the selected multilib set and multilib. + if (GCCInstallation.isValid()) { + const auto &Callback = Multilibs.includeDirsCallback(); + if (Callback) { + for (const auto &Path : Callback(GCCInstallation.getMultilib())) + addExternCSystemIncludeIfExists( + DriverArgs, Flang1Args, GCCInstallation.getInstallPath() + Path); + } + } + + // Implement generic Debian multiarch support. + const StringRef X86_64MultiarchIncludeDirs[] = { + "/usr/include/x86_64-linux-gnu", + + // FIXME: These are older forms of multiarch. It's not clear that they're + // in use in any released version of Debian, so we should consider + // removing them. + "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64"}; + const StringRef X86MultiarchIncludeDirs[] = { + "/usr/include/i386-linux-gnu", + + // FIXME: These are older forms of multiarch. It's not clear that they're + // in use in any released version of Debian, so we should consider + // removing them. + "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu", + "/usr/include/i486-linux-gnu"}; + const StringRef AArch64MultiarchIncludeDirs[] = { + "/usr/include/aarch64-linux-gnu"}; + const StringRef ARMMultiarchIncludeDirs[] = { + "/usr/include/arm-linux-gnueabi"}; + const StringRef ARMHFMultiarchIncludeDirs[] = { + "/usr/include/arm-linux-gnueabihf"}; + const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"}; + const StringRef MIPSELMultiarchIncludeDirs[] = { + "/usr/include/mipsel-linux-gnu"}; + const StringRef MIPS64MultiarchIncludeDirs[] = { + "/usr/include/mips64-linux-gnu", "/usr/include/mips64-linux-gnuabi64"}; + const StringRef MIPS64ELMultiarchIncludeDirs[] = { + "/usr/include/mips64el-linux-gnu", + "/usr/include/mips64el-linux-gnuabi64"}; + const StringRef PPCMultiarchIncludeDirs[] = { + "/usr/include/powerpc-linux-gnu"}; + const StringRef PPC64MultiarchIncludeDirs[] = { + "/usr/include/powerpc64-linux-gnu"}; + const StringRef PPC64LEMultiarchIncludeDirs[] = { + "/usr/include/powerpc64le-linux-gnu"}; + const StringRef SparcMultiarchIncludeDirs[] = { + "/usr/include/sparc-linux-gnu"}; + const StringRef Sparc64MultiarchIncludeDirs[] = { + "/usr/include/sparc64-linux-gnu"}; + ArrayRef MultiarchIncludeDirs; + switch (getTriple().getArch()) { + case llvm::Triple::x86_64: + MultiarchIncludeDirs = X86_64MultiarchIncludeDirs; + break; + case llvm::Triple::x86: + MultiarchIncludeDirs = X86MultiarchIncludeDirs; + break; + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + MultiarchIncludeDirs = AArch64MultiarchIncludeDirs; + break; + case llvm::Triple::arm: + if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) + MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs; + else + MultiarchIncludeDirs = ARMMultiarchIncludeDirs; + break; + case llvm::Triple::mips: + MultiarchIncludeDirs = MIPSMultiarchIncludeDirs; + break; + case llvm::Triple::mipsel: + MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs; + break; + case llvm::Triple::mips64: + MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs; + break; + case llvm::Triple::mips64el: + MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs; + break; + case llvm::Triple::ppc: + MultiarchIncludeDirs = PPCMultiarchIncludeDirs; + break; + case llvm::Triple::ppc64: + MultiarchIncludeDirs = PPC64MultiarchIncludeDirs; + break; + case llvm::Triple::ppc64le: + MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs; + break; + case llvm::Triple::sparc: + MultiarchIncludeDirs = SparcMultiarchIncludeDirs; + break; + case llvm::Triple::sparcv9: + MultiarchIncludeDirs = Sparc64MultiarchIncludeDirs; + break; + default: + break; + } + for (StringRef Dir : MultiarchIncludeDirs) { + if (llvm::sys::fs::exists(SysRoot + Dir)) { + IncludePathList.push_back(SysRoot + Dir.str()); + break; + } + } + + if (getTriple().getOS() == llvm::Triple::RTEMS) { + AddFlangSysIncludeArg(DriverArgs, Flang1Args, IncludePathList); + return; + } + + // Add an include of '/include' directly. This isn't provided by default by + // system GCCs, but is often used with cross-compiling GCCs, and harmless to + // add even when Clang is acting as-if it were a system compiler. + IncludePathList.push_back(SysRoot + "/include"); + + IncludePathList.push_back(SysRoot + "/usr/include"); + + AddFlangSysIncludeArg(DriverArgs, Flang1Args, IncludePathList); +} + void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); diff --git a/lib/Driver/ToolChains/Linux.h b/lib/Driver/ToolChains/Linux.h index 9778c1832ccc..34e41752d934 100644 --- a/lib/Driver/ToolChains/Linux.h +++ b/lib/Driver/ToolChains/Linux.h @@ -27,6 +27,9 @@ class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void + AddFlangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &Flang1Args) const override; std::string findLibCxxIncludePath() const override; void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp old mode 100644 new mode 100755 index ab63f0e81b12..526db0fabef5 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -99,6 +99,8 @@ bool types::isAcceptedByClang(ID Id) { case TY_Asm: case TY_C: case TY_PP_C: + case TY_F_FreeForm: case TY_PP_F_FreeForm: + case TY_F_FixedForm: case TY_PP_F_FixedForm: case TY_CL: case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: @@ -117,6 +119,33 @@ bool types::isAcceptedByClang(ID Id) { } } +bool types::isFortran(ID Id) { + switch (Id) { + default: + return false; + + case TY_F_FreeForm: + case TY_PP_F_FreeForm: + case TY_F_FixedForm: + case TY_PP_F_FixedForm: + return true; + } +} + +bool types::isFreeFormFortran(ID Id) { + if (!isFortran(Id)) + return false; + + return (Id == TY_F_FreeForm || Id == TY_PP_F_FreeForm); +} + +bool types::isFixedFormFortran(ID Id) { + if (!isFortran(Id)) + return false; + + return (Id == TY_F_FixedForm || Id == TY_PP_F_FixedForm); +} + bool types::isObjC(ID Id) { switch (Id) { default: @@ -178,8 +207,8 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { return llvm::StringSwitch(Ext) .Case("c", TY_C) .Case("C", TY_CXX) - .Case("F", TY_Fortran) - .Case("f", TY_PP_Fortran) + .Case("F", TY_F_FixedForm) + .Case("f", TY_PP_F_FixedForm) .Case("h", TY_CHeader) .Case("H", TY_CXXHeader) .Case("i", TY_PP_C) @@ -212,18 +241,22 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { .Case("cui", TY_PP_CUDA) .Case("cxx", TY_CXX) .Case("CXX", TY_CXX) - .Case("F90", TY_Fortran) - .Case("f90", TY_PP_Fortran) - .Case("F95", TY_Fortran) - .Case("f95", TY_PP_Fortran) - .Case("for", TY_PP_Fortran) - .Case("FOR", TY_PP_Fortran) - .Case("fpp", TY_Fortran) - .Case("FPP", TY_Fortran) .Case("gch", TY_PCH) .Case("hpp", TY_CXXHeader) .Case("iim", TY_PP_CXXModule) .Case("lib", TY_Object) + .Case("for", TY_PP_F_FixedForm) + .Case("FOR", TY_PP_F_FixedForm) + .Case("fpp", TY_F_FixedForm) + .Case("FPP", TY_F_FixedForm) + .Case("f90", TY_PP_F_FreeForm) + .Case("f95", TY_PP_F_FreeForm) + .Case("f03", TY_PP_F_FreeForm) + .Case("f08", TY_PP_F_FreeForm) + .Case("F90", TY_F_FreeForm) + .Case("F95", TY_F_FreeForm) + .Case("F03", TY_F_FreeForm) + .Case("F08", TY_F_FreeForm) .Case("mii", TY_PP_ObjCXX) .Case("obj", TY_Object) .Case("pch", TY_PCH) @@ -248,7 +281,9 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) { // FIXME: Why don't we just put this list in the defs file, eh. void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl &P) { if (Id != TY_Object) { - if (getPreprocessedType(Id) != TY_INVALID) { + // Delegate preprocessing to the "upper" part of Fortran compiler, + // preprocess for other preprocessable inputs + if (getPreprocessedType(Id) != TY_INVALID && !isFortran(Id)) { P.push_back(phases::Preprocess); } @@ -258,6 +293,9 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl &P) { if (!onlyPrecompileType(Id)) { if (!onlyAssembleType(Id)) { + if (isFortran(Id)) { + P.push_back(phases::FortranFrontend); + } P.push_back(phases::Compile); P.push_back(phases::Backend); } diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 22a498422aef..fd9d5b78b473 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -60,7 +60,7 @@ endif() add_dependencies(clang clang-headers) if(NOT CLANG_LINKS_TO_CREATE) - set(CLANG_LINKS_TO_CREATE clang++ clang-cl clang-cpp) + set(CLANG_LINKS_TO_CREATE clang++ clang-cl clang-cpp flang) if (MSVC) list(APPEND CLANG_LINKS_TO_CREATE ../msbuild-bin/cl) From ea5b8bc0b7e7cb49386fb47de342c235f0836814 Mon Sep 17 00:00:00 2001 From: Varun Jayathirtha Date: Wed, 14 Mar 2018 11:05:35 -0700 Subject: [PATCH 07/10] Enable new name generation for math intrinsic calls --- lib/Driver/ToolChains/Flang.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Driver/ToolChains/Flang.cpp b/lib/Driver/ToolChains/Flang.cpp index eb619a860e93..184c3afd81e0 100644 --- a/lib/Driver/ToolChains/Flang.cpp +++ b/lib/Driver/ToolChains/Flang.cpp @@ -767,6 +767,7 @@ void FlangFrontend::ConstructJob(Compilation &C, const JobAction &JA, LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("70"); LowerCmdArgs.push_back("0x8000"); LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("122"); LowerCmdArgs.push_back("1"); LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("125"); LowerCmdArgs.push_back("0x20000"); + LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("164"); LowerCmdArgs.push_back("0x800000"); LowerCmdArgs.push_back("-quad"); LowerCmdArgs.push_back("-x"); LowerCmdArgs.push_back("59"); LowerCmdArgs.push_back("4"); LowerCmdArgs.push_back("-tp"); LowerCmdArgs.push_back("px"); From 531cfd467ead2c0275371a1f77fb51c2adb6d7fe Mon Sep 17 00:00:00 2001 From: Varun Jayathirtha Date: Thu, 15 Mar 2018 11:11:23 -0700 Subject: [PATCH 08/10] 1. Undo default IEEE setting. 2. Fix the command line option interpretation to choose the last one among the conflicting flags to be the final effect. The conflicting flags being i. -ffast-math / -Ofast ii. -fno-fast-math iii. -Kieee iv. -Knoieee v. -frelaxed-math 3. Fix "-Ofast" to have the effects of "-ffast-math" along with "-O2" --- include/clang/Driver/Options.td | 2 + lib/Driver/ToolChains/Flang.cpp | 138 ++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 62 deletions(-) diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 1f1792099d24..3348342883ac 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -2916,6 +2916,8 @@ def no_fortran_main: Flag<["-"], "fno-fortran-main">, Group, HelpText<"Don't link in Fortran main">; def Mnomain: Flag<["-"], "Mnomain">, Group, HelpText<"Don't link in Fortran main">; +def frelaxed_math : Flag<["-"], "frelaxed-math">, Group, + HelpText<"Use relaxed Math intrinsic functions">; // Flang internal debug options def Mx_EQ : Joined<["-"], "Mx,">, Group; diff --git a/lib/Driver/ToolChains/Flang.cpp b/lib/Driver/ToolChains/Flang.cpp index 184c3afd81e0..1025c6910ff1 100644 --- a/lib/Driver/ToolChains/Flang.cpp +++ b/lib/Driver/ToolChains/Flang.cpp @@ -46,7 +46,9 @@ void FlangFrontend::ConstructJob(Compilation &C, const JobAction &JA, ArgStringList LowerCmdArgs; SmallString<256> Stem; std::string OutFile; - bool NeedIEEE = true; + bool NeedIEEE = false; + bool NeedFastMath = false; + bool NeedRelaxedMath = false; // Check number of inputs for sanity. We need at least one input. assert(Inputs.size() >= 1 && "Must have at least one input."); @@ -76,55 +78,7 @@ void FlangFrontend::ConstructJob(Compilation &C, const JobAction &JA, /***** Process common args *****/ - // Override IEEE mode if needed - if (Args.hasArg(options::OPT_Ofast) || - Args.hasArg(options::OPT_ffast_math) || - Args.hasArg(options::OPT_fno_fast_math) || - Args.hasArg(options::OPT_Kieee_on) || - Args.hasArg(options::OPT_Kieee_off)) { - auto A = Args.getLastArg(options::OPT_Ofast, - options::OPT_ffast_math, - options::OPT_fno_fast_math, - options::OPT_Kieee_on, - options::OPT_Kieee_off); - auto Opt = A->getOption(); - if (Opt.matches(options::OPT_Ofast) || - Opt.matches(options::OPT_ffast_math) || - Opt.matches(options::OPT_Kieee_off)) { - NeedIEEE = false; - } - } - - // -Kieee is on by default - if (!Args.hasArg(options::OPT_Kieee_off)) { - CommonCmdArgs.push_back("-y"); // Common: -y 129 2 - CommonCmdArgs.push_back("129"); - CommonCmdArgs.push_back("2"); - // Lower: -x 6 0x100 - LowerCmdArgs.push_back("-x"); - LowerCmdArgs.push_back("6"); - LowerCmdArgs.push_back("0x100"); - // -x 42 0x400000 - LowerCmdArgs.push_back("-x"); - LowerCmdArgs.push_back("42"); - LowerCmdArgs.push_back("0x400000"); - // -y 129 4 - LowerCmdArgs.push_back("-y"); - LowerCmdArgs.push_back("129"); - LowerCmdArgs.push_back("4"); - // -x 129 0x400 - LowerCmdArgs.push_back("-x"); - LowerCmdArgs.push_back("129"); - LowerCmdArgs.push_back("0x400"); - for (auto Arg : Args.filtered(options::OPT_Kieee_on)) { - Arg->claim(); - } - } else { - for (auto Arg : Args.filtered(options::OPT_Kieee_off)) { - Arg->claim(); - } - } - + // Add "inform level" flag if (Args.hasArg(options::OPT_Minform_EQ)) { // Parse arguments to set its value @@ -506,22 +460,82 @@ void FlangFrontend::ConstructJob(Compilation &C, const JobAction &JA, // pass -g to lower LowerCmdArgs.push_back("-debug"); } - - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math)) { - if (A->getOption().matches(options::OPT_ffast_math)) { - LowerCmdArgs.push_back("-x"); - } else { - LowerCmdArgs.push_back("-y"); + + /* Pick the last among conflicting flags, if a positive and negative flag + exists for ex. "-ffast-math -fno-fast-math" they get nullified. Also any + previously overwritten flag remains that way. + For ex. "-Kieee -ffast-math -fno-fast-math". -Kieee gets overwritten by + -ffast-math which then gets negated by -fno-fast-math, finally behaving as + if none of those flags were passed. + */ + for(Arg *A: Args.filtered(options::OPT_ffast_math, options::OPT_fno_fast_math, + options::OPT_Ofast, options::OPT_Kieee_off, + options::OPT_Kieee_on, options::OPT_frelaxed_math)) { + if (A->getOption().matches(options::OPT_ffast_math) || + A->getOption().matches(options::OPT_Ofast)) { + NeedIEEE = NeedRelaxedMath = false; + NeedFastMath = true; + } else if (A->getOption().matches(options::OPT_Kieee_on)) { + NeedFastMath = NeedRelaxedMath = false; + NeedIEEE = true; + } else if (A->getOption().matches(options::OPT_frelaxed_math)) { + NeedFastMath = NeedIEEE = false; + NeedRelaxedMath = true; + } else if (A->getOption().matches(options::OPT_fno_fast_math)) { + NeedFastMath = false; + } else if (A->getOption().matches(options::OPT_Kieee_off)) { + NeedIEEE = false; } - LowerCmdArgs.push_back("216"); - LowerCmdArgs.push_back("1"); + A->claim(); } - // IEEE compatibility mode - LowerCmdArgs.push_back("-ieee"); - if (NeedIEEE) { + if (NeedFastMath) { + // Lower: -x 216 1 + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("216"); LowerCmdArgs.push_back("1"); - } else { + // Lower: -ieee 0 + LowerCmdArgs.push_back("-ieee"); + LowerCmdArgs.push_back("0"); + } else if (NeedIEEE) { + // Common: -y 129 2 + CommonCmdArgs.push_back("-y"); + CommonCmdArgs.push_back("129"); + CommonCmdArgs.push_back("2"); + // Lower: -x 6 0x100 + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("6"); + LowerCmdArgs.push_back("0x100"); + // Lower: -x 42 0x400000 + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("42"); + LowerCmdArgs.push_back("0x400000"); + // Lower: -y 129 4 + LowerCmdArgs.push_back("-y"); + LowerCmdArgs.push_back("129"); + LowerCmdArgs.push_back("4"); + // Lower: -x 129 0x400 + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("129"); + LowerCmdArgs.push_back("0x400"); + // Lower: -y 216 1 (OPT_fno_fast_math) + LowerCmdArgs.push_back("-y"); + LowerCmdArgs.push_back("216"); + LowerCmdArgs.push_back("1"); + // Lower: -ieee 1 + LowerCmdArgs.push_back("-ieee"); + LowerCmdArgs.push_back("1"); + } else if (NeedRelaxedMath) { + // Lower: -x 15 0x400 + LowerCmdArgs.push_back("-x"); + LowerCmdArgs.push_back("15"); + LowerCmdArgs.push_back("0x400"); + // Lower: -y 216 1 (OPT_fno_fast_math) + LowerCmdArgs.push_back("-y"); + LowerCmdArgs.push_back("216"); + LowerCmdArgs.push_back("1"); + // Lower: -ieee 0 + LowerCmdArgs.push_back("-ieee"); LowerCmdArgs.push_back("0"); } From 81f6de416de1ab0399cfd44ed7e25effd42a3168 Mon Sep 17 00:00:00 2001 From: Varun Jayathirtha Date: Mon, 26 Mar 2018 11:30:29 -0700 Subject: [PATCH 09/10] Link libpgmath library --- lib/Driver/ToolChain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index eab990e236ae..c2daa5bbb10f 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -785,6 +785,7 @@ void ToolChain::AddFortranStdlibLibArgs(const ArgList &Args, } CmdArgs.push_back("-lflang"); CmdArgs.push_back("-lflangrti"); + CmdArgs.push_back("-lpgmath"); if( useOpenMP ) { CmdArgs.push_back("-lomp"); } From 9e0bc9215b14d7113192aca7e9359d01023bc8c7 Mon Sep 17 00:00:00 2001 From: Varun Jayathirtha Date: Wed, 4 Apr 2018 13:17:02 -0700 Subject: [PATCH 10/10] Fix bug in ieee flag generation --- lib/Driver/ToolChains/Flang.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Driver/ToolChains/Flang.cpp b/lib/Driver/ToolChains/Flang.cpp index 1025c6910ff1..504365041eaa 100644 --- a/lib/Driver/ToolChains/Flang.cpp +++ b/lib/Driver/ToolChains/Flang.cpp @@ -537,6 +537,10 @@ void FlangFrontend::ConstructJob(Compilation &C, const JobAction &JA, // Lower: -ieee 0 LowerCmdArgs.push_back("-ieee"); LowerCmdArgs.push_back("0"); + } else { + // Lower: -ieee 0 + LowerCmdArgs.push_back("-ieee"); + LowerCmdArgs.push_back("0"); } /***** Upper part of the Fortran frontend *****/