Index: include/llvm/CodeGen/GlobalISel/Canonicalize.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/Canonicalize.h @@ -0,0 +1,24 @@ +//===--- GISelCanonicalize.h - Canonicalize IR before GlobalISel codegen---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_CANONICALIZE_H +#define LLVM_CODEGEN_GLOBALISEL_CANONICALIZE_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class GISelCanonicalizePass + : public PassInfoMixin { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} // end namespace llvm + +#endif // LLVM_CODEGEN_GLOBALISEL_CANONICALIZE_H Index: include/llvm/CodeGen/Passes.h =================================================================== --- include/llvm/CodeGen/Passes.h +++ include/llvm/CodeGen/Passes.h @@ -441,6 +441,9 @@ /// Creates CFI Instruction Inserter pass. \see CFIInstrInserter.cpp FunctionPass *createCFIInstrInserter(); + // Do some IR canonicalization for the GlobalISel pipeline. + FunctionPass *createGISelCanonicalizePass(); + } // End llvm namespace #endif Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -152,6 +152,7 @@ void initializeGCMachineCodeAnalysisPass(PassRegistry&); void initializeGCModuleInfoPass(PassRegistry&); void initializeGCOVProfilerLegacyPassPass(PassRegistry&); +void initializeGISelCanonicalizePass(PassRegistry &); void initializeGVNHoistLegacyPassPass(PassRegistry&); void initializeGVNLegacyPassPass(PassRegistry&); void initializeGVNSinkLegacyPassPass(PassRegistry&); Index: lib/CodeGen/GlobalISel/CMakeLists.txt =================================================================== --- lib/CodeGen/GlobalISel/CMakeLists.txt +++ lib/CodeGen/GlobalISel/CMakeLists.txt @@ -3,6 +3,7 @@ GlobalISel.cpp Combiner.cpp CombinerHelper.cpp + Canonicalize.cpp IRTranslator.cpp InstructionSelect.cpp InstructionSelector.cpp Index: lib/CodeGen/GlobalISel/Canonicalize.cpp =================================================================== --- /dev/null +++ lib/CodeGen/GlobalISel/Canonicalize.cpp @@ -0,0 +1,90 @@ +//===--- GISelCanonicalize.cpp - Canonicalize IR before GlobalISel codegen-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass does some canonicalization of the IR into standard forms to make +// GlobalISel codegen more effective. This runs at all optimization levels, +// although some canonicalization may be done already when optimizations are +// enabled. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/Canonicalize.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Pass.h" + +#define DEBUG_TYPE "gisel-canonicalize" + +using namespace llvm; + +namespace { + +bool visitICmp(ICmpInst &I) { + if (isa(I.getOperand(0)) && !isa(I.getOperand(1))) { + LLVM_DEBUG(dbgs() << "GISelCanonicalize: swapping operands of " << I + << "\n"); + I.swapOperands(); + return true; + } + return false; +} + +bool canonicalizeFunction(Function &F) { + bool Changed = false; + for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) { + Instruction *I = &*II; + switch (I->getOpcode()) { + case Instruction::ICmp: + Changed |= visitICmp(*cast(I)); + break; + default: + continue; + } + } + return Changed; +} + +class GISelCanonicalize : public FunctionPass { +public: + static char ID; + GISelCanonicalize() : FunctionPass(ID) { + initializeGISelCanonicalizePass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override { + return canonicalizeFunction(F); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + } +}; +} + +char GISelCanonicalize::ID; +INITIALIZE_PASS_BEGIN(GISelCanonicalize, "gisel-canonicalize", + "GISel canonicalization", false, false) +INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) +INITIALIZE_PASS_END(GISelCanonicalize, "gisel-canonicalize", + "GISel canonicalization", false, false) + +FunctionPass *llvm::createGISelCanonicalizePass() { + return new GISelCanonicalize(); +} + +PreservedAnalyses GISelCanonicalizePass::run(Function &F, + FunctionAnalysisManager &AM) { + if (!canonicalizeFunction(F)) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserveSet(); + return PA; +} Index: lib/CodeGen/TargetPassConfig.cpp =================================================================== --- lib/CodeGen/TargetPassConfig.cpp +++ lib/CodeGen/TargetPassConfig.cpp @@ -144,6 +144,10 @@ "2 disable the abort but emit a diagnostic on failure"), cl::init(1)); +static cl::opt EnableGISelCanonicalize( + "enable-gisel-canonicalize", cl::Hidden, cl::init(true), + cl::desc("Enable IR canonicalization for GlobalISel")); + // Temporary option to allow experimenting with MachineScheduler as a post-RA // scheduler. Targets can "properly" enable this with // substitutePass(&PostRASchedulerID, &PostMachineSchedulerID). @@ -687,6 +691,12 @@ addPass(createRewriteSymbolsPass()); } +static bool shouldEnableGlobalISelPasses(TargetMachine *TM) { + return EnableGlobalISelOption == cl::BOU_TRUE || + (EnableGlobalISelOption == cl::BOU_UNSET && + TM->Options.EnableGlobalISel && EnableFastISelOption != cl::BOU_TRUE); +} + /// Add common passes that perform LLVM IR to IR transforms in preparation for /// instruction selection. void TargetPassConfig::addISelPrepare() { @@ -696,6 +706,10 @@ if (requiresCodeGenSCCOrder()) addPass(new DummyCGSCCPass); + // Do some IR canonicalizations for GlobalISel at all opt levels. + if (shouldEnableGlobalISelPasses(TM) && EnableGISelCanonicalize) + addPass(createGISelCanonicalizePass()); + // Add both the safe stack and the stack protection passes: each of them will // only protect functions that have corresponding attributes. addPass(createSafeStackPass()); @@ -721,11 +735,10 @@ // Ask the target for an instruction selector. // Explicitly enabling fast-isel should override implicitly enabled // global-isel. - if (EnableGlobalISelOption == cl::BOU_TRUE || - (EnableGlobalISelOption == cl::BOU_UNSET && - TM->Options.EnableGlobalISel && EnableFastISelOption != cl::BOU_TRUE)) { + if (shouldEnableGlobalISelPasses(TM)) { TM->setFastISel(false); + if (addIRTranslator()) return true; Index: test/CodeGen/AArch64/O0-pipeline.ll =================================================================== --- test/CodeGen/AArch64/O0-pipeline.ll +++ test/CodeGen/AArch64/O0-pipeline.ll @@ -29,6 +29,7 @@ ; CHECK-NEXT: FunctionPass Manager ; CHECK-NEXT: Dominator Tree Construction ; CHECK-NEXT: Exception handling preparation +; CHECK-NEXT: GISel canonicalization ; CHECK-NEXT: Safe Stack instrumentation pass ; CHECK-NEXT: Insert stack protectors ; CHECK-NEXT: Module Verifier Index: test/CodeGen/Generic/gisel-canonicalize.ll =================================================================== --- /dev/null +++ test/CodeGen/Generic/gisel-canonicalize.ll @@ -0,0 +1,9 @@ +; RUN: opt %s -gisel-canonicalize -S | FileCheck %s + +; CHECK-PREFIX: icmp_test +; CHECK: %c = icmp sgt i64 %a, 42 +; CHECK: ret +define i1 @icmp_test(i64 %a) { + %c = icmp slt i64 42, %a + ret i1 %c +} Index: tools/llc/llc.cpp =================================================================== --- tools/llc/llc.cpp +++ tools/llc/llc.cpp @@ -302,6 +302,7 @@ initializeVectorization(*Registry); initializeScalarizeMaskedMemIntrinPass(*Registry); initializeExpandReductionsPass(*Registry); + initializeGISelCanonicalizePass(*Registry); // Initialize debugging passes. initializeScavengerTestPass(*Registry); Index: tools/opt/opt.cpp =================================================================== --- tools/opt/opt.cpp +++ tools/opt/opt.cpp @@ -470,6 +470,7 @@ initializeExpandReductionsPass(Registry); initializeWasmEHPreparePass(Registry); initializeWriteBitcodePassPass(Registry); + initializeGISelCanonicalizePass(Registry); #ifdef LINK_POLLY_INTO_TOOLS polly::initializePollyPasses(Registry);