[X86][MC] Support enhanced relaxation for branch align
authorShengchen Kan <shengchen.kan@intel.com>
Tue, 7 Apr 2020 04:27:45 +0000 (12:27 +0800)
committerShengchen Kan <shengchen.kan@intel.com>
Wed, 8 Apr 2020 11:08:19 +0000 (19:08 +0800)
Summary:
Since D75300 has been landed, I want to support enhanced relaxation when we need to align branches and allow prefix padding. "Enhanced Relaxtion" means we allow an instruction that could not be traditionally relaxed to be emitted into RelaxableFragment so that we increase its length by adding prefixes for optimization.

The motivation is straightforward, RelaxFragment is mostly for relative jumps and we can not increase the length of jumps when we need to align them, so if we need to achieve D75300's purpose (reducing the bytes of nops) when need to align jumps, we have to make more instructions "relaxable".

Reviewers: reames, MaskRay, craig.topper, LuoYuanke, jyknight

Reviewed By: reames

Subscribers: hiraditya, llvm-commits, annita.zhang

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D76286

llvm/include/llvm/MC/MCAsmBackend.h
llvm/lib/MC/MCObjectStreamer.cpp
llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
llvm/test/MC/X86/align-branch-enhanced-relaxation.s [new file with mode: 0644]

index f859d0c..9b67c92 100644 (file)
@@ -49,6 +49,10 @@ public:
   /// Return true if this target might automatically pad instructions and thus
   /// need to emit padding enable/disable directives around sensative code.
   virtual bool allowAutoPadding() const { return false; }
+  /// Return true if this target allows an unrelaxable instruction to be
+  /// emitted into RelaxableFragment and then we can increase its size in a
+  /// tricky way for optimization.
+  virtual bool allowEnhancedRelaxation() const { return false; }
 
   /// Give the target a chance to manipulate state related to instruction
   /// alignment (e.g. padding for optimization), instruction relaxablility, etc.
index 70c9201..3cb3faa 100644 (file)
@@ -385,7 +385,9 @@ void MCObjectStreamer::emitInstructionImpl(const MCInst &Inst,
 
   // If this instruction doesn't need relaxation, just emit it as data.
   MCAssembler &Assembler = getAssembler();
-  if (!Assembler.getBackend().mayNeedRelaxation(Inst, STI)) {
+  MCAsmBackend &Backend = Assembler.getBackend();
+  if (!(Backend.mayNeedRelaxation(Inst, STI) ||
+        Backend.allowEnhancedRelaxation())) {
     EmitInstToData(Inst, STI);
     return;
   }
index c2eb78b..fd2c3ab 100644 (file)
@@ -164,6 +164,7 @@ public:
   }
 
   bool allowAutoPadding() const override;
+  bool allowEnhancedRelaxation() const override;
   void emitInstructionBegin(MCObjectStreamer &OS, const MCInst &Inst) override;
   void emitInstructionEnd(MCObjectStreamer &OS, const MCInst &Inst) override;
 
@@ -457,6 +458,10 @@ bool X86AsmBackend::allowAutoPadding() const {
   return (AlignBoundary != Align(1) && AlignBranchType != X86::AlignBranchNone);
 }
 
+bool X86AsmBackend::allowEnhancedRelaxation() const {
+  return allowAutoPadding() && X86PadMaxPrefixSize != 0 && X86PadForBranchAlign;
+}
+
 bool X86AsmBackend::needAlign(MCObjectStreamer &OS) const {
   if (!OS.getAllowAutoPadding())
     return false;
diff --git a/llvm/test/MC/X86/align-branch-enhanced-relaxation.s b/llvm/test/MC/X86/align-branch-enhanced-relaxation.s
new file mode 100644 (file)
index 0000000..4720e35
--- /dev/null
@@ -0,0 +1,52 @@
+  # RUN: llvm-mc -mcpu=skylake -filetype=obj -triple x86_64-pc-linux-gnu %s -x86-pad-max-prefix-size=1 --x86-align-branch-boundary=32 --x86-align-branch=jmp+indirect | llvm-objdump -d - | FileCheck %s
+  # RUN: llvm-mc -mcpu=skylake -filetype=obj -triple x86_64-pc-linux-gnu %s --mc-relax-all | llvm-objdump -d - | FileCheck --check-prefixes=RELAX-ALL %s
+
+  # Exercise cases where we are allowed to increase the length of unrelaxable
+  # instructions (by adding prefixes) for alignment purposes.
+
+  # The first test checks instructions 'int3', 'push %rbp', which will be padded
+  # later are unrelaxable (their encoding size is still 1 byte when
+  # --mc-relax-all is passed).
+  .text
+  .globl labeled_unrelaxable_test
+labeled_unrelaxable_test:
+# RELAX-ALL:       0: cc                               int3
+# RELAX-ALL:       1: 54                               pushq    %rsp
+  int3
+  push %rsp
+
+  # The second test is a basic test, we just check the jmp is aligned by prefix
+  # padding the previous instructions.
+  .text
+  .globl labeled_basic_test
+labeled_basic_test:
+  .p2align 5
+  .rept 28
+  int3
+  .endr
+# CHECK:      3c: 2e cc                            int3
+# CHECK:      3e: 2e 54                            pushq    %rsp
+# CHECK:      40: eb 00                            jmp
+  int3
+  push %rsp
+  jmp foo
+foo:
+  ret
+
+   # The third test check the correctness cornercase - can't add prefixes on a
+   # prefix or a instruction following by a prefix.
+  .globl labeled_prefix_test
+labeled_prefix_test:
+  .p2align 5
+  .rept 28
+  int3
+  .endr
+# CHECK:      7c: 2e cc                            int3
+  int3
+# CHECK:      7e: 3e cc                            int3
+  DS
+  int3
+# CHECK:      80: eb 00                            jmp
+  jmp bar
+bar:
+  ret