diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index 3c95f01b86361..c10c32e65a7fa 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -580,6 +580,23 @@ static void getOperandsForBranch(Register CondReg, RISCVCC::CondCode &CC, CC = getRISCVCCFromICmp(Pred); } +/// Select the RISC-V opcode for the G_LOAD or G_STORE operation \p GenericOpc, +/// appropriate for the (value) register bank \p RegBankID and of memory access +/// size \p OpSize. +/// \returns \p GenericOpc if the combination is unsupported. +static unsigned selectLoadStoreOp(unsigned GenericOpc, unsigned RegBankID, + unsigned OpSize) { + const bool IsStore = GenericOpc == TargetOpcode::G_STORE; + if (RegBankID == RISCV::GPRBRegBankID) { + switch (OpSize) { + case 16: + return IsStore ? RISCV::SH : RISCV::LH; + } + } + + return GenericOpc; +} + bool RISCVInstructionSelector::select(MachineInstr &MI) { MachineBasicBlock &MBB = *MI.getParent(); MachineFunction &MF = *MBB.getParent(); @@ -786,6 +803,54 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) { return selectMergeValues(MI, MIB); case TargetOpcode::G_UNMERGE_VALUES: return selectUnmergeValues(MI, MIB); + case TargetOpcode::G_LOAD: + case TargetOpcode::G_STORE: { + GLoadStore &LdSt = cast(MI); + LLT PtrTy = MRI->getType(LdSt.getPointerReg()); + + if (PtrTy != LLT::pointer(0, STI.getXLen())) { + LLVM_DEBUG(dbgs() << "Load/Store pointer has type: " << PtrTy + << ", expected: " << LLT::pointer(0, STI.getXLen()) + << '\n'); + return false; + } + +#ifndef NDEBUG + const RegisterBank &PtrRB = + *RBI.getRegBank(LdSt.getPointerReg(), *MRI, TRI); + // Check that the pointer register is valid. + assert(PtrRB.getID() == RISCV::GPRBRegBankID && + "Load/Store pointer operand isn't a GPR"); +#endif + + unsigned MemSizeInBits = LdSt.getMemSizeInBits().getValue(); + + const Register ValReg = LdSt.getReg(0); + const RegisterBank &RB = *RBI.getRegBank(ValReg, *MRI, TRI); + + const unsigned NewOpc = + selectLoadStoreOp(MI.getOpcode(), RB.getID(), MemSizeInBits); + if (NewOpc == MI.getOpcode()) + return false; + + // Check if we can fold anything into the addressing mode. + auto AddrModeFns = selectAddrRegImm(MI.getOperand(1)); + if (!AddrModeFns) + return false; + + // Folded something. Create a new instruction and return it. + auto NewInst = MIB.buildInstr(NewOpc, {}, {}, MI.getFlags()); + if (isa(MI)) + NewInst.addUse(ValReg); + else + NewInst.addDef(ValReg); + NewInst.cloneMemRefs(MI); + for (auto &Fn : *AddrModeFns) + Fn(NewInst); + MI.eraseFromParent(); + + return constrainSelectedInstRegOperands(*NewInst, TII, TRI, RBI); + } default: return false; } diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/load-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/load-rv32.mir index 36c604d4f5c52..3964fd1a918aa 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/load-rv32.mir +++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/load-rv32.mir @@ -1,6 +1,6 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -mtriple=riscv32 -run-pass=instruction-select %s -o - \ -# RUN: | FileCheck %s +# RUN: -disable-gisel-legality-check | FileCheck %s --- name: load_i8 @@ -45,6 +45,29 @@ body: | $x10 = COPY %1(s32) PseudoRET implicit $x10 +... +--- +name: load_i16_i16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: load_i16_i16 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[LH:%[0-9]+]]:gpr = LH [[COPY]], 0 :: (load (s16)) + ; CHECK-NEXT: $x10 = COPY [[LH]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(p0) = COPY $x10 + %1:gprb(s16) = G_LOAD %0(p0) :: (load (s16)) + %2:gprb(s32) = G_ANYEXT %1 + $x10 = COPY %2(s32) + PseudoRET implicit $x10 + ... --- name: load_i32 diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/load-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/load-rv64.mir index 647e1e5287a80..70dd2bfee28ba 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/load-rv64.mir +++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/load-rv64.mir @@ -1,6 +1,6 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -mtriple=riscv64 -run-pass=instruction-select %s -o - \ -# RUN: | FileCheck %s +# RUN: -disable-gisel-legality-check | FileCheck %s --- name: load_i8_i64 @@ -45,6 +45,29 @@ body: | $x10 = COPY %1(s64) PseudoRET implicit $x10 +... +--- +name: load_i16_i16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: load_i16_i16 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[LH:%[0-9]+]]:gpr = LH [[COPY]], 0 :: (load (s16)) + ; CHECK-NEXT: $x10 = COPY [[LH]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(p0) = COPY $x10 + %1:gprb(s16) = G_LOAD %0(p0) :: (load (s16)) + %2:gprb(s64) = G_ANYEXT %1 + $x10 = COPY %2(s64) + PseudoRET implicit $x10 + ... --- name: load_i32_i64 diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/store-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/store-rv32.mir index e4111417ece67..f1cc69517cf8f 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/store-rv32.mir +++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/store-rv32.mir @@ -1,6 +1,6 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -mtriple=riscv32 -run-pass=instruction-select %s -o - \ -# RUN: | FileCheck %s +# RUN: -disable-gisel-legality-check | FileCheck %s # --- name: store_i8 @@ -45,6 +45,29 @@ body: | G_STORE %0(s32), %1(p0) :: (store (s16)) PseudoRET +... +--- +name: store_i16_i16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11 + + ; CHECK-LABEL: name: store_i16_i16 + ; CHECK: liveins: $x10, $x11 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: SH [[COPY]], [[COPY1]], 0 :: (store (s16)) + ; CHECK-NEXT: PseudoRET + %0:gprb(s32) = COPY $x10 + %1:gprb(p0) = COPY $x11 + %2:gprb(s16) = G_TRUNC %0 + G_STORE %2(s16), %1(p0) :: (store (s16)) + PseudoRET + ... --- name: store_i32 diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/store-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/store-rv64.mir index 385a330a97a17..69f590c1df597 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/store-rv64.mir +++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/store-rv64.mir @@ -1,6 +1,6 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -mtriple=riscv64 -run-pass=instruction-select %s -o - \ -# RUN: | FileCheck %s +# RUN: -disable-gisel-legality-check | FileCheck %s --- name: store_i8_i64 @@ -45,6 +45,29 @@ body: | G_STORE %0(s64), %1(p0) :: (store (s16)) PseudoRET +... +--- +name: store_i16_i16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11 + + ; CHECK-LABEL: name: store_i16_i16 + ; CHECK: liveins: $x10, $x11 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: SH [[COPY]], [[COPY1]], 0 :: (store (s16)) + ; CHECK-NEXT: PseudoRET + %0:gprb(s64) = COPY $x10 + %1:gprb(p0) = COPY $x11 + %2:gprb(s16) = G_TRUNC %0 + G_STORE %2(s16), %1(p0) :: (store (s16)) + PseudoRET + ... --- name: store_i32_i64