Index: lib/Target/X86/X86InstructionSelector.cpp =================================================================== --- lib/Target/X86/X86InstructionSelector.cpp +++ lib/Target/X86/X86InstructionSelector.cpp @@ -68,8 +68,8 @@ MachineFunction &MF) const; bool selectLoadStoreOp(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const; - bool selectFrameIndex(MachineInstr &I, MachineRegisterInfo &MRI, - MachineFunction &MF) const; + bool selectFrameIndexOrGep(MachineInstr &I, MachineRegisterInfo &MRI, + MachineFunction &MF) const; bool selectConstant(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const; bool selectTrunc(MachineInstr &I, MachineRegisterInfo &MRI, @@ -229,7 +229,7 @@ return true; if (selectLoadStoreOp(I, MRI, MF)) return true; - if (selectFrameIndex(I, MRI, MF)) + if (selectFrameIndexOrGep(I, MRI, MF)) return true; if (selectConstant(I, MRI, MF)) return true; @@ -465,16 +465,18 @@ return constrainSelectedInstRegOperands(I, TII, TRI, RBI); } -bool X86InstructionSelector::selectFrameIndex(MachineInstr &I, - MachineRegisterInfo &MRI, - MachineFunction &MF) const { - if (I.getOpcode() != TargetOpcode::G_FRAME_INDEX) +bool X86InstructionSelector::selectFrameIndexOrGep(MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + unsigned Opc = I.getOpcode(); + + if (Opc != TargetOpcode::G_FRAME_INDEX && Opc != TargetOpcode::G_GEP) return false; const unsigned DefReg = I.getOperand(0).getReg(); LLT Ty = MRI.getType(DefReg); - // Use LEA to calculate frame index. + // Use LEA to calculate frame index and GEP unsigned NewOpc; if (Ty == LLT::pointer(0, 64)) NewOpc = X86::LEA64r; @@ -485,7 +487,15 @@ I.setDesc(TII.get(NewOpc)); MachineInstrBuilder MIB(MF, I); - addOffset(MIB, 0); + + if (Opc == TargetOpcode::G_FRAME_INDEX) { + addOffset(MIB, 0); + } else { + MachineOperand &InxOp = I.getOperand(2); + I.addOperand(InxOp); // set IndexReg + InxOp.ChangeToImmediate(1); // set Scale + MIB.addImm(0).addReg(0); + } return constrainSelectedInstRegOperands(I, TII, TRI, RBI); } Index: lib/Target/X86/X86LegalizerInfo.cpp =================================================================== --- lib/Target/X86/X86LegalizerInfo.cpp +++ lib/Target/X86/X86LegalizerInfo.cpp @@ -65,6 +65,12 @@ // Pointer-handling setAction({G_FRAME_INDEX, p0}, Legal); + setAction({G_GEP, p0}, Legal); + setAction({G_GEP, 1, s32}, Legal); + + for (auto Ty : {s1, s8, s16}) + setAction({G_GEP, 1, Ty}, WidenScalar); + // Constants for (auto Ty : {s8, s16, s32, p0}) setAction({TargetOpcode::G_CONSTANT, Ty}, Legal); @@ -100,6 +106,13 @@ // Pointer-handling setAction({G_FRAME_INDEX, p0}, Legal); + setAction({G_GEP, p0}, Legal); + setAction({G_GEP, 1, s32}, Legal); + setAction({G_GEP, 1, s64}, Legal); + + for (auto Ty : {s1, s8, s16}) + setAction({G_GEP, 1, Ty}, WidenScalar); + // Constants for (auto Ty : {s8, s16, s32, s64, p0}) setAction({TargetOpcode::G_CONSTANT, Ty}, Legal); Index: test/CodeGen/X86/GlobalISel/X86-regbankselect.mir =================================================================== --- test/CodeGen/X86/GlobalISel/X86-regbankselect.mir +++ test/CodeGen/X86/GlobalISel/X86-regbankselect.mir @@ -110,6 +110,12 @@ ret void } + define void @test_gep() { + %p1 = getelementptr i32, i32* undef, i32 5 + %p2 = getelementptr i32, i32* undef, i64 5 + ret void + } + ... --- name: test_add_i8 @@ -660,3 +666,29 @@ RET 0 ... +--- +name: test_gep +legalized: true +# CHECK-LABEL: name: test_gep +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gpr } +# CHECK-NEXT: - { id: 1, class: gpr } +# CHECK-NEXT: - { id: 2, class: gpr } +# CHECK-NEXT: - { id: 3, class: gpr } +# CHECK-NEXT: - { id: 4, class: gpr } +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } + - { id: 3, class: _ } + - { id: 4, class: _ } +body: | + bb.0 (%ir-block.0): + %0(p0) = IMPLICIT_DEF + %1(s32) = G_CONSTANT i32 20 + %2(p0) = G_GEP %0, %1(s32) + %3(s64) = G_CONSTANT i64 20 + %4(p0) = G_GEP %0, %3(s64) + RET 0 + +... Index: test/CodeGen/X86/GlobalISel/gep.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/gep.ll @@ -0,0 +1,34 @@ +; 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 --check-prefix=ALL --check-prefix=X64_GISEL +; RUN: llc -mtriple=x86_64-linux-gnu < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64 + +define i32* @test_gep_i32(i32 *%arr) { +; X64_GISEL-LABEL: test_gep_i32: +; X64_GISEL: # BB#0: +; X64_GISEL-NEXT: movq $20, %rax +; X64_GISEL-NEXT: leaq (%rdi,%rax), %rax +; X64_GISEL-NEXT: retq +; +; X64-LABEL: test_gep_i32: +; X64: # BB#0: +; X64-NEXT: leaq 20(%rdi), %rax +; X64-NEXT: retq + %arrayidx = getelementptr i32, i32* %arr, i32 5 + ret i32* %arrayidx +} + +define i32* @test_gep_i64(i32 *%arr) { +; X64_GISEL-LABEL: test_gep_i64: +; X64_GISEL: # BB#0: +; X64_GISEL-NEXT: movq $20, %rax +; X64_GISEL-NEXT: leaq (%rdi,%rax), %rax +; X64_GISEL-NEXT: retq +; +; X64-LABEL: test_gep_i64: +; X64: # BB#0: +; X64-NEXT: leaq 20(%rdi), %rax +; X64-NEXT: retq + %arrayidx = getelementptr i32, i32* %arr, i64 5 + ret i32* %arrayidx +} + Index: test/CodeGen/X86/GlobalISel/legalize-gep.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/legalize-gep.mir @@ -0,0 +1,32 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s + +--- | + define void @test_gep() { + %arrayidx = getelementptr i32, i32* undef, i32 5 + ret void + } + +... +--- +name: test_gep +# CHECK-LABEL: name: test_gep +legalized: false +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } + - { id: 3, class: _ } + - { id: 4, class: _ } +body: | + bb.1 (%ir-block.0): + %0(p0) = IMPLICIT_DEF + %1(s32) = G_CONSTANT i32 20 + ; CHECK: %2(p0) = G_GEP %0, %1(s32) + %2(p0) = G_GEP %0, %1(s32) + + %3(s64) = G_CONSTANT i64 20 + ; CHECK: %4(p0) = G_GEP %0, %3(s64) + %4(p0) = G_GEP %0, %3(s64) + RET 0 + +... Index: test/CodeGen/X86/GlobalISel/select-gep.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/select-gep.mir @@ -0,0 +1,37 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select %s -o - | FileCheck %s --check-prefix=CHECK + +--- | + define i32* @test_gep_i32(i32* %arr) { + %arrayidx = getelementptr i32, i32* %arr, i32 5 + ret i32* %arrayidx + } +... +--- +name: test_gep_i32 +alignment: 4 +legalized: true +regBankSelected: true +selected: false +# CHECK-LABEL: name: test_gep_i32 +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr64 } +# CHECK-NEXT: - { id: 1, class: gr64_nosp } +# CHECK-NEXT: - { id: 2, class: gr64 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } +# CHECK: body: +# CHECK: %1 = MOV64ri32 20 +# CHECK-NEXT: %2 = LEA64r %0, 1, %1, 0, _ +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(p0) = COPY %rdi + %1(s64) = G_CONSTANT i64 20 + %2(p0) = G_GEP %0, %1(s64) + %rax = COPY %2(p0) + RET 0, implicit %rax + +...