diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h --- a/llvm/include/llvm/MC/MCAsmBackend.h +++ b/llvm/include/llvm/MC/MCAsmBackend.h @@ -49,6 +49,10 @@ /// 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. diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -385,7 +385,9 @@ // 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; } diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp --- a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp @@ -164,6 +164,7 @@ } 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 @@ 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 --- /dev/null +++ b/llvm/test/MC/X86/align-branch-enhanced-relaxation.s @@ -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