Index: lib/CodeGen/GlobalISel/InstructionSelector.cpp =================================================================== --- lib/CodeGen/GlobalISel/InstructionSelector.cpp +++ lib/CodeGen/GlobalISel/InstructionSelector.cpp @@ -55,6 +55,13 @@ // constrainOperandRegClass does that for us. MO.setReg(constrainOperandRegClass(MF, TRI, MRI, TII, RBI, I, I.getDesc(), Reg, OpI)); + + // Tie uses to defs as indicated in MCInstrDesc. + if (MO.isUse()) { + int DefIdx = I.getDesc().getOperandConstraint(OpI, MCOI::TIED_TO); + if (DefIdx != -1) + I.tieOperands(DefIdx, OpI); + } } return true; } Index: lib/Target/X86/CMakeLists.txt =================================================================== --- lib/Target/X86/CMakeLists.txt +++ lib/Target/X86/CMakeLists.txt @@ -12,6 +12,7 @@ tablegen(LLVM X86GenSubtargetInfo.inc -gen-subtarget) if(LLVM_BUILD_GLOBAL_ISEL) tablegen(LLVM X86GenRegisterBank.inc -gen-register-bank) + tablegen(LLVM X86GenGlobalISel.inc -gen-global-isel) endif() add_public_tablegen_target(X86CommonTableGen) @@ -21,6 +22,7 @@ X86CallLowering.cpp X86LegalizerInfo.cpp X86RegisterBankInfo.cpp + X86InstructionSelector.cpp ) if(LLVM_BUILD_GLOBAL_ISEL) Index: lib/Target/X86/X86InstructionSelector.h =================================================================== --- /dev/null +++ lib/Target/X86/X86InstructionSelector.h @@ -0,0 +1,47 @@ +//===- X86InstructionSelector --------------------------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares the targeting of the InstructionSelector class for X86. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_X86_X86INSTRUCTIONSELECTOR_H +#define LLVM_LIB_TARGET_X86_X86INSTRUCTIONSELECTOR_H + +#include "llvm/CodeGen/GlobalISel/InstructionSelector.h" + +namespace llvm { + +class X86InstrInfo; +class X86RegisterBankInfo; +class X86RegisterInfo; +class X86Subtarget; +class X86TargetMachine; + +class X86InstructionSelector : public InstructionSelector { +public: + X86InstructionSelector(const X86TargetMachine &TM, const X86Subtarget &STI, + const X86RegisterBankInfo &RBI); + + bool select(MachineInstr &I) const override; + +private: + /// tblgen-erated 'select' implementation, used as the initial selector for + /// the patterns that don't require complex C++. + bool selectImpl(MachineInstr &I) const; + + const X86TargetMachine &TM; + const X86Subtarget &STI; + const X86InstrInfo &TII; + const X86RegisterInfo &TRI; + const X86RegisterBankInfo &RBI; +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_X86_X86INSTRUCTIONSELECTOR_H Index: lib/Target/X86/X86InstructionSelector.cpp =================================================================== --- /dev/null +++ lib/Target/X86/X86InstructionSelector.cpp @@ -0,0 +1,135 @@ +//===- X86InstructionSelector.cpp ----------------------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the targeting of the InstructionSelector class for +/// X86. +/// \todo This should be generated by TableGen. +//===----------------------------------------------------------------------===// + +#include "X86InstructionSelector.h" +#include "X86InstrInfo.h" +#include "X86RegisterBankInfo.h" +#include "X86RegisterInfo.h" +#include "X86Subtarget.h" +#include "X86TargetMachine.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "X86-isel" + +using namespace llvm; + +#ifndef LLVM_BUILD_GLOBAL_ISEL +#error "You shouldn't build this" +#endif + +#include "X86GenGlobalISel.inc" + +X86InstructionSelector::X86InstructionSelector(const X86TargetMachine &TM, + const X86Subtarget &STI, + const X86RegisterBankInfo &RBI) + : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()), + TRI(*STI.getRegisterInfo()), RBI(RBI) {} + +// FIXME: This should be target-independent, inferred from the types declared +// for each class in the bank. +static const TargetRegisterClass * +getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) { + if (RB.getID() == X86::GPRRegBankID) { + if (Ty.getSizeInBits() <= 32) + return &X86::GR32RegClass; + if (Ty.getSizeInBits() == 64) + return &X86::GR64RegClass; + } + + llvm_unreachable("Unknown RegBank!"); + return nullptr; +} + +// Set X86 Opcode and constrain DestReg. +static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, + MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) { + + unsigned DstReg = I.getOperand(0).getReg(); + if (TargetRegisterInfo::isPhysicalRegister(DstReg)) { + assert(I.isCopy() && "Generic operators do not allow physical registers"); + return true; + } + + const RegisterBank &RegBank = *RBI.getRegBank(DstReg, MRI, TRI); + const unsigned DstSize = MRI.getType(DstReg).getSizeInBits(); + unsigned SrcReg = I.getOperand(1).getReg(); + const unsigned SrcSize = RBI.getSizeInBits(SrcReg, MRI, TRI); + (void)SrcSize; + assert((!TargetRegisterInfo::isPhysicalRegister(SrcReg) || I.isCopy()) && + "No phys reg on generic operators"); + assert((DstSize == SrcSize || + // Copies are a mean to setup initial types, the number of + // bits may not exactly match. + (TargetRegisterInfo::isPhysicalRegister(SrcReg) && + DstSize <= RBI.getSizeInBits(SrcReg, MRI, TRI))) && + "Copy with different width?!"); + + const TargetRegisterClass *RC = nullptr; + + switch (RegBank.getID()) { + case X86::GPRRegBankID: + assert((DstSize <= 64) && "GPRs cannot get more than 64-bit width values."); + RC = getRegClassForTypeOnBank(MRI.getType(DstReg), RegBank); + break; + default: + llvm_unreachable("Unknown RegBank!"); + break; + } + + // No need to constrain SrcReg. It will get constrained when + // we hit another of its use or its defs. + // Copies do not have constraints. + if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { + DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) + << " operand\n"); + return false; + } + I.setDesc(TII.get(X86::COPY)); + return true; +} + +bool X86InstructionSelector::select(MachineInstr &I) const { + assert(I.getParent() && "Instruction should be in a basic block!"); + assert(I.getParent()->getParent() && "Instruction should be in a function!"); + + MachineBasicBlock &MBB = *I.getParent(); + MachineFunction &MF = *MBB.getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + + unsigned Opcode = I.getOpcode(); + if (!isPreISelGenericOpcode(Opcode)) { + // Certain non-generic instructions also need some special handling. + + if (I.isCopy()) + return selectCopy(I, TII, MRI, TRI, RBI); + + // TODO: handle more cases - LOAD_STACK_GUARD, PHI + return true; + } + + if (I.getNumOperands() != I.getNumExplicitOperands()) { + + llvm_unreachable("Generic instruction has unexpected implicit operands\n"); + } + + return selectImpl(I); +} Index: lib/Target/X86/X86LegalizerInfo.cpp =================================================================== --- lib/Target/X86/X86LegalizerInfo.cpp +++ lib/Target/X86/X86LegalizerInfo.cpp @@ -38,12 +38,13 @@ const LLT s16 = LLT::scalar(16); const LLT s32 = LLT::scalar(32); - for (auto Ty : {s8, s16, s32}) + for (auto Ty : {s8, s16, s32}) { setAction({TargetOpcode::G_ADD, Ty}, Legal); + setAction({TargetOpcode::G_SUB, Ty}, Legal); + } } -void -X86LegalizerInfo::setLegalizerInfo64bit() { +void X86LegalizerInfo::setLegalizerInfo64bit() { if (!Subtarget.is64Bit()) return; @@ -51,4 +52,5 @@ const LLT s64 = LLT::scalar(64); setAction({TargetOpcode::G_ADD, s64}, Legal); + setAction({TargetOpcode::G_SUB, s64}, Legal); } Index: lib/Target/X86/X86RegisterBankInfo.cpp =================================================================== --- lib/Target/X86/X86RegisterBankInfo.cpp +++ lib/Target/X86/X86RegisterBankInfo.cpp @@ -111,6 +111,7 @@ switch (Opc) { case TargetOpcode::G_ADD: + case TargetOpcode::G_SUB: return getOperandsMapping(MI, false); break; default: Index: lib/Target/X86/X86TargetMachine.cpp =================================================================== --- lib/Target/X86/X86TargetMachine.cpp +++ lib/Target/X86/X86TargetMachine.cpp @@ -15,6 +15,7 @@ #include "X86.h" #include "X86CallLowering.h" #include "X86LegalizerInfo.h" +#include "X86InstructionSelector.h" #ifdef LLVM_BUILD_GLOBAL_ISEL #include "X86RegisterBankInfo.h" #endif @@ -34,6 +35,7 @@ #include "llvm/CodeGen/GlobalISel/IRTranslator.h" #include "llvm/CodeGen/GlobalISel/Legalizer.h" #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelect.h" #include "llvm/CodeGen/MachineScheduler.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetPassConfig.h" @@ -211,14 +213,14 @@ std::unique_ptr CallLoweringInfo; std::unique_ptr Legalizer; std::unique_ptr RegBankInfo; + std::unique_ptr InstSelector; const CallLowering *getCallLowering() const override { return CallLoweringInfo.get(); } const InstructionSelector *getInstructionSelector() const override { - //TODO: Implement - return nullptr; + return InstSelector.get(); } const LegalizerInfo *getLegalizerInfo() const override { @@ -282,6 +284,7 @@ auto *RBI = new X86RegisterBankInfo(*I->getRegisterInfo()); GISel->RegBankInfo.reset(RBI); + GISel->InstSelector.reset(new X86InstructionSelector(*this, *I, *RBI)); #endif I->setGISelAccessor(*GISel); @@ -391,7 +394,7 @@ } bool X86PassConfig::addGlobalInstructionSelect() { - //TODO: Implement + addPass(new InstructionSelect()); return false; } #endif Index: test/CodeGen/X86/GlobalISel/binop-isel.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/binop-isel.ll @@ -0,0 +1,23 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel < %s -o - | FileCheck %s + +define i32 @test_add_i32(i32 %arg1, i32 %arg2) { +; CHECK-LABEL: test_add_i32: +; CHECK: # BB#0: +; CHECK-NEXT: # kill: %EDI %EDI %RDI +; CHECK-NEXT: # kill: %ESI %ESI %RSI +; CHECK-NEXT: leal (%rsi,%rdi), %eax +; CHECK-NEXT: retq + %ret = add i32 %arg1, %arg2 + ret i32 %ret +} + +define i32 @test_sub_i32(i32 %arg1, i32 %arg2) { +; CHECK-LABEL: test_sub_i32: +; CHECK: # BB#0: +; CHECK-NEXT: subl %esi, %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %ret = sub i32 %arg1, %arg2 + ret i32 %ret +} Index: test/CodeGen/X86/GlobalISel/legalize-sub.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/legalize-sub.mir @@ -0,0 +1,40 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s + +--- | + ; ModuleID = '' + source_filename = "" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64--linux-gnu" + + define i32 @test_sub_i32(i32 %arg1, i32 %arg2) { + %ret = sub i32 %arg1, %arg2 + ret i32 %ret + } + +... +--- +name: test_sub_i32 +alignment: 4 +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + ; CHECK-LABEL: name: test_sub_i32 + ; CHECK: [[VAL1:%.*]](s32) = COPY %edi + ; CHECK: [[VAL2:%.*]](s32) = COPY %esi + ; CHECK: [[RES:%.*]](s32) = G_SUB [[VAL1:%.*]], [[VAL2:%.*]] + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s32) = G_SUB %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... Index: test/CodeGen/X86/GlobalISel/x86_64-instructionselect.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/x86_64-instructionselect.mir @@ -0,0 +1,64 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s + +--- | + define i32 @test_add_i32(i32 %arg1, i32 %arg2) { + %ret = add i32 %arg1, %arg2 + ret i32 %ret + } + + define i32 @test_sub_i32(i32 %arg1, i32 %arg2) { + %ret = sub i32 %arg1, %arg2 + ret i32 %ret + } + +... + +--- +name: test_add_i32 +legalized: true +regBankSelected: true +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr32 } +# CHECK-NEXT: - { id: 1, class: gr32 } +# CHECK-NEXT: - { id: 2, class: gr32 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } +# CHECK: %0 = COPY %edi +# CHECK-NEXT: %1 = COPY %esi +# CHECK-NEXT: %2 = ADD32rr %0, %1 +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s32) = G_ADD %0, %1 + +... + +--- +name: test_sub_i32 +legalized: true +regBankSelected: true +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr32 } +# CHECK-NEXT: - { id: 1, class: gr32 } +# CHECK-NEXT: - { id: 2, class: gr32 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } +# CHECK: %0 = COPY %edi +# CHECK-NEXT: %1 = COPY %esi +# CHECK-NEXT: %2 = SUB32rr %0, %1 +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s32) = G_SUB %0, %1 + +...