Index: lib/Target/X86/X86InstructionSelector.cpp =================================================================== --- lib/Target/X86/X86InstructionSelector.cpp +++ lib/Target/X86/X86InstructionSelector.cpp @@ -65,8 +65,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, @@ -235,7 +235,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; @@ -427,27 +427,37 @@ 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; else if (Ty == LLT::pointer(0, 32)) NewOpc = STI.isTarget64BitILP32() ? X86::LEA64_32r : X86::LEA32r; else - llvm_unreachable("Can't select G_FRAME_INDEX, unsupported type."); + llvm_unreachable("Can't select G_FRAME_INDEX/G_GEP, unsupported type."); 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 @@ -70,6 +70,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); @@ -114,6 +120,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/gep.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/gep.ll @@ -0,0 +1,136 @@ +; 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_i8(i32 *%arr, i8 %ind) { +; X64_GISEL-LABEL: test_gep_i8: +; X64_GISEL: # BB#0: +; X64_GISEL-NEXT: movq $4, %rax +; X64_GISEL-NEXT: movsbq %sil, %rcx +; X64_GISEL-NEXT: imulq %rax, %rcx +; X64_GISEL-NEXT: leaq (%rdi,%rcx), %rax +; X64_GISEL-NEXT: retq +; +; X64-LABEL: test_gep_i8: +; X64: # BB#0: +; X64-NEXT: # kill: %ESI %ESI %RSI +; X64-NEXT: movsbq %sil, %rax +; X64-NEXT: leaq (%rdi,%rax,4), %rax +; X64-NEXT: retq + %arrayidx = getelementptr i32, i32* %arr, i8 %ind + ret i32* %arrayidx +} + +define i32* @test_gep_i8_const(i32 *%arr) { +; X64_GISEL-LABEL: test_gep_i8_const: +; X64_GISEL: # BB#0: +; X64_GISEL-NEXT: movq $80, %rax +; X64_GISEL-NEXT: leaq (%rdi,%rax), %rax +; X64_GISEL-NEXT: retq +; +; X64-LABEL: test_gep_i8_const: +; X64: # BB#0: +; X64-NEXT: leaq 80(%rdi), %rax +; X64-NEXT: retq + %arrayidx = getelementptr i32, i32* %arr, i8 20 + ret i32* %arrayidx +} + +define i32* @test_gep_i16(i32 *%arr, i16 %ind) { +; X64_GISEL-LABEL: test_gep_i16: +; X64_GISEL: # BB#0: +; X64_GISEL-NEXT: movq $4, %rax +; X64_GISEL-NEXT: movswq %si, %rcx +; X64_GISEL-NEXT: imulq %rax, %rcx +; X64_GISEL-NEXT: leaq (%rdi,%rcx), %rax +; X64_GISEL-NEXT: retq +; +; X64-LABEL: test_gep_i16: +; X64: # BB#0: +; X64-NEXT: # kill: %ESI %ESI %RSI +; X64-NEXT: movswq %si, %rax +; X64-NEXT: leaq (%rdi,%rax,4), %rax +; X64-NEXT: retq + %arrayidx = getelementptr i32, i32* %arr, i16 %ind + ret i32* %arrayidx +} + +define i32* @test_gep_i16_const(i32 *%arr) { +; X64_GISEL-LABEL: test_gep_i16_const: +; X64_GISEL: # BB#0: +; X64_GISEL-NEXT: movq $80, %rax +; X64_GISEL-NEXT: leaq (%rdi,%rax), %rax +; X64_GISEL-NEXT: retq +; +; X64-LABEL: test_gep_i16_const: +; X64: # BB#0: +; X64-NEXT: leaq 80(%rdi), %rax +; X64-NEXT: retq + %arrayidx = getelementptr i32, i32* %arr, i16 20 + ret i32* %arrayidx +} + +define i32* @test_gep_i32(i32 *%arr, i32 %ind) { +; X64_GISEL-LABEL: test_gep_i32: +; X64_GISEL: # BB#0: +; X64_GISEL-NEXT: movq $4, %rax +; X64_GISEL-NEXT: movslq %esi, %rcx +; X64_GISEL-NEXT: imulq %rax, %rcx +; X64_GISEL-NEXT: leaq (%rdi,%rcx), %rax +; X64_GISEL-NEXT: retq +; +; X64-LABEL: test_gep_i32: +; X64: # BB#0: +; X64-NEXT: movslq %esi, %rax +; X64-NEXT: leaq (%rdi,%rax,4), %rax +; X64-NEXT: retq + %arrayidx = getelementptr i32, i32* %arr, i32 %ind + ret i32* %arrayidx +} + +define i32* @test_gep_i32_const(i32 *%arr) { +; X64_GISEL-LABEL: test_gep_i32_const: +; 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_const: +; 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, i64 %ind) { +; X64_GISEL-LABEL: test_gep_i64: +; X64_GISEL: # BB#0: +; X64_GISEL-NEXT: movq $4, %rax +; X64_GISEL-NEXT: imulq %rsi, %rax +; X64_GISEL-NEXT: leaq (%rdi,%rax), %rax +; X64_GISEL-NEXT: retq +; +; X64-LABEL: test_gep_i64: +; X64: # BB#0: +; X64-NEXT: leaq (%rdi,%rsi,4), %rax +; X64-NEXT: retq + %arrayidx = getelementptr i32, i32* %arr, i64 %ind + ret i32* %arrayidx +} + +define i32* @test_gep_i64_const(i32 *%arr) { +; X64_GISEL-LABEL: test_gep_i64_const: +; 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_const: +; 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,101 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s + +--- | + define void @test_gep_i8() { + %arrayidx = getelementptr i32, i32* undef, i8 5 + ret void + } + + define void @test_gep_i16() { + %arrayidx = getelementptr i32, i32* undef, i16 5 + ret void + } + + define void @test_gep_i32() { + %arrayidx = getelementptr i32, i32* undef, i32 5 + ret void + } + + define void @test_gep_i64() { + %arrayidx = getelementptr i32, i32* undef, i64 5 + ret void + } +... +--- +name: test_gep_i8 +# CHECK-LABEL: name: test_gep_i8 +legalized: false +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +# CHECK: %0(p0) = IMPLICIT_DEF +# CHECK-NEXT: %1(s8) = G_CONSTANT i8 20 +# CHECK-NEXT: %3(s32) = G_SEXT %1(s8) +# CHECK-NEXT: %2(p0) = G_GEP %0, %3(s32) +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + %0(p0) = IMPLICIT_DEF + %1(s8) = G_CONSTANT i8 20 + %2(p0) = G_GEP %0, %1(s8) + RET 0 +... +--- +name: test_gep_i16 +# CHECK-LABEL: name: test_gep_i16 +legalized: false +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +# CHECK: %0(p0) = IMPLICIT_DEF +# CHECK-NEXT: %1(s16) = G_CONSTANT i16 20 +# CHECK-NEXT: %3(s32) = G_SEXT %1(s16) +# CHECK-NEXT: %2(p0) = G_GEP %0, %3(s32) +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + %0(p0) = IMPLICIT_DEF + %1(s16) = G_CONSTANT i16 20 + %2(p0) = G_GEP %0, %1(s16) + RET 0 +... +--- +name: test_gep_i32 +# CHECK-LABEL: name: test_gep_i32 +legalized: false +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +# CHECK: %0(p0) = IMPLICIT_DEF +# CHECK-NEXT: %1(s32) = G_CONSTANT i32 20 +# CHECK-NEXT: %2(p0) = G_GEP %0, %1(s32) +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + %0(p0) = IMPLICIT_DEF + %1(s32) = G_CONSTANT i32 20 + %2(p0) = G_GEP %0, %1(s32) + RET 0 +... +--- +name: test_gep_i64 +# CHECK-LABEL: name: test_gep_i64 +legalized: false +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +# CHECK: %0(p0) = IMPLICIT_DEF +# CHECK-NEXT: %1(s64) = G_CONSTANT i64 20 +# CHECK-NEXT: %2(p0) = G_GEP %0, %1(s64) +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + %0(p0) = IMPLICIT_DEF + %1(s64) = G_CONSTANT i64 20 + %2(p0) = G_GEP %0, %1(s64) + RET 0 +... Index: test/CodeGen/X86/GlobalISel/regbankselect-X86_64.mir =================================================================== --- test/CodeGen/X86/GlobalISel/regbankselect-X86_64.mir +++ test/CodeGen/X86/GlobalISel/regbankselect-X86_64.mir @@ -114,6 +114,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 @@ -703,3 +709,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/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 + +...