Skip to content

[RISCV][clang] Don't enable -mrelax-all for -O0 on RISC-V #88538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 22, 2024

Conversation

topperc
Copy link
Collaborator

@topperc topperc commented Apr 12, 2024

-O0 implies -mrelax-all as an assembler compile time optimization. -mrelax-all allows the assembler to complete layout in 2 passes instead of doing iterative branch relaxation.

Jump offsets larger than +/-1MiB require an indirect jump on RISC-V. This can't be done by the assembler, so we use a branch relaxation MIR pass and use register scavenging to find a free register.

The conditional branch offsets for RISC-V are also somewhat small so we support MC layer branch relaxation to make life easier for assembly programmers. This may also cover up bugs in our function size estimation in MachineIR.

Enabling -mrelax-all causes the MC layer relaxation to agressively relax branches. This increases code size and can create cases where we need an indirect jump, but we can't create one. This leads to linker failures.

The easiest way to avoid this is to not default to -mrelax-all for -O0 and sacrifice the compile time optimization. That's what this patch does.

Fixes #87127

-O0 implies -mrelax-all as an assembler compile time optimization.
-mrelax-all allows the assembler to complete layout in 2 passes
instead of doing iterative branch relaxation.

Jump offsets larger than +/-1MiB require an indirect jump on RISC-V.
This can't be done by the assembler, so we use a branch relaxation
MIR pass and use register scavenging to find a free register.

The conditional branch offsets for RISC-V are also somewhat small
so we support MC layer branch relaxation to make life easier for
assembly programmers. This may also cover up bugs in our function
size estimation in MachineIR.

Enabling -mrelax-all causes the MC layer relaxation to agressively
relax branches. This increases code size and can create cases where
we need an indirect jump, but we can't create one. This leads to
linker failures.

The easiest way to avoid this is to not default to -mrelax-all for
-O0 and sacrifice the compile time optimization. That's what this
patch does.

Fixes llvm#87127
@topperc topperc requested review from asb, MaskRay, jrtc27 and preames April 12, 2024 17:21
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' labels Apr 12, 2024
@llvmbot
Copy link
Member

llvmbot commented Apr 12, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-driver

Author: Craig Topper (topperc)

Changes

-O0 implies -mrelax-all as an assembler compile time optimization. -mrelax-all allows the assembler to complete layout in 2 passes instead of doing iterative branch relaxation.

Jump offsets larger than +/-1MiB require an indirect jump on RISC-V. This can't be done by the assembler, so we use a branch relaxation MIR pass and use register scavenging to find a free register.

The conditional branch offsets for RISC-V are also somewhat small so we support MC layer branch relaxation to make life easier for assembly programmers. This may also cover up bugs in our function size estimation in MachineIR.

Enabling -mrelax-all causes the MC layer relaxation to agressively relax branches. This increases code size and can create cases where we need an indirect jump, but we can't create one. This leads to linker failures.

The easiest way to avoid this is to not default to -mrelax-all for -O0 and sacrifice the compile time optimization. That's what this patch does.

Fixes #87127


Full diff: https://github.com/llvm/llvm-project/pull/88538.diff

2 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+10)
  • (modified) clang/test/Driver/integrated-as.c (+1-1)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 766a9b91e3c0ad..856a88bdc3aad4 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -844,6 +844,16 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
   if (Arg *A = Args.getLastArg(options::OPT_O_Group))
     RelaxDefault = A->getOption().matches(options::OPT_O0);
 
+  // RISC-V requires an indirect jump for offsets larger than 1MiB. This cannot
+  // be done by assembler branch relaxation as it needs a free temporary
+  // register. Because of this, branch relaxation is handled by a MachineIR
+  // pass before the assembler. Forcing assembler branch relaxation for -O0
+  // makes the MachineIR branch relaxation inaccurate and it will miss cases
+  // where an indirect branch is necessary. To avoid this issue we are
+  // sacrificing the compile time improvement of using -mrelax-all for -O0.
+  if (C.getDefaultToolChain().getTriple().isRISCV())
+    RelaxDefault = false;
+
   if (RelaxDefault) {
     RelaxDefault = false;
     for (const auto &Act : C.getActions()) {
diff --git a/clang/test/Driver/integrated-as.c b/clang/test/Driver/integrated-as.c
index d7658fdfd63374..5b79714a2c547e 100644
--- a/clang/test/Driver/integrated-as.c
+++ b/clang/test/Driver/integrated-as.c
@@ -1,4 +1,4 @@
-// XFAIL: target={{.*}}-aix{{.*}}
+// XFAIL: target={{.*}}-aix{{.*}}, target=riscv{{.*}}
 
 // RUN: %clang -### -c -save-temps -integrated-as %s 2>&1 | FileCheck %s
 

Copy link
Member

@MaskRay MaskRay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a comment at
#87127 (comment)

This is more about a weird -O0 -mrelax-all behavior that RISC-V now opts out, which is good on its own, even if the basis looks like a self-inflicted problem...

@@ -1,4 +1,4 @@
// XFAIL: target={{.*}}-aix{{.*}}
// XFAIL: target={{.*}}-aix{{.*}}, target=riscv{{.*}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes different behaviors with the default target triple, which is probably not perfect.

I think we can change the -mrelax-all check with an explicit target triple and then add a --target=riscv64.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What triple should i use for the -mrelax-all test?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the commonplace --target=x86_64

Copy link
Collaborator

@preames preames left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[RISCV] Relocation truncated to fit with -O0 on very large functions.
4 participants