From d7b3d72efa7251bcefd2a0516f847696d95aa07b Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Tue, 8 May 2018 22:26:39 +0000 Subject: [PATCH] [globalisel] Add a combiner helpers for extending loads and use them in a pre-legalize combiner for AArch64 Summary: Depends on D45541 Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, javed.absar, aemerson Reviewed By: aemerson Subscribers: aemerson, rengolin, mgorny, javed.absar, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D45543 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@331816 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/GlobalISel/CombinerHelper.h | 4 + lib/CodeGen/GlobalISel/CombinerHelper.cpp | 34 ++++++- lib/Target/AArch64/AArch64.h | 2 + lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp | 104 +++++++++++++++++++++ lib/Target/AArch64/AArch64TargetMachine.cpp | 6 ++ lib/Target/AArch64/CMakeLists.txt | 1 + test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll | 2 +- .../AArch64/GlobalISel/gisel-commandline-option.ll | 1 + .../GlobalISel/prelegalizercombiner-extload.mir | 25 +++++ .../GlobalISel/prelegalizercombiner-sextload.mir | 45 +++++++++ .../GlobalISel/prelegalizercombiner-zextload.mir | 25 +++++ test/CodeGen/AArch64/O0-pipeline.ll | 1 + 12 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp create mode 100644 test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extload.mir create mode 100644 test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-sextload.mir create mode 100644 test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-zextload.mir diff --git a/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/include/llvm/CodeGen/GlobalISel/CombinerHelper.h index 5d5b8398452..c1484ff8046 100644 --- a/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -35,6 +35,10 @@ public: /// Returns true if MI changed. bool tryCombineCopy(MachineInstr &MI); + /// If \p MI is extend that consumes the result of a load, try to combine it. + /// Returns true if MI changed. + bool tryCombineExtendingLoads(MachineInstr &MI); + /// Try to transform \p MI by using all of the above /// combine functions. Returns true if changed. bool tryCombine(MachineInstr &MI); diff --git a/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 44e904a6391..25b40da4dd7 100644 --- a/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -36,6 +36,38 @@ bool CombinerHelper::tryCombineCopy(MachineInstr &MI) { return false; } +bool CombinerHelper::tryCombineExtendingLoads(MachineInstr &MI) { + unsigned DstReg = MI.getOperand(0).getReg(); + unsigned SrcReg = MI.getOperand(1).getReg(); + + if (MI.getOpcode() != TargetOpcode::G_ANYEXT && + MI.getOpcode() != TargetOpcode::G_SEXT && + MI.getOpcode() != TargetOpcode::G_ZEXT) + return false; + + LLT DstTy = MRI.getType(DstReg); + if (!DstTy.isScalar()) + return false; + + if (MachineInstr *DefMI = getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI)) { + unsigned PtrReg = DefMI->getOperand(1).getReg(); + MachineMemOperand &MMO = **DefMI->memoperands_begin(); + DEBUG(dbgs() << ".. Combine MI: " << MI;); + Builder.setInstr(MI); + Builder.buildLoadInstr(MI.getOpcode() == TargetOpcode::G_SEXT + ? TargetOpcode::G_SEXTLOAD + : MI.getOpcode() == TargetOpcode::G_ZEXT + ? TargetOpcode::G_ZEXTLOAD + : TargetOpcode::G_LOAD, + DstReg, PtrReg, MMO); + MI.eraseFromParent(); + return true; + } + return false; +} + bool CombinerHelper::tryCombine(MachineInstr &MI) { - return tryCombineCopy(MI); + if (tryCombineCopy(MI)) + return true; + return tryCombineExtendingLoads(MI);; } diff --git a/lib/Target/AArch64/AArch64.h b/lib/Target/AArch64/AArch64.h index edda13ce97e..74f22e287f8 100644 --- a/lib/Target/AArch64/AArch64.h +++ b/lib/Target/AArch64/AArch64.h @@ -53,6 +53,7 @@ FunctionPass *createAArch64CollectLOHPass(); InstructionSelector * createAArch64InstructionSelector(const AArch64TargetMachine &, AArch64Subtarget &, AArch64RegisterBankInfo &); +FunctionPass *createAArch64PreLegalizeCombiner(); void initializeAArch64A53Fix835769Pass(PassRegistry&); void initializeAArch64A57FPLoadBalancingPass(PassRegistry&); @@ -65,6 +66,7 @@ void initializeAArch64DeadRegisterDefinitionsPass(PassRegistry&); void initializeAArch64ExpandPseudoPass(PassRegistry&); void initializeAArch64LoadStoreOptPass(PassRegistry&); void initializeAArch64SIMDInstrOptPass(PassRegistry&); +void initializeAArch64PreLegalizerCombinerPass(PassRegistry&); void initializeAArch64PromoteConstantPass(PassRegistry&); void initializeAArch64RedundantCopyEliminationPass(PassRegistry&); void initializeAArch64StorePairSuppressPass(PassRegistry&); diff --git a/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp b/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp new file mode 100644 index 00000000000..2a0692b888a --- /dev/null +++ b/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp @@ -0,0 +1,104 @@ +//=== lib/CodeGen/GlobalISel/AArch64PreLegalizerCombiner.cpp --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass does combining of machine instructions at the generic MI level, +// before the legalizer. +// +//===----------------------------------------------------------------------===// + +#include "AArch64TargetMachine.h" +#include "llvm/CodeGen/GlobalISel/Combiner.h" +#include "llvm/CodeGen/GlobalISel/CombinerHelper.h" +#include "llvm/CodeGen/GlobalISel/CombinerInfo.h" +#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "aarch64-prelegalizer-combiner" + +using namespace llvm; +using namespace MIPatternMatch; + +namespace { +class AArch64PreLegalizerCombinerInfo : public CombinerInfo { +public: + AArch64PreLegalizerCombinerInfo() + : CombinerInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false, + /*LegalizerInfo*/ nullptr) {} + virtual bool combine(MachineInstr &MI, MachineIRBuilder &B) const override; +}; + +bool AArch64PreLegalizerCombinerInfo::combine(MachineInstr &MI, + MachineIRBuilder &B) const { + CombinerHelper Helper(B); + + switch (MI.getOpcode()) { + default: + return false; + case TargetOpcode::G_ANYEXT: + case TargetOpcode::G_SEXT: + case TargetOpcode::G_ZEXT: + return Helper.tryCombineExtendingLoads(MI); + } + + return false; +} + +// Pass boilerplate +// ================ + +class AArch64PreLegalizerCombiner : public MachineFunctionPass { +public: + static char ID; + + AArch64PreLegalizerCombiner(); + + StringRef getPassName() const override { return "AArch64PreLegalizerCombiner"; } + + bool runOnMachineFunction(MachineFunction &MF) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; +} + +void AArch64PreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +AArch64PreLegalizerCombiner::AArch64PreLegalizerCombiner() : MachineFunctionPass(ID) { + initializeAArch64PreLegalizerCombinerPass(*PassRegistry::getPassRegistry()); +} + +bool AArch64PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) { + if (MF.getProperties().hasProperty( + MachineFunctionProperties::Property::FailedISel)) + return false; + auto *TPC = &getAnalysis(); + AArch64PreLegalizerCombinerInfo PCInfo; + Combiner C(PCInfo, TPC); + return C.combineMachineInstrs(MF); +} + +char AArch64PreLegalizerCombiner::ID = 0; +INITIALIZE_PASS_BEGIN(AArch64PreLegalizerCombiner, DEBUG_TYPE, + "Combine AArch64 machine instrs before legalization", + false, false) +INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_END(AArch64PreLegalizerCombiner, DEBUG_TYPE, + "Combine AArch64 machine instrs before legalization", false, + false) + + +namespace llvm { +FunctionPass *createAArch64PreLegalizeCombiner() { + return new AArch64PreLegalizerCombiner(); +} +} // end namespace llvm diff --git a/lib/Target/AArch64/AArch64TargetMachine.cpp b/lib/Target/AArch64/AArch64TargetMachine.cpp index d7dea46a351..25ea772bf87 100644 --- a/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -158,6 +158,7 @@ extern "C" void LLVMInitializeAArch64Target() { initializeAArch64ExpandPseudoPass(*PR); initializeAArch64LoadStoreOptPass(*PR); initializeAArch64SIMDInstrOptPass(*PR); + initializeAArch64PreLegalizerCombinerPass(*PR); initializeAArch64PromoteConstantPass(*PR); initializeAArch64RedundantCopyEliminationPass(*PR); initializeAArch64StorePairSuppressPass(*PR); @@ -338,6 +339,7 @@ public: bool addPreISel() override; bool addInstSelector() override; bool addIRTranslator() override; + void addPreLegalizeMachineIR() override; bool addLegalizeMachineIR() override; bool addRegBankSelect() override; void addPreGlobalInstructionSelect() override; @@ -439,6 +441,10 @@ bool AArch64PassConfig::addIRTranslator() { return false; } +void AArch64PassConfig::addPreLegalizeMachineIR() { + addPass(createAArch64PreLegalizeCombiner()); +} + bool AArch64PassConfig::addLegalizeMachineIR() { addPass(new Legalizer()); return false; diff --git a/lib/Target/AArch64/CMakeLists.txt b/lib/Target/AArch64/CMakeLists.txt index d9a00512f71..e6ca69c1971 100644 --- a/lib/Target/AArch64/CMakeLists.txt +++ b/lib/Target/AArch64/CMakeLists.txt @@ -43,6 +43,7 @@ add_llvm_target(AArch64CodeGen AArch64LoadStoreOptimizer.cpp AArch64MacroFusion.cpp AArch64MCInstLower.cpp + AArch64PreLegalizerCombiner.cpp AArch64PromoteConstant.cpp AArch64PBQPRegAlloc.cpp AArch64RegisterBankInfo.cpp diff --git a/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll b/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll index 59b56ac4547..fb8f845abbc 100644 --- a/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll +++ b/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll @@ -65,7 +65,7 @@ false: } -; FALLBACK-WITH-REPORT-ERR: remark: :0:0: unable to legalize instruction: %0:_(s24) = G_LOAD %1:_(p0) :: (load 3 from `i24* undef`, align 1) (in function: odd_type_load) +; FALLBACK-WITH-REPORT-ERR: remark: :0:0: unable to legalize instruction: %2:_(s32) = G_ZEXTLOAD %1:_(p0) :: (load 3 from `i24* undef`, align 1) (in function: odd_type_load) ; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for odd_type_load ; FALLBACK-WITH-REPORT-OUT-LABEL: odd_type_load define i32 @odd_type_load() { diff --git a/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll b/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll index 3920e1d99c2..6d512e139ad 100644 --- a/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll +++ b/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll @@ -36,6 +36,7 @@ ; RUN: -debug-pass=Structure %s -o /dev/null 2>&1 | FileCheck %s --check-prefix DISABLED ; ENABLED: IRTranslator +; ENABLED-NEXT: PreLegalizerCombiner ; ENABLED-NEXT: Legalizer ; ENABLED-NEXT: RegBankSelect ; ENABLED-O0-NEXT: Localizer diff --git a/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extload.mir b/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extload.mir new file mode 100644 index 00000000000..0131ea17c08 --- /dev/null +++ b/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extload.mir @@ -0,0 +1,25 @@ +# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - | FileCheck %s + +--- | + target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + target triple = "aarch64--" + define void @test_extload(i8* %addr) { + entry: + ret void + } +... + +--- +name: test_extload +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_extload + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_LOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ANYEXT %1 + $w0 = COPY %2 +... diff --git a/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-sextload.mir b/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-sextload.mir new file mode 100644 index 00000000000..018741035ff --- /dev/null +++ b/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-sextload.mir @@ -0,0 +1,45 @@ +# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - | FileCheck %s + +--- | + target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + target triple = "aarch64--" + define void @test_sextload(i8* %addr) { + entry: + ret void + } + define void @test_sextload_with_copy(i8* %addr) { + entry: + ret void + } +... + +--- +name: test_sextload +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_sextload + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_SEXT %1 + $w0 = COPY %2 +... + +--- +name: test_sextload_with_copy +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_sextload_with_copy + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s8) = COPY %1 + %3:_(s32) = G_SEXT %2 + $w0 = COPY %3 +... diff --git a/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-zextload.mir b/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-zextload.mir new file mode 100644 index 00000000000..5585364d0e1 --- /dev/null +++ b/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-zextload.mir @@ -0,0 +1,25 @@ +# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - | FileCheck %s + +--- | + target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + target triple = "aarch64--" + define void @test_zextload(i8* %addr) { + entry: + ret void + } +... + +--- +name: test_zextload +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_zextload + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_ZEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ZEXT %1 + $w0 = COPY %2 +... diff --git a/test/CodeGen/AArch64/O0-pipeline.ll b/test/CodeGen/AArch64/O0-pipeline.ll index dd0d08e68e9..5121cf76ac4 100644 --- a/test/CodeGen/AArch64/O0-pipeline.ll +++ b/test/CodeGen/AArch64/O0-pipeline.ll @@ -33,6 +33,7 @@ ; CHECK-NEXT: Insert stack protectors ; CHECK-NEXT: Module Verifier ; CHECK-NEXT: IRTranslator +; CHECK-NEXT: AArch64PreLegalizerCombiner ; CHECK-NEXT: Legalizer ; CHECK-NEXT: RegBankSelect ; CHECK-NEXT: Localizer -- 2.11.0