aboutsummaryrefslogtreecommitdiff
path: root/backend/lib
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib')
-rw-r--r--backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp106
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp28
2 files changed, 134 insertions, 0 deletions
diff --git a/backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index f932db8..4ac88ed 100644
--- a/backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -2884,6 +2884,9 @@ Expected<void> LegalizerHelper::lower(MachineInstr &Instruction,
case GenericOpcode::G_SCMP:
case GenericOpcode::G_UCMP:
return lowerThreewayCompare(Instruction);
+ case GenericOpcode::G_ROTL:
+ case GenericOpcode::G_ROTR:
+ return lowerRotate(Instruction);
case GenericOpcode::G_ABDS:
case GenericOpcode::G_ABDU: {
const bool IsSigned = Instruction.opcode() == opcode(GenericOpcode::G_ABDS);
@@ -3339,6 +3342,109 @@ Expected<void> LegalizerHelper::lowerThreewayCompare(MachineInstr &Instruction)
return Block->removeInstruction(Instruction);
}
+Expected<void> LegalizerHelper::lowerRotate(MachineInstr &Instruction) {
+ const Register Destination = *Instruction.operandAt(0)->getIf<Register>();
+ const Register Source = *Instruction.operandAt(1)->getIf<Register>();
+ const Register Amount = *Instruction.operandAt(2)->getIf<Register>();
+ auto DestinationType = MRI.getType(Destination);
+ auto AmountType = MRI.getType(Amount);
+ if (!DestinationType)
+ return std::unexpected(DestinationType.error());
+ if (!AmountType)
+ return std::unexpected(AmountType.error());
+
+ const std::uint32_t ElementWidth = DestinationType->scalarBitWidth();
+ const bool IsLeft = Instruction.opcode() == opcode(GenericOpcode::G_ROTL);
+ const GenericOpcode ShiftOpcode = IsLeft ? GenericOpcode::G_SHL : GenericOpcode::G_LSHR;
+ const GenericOpcode ReverseShiftOpcode = IsLeft ? GenericOpcode::G_LSHR : GenericOpcode::G_SHL;
+
+ if (auto Point = MIRBuilder.setInsertPointBefore(Instruction); !Point)
+ return std::unexpected(Point.error());
+ auto Zero = buildConstantRegister(MIRBuilder, *AmountType, 0);
+ auto WidthMinusOne =
+ buildConstantRegister(MIRBuilder, *AmountType, static_cast<std::int64_t>(ElementWidth - 1U));
+ if (!Zero)
+ return std::unexpected(Zero.error());
+ if (!WidthMinusOne)
+ return std::unexpected(WidthMinusOne.error());
+
+ Register Shifted;
+ Register ReverseShifted;
+ if (std::has_single_bit(ElementWidth)) {
+ auto NegativeAmount =
+ buildResultInstruction(MIRBuilder, GenericOpcode::G_SUB, *AmountType, {*Zero, Amount});
+ auto ShiftAmount = buildResultInstruction(MIRBuilder, GenericOpcode::G_AND, *AmountType,
+ {Amount, *WidthMinusOne});
+ if (!NegativeAmount)
+ return std::unexpected(NegativeAmount.error());
+ if (!ShiftAmount)
+ return std::unexpected(ShiftAmount.error());
+ auto Shift =
+ buildResultInstruction(MIRBuilder, ShiftOpcode, *DestinationType, {Source, *ShiftAmount});
+ auto ReverseAmount = buildResultInstruction(MIRBuilder, GenericOpcode::G_AND, *AmountType,
+ {*NegativeAmount, *WidthMinusOne});
+ if (!Shift)
+ return std::unexpected(Shift.error());
+ if (!ReverseAmount)
+ return std::unexpected(ReverseAmount.error());
+ auto ReverseShift = buildResultInstruction(MIRBuilder, ReverseShiftOpcode, *DestinationType,
+ {Source, *ReverseAmount});
+ if (!ReverseShift)
+ return std::unexpected(ReverseShift.error());
+ Shifted = *Shift;
+ ReverseShifted = *ReverseShift;
+ } else {
+ auto Width =
+ buildConstantRegister(MIRBuilder, *AmountType, static_cast<std::int64_t>(ElementWidth));
+ if (!Width)
+ return std::unexpected(Width.error());
+ auto ShiftAmount =
+ buildResultInstruction(MIRBuilder, GenericOpcode::G_UREM, *AmountType, {Amount, *Width});
+ if (!ShiftAmount)
+ return std::unexpected(ShiftAmount.error());
+ auto Shift =
+ buildResultInstruction(MIRBuilder, ShiftOpcode, *DestinationType, {Source, *ShiftAmount});
+ auto ReverseAmount = buildResultInstruction(MIRBuilder, GenericOpcode::G_SUB, *AmountType,
+ {*WidthMinusOne, *ShiftAmount});
+ auto One = buildConstantRegister(MIRBuilder, *AmountType, 1);
+ if (!Shift)
+ return std::unexpected(Shift.error());
+ if (!ReverseAmount)
+ return std::unexpected(ReverseAmount.error());
+ if (!One)
+ return std::unexpected(One.error());
+ auto Inner =
+ buildResultInstruction(MIRBuilder, ReverseShiftOpcode, *DestinationType, {Source, *One});
+ if (!Inner)
+ return std::unexpected(Inner.error());
+ auto ReverseShift = buildResultInstruction(MIRBuilder, ReverseShiftOpcode, *DestinationType,
+ {*Inner, *ReverseAmount});
+ if (!ReverseShift)
+ return std::unexpected(ReverseShift.error());
+ Shifted = *Shift;
+ ReverseShifted = *ReverseShift;
+ }
+
+ auto Result = MIRBuilder.buildInstr(opcode(GenericOpcode::G_OR));
+ if (!Result)
+ return std::unexpected(Result.error());
+ if (auto Added = Result->addDef(Destination); !Added)
+ return std::unexpected(Added.error());
+ if (auto Added = Result->addUse(Shifted); !Added)
+ return std::unexpected(Added.error());
+ if (auto Added = Result->addUse(ReverseShifted); !Added)
+ return std::unexpected(Added.error());
+ if (auto Flags = Result->setFlags({MachineInstrFlag::Disjoint}); !Flags)
+ return std::unexpected(Flags.error());
+ if (auto Built = Result->build(); !Built)
+ return std::unexpected(Built.error());
+
+ MachineBasicBlock *Block = Instruction.parent();
+ if (Block == nullptr)
+ return makeUnexpected(ErrorCode::InternalError, "rotate became detached during lowering");
+ return Block->removeInstruction(Instruction);
+}
+
Expected<void> LegalizerHelper::lowerSignedAddSubOverflow(MachineInstr &Instruction) {
const bool IsAdd = Instruction.opcode() == opcode(GenericOpcode::G_SADDO);
const Register Destination = *Instruction.operandAt(0)->getIf<Register>();
diff --git a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 37fad6d..cbd3a31 100644
--- a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -643,6 +643,8 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &Subtarget) {
getActionDefinitionsBuilder({opcode(GenericOpcode::G_FSHL), opcode(GenericOpcode::G_FSHR)})
.lower();
getActionDefinitionsBuilder({opcode(GenericOpcode::G_ROTR), opcode(GenericOpcode::G_ROTL)})
+ .legalFor(HasZbb, {{S64, S64}})
+ .customFor(HasZbb, {{S32, S32}})
.lower();
getActionDefinitionsBuilder(opcode(GenericOpcode::G_BITREVERSE)).maxScalar(0, S64).lower();
getActionDefinitionsBuilder(opcode(GenericOpcode::G_BSWAP)).maxScalar(0, S64).lower();
@@ -1076,6 +1078,32 @@ Expected<void> RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
Helper.Observer.changedInstr(Instruction);
return {};
}
+ if (Instruction.opcode() == opcode(GenericOpcode::G_SDIV) ||
+ Instruction.opcode() == opcode(GenericOpcode::G_UDIV) ||
+ Instruction.opcode() == opcode(GenericOpcode::G_UREM) ||
+ Instruction.opcode() == opcode(GenericOpcode::G_ROTL) ||
+ Instruction.opcode() == opcode(GenericOpcode::G_ROTR)) {
+ auto XLenType = LowLevelType::makeCategoryNeutralScalar(64);
+ if (!XLenType)
+ return std::unexpected(XLenType.error());
+
+ Helper.Observer.changingInstr(Instruction);
+ if (auto Widened = Helper.widenScalarSrc(Instruction, *XLenType, 1, GenericOpcode::G_ANYEXT);
+ !Widened)
+ return std::unexpected(Widened.error());
+ if (auto Widened = Helper.widenScalarSrc(Instruction, *XLenType, 2, GenericOpcode::G_ANYEXT);
+ !Widened)
+ return std::unexpected(Widened.error());
+ if (auto Widened = Helper.widenScalarDst(Instruction, *XLenType); !Widened)
+ return std::unexpected(Widened.error());
+ auto WordOpcode = getRISCVWOpcode(static_cast<GenericOpcode>(Instruction.opcode().value()));
+ if (!WordOpcode)
+ return std::unexpected(WordOpcode.error());
+ if (auto Changed = Instruction.setOpcode(*WordOpcode); !Changed)
+ return std::unexpected(Changed.error());
+ Helper.Observer.changedInstr(Instruction);
+ return {};
+ }
if (Instruction.opcode() == opcode(GenericOpcode::G_ATOMIC_CMPXCHG))
return lowerAtomicCompareExchange(Instruction, Function, Target);
if (Instruction.opcode() == opcode(GenericOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS))