Skip to content

Commit

Permalink
[RISCV] Initial infrastructure for code generation of the RISC-V V-ex…
Browse files Browse the repository at this point in the history
…tension

The companion RFC (http://lists.llvm.org/pipermail/llvm-dev/2020-October/145850.html) gives lots of details on the overall strategy, but we summarize it here:

LLVM IR involving vector types is going to be selected using pseudo instructions (only MachineInstr). These pseudo instructions contain dummy operands to represent the vector type being operated and the vector length for the operation.
These two dummy operands, as set by instruction selection, will be used by the custom inserter to prepend every operation with an appropriate vsetvli instruction that ensures the vector architecture is properly configured for the operation. Not in this patch: later passes will remove the redundant vsetvli instructions.
Register classes of tuples of vector registers are used to represent vector register groups (LMUL > 1).
Those pseudos are eventually lowered into the actual instructions when emitting the MCInsts.
About the patch:

Because there is a bit of initial infrastructure required, this is the minimal patch that allows us to select instructions for 3 LLVM IR instructions: load, add and store vectors of integers. LLVM IR operations have "whole-vector" semantics (as in they generate values for all the elements).

Later patches will extend the information represented in TableGen.

Authored-by: Roger Ferrer Ibanez <rofirrim@gmail.com>
Co-Authored-by: Evandro Menezes <evandro.menezes@sifive.com>
Co-Authored-by: Craig Topper <craig.topper@sifive.com>

Differential Revision: https://reviews.llvm.org/D89449
  • Loading branch information
topperc committed Dec 4, 2020
1 parent e460654 commit 5baef63
Show file tree
Hide file tree
Showing 16 changed files with 1,308 additions and 38 deletions.
25 changes: 25 additions & 0 deletions llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
Expand Up @@ -59,6 +59,7 @@ class RISCVExpandPseudo : public MachineFunctionPass {
bool expandLoadTLSGDAddress(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
bool expandVSetVL(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI);
};

char RISCVExpandPseudo::ID = 0;
Expand Down Expand Up @@ -99,6 +100,8 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
return expandLoadTLSIEAddress(MBB, MBBI, NextMBBI);
case RISCV::PseudoLA_TLS_GD:
return expandLoadTLSGDAddress(MBB, MBBI, NextMBBI);
case RISCV::PseudoVSETVLI:
return expandVSetVL(MBB, MBBI);
}

return false;
Expand Down Expand Up @@ -188,6 +191,28 @@ bool RISCVExpandPseudo::expandLoadTLSGDAddress(
RISCV::ADDI);
}

bool RISCVExpandPseudo::expandVSetVL(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI) {
assert(MBBI->getNumOperands() == 5 && "Unexpected instruction format");

DebugLoc DL = MBBI->getDebugLoc();

assert(MBBI->getOpcode() == RISCV::PseudoVSETVLI &&
"Unexpected pseudo instruction");
const MCInstrDesc &Desc = TII->get(RISCV::VSETVLI);
assert(Desc.getNumOperands() == 3 && "Unexpected instruction format");

Register DstReg = MBBI->getOperand(0).getReg();
bool DstIsDead = MBBI->getOperand(0).isDead();
BuildMI(MBB, MBBI, DL, Desc)
.addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
.add(MBBI->getOperand(1)) // VL
.add(MBBI->getOperand(2)); // VType

MBBI->eraseFromParent(); // The pseudo instruction is gone now.
return true;
}

} // end of anonymous namespace

INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo",
Expand Down
136 changes: 136 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Expand Up @@ -89,6 +89,53 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
if (Subtarget.hasStdExtD())
addRegisterClass(MVT::f64, &RISCV::FPR64RegClass);

if (Subtarget.hasStdExtV()) {
addRegisterClass(RISCVVMVTs::vbool64_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vbool32_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vbool16_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vbool8_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vbool4_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vbool2_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vbool1_t, &RISCV::VRRegClass);

addRegisterClass(RISCVVMVTs::vint8mf8_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint8mf4_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint8mf2_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint8m1_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint8m2_t, &RISCV::VRM2RegClass);
addRegisterClass(RISCVVMVTs::vint8m4_t, &RISCV::VRM4RegClass);
addRegisterClass(RISCVVMVTs::vint8m8_t, &RISCV::VRM8RegClass);

addRegisterClass(RISCVVMVTs::vint16mf4_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint16mf2_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint16m1_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint16m2_t, &RISCV::VRM2RegClass);
addRegisterClass(RISCVVMVTs::vint16m4_t, &RISCV::VRM4RegClass);
addRegisterClass(RISCVVMVTs::vint16m8_t, &RISCV::VRM8RegClass);

addRegisterClass(RISCVVMVTs::vint32mf2_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint32m1_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint32m2_t, &RISCV::VRM2RegClass);
addRegisterClass(RISCVVMVTs::vint32m4_t, &RISCV::VRM4RegClass);
addRegisterClass(RISCVVMVTs::vint32m8_t, &RISCV::VRM8RegClass);

addRegisterClass(RISCVVMVTs::vint64m1_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vint64m2_t, &RISCV::VRM2RegClass);
addRegisterClass(RISCVVMVTs::vint64m4_t, &RISCV::VRM4RegClass);
addRegisterClass(RISCVVMVTs::vint64m8_t, &RISCV::VRM8RegClass);

addRegisterClass(RISCVVMVTs::vfloat32mf2_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vfloat32m1_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vfloat32m2_t, &RISCV::VRM2RegClass);
addRegisterClass(RISCVVMVTs::vfloat32m4_t, &RISCV::VRM4RegClass);
addRegisterClass(RISCVVMVTs::vfloat32m8_t, &RISCV::VRM8RegClass);

addRegisterClass(RISCVVMVTs::vfloat64m1_t, &RISCV::VRRegClass);
addRegisterClass(RISCVVMVTs::vfloat64m2_t, &RISCV::VRM2RegClass);
addRegisterClass(RISCVVMVTs::vfloat64m4_t, &RISCV::VRM4RegClass);
addRegisterClass(RISCVVMVTs::vfloat64m8_t, &RISCV::VRM8RegClass);
}

// Compute derived properties from the register classes.
computeRegisterProperties(STI.getRegisterInfo());

Expand Down Expand Up @@ -284,6 +331,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,

setBooleanContents(ZeroOrOneBooleanContent);

if (Subtarget.hasStdExtV())
setBooleanVectorContents(ZeroOrOneBooleanContent);

// Function alignments.
const Align FunctionAlignment(Subtarget.hasStdExtC() ? 2 : 4);
setMinFunctionAlignment(FunctionAlignment);
Expand Down Expand Up @@ -1856,9 +1906,95 @@ static MachineBasicBlock *emitSelectPseudo(MachineInstr &MI,
return TailMBB;
}

static MachineBasicBlock *addVSetVL(MachineInstr &MI, MachineBasicBlock *BB,
int VLIndex, unsigned SEWIndex,
unsigned VLMul) {
MachineFunction &MF = *BB->getParent();
DebugLoc DL = MI.getDebugLoc();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();

unsigned SEW = MI.getOperand(SEWIndex).getImm();
RISCVVLengthMultiplier::LengthMultiplier Multiplier;

switch (VLMul) {
default:
llvm_unreachable("Unexpected LMUL for instruction");
case 0:
case 1:
case 2:
case 3:
case 5:
case 6:
case 7:
Multiplier = static_cast<RISCVVLengthMultiplier::LengthMultiplier>(VLMul);
break;
}

RISCVVStandardElementWidth::StandardElementWidth ElementWidth;
switch (SEW) {
default:
llvm_unreachable("Unexpected SEW for instruction");
case 8:
ElementWidth = RISCVVStandardElementWidth::ElementWidth8;
break;
case 16:
ElementWidth = RISCVVStandardElementWidth::ElementWidth16;
break;
case 32:
ElementWidth = RISCVVStandardElementWidth::ElementWidth32;
break;
case 64:
ElementWidth = RISCVVStandardElementWidth::ElementWidth64;
break;
}

MachineRegisterInfo &MRI = MF.getRegInfo();

// VL and VTYPE are alive here.
MachineInstrBuilder MIB = BuildMI(*BB, MI, DL, TII.get(RISCV::PseudoVSETVLI));

if (VLIndex >= 0) {
// Set VL (rs1 != X0).
unsigned DestReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
MIB.addReg(DestReg, RegState::Define | RegState::Dead)
.addReg(MI.getOperand(VLIndex).getReg());
} else
// With no VL operator in the pseudo, do not modify VL (rd = X0, rs1 = X0).
MIB.addReg(RISCV::X0, RegState::Dead)
.addReg(RISCV::X0, RegState::Kill);

// For simplicity we reuse the vtype representation here.
// Bits | Name | Description
// -----+------------+------------------------------------------------
// 5 | vlmul[2] | Fractional lmul?
// 4:2 | vsew[2:0] | Standard element width (SEW) setting
// 1:0 | vlmul[1:0] | Vector register group multiplier (LMUL) setting
MIB.addImm(((Multiplier & 0x4) << 3) | ((ElementWidth & 0x3) << 2) |
(Multiplier & 0x3));

// Remove (now) redundant operands from pseudo
MI.getOperand(SEWIndex).setImm(-1);
if (VLIndex >= 0) {
MI.getOperand(VLIndex).setReg(RISCV::NoRegister);
MI.getOperand(VLIndex).setIsKill(false);
}

return BB;
}

MachineBasicBlock *
RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const {

if (const RISCVVPseudosTable::PseudoInfo *RVV =
RISCVVPseudosTable::getPseudoInfo(MI.getOpcode())) {
int VLIndex = RVV->getVLIndex();
int SEWIndex = RVV->getSEWIndex();

assert(SEWIndex >= 0 && "SEWIndex must be >= 0");
return addVSetVL(MI, BB, VLIndex, SEWIndex, RVV->VLMul);
}

switch (MI.getOpcode()) {
default:
llvm_unreachable("Unexpected instr type to insert");
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoV.td
Expand Up @@ -1127,3 +1127,5 @@ let Predicates = [HasStdExtZvamo, HasStdExtA, IsRV64] in {
defm VAMOMINUEI64 : VAMO<AMOOPVamoMinu, LSWidth64, "vamominuei64.v">;
defm VAMOMAXUEI64 : VAMO<AMOOPVamoMaxu, LSWidth64, "vamomaxuei64.v">;
} // Predicates = [HasStdExtZvamo, HasStdExtA, IsRV64]

include "RISCVInstrInfoVPseudos.td"

0 comments on commit 5baef63

Please sign in to comment.