diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -11,11 +11,13 @@ /// \todo This should be generated by TableGen. //===----------------------------------------------------------------------===// +#include "MCTargetDesc/RISCVMatInt.h" #include "RISCVRegisterBankInfo.h" #include "RISCVSubtarget.h" #include "RISCVTargetMachine.h" #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h" #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/IR/IntrinsicsRISCV.h" #include "llvm/Support/Debug.h" @@ -35,7 +37,9 @@ const RISCVSubtarget &STI, const RISCVRegisterBankInfo &RBI); - bool select(MachineInstr &I) override; + bool select(MachineInstr &MI) override; + bool selectConstant(MachineInstr &MI, MachineIRBuilder &MIB, + MachineRegisterInfo &MRI); static const char *getName() { return DEBUG_TYPE; } private: @@ -80,17 +84,91 @@ { } -bool RISCVInstructionSelector::select(MachineInstr &I) { +bool RISCVInstructionSelector::select(MachineInstr &MI) { + unsigned Opc = MI.getOpcode(); + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + MachineIRBuilder MIB(MF); - if (!isPreISelGenericOpcode(I.getOpcode())) { + if (!isPreISelGenericOpcode(MI.getOpcode())) { // Certain non-generic instructions also need some special handling. return true; } - if (selectImpl(I, *CoverageInfo)) + if (selectImpl(MI, *CoverageInfo)) return true; - return false; + MIB.setInstrAndDebugLoc(MI); + + switch (Opc) { + case TargetOpcode::G_CONSTANT: + if (!selectConstant(MI, MIB, MRI)) + return false; + break; + default: + return false; + } + + MI.eraseFromParent(); + + return true; +} + +bool RISCVInstructionSelector::selectConstant(MachineInstr &MI, + MachineIRBuilder &MIB, + MachineRegisterInfo &MRI) { + assert(MI.getOpcode() == TargetOpcode::G_CONSTANT); + Register FinalReg = MI.getOperand(0).getReg(); + int64_t Imm = MI.getOperand(1).getCImm()->getSExtValue(); + + RISCVMatInt::InstSeq Seq = + RISCVMatInt::generateInstSeq(Imm, Subtarget->getFeatureBits()); + unsigned NumInsts = Seq.size(); + Register SrcReg = RISCV::X0; + + for (unsigned i = 0; i < NumInsts; i++) { + Register DstReg = i < NumInsts - 1 + ? MRI.createVirtualRegister(&RISCV::GPRRegClass) + : FinalReg; + const RISCVMatInt::Inst I = Seq[i]; + MachineInstr *Result; + + switch (I.getOpndKind()) { + case RISCVMatInt::Imm: + // clang-format off + Result = MIB.buildInstr(I.getOpcode()) + .addDef(DstReg) + .addImm(I.getImm()); + // clang-format on + break; + case RISCVMatInt::RegX0: + Result = MIB.buildInstr(I.getOpcode()) + .addDef(DstReg) + .addReg(SrcReg) + .addReg(RISCV::X0); + break; + case RISCVMatInt::RegReg: + Result = MIB.buildInstr(I.getOpcode()) + .addDef(DstReg) + .addReg(SrcReg) + .addReg(SrcReg); + break; + case RISCVMatInt::RegImm: + Result = MIB.buildInstr(I.getOpcode()) + .addDef(DstReg) + .addReg(SrcReg) + .addImm(I.getImm()); + break; + } + + if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI)) + return false; + + SrcReg = DstReg; + } + + return true; } namespace llvm { diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/constant32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/constant32.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/constant32.mir @@ -0,0 +1,125 @@ +# 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 +--- +name: const_i32_INT_MIN +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i32_INT_MIN + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[LUI:%[0-9]+]]:gpr = LUI 524288 + ; CHECK-NEXT: $x10 = COPY [[LUI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = G_CONSTANT i32 -2147483648 + $x10 = COPY %0(s32) + PseudoRET implicit $x10 + +... +--- +name: const_i32_neg_2147483000 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i32_neg_2147483000 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[LUI:%[0-9]+]]:gpr = LUI 524288 + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[LUI]], 648 + ; CHECK-NEXT: $x10 = COPY [[ADDI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = G_CONSTANT i32 -2147483000 + $x10 = COPY %0(s32) + PseudoRET implicit $x10 + +... +--- +name: const_i32_INT_MAX +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i32_INT_MAX + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[LUI:%[0-9]+]]:gpr = LUI 524288 + ; CHECK-NEXT: $x10 = COPY [[LUI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = G_CONSTANT i32 2147483648 + $x10 = COPY %0(s32) + PseudoRET implicit $x10 + +... +--- +name: const_i32_2147483000 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i32_2147483000 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[LUI:%[0-9]+]]:gpr = LUI 524288 + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[LUI]], -648 + ; CHECK-NEXT: $x10 = COPY [[ADDI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = G_CONSTANT i32 2147483000 + $x10 = COPY %0(s32) + PseudoRET implicit $x10 + +... +--- +name: const_i32_256 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i32_256 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 256 + ; CHECK-NEXT: $x10 = COPY [[ADDI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = G_CONSTANT i32 256 + $x10 = COPY %0(s32) + PseudoRET implicit $x10 + +... +--- +name: const_i32_0 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i32_0 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 0 + ; CHECK-NEXT: $x10 = COPY [[ADDI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = G_CONSTANT i32 0 + $x10 = COPY %0(s32) + PseudoRET implicit $x10 + +... diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/constant64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/constant64.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/constant64.mir @@ -0,0 +1,128 @@ +# 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 +--- +name: const_i64_INT_MIN +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i64_INT_MIN + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, -1 + ; CHECK-NEXT: [[SLLI:%[0-9]+]]:gpr = SLLI [[ADDI]], 63 + ; CHECK-NEXT: $x10 = COPY [[SLLI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = G_CONSTANT i64 -9223372036854775808 + $x10 = COPY %0(s64) + PseudoRET implicit $x10 + +... +--- +name: const_i64_neg_9223372036854775000 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i64_neg_9223372036854775000 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, -1 + ; CHECK-NEXT: [[SLLI:%[0-9]+]]:gpr = SLLI [[ADDI]], 63 + ; CHECK-NEXT: [[ADDI1:%[0-9]+]]:gpr = ADDI [[SLLI]], 808 + ; CHECK-NEXT: $x10 = COPY [[ADDI1]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = G_CONSTANT i64 -9223372036854775000 + $x10 = COPY %0(s64) + PseudoRET implicit $x10 + +... +--- +name: const_i64_INT_MAX +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i64_INT_MAX + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, -1 + ; CHECK-NEXT: [[SRLI:%[0-9]+]]:gpr = SRLI [[ADDI]], 1 + ; CHECK-NEXT: $x10 = COPY [[SRLI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = G_CONSTANT i64 9223372036854775807 + $x10 = COPY %0(s64) + PseudoRET implicit $x10 + +... +--- +name: const_i64_9223372036854775000 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i64_9223372036854775000 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, -1615 + ; CHECK-NEXT: [[SRLI:%[0-9]+]]:gpr = SRLI [[ADDI]], 1 + ; CHECK-NEXT: $x10 = COPY [[SRLI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = G_CONSTANT i64 9223372036854775000 + $x10 = COPY %0(s64) + PseudoRET implicit $x10 + +... +--- +name: const_i64_256 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i64_256 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 256 + ; CHECK-NEXT: $x10 = COPY [[ADDI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = G_CONSTANT i64 256 + $x10 = COPY %0(s64) + PseudoRET implicit $x10 + +... +--- +name: const_i64_0 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; CHECK-LABEL: name: const_i64_0 + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 0 + ; CHECK-NEXT: $x10 = COPY [[ADDI]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = G_CONSTANT i64 0 + $x10 = COPY %0(s64) + PseudoRET implicit $x10 + +...