Skip to content

Commit f7359d8

Browse files
author
Igor Breger
committedFeb 22, 2017
[X86][GlobalISel] Initial implementation , select G_ADD gpr, gpr
Summary: Initial implementation for X86InstructionSelector. Handle selection COPY and G_ADD/G_SUB gpr, gpr . Reviewers: qcolombet, rovka, zvi, ab Reviewed By: rovka Subscribers: mgorny, dberris, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D29816 llvm-svn: 295824
1 parent a2fc1e0 commit f7359d8

10 files changed

+407
-6
lines changed
 

‎llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ bool InstructionSelector::constrainSelectedInstRegOperands(
5555
// constrainOperandRegClass does that for us.
5656
MO.setReg(constrainOperandRegClass(MF, TRI, MRI, TII, RBI, I, I.getDesc(),
5757
Reg, OpI));
58+
59+
// Tie uses to defs as indicated in MCInstrDesc.
60+
if (MO.isUse()) {
61+
int DefIdx = I.getDesc().getOperandConstraint(OpI, MCOI::TIED_TO);
62+
if (DefIdx != -1)
63+
I.tieOperands(DefIdx, OpI);
64+
}
5865
}
5966
return true;
6067
}

‎llvm/lib/Target/X86/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ tablegen(LLVM X86GenCallingConv.inc -gen-callingconv)
1212
tablegen(LLVM X86GenSubtargetInfo.inc -gen-subtarget)
1313
if(LLVM_BUILD_GLOBAL_ISEL)
1414
tablegen(LLVM X86GenRegisterBank.inc -gen-register-bank)
15+
tablegen(LLVM X86GenGlobalISel.inc -gen-global-isel)
1516
endif()
1617

1718
add_public_tablegen_target(X86CommonTableGen)
@@ -21,6 +22,7 @@ set(GLOBAL_ISEL_FILES
2122
X86CallLowering.cpp
2223
X86LegalizerInfo.cpp
2324
X86RegisterBankInfo.cpp
25+
X86InstructionSelector.cpp
2426
)
2527

2628
if(LLVM_BUILD_GLOBAL_ISEL)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//===- X86InstructionSelector.cpp ----------------------------*- C++ -*-==//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
/// \file
10+
/// This file implements the targeting of the InstructionSelector class for
11+
/// X86.
12+
/// \todo This should be generated by TableGen.
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "X86InstructionSelector.h"
16+
#include "X86InstrInfo.h"
17+
#include "X86RegisterBankInfo.h"
18+
#include "X86RegisterInfo.h"
19+
#include "X86Subtarget.h"
20+
#include "X86TargetMachine.h"
21+
#include "llvm/CodeGen/MachineBasicBlock.h"
22+
#include "llvm/CodeGen/MachineFunction.h"
23+
#include "llvm/CodeGen/MachineInstr.h"
24+
#include "llvm/CodeGen/MachineInstrBuilder.h"
25+
#include "llvm/CodeGen/MachineRegisterInfo.h"
26+
#include "llvm/IR/Type.h"
27+
#include "llvm/Support/Debug.h"
28+
#include "llvm/Support/raw_ostream.h"
29+
30+
#define DEBUG_TYPE "X86-isel"
31+
32+
using namespace llvm;
33+
34+
#ifndef LLVM_BUILD_GLOBAL_ISEL
35+
#error "You shouldn't build this"
36+
#endif
37+
38+
#include "X86GenGlobalISel.inc"
39+
40+
X86InstructionSelector::X86InstructionSelector(const X86TargetMachine &TM,
41+
const X86Subtarget &STI,
42+
const X86RegisterBankInfo &RBI)
43+
: InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
44+
TRI(*STI.getRegisterInfo()), RBI(RBI) {}
45+
46+
// FIXME: This should be target-independent, inferred from the types declared
47+
// for each class in the bank.
48+
static const TargetRegisterClass *
49+
getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) {
50+
if (RB.getID() == X86::GPRRegBankID) {
51+
if (Ty.getSizeInBits() <= 32)
52+
return &X86::GR32RegClass;
53+
if (Ty.getSizeInBits() == 64)
54+
return &X86::GR64RegClass;
55+
}
56+
57+
llvm_unreachable("Unknown RegBank!");
58+
}
59+
60+
// Set X86 Opcode and constrain DestReg.
61+
static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
62+
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
63+
const RegisterBankInfo &RBI) {
64+
65+
unsigned DstReg = I.getOperand(0).getReg();
66+
if (TargetRegisterInfo::isPhysicalRegister(DstReg)) {
67+
assert(I.isCopy() && "Generic operators do not allow physical registers");
68+
return true;
69+
}
70+
71+
const RegisterBank &RegBank = *RBI.getRegBank(DstReg, MRI, TRI);
72+
const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
73+
unsigned SrcReg = I.getOperand(1).getReg();
74+
const unsigned SrcSize = RBI.getSizeInBits(SrcReg, MRI, TRI);
75+
(void)SrcSize;
76+
assert((!TargetRegisterInfo::isPhysicalRegister(SrcReg) || I.isCopy()) &&
77+
"No phys reg on generic operators");
78+
assert((DstSize == SrcSize ||
79+
// Copies are a mean to setup initial types, the number of
80+
// bits may not exactly match.
81+
(TargetRegisterInfo::isPhysicalRegister(SrcReg) &&
82+
DstSize <= RBI.getSizeInBits(SrcReg, MRI, TRI))) &&
83+
"Copy with different width?!");
84+
85+
const TargetRegisterClass *RC = nullptr;
86+
87+
switch (RegBank.getID()) {
88+
case X86::GPRRegBankID:
89+
assert((DstSize <= 64) && "GPRs cannot get more than 64-bit width values.");
90+
RC = getRegClassForTypeOnBank(MRI.getType(DstReg), RegBank);
91+
break;
92+
default:
93+
llvm_unreachable("Unknown RegBank!");
94+
}
95+
96+
// No need to constrain SrcReg. It will get constrained when
97+
// we hit another of its use or its defs.
98+
// Copies do not have constraints.
99+
if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
100+
DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
101+
<< " operand\n");
102+
return false;
103+
}
104+
I.setDesc(TII.get(X86::COPY));
105+
return true;
106+
}
107+
108+
bool X86InstructionSelector::select(MachineInstr &I) const {
109+
assert(I.getParent() && "Instruction should be in a basic block!");
110+
assert(I.getParent()->getParent() && "Instruction should be in a function!");
111+
112+
MachineBasicBlock &MBB = *I.getParent();
113+
MachineFunction &MF = *MBB.getParent();
114+
MachineRegisterInfo &MRI = MF.getRegInfo();
115+
116+
unsigned Opcode = I.getOpcode();
117+
if (!isPreISelGenericOpcode(Opcode)) {
118+
// Certain non-generic instructions also need some special handling.
119+
120+
if (I.isCopy())
121+
return selectCopy(I, TII, MRI, TRI, RBI);
122+
123+
// TODO: handle more cases - LOAD_STACK_GUARD, PHI
124+
return true;
125+
}
126+
127+
if (I.getNumOperands() != I.getNumExplicitOperands()) {
128+
assert("Generic instruction has unexpected implicit operands\n");
129+
return false;
130+
}
131+
132+
return selectImpl(I);
133+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===- X86InstructionSelector --------------------------------*- C++ -*-==//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
/// \file
10+
/// This file declares the targeting of the InstructionSelector class for X86.
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_LIB_TARGET_X86_X86INSTRUCTIONSELECTOR_H
14+
#define LLVM_LIB_TARGET_X86_X86INSTRUCTIONSELECTOR_H
15+
16+
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
17+
18+
namespace llvm {
19+
20+
class X86InstrInfo;
21+
class X86RegisterBankInfo;
22+
class X86RegisterInfo;
23+
class X86Subtarget;
24+
class X86TargetMachine;
25+
26+
class X86InstructionSelector : public InstructionSelector {
27+
public:
28+
X86InstructionSelector(const X86TargetMachine &TM, const X86Subtarget &STI,
29+
const X86RegisterBankInfo &RBI);
30+
31+
bool select(MachineInstr &I) const override;
32+
33+
private:
34+
/// tblgen-erated 'select' implementation, used as the initial selector for
35+
/// the patterns that don't require complex C++.
36+
bool selectImpl(MachineInstr &I) const;
37+
38+
const X86TargetMachine &TM;
39+
const X86Subtarget &STI;
40+
const X86InstrInfo &TII;
41+
const X86RegisterInfo &TRI;
42+
const X86RegisterBankInfo &RBI;
43+
};
44+
45+
} // end namespace llvm
46+
47+
#endif // LLVM_LIB_TARGET_X86_X86INSTRUCTIONSELECTOR_H

‎llvm/lib/Target/X86/X86LegalizerInfo.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,19 @@ void X86LegalizerInfo::setLegalizerInfo32bit() {
3838
const LLT s16 = LLT::scalar(16);
3939
const LLT s32 = LLT::scalar(32);
4040

41-
for (auto Ty : {s8, s16, s32})
41+
for (auto Ty : {s8, s16, s32}) {
4242
setAction({TargetOpcode::G_ADD, Ty}, Legal);
43+
setAction({TargetOpcode::G_SUB, Ty}, Legal);
44+
}
4345
}
44-
void
4546

46-
X86LegalizerInfo::setLegalizerInfo64bit() {
47+
void X86LegalizerInfo::setLegalizerInfo64bit() {
4748

4849
if (!Subtarget.is64Bit())
4950
return;
5051

5152
const LLT s64 = LLT::scalar(64);
5253

5354
setAction({TargetOpcode::G_ADD, s64}, Legal);
55+
setAction({TargetOpcode::G_SUB, s64}, Legal);
5456
}

‎llvm/lib/Target/X86/X86RegisterBankInfo.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ X86RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
111111

112112
switch (Opc) {
113113
case TargetOpcode::G_ADD:
114+
case TargetOpcode::G_SUB:
114115
return getOperandsMapping(MI, false);
115116
break;
116117
default:

‎llvm/lib/Target/X86/X86TargetMachine.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "X86.h"
1616
#include "X86CallLowering.h"
1717
#include "X86LegalizerInfo.h"
18+
#include "X86InstructionSelector.h"
1819
#ifdef LLVM_BUILD_GLOBAL_ISEL
1920
#include "X86RegisterBankInfo.h"
2021
#endif
@@ -34,6 +35,7 @@
3435
#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
3536
#include "llvm/CodeGen/GlobalISel/Legalizer.h"
3637
#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
38+
#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
3739
#include "llvm/CodeGen/MachineScheduler.h"
3840
#include "llvm/CodeGen/Passes.h"
3941
#include "llvm/CodeGen/TargetPassConfig.h"
@@ -211,14 +213,14 @@ struct X86GISelActualAccessor : public GISelAccessor {
211213
std::unique_ptr<CallLowering> CallLoweringInfo;
212214
std::unique_ptr<LegalizerInfo> Legalizer;
213215
std::unique_ptr<RegisterBankInfo> RegBankInfo;
216+
std::unique_ptr<InstructionSelector> InstSelector;
214217

215218
const CallLowering *getCallLowering() const override {
216219
return CallLoweringInfo.get();
217220
}
218221

219222
const InstructionSelector *getInstructionSelector() const override {
220-
//TODO: Implement
221-
return nullptr;
223+
return InstSelector.get();
222224
}
223225

224226
const LegalizerInfo *getLegalizerInfo() const override {
@@ -282,6 +284,7 @@ X86TargetMachine::getSubtargetImpl(const Function &F) const {
282284

283285
auto *RBI = new X86RegisterBankInfo(*I->getRegisterInfo());
284286
GISel->RegBankInfo.reset(RBI);
287+
GISel->InstSelector.reset(new X86InstructionSelector(*this, *I, *RBI));
285288

286289
#endif
287290
I->setGISelAccessor(*GISel);
@@ -391,7 +394,7 @@ bool X86PassConfig::addRegBankSelect() {
391394
}
392395

393396
bool X86PassConfig::addGlobalInstructionSelect() {
394-
//TODO: Implement
397+
addPass(new InstructionSelect());
395398
return false;
396399
}
397400
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=x86_64-linux-gnu -global-isel < %s -o - | FileCheck %s
3+
4+
define i64 @test_add_i64(i64 %arg1, i64 %arg2) {
5+
; CHECK-LABEL: test_add_i64:
6+
; CHECK: # BB#0:
7+
; CHECK-NEXT: leaq (%rsi,%rdi), %rax
8+
; CHECK-NEXT: retq
9+
%ret = add i64 %arg1, %arg2
10+
ret i64 %ret
11+
}
12+
13+
define i32 @test_add_i32(i32 %arg1, i32 %arg2) {
14+
; CHECK-LABEL: test_add_i32:
15+
; CHECK: # BB#0:
16+
; CHECK-NEXT: # kill: %EDI<def> %EDI<kill> %RDI<def>
17+
; CHECK-NEXT: # kill: %ESI<def> %ESI<kill> %RSI<def>
18+
; CHECK-NEXT: leal (%rsi,%rdi), %eax
19+
; CHECK-NEXT: retq
20+
%ret = add i32 %arg1, %arg2
21+
ret i32 %ret
22+
}
23+
24+
define i64 @test_sub_i64(i64 %arg1, i64 %arg2) {
25+
; CHECK-LABEL: test_sub_i64:
26+
; CHECK: # BB#0:
27+
; CHECK-NEXT: subq %rsi, %rdi
28+
; CHECK-NEXT: movq %rdi, %rax
29+
; CHECK-NEXT: retq
30+
%ret = sub i64 %arg1, %arg2
31+
ret i64 %ret
32+
}
33+
34+
define i32 @test_sub_i32(i32 %arg1, i32 %arg2) {
35+
; CHECK-LABEL: test_sub_i32:
36+
; CHECK: # BB#0:
37+
; CHECK-NEXT: subl %esi, %edi
38+
; CHECK-NEXT: movl %edi, %eax
39+
; CHECK-NEXT: retq
40+
%ret = sub i32 %arg1, %arg2
41+
ret i32 %ret
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s
2+
3+
--- |
4+
; ModuleID = '<stdin>'
5+
source_filename = "<stdin>"
6+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7+
target triple = "x86_64--linux-gnu"
8+
9+
define i32 @test_sub_i32(i32 %arg1, i32 %arg2) {
10+
%ret = sub i32 %arg1, %arg2
11+
ret i32 %ret
12+
}
13+
14+
...
15+
---
16+
name: test_sub_i32
17+
alignment: 4
18+
legalized: false
19+
regBankSelected: false
20+
selected: false
21+
tracksRegLiveness: true
22+
registers:
23+
- { id: 0, class: _ }
24+
- { id: 1, class: _ }
25+
- { id: 2, class: _ }
26+
body: |
27+
bb.1 (%ir-block.0):
28+
liveins: %edi, %esi
29+
; CHECK-LABEL: name: test_sub_i32
30+
; CHECK: [[VAL1:%.*]](s32) = COPY %edi
31+
; CHECK: [[VAL2:%.*]](s32) = COPY %esi
32+
; CHECK: [[RES:%.*]](s32) = G_SUB [[VAL1:%.*]], [[VAL2:%.*]]
33+
34+
%0(s32) = COPY %edi
35+
%1(s32) = COPY %esi
36+
%2(s32) = G_SUB %0, %1
37+
%eax = COPY %2(s32)
38+
RET 0, implicit %eax
39+
40+
...
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
2+
3+
--- |
4+
define i64 @test_add_i64(i64 %arg1, i64 %arg2) {
5+
%ret = add i64 %arg1, %arg2
6+
ret i64 %ret
7+
}
8+
9+
define i32 @test_add_i32(i32 %arg1, i32 %arg2) {
10+
%ret = add i32 %arg1, %arg2
11+
ret i32 %ret
12+
}
13+
14+
define i64 @test_sub_i64(i64 %arg1, i64 %arg2) {
15+
%ret = sub i64 %arg1, %arg2
16+
ret i64 %ret
17+
}
18+
19+
define i32 @test_sub_i32(i32 %arg1, i32 %arg2) {
20+
%ret = sub i32 %arg1, %arg2
21+
ret i32 %ret
22+
}
23+
24+
...
25+
26+
---
27+
name: test_add_i64
28+
legalized: true
29+
regBankSelected: true
30+
# CHECK: registers:
31+
# CHECK-NEXT: - { id: 0, class: gr64 }
32+
# CHECK-NEXT: - { id: 1, class: gr64 }
33+
# CHECK-NEXT: - { id: 2, class: gr64 }
34+
registers:
35+
- { id: 0, class: gpr }
36+
- { id: 1, class: gpr }
37+
- { id: 2, class: gpr }
38+
# CHECK: %0 = COPY %rdi
39+
# CHECK-NEXT: %1 = COPY %rsi
40+
# CHECK-NEXT: %2 = ADD64rr %0, %1
41+
body: |
42+
bb.1 (%ir-block.0):
43+
liveins: %edi, %esi
44+
45+
%0(s64) = COPY %rdi
46+
%1(s64) = COPY %rsi
47+
%2(s64) = G_ADD %0, %1
48+
49+
...
50+
51+
---
52+
name: test_add_i32
53+
legalized: true
54+
regBankSelected: true
55+
# CHECK: registers:
56+
# CHECK-NEXT: - { id: 0, class: gr32 }
57+
# CHECK-NEXT: - { id: 1, class: gr32 }
58+
# CHECK-NEXT: - { id: 2, class: gr32 }
59+
registers:
60+
- { id: 0, class: gpr }
61+
- { id: 1, class: gpr }
62+
- { id: 2, class: gpr }
63+
# CHECK: %0 = COPY %edi
64+
# CHECK-NEXT: %1 = COPY %esi
65+
# CHECK-NEXT: %2 = ADD32rr %0, %1
66+
body: |
67+
bb.1 (%ir-block.0):
68+
liveins: %edi, %esi
69+
70+
%0(s32) = COPY %edi
71+
%1(s32) = COPY %esi
72+
%2(s32) = G_ADD %0, %1
73+
74+
...
75+
76+
---
77+
name: test_sub_i64
78+
legalized: true
79+
regBankSelected: true
80+
# CHECK: registers:
81+
# CHECK-NEXT: - { id: 0, class: gr64 }
82+
# CHECK-NEXT: - { id: 1, class: gr64 }
83+
# CHECK-NEXT: - { id: 2, class: gr64 }
84+
registers:
85+
- { id: 0, class: gpr }
86+
- { id: 1, class: gpr }
87+
- { id: 2, class: gpr }
88+
# CHECK: %0 = COPY %rdi
89+
# CHECK-NEXT: %1 = COPY %rsi
90+
# CHECK-NEXT: %2 = SUB64rr %0, %1
91+
body: |
92+
bb.1 (%ir-block.0):
93+
liveins: %edi, %esi
94+
95+
%0(s64) = COPY %rdi
96+
%1(s64) = COPY %rsi
97+
%2(s64) = G_SUB %0, %1
98+
99+
...
100+
101+
---
102+
name: test_sub_i32
103+
legalized: true
104+
regBankSelected: true
105+
# CHECK: registers:
106+
# CHECK-NEXT: - { id: 0, class: gr32 }
107+
# CHECK-NEXT: - { id: 1, class: gr32 }
108+
# CHECK-NEXT: - { id: 2, class: gr32 }
109+
registers:
110+
- { id: 0, class: gpr }
111+
- { id: 1, class: gpr }
112+
- { id: 2, class: gpr }
113+
# CHECK: %0 = COPY %edi
114+
# CHECK-NEXT: %1 = COPY %esi
115+
# CHECK-NEXT: %2 = SUB32rr %0, %1
116+
body: |
117+
bb.1 (%ir-block.0):
118+
liveins: %edi, %esi
119+
120+
%0(s32) = COPY %edi
121+
%1(s32) = COPY %esi
122+
%2(s32) = G_SUB %0, %1
123+
124+
...

0 commit comments

Comments
 (0)
Please sign in to comment.