llvm.org GIT mirror llvm / b1879fb
[ARM] GlobalISel: Select add i32, i32 Add the minimal support necessary to select a function that returns the sum of two i32 values. This includes some support for argument/return lowering of i32 values through registers, as well as the handling of copy and add instructions throughout the GlobalISel pipeline. Differential Revision: https://reviews.llvm.org/D26677 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289940 91177308-0d34-0410-b5e6-96231b3b80d8 Diana Picus 3 years ago
13 changed file(s) with 429 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
4242 if (TRI.isPhysicalRegister(MO.getReg()))
4343 continue;
4444
45 // Register operands with a value of 0 (e.g. predicate operands) don't need
46 // to be constrained.
47 if (MO.getReg() == 0)
48 continue;
49
4550 const TargetRegisterClass *RC = TII.getRegClass(I.getDesc(), OpI, &TRI, MF);
4651 assert(RC && "Selected inst should have regclass operand");
4752
2828 ARMCallLowering::ARMCallLowering(const ARMTargetLowering &TLI)
2929 : CallLowering(&TLI) {}
3030
31 static bool isSupportedType(const DataLayout DL, const ARMTargetLowering &TLI,
32 Type *T) {
33 EVT VT = TLI.getValueType(DL, T);
34 return VT.isSimple() && VT.isInteger() &&
35 VT.getSimpleVT().getSizeInBits() == 32;
36 }
37
38 namespace {
39 struct FuncReturnHandler : public CallLowering::ValueHandler {
40 FuncReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
41 MachineInstrBuilder &MIB)
42 : ValueHandler(MIRBuilder, MRI), MIB(MIB) {}
43
44 unsigned getStackAddress(uint64_t Size, int64_t Offset,
45 MachinePointerInfo &MPO) override {
46 llvm_unreachable("Don't know how to get a stack address yet");
47 }
48
49 void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
50 CCValAssign &VA) override {
51 assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
52 assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
53
54 assert(VA.getValVT().getSizeInBits() == 32 && "Unsupported value size");
55 assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
56
57 MIRBuilder.buildCopy(PhysReg, ValVReg);
58 MIB.addUse(PhysReg, RegState::Implicit);
59 }
60
61 void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
62 MachinePointerInfo &MPO, CCValAssign &VA) override {
63 llvm_unreachable("Don't know how to assign a value to an address yet");
64 }
65
66 MachineInstrBuilder &MIB;
67 };
68 } // End anonymous namespace.
69
70 /// Lower the return value for the already existing \p Ret. This assumes that
71 /// \p MIRBuilder's insertion point is correct.
72 bool ARMCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
73 const Value *Val, unsigned VReg,
74 MachineInstrBuilder &Ret) const {
75 if (!Val)
76 // Nothing to do here.
77 return true;
78
79 auto &MF = MIRBuilder.getMF();
80 const auto &F = *MF.getFunction();
81
82 auto DL = MF.getDataLayout();
83 auto &TLI = *getTLI();
84 if (!isSupportedType(DL, TLI, Val->getType()))
85 return false;
86
87 CCAssignFn *AssignFn =
88 TLI.CCAssignFnForReturn(F.getCallingConv(), F.isVarArg());
89
90 ArgInfo RetInfo(VReg, Val->getType());
91 setArgFlags(RetInfo, AttributeSet::ReturnIndex, DL, F);
92
93 FuncReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret);
94 return handleAssignments(MIRBuilder, AssignFn, RetInfo, RetHandler);
95 }
96
3197 bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
3298 const Value *Val, unsigned VReg) const {
33 // We're currently only handling void returns
34 if (Val != nullptr)
99 assert(!Val == !VReg && "Return value without a vreg");
100
101 auto Ret = AddDefaultPred(MIRBuilder.buildInstrNoInsert(ARM::BX_RET));
102
103 if (!lowerReturnVal(MIRBuilder, Val, VReg, Ret))
35104 return false;
36105
37 AddDefaultPred(MIRBuilder.buildInstr(ARM::BX_RET));
38
106 MIRBuilder.insertInstr(Ret);
39107 return true;
40108 }
109
110 namespace {
111 struct FormalArgHandler : public CallLowering::ValueHandler {
112 FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
113 : ValueHandler(MIRBuilder, MRI) {}
114
115 unsigned getStackAddress(uint64_t Size, int64_t Offset,
116 MachinePointerInfo &MPO) override {
117 llvm_unreachable("Don't know how to get a stack address yet");
118 }
119
120 void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
121 CCValAssign &VA) override {
122 assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
123 assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
124
125 assert(VA.getValVT().getSizeInBits() == 32 && "Unsupported value size");
126 assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
127
128 MIRBuilder.getMBB().addLiveIn(PhysReg);
129 MIRBuilder.buildCopy(ValVReg, PhysReg);
130 }
131
132 void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
133 MachinePointerInfo &MPO, CCValAssign &VA) override {
134 llvm_unreachable("Don't know how to assign a value to an address yet");
135 }
136 };
137 } // End anonymous namespace
41138
42139 bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
43140 const Function &F,
44141 ArrayRef VRegs) const {
45 return F.arg_empty();
142 // Quick exit if there aren't any args
143 if (F.arg_empty())
144 return true;
145
146 // Stick to only 4 arguments for now
147 if (F.arg_size() > 4)
148 return false;
149
150 if (F.isVarArg())
151 return false;
152
153 auto DL = MIRBuilder.getMF().getDataLayout();
154 auto &TLI = *getTLI();
155
156 auto &Args = F.getArgumentList();
157 for (auto &Arg : Args)
158 if (!isSupportedType(DL, TLI, Arg.getType()))
159 return false;
160
161 CCAssignFn *AssignFn =
162 TLI.CCAssignFnForCall(F.getCallingConv(), F.isVarArg());
163
164 SmallVector ArgInfos;
165 unsigned Idx = 0;
166 for (auto &Arg : Args) {
167 ArgInfo AInfo(VRegs[Idx], Arg.getType());
168 setArgFlags(AInfo, Idx + 1, DL, F);
169 ArgInfos.push_back(AInfo);
170 Idx++;
171 }
172
173 FormalArgHandler ArgHandler(MIRBuilder, MIRBuilder.getMF().getRegInfo());
174 return handleAssignments(MIRBuilder, AssignFn, ArgInfos, ArgHandler);
46175 }
2121 namespace llvm {
2222
2323 class ARMTargetLowering;
24 class MachineInstrBuilder;
2425
2526 class ARMCallLowering : public CallLowering {
2627 public:
3132
3233 bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
3334 ArrayRef VRegs) const override;
35
36 private:
37 bool lowerReturnVal(MachineIRBuilder &MIRBuilder, const Value *Val,
38 unsigned VReg, MachineInstrBuilder &Ret) const;
3439 };
3540 } // End of namespace llvm
3641 #endif
1414 #include "ARMRegisterBankInfo.h"
1515 #include "ARMSubtarget.h"
1616 #include "ARMTargetMachine.h"
17 #include "llvm/CodeGen/MachineRegisterInfo.h"
1718 #include "llvm/Support/Debug.h"
1819
1920 #define DEBUG_TYPE "arm-isel"
2728 ARMInstructionSelector::ARMInstructionSelector(const ARMSubtarget &STI,
2829 const ARMRegisterBankInfo &RBI)
2930 : InstructionSelector(), TII(*STI.getInstrInfo()),
30 TRI(*STI.getRegisterInfo()) {}
31 TRI(*STI.getRegisterInfo()), RBI(RBI) {}
3132
32 bool ARMInstructionSelector::select(llvm::MachineInstr &I) const {
33 return !isPreISelGenericOpcode(I.getOpcode());
33 static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
34 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
35 const RegisterBankInfo &RBI) {
36 unsigned DstReg = I.getOperand(0).getReg();
37 if (TargetRegisterInfo::isPhysicalRegister(DstReg))
38 return true;
39
40 const RegisterBank *RegBank = RBI.getRegBank(DstReg, MRI, TRI);
41 assert(RegBank && "Can't get reg bank for virtual register");
42
43 const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
44 unsigned SrcReg = I.getOperand(1).getReg();
45 const unsigned SrcSize = RBI.getSizeInBits(SrcReg, MRI, TRI);
46 (void)SrcSize;
47 assert(DstSize == SrcSize && "Copy with different width?!");
48
49 assert(RegBank->getID() == ARM::GPRRegBankID && "Unsupported reg bank");
50 const TargetRegisterClass *RC = &ARM::GPRRegClass;
51
52 // No need to constrain SrcReg. It will get constrained when
53 // we hit another of its uses or its defs.
54 // Copies do not have constraints.
55 if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
56 DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
57 << " operand\n");
58 return false;
59 }
60 return true;
3461 }
62
63 bool ARMInstructionSelector::select(MachineInstr &I) const {
64 assert(I.getParent() && "Instruction should be in a basic block!");
65 assert(I.getParent()->getParent() && "Instruction should be in a function!");
66
67 auto &MBB = *I.getParent();
68 auto &MF = *MBB.getParent();
69 auto &MRI = MF.getRegInfo();
70
71 if (!isPreISelGenericOpcode(I.getOpcode())) {
72 if (I.isCopy())
73 return selectCopy(I, TII, MRI, TRI, RBI);
74
75 return true;
76 }
77
78 if (I.getOpcode() == TargetOpcode::G_ADD) {
79 I.setDesc(TII.get(ARM::ADDrr));
80 AddDefaultCC(AddDefaultPred(MachineInstrBuilder(MF, I)));
81 return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
82 }
83
84 return false;
85 }
3131 private:
3232 const ARMBaseInstrInfo &TII;
3333 const ARMBaseRegisterInfo &TRI;
34 const ARMRegisterBankInfo &RBI;
3435 };
3536
3637 } // End llvm namespace.
2323 #endif
2424
2525 ARMLegalizerInfo::ARMLegalizerInfo() {
26 using namespace TargetOpcode;
27 const LLT s32 = LLT::scalar(32);
28
29 setAction({G_ADD, s32}, Legal);
30
2631 computeTables();
2732 }
1111 //===----------------------------------------------------------------------===//
1212
1313 #include "ARMRegisterBankInfo.h"
14 #include "ARMInstrInfo.h" // For the register classes
1415 #include "llvm/CodeGen/GlobalISel/RegisterBank.h"
1516 #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
1617 #include "llvm/CodeGen/MachineRegisterInfo.h"
2223 #error "You shouldn't build this"
2324 #endif
2425
26 // FIXME: TableGen this.
27 // If it grows too much and TableGen still isn't ready to do the job, extract it
28 // into an ARMGenRegisterBankInfo.def (similar to AArch64).
29 namespace llvm {
30 namespace ARM {
31 RegisterBank GPRRegBank;
32 RegisterBank *RegBanks[] = {&GPRRegBank};
33
34 RegisterBankInfo::PartialMapping GPRPartialMapping{0, 32, GPRRegBank};
35
36 RegisterBankInfo::ValueMapping ValueMappings[] = {
37 {&GPRPartialMapping, 1}, {&GPRPartialMapping, 1}, {&GPRPartialMapping, 1}};
38 } // end namespace arm
39 } // end namespace llvm
40
2541 ARMRegisterBankInfo::ARMRegisterBankInfo(const TargetRegisterInfo &TRI)
26 : RegisterBankInfo(nullptr, 0) {}
42 : RegisterBankInfo(ARM::RegBanks, ARM::NumRegisterBanks) {
43 static bool AlreadyInit = false;
44 // We have only one set of register banks, whatever the subtarget
45 // is. Therefore, the initialization of the RegBanks table should be
46 // done only once. Indeed the table of all register banks
47 // (ARM::RegBanks) is unique in the compiler. At some point, it
48 // will get tablegen'ed and the whole constructor becomes empty.
49 if (AlreadyInit)
50 return;
51 AlreadyInit = true;
52
53 // Initialize the GPR bank.
54 createRegisterBank(ARM::GPRRegBankID, "GPRB");
55
56 addRegBankCoverage(ARM::GPRRegBankID, ARM::GPRRegClassID, TRI);
57 addRegBankCoverage(ARM::GPRRegBankID, ARM::GPRwithAPSRRegClassID, TRI);
58 const RegisterBank &RBGPR = getRegBank(ARM::GPRRegBankID);
59 (void)RBGPR;
60 assert(&ARM::GPRRegBank == &RBGPR && "The order in RegBanks is messed up");
61 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRRegClassID)) &&
62 "Subclass not added?");
63 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRwithAPSRRegClassID)) &&
64 "Subclass not added?");
65 assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRnopcRegClassID)) &&
66 "Subclass not added?");
67 assert(RBGPR.covers(*TRI.getRegClass(ARM::rGPRRegClassID)) &&
68 "Subclass not added?");
69 assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPRRegClassID)) &&
70 "Subclass not added?");
71 assert(RBGPR.covers(*TRI.getRegClass(ARM::tcGPRRegClassID)) &&
72 "Subclass not added?");
73 assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPR_and_tcGPRRegClassID)) &&
74 "Subclass not added?");
75 assert(RBGPR.getSize() == 32 && "GPRs should hold up to 32-bit");
76 }
77
78 const RegisterBank &ARMRegisterBankInfo::getRegBankFromRegClass(
79 const TargetRegisterClass &RC) const {
80 using namespace ARM;
81
82 switch (RC.getID()) {
83 case GPRRegClassID:
84 case tGPR_and_tcGPRRegClassID:
85 return getRegBank(ARM::GPRRegBankID);
86 default:
87 llvm_unreachable("Unsupported register kind");
88 }
89
90 llvm_unreachable("Switch should handle all register classes");
91 }
92
93 RegisterBankInfo::InstructionMapping
94 ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
95 auto Opc = MI.getOpcode();
96
97 // Try the default logic for non-generic instructions that are either copies
98 // or already have some operands assigned to banks.
99 if (!isPreISelGenericOpcode(Opc)) {
100 InstructionMapping Mapping = getInstrMappingImpl(MI);
101 if (Mapping.isValid())
102 return Mapping;
103 }
104
105 if (Opc == TargetOpcode::G_ADD) {
106 unsigned NumOperands = MI.getNumOperands();
107 ValueMapping *OperandsMapping = &ARM::ValueMappings[0];
108 return InstructionMapping{DefaultMappingID, /*Cost=*/1, OperandsMapping,
109 NumOperands};
110 }
111
112 return InstructionMapping{};
113 }
1919
2020 class TargetRegisterInfo;
2121
22 namespace ARM {
23 enum {
24 GPRRegBankID = 0, // General purpose registers
25 NumRegisterBanks,
26 };
27 } // end namespace ARM
28
2229 /// This class provides the information for the target register banks.
2330 class ARMRegisterBankInfo final : public RegisterBankInfo {
2431 public:
2532 ARMRegisterBankInfo(const TargetRegisterInfo &TRI);
33
34 const RegisterBank &
35 getRegBankFromRegClass(const TargetRegisterClass &RC) const override;
36
37 InstructionMapping getInstrMapping(const MachineInstr &MI) const override;
2638 };
2739 } // End llvm namespace.
2840 #endif
0 # RUN: llc -O0 -mtriple arm-- -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
1 --- |
2 define void @test_adds32() { ret void }
3 ...
4 ---
5 name: test_adds32
6 # CHECK-LABEL: name: test_adds32
7 legalized: true
8 regBankSelected: true
9 selected: false
10 # CHECK: selected: true
11 registers:
12 - { id: 0, class: gprb }
13 - { id: 1, class: gprb }
14 - { id: 2, class: gprb }
15 #CHECK: id: 0, class: gpr
16 #CHECK: id: 1, class: gpr
17 #CHECK: id: 2, class: gpr
18 body: |
19 bb.0:
20 liveins: %r0, %r1
21
22 %0(s32) = COPY %r0
23 ; CHECK: [[VREGX:%[0-9]+]] = COPY %r0
24
25 %1(s32) = COPY %r1
26 ; CHECK: [[VREGY:%[0-9]+]] = COPY %r1
27
28 %2(s32) = G_ADD %0, %1
29 ; CHECK: [[VREGSUM:%[0-9]+]] = ADDrr [[VREGX]], [[VREGY]], 14, _, _
30
31 %r0 = COPY %2(s32)
32 ; CHECK: %r0 = COPY [[VREGSUM]]
33
34 BX_RET 14, _, implicit %r0
35 ; CHECK: BX_RET 14, _, implicit %r0
36 ...
66 ret void
77 }
88
9 define i32 @test_add(i32 %x, i32 %y) {
10 ; CHECK-LABEL: name: test_add
11 ; CHECK: liveins: %r0, %r1
12 ; CHECK: [[VREGX:%[0-9]+]]{{.*}} = COPY %r0
13 ; CHECK: [[VREGY:%[0-9]+]]{{.*}} = COPY %r1
14 ; CHECK: [[SUM:%[0-9]+]]{{.*}} = G_ADD [[VREGX]], [[VREGY]]
15 ; CHECK: %r0 = COPY [[SUM]]
16 ; CHECK: BX_RET 14, _, implicit %r0
17 entry:
18 %sum = add i32 %x, %y
19 ret i32 %sum
20 }
0 ; RUN: llc -mtriple arm-unknown -global-isel %s -o - | FileCheck %s
1
2 define void @test_void_return() {
3 ; CHECK-LABEL: test_void_return:
4 ; CHECK: bx lr
5 entry:
6 ret void
7 }
8
9 define i32 @test_add(i32 %x, i32 %y) {
10 ; CHECK-LABEL: test_add:
11 ; CHECK: add r0, r0, r1
12 ; CHECK: bx lr
13 entry:
14 %sum = add i32 %x, %y
15 ret i32 %sum
16 }
0 # RUN: llc -mtriple arm-- -global-isel -run-pass=legalizer %s -o - | FileCheck %s
1 --- |
2 define void @test_add_s32() { ret void }
3 ...
4 ---
5 name: test_add_s32
6 # CHECK-LABEL: name: test_add_s32
7 legalized: false
8 # CHECK: legalized: true
9 regBankSelected: false
10 selected: false
11 tracksRegLiveness: true
12 registers:
13 - { id: 0, class: _ }
14 - { id: 1, class: _ }
15 - { id: 2, class: _ }
16 body: |
17 bb.0:
18 liveins: %r0, %r1
19
20 %0(s32) = COPY %r0
21 %1(s32) = COPY %r1
22 %2(s32) = G_ADD %0, %1
23 ; G_ADD with s32 is legal, so we should find it unchanged in the output
24 ; CHECK: {{%[0-9]+}}(s32) = G_ADD {{%[0-9]+, %[0-9]+}}
25 %r0 = COPY %2(s32)
26 BX_RET 14, _, implicit %r0
27
28 ...
0 # RUN: llc -mtriple arm-- -global-isel -run-pass=regbankselect %s -o - | FileCheck %s
1 --- |
2 define void @test_add_s32() { ret void }
3 ...
4 ---
5 name: test_add_s32
6 # CHECK-LABEL: name: test_add_s32
7 legalized: true
8 regBankSelected: false
9 selected: false
10 # CHECK: registers:
11 # CHECK: - { id: 0, class: gprb }
12 # CHECK: - { id: 1, class: gprb }
13 # CHECK: - { id: 2, class: gprb }
14
15 registers:
16 - { id: 0, class: _ }
17 - { id: 1, class: _ }
18 - { id: 2, class: _ }
19 body: |
20 bb.0:
21 liveins: %r0, %r1
22
23 %0(s32) = COPY %r0
24 %1(s32) = COPY %r1
25 %2(s32) = G_ADD %0, %1
26 %r0 = COPY %2(s32)
27 BX_RET 14, _, implicit %r0
28
29 ...