aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Nacke <kai@redstar.de>2022-07-17 20:57:41 -0400
committerKai Nacke <kai@redstar.de>2022-11-13 11:07:36 -0500
commit8bd2415dfa4a024cfa7b9301ed8ddb1a03d23c4d (patch)
tree5f989ff564e0aae4086434ec47a0c197e0d2d776
parentf85f5b6f9d46958c2013a215ce4a6e651b10f2c5 (diff)
downloadllvm-8bd2415dfa4a024cfa7b9301ed8ddb1a03d23c4d.zip
llvm-8bd2415dfa4a024cfa7b9301ed8ddb1a03d23c4d.tar.gz
llvm-8bd2415dfa4a024cfa7b9301ed8ddb1a03d23c4d.tar.bz2
[m88k] First try at divs/divu instruction.
- Introduces new clang option: -muse-div-instruction - Reuse clang option from MIPS: -mcheck-zero-division, -mno-check-zero-division - Add trap after divs if not MC88110 or no -mno-check-zero-division - Replacing divs with divu not yet working. Main reason is that the legalizer does not allow splitting blocks.
-rw-r--r--clang/include/clang/Driver/Options.td6
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp28
-rw-r--r--clang/lib/Driver/ToolChains/Clang.h2
-rw-r--r--llvm/lib/Target/M88k/GISel/M88kInstructionSelector.cpp52
-rw-r--r--llvm/lib/Target/M88k/GISel/M88kLegalizerInfo.cpp120
-rw-r--r--llvm/lib/Target/M88k/M88kInstrInfo.td5
-rw-r--r--llvm/lib/Target/M88k/M88kSubtarget.cpp14
-rw-r--r--llvm/lib/Target/M88k/M88kSubtarget.h3
8 files changed, 227 insertions, 3 deletions
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 78cab84..cda4840 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4531,6 +4531,12 @@ foreach i = {0-7} in
def m88000 : Flag<["-"], "m88000">, Group<m_m88k_Features_Group>;
def m88100 : Flag<["-"], "m88100">, Group<m_m88k_Features_Group>;
def m88110 : Flag<["-"], "m88110">, Group<m_m88k_Features_Group>;
+// TODO This flag is already in the MIPS group.
+//def mcheck_zero_division : Flag<["-"], "mcheck-zero-division">, Group<m_m88k_Features_Group>;
+//def mno_check_zero_division : Flag<["-"], "mno-check-zero-division">, Group<m_m88k_Features_Group>;
+def muse_div_instruction : Flag<["-"], "muse-div-instruction">,
+ Group<m_m88k_Features_Group>,
+ HelpText<"Use div instruction for signed integer division (MC88100 only)">;
// X86 feature flags
def mx87 : Flag<["-"], "mx87">, Group<m_x86_Features_Group>;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 22e15f7..4075ba4 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1783,6 +1783,10 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple,
AddLoongArchTargetArgs(Args, CmdArgs);
break;
+ case llvm::Triple::m88k:
+ AddM88kTargetArgs(Args, CmdArgs);
+ break;
+
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
@@ -1930,6 +1934,30 @@ void Clang::AddLoongArchTargetArgs(const ArgList &Args,
.data());
}
+void Clang::AddM88kTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
+ CmdArgs.push_back("-tune-cpu");
+ if (strcmp(A->getValue(), "native") == 0)
+ CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName()));
+ else
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division,
+ options::OPT_mno_check_zero_division)) {
+ if (A->getOption().matches(options::OPT_mno_check_zero_division)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-m88k-no-check-zero-division");
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_muse_div_instruction)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-m88k-use-div-instruction");
+ }
+}
+
void Clang::AddMIPSTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h
index d755066..cef80f2 100644
--- a/clang/lib/Driver/ToolChains/Clang.h
+++ b/clang/lib/Driver/ToolChains/Clang.h
@@ -59,6 +59,8 @@ private:
llvm::opt::ArgStringList &CmdArgs) const;
void AddLoongArchTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+ void AddM88kTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
void AddPPCTargetArgs(const llvm::opt::ArgList &Args,
diff --git a/llvm/lib/Target/M88k/GISel/M88kInstructionSelector.cpp b/llvm/lib/Target/M88k/GISel/M88kInstructionSelector.cpp
index 834d291..9fc012e 100644
--- a/llvm/lib/Target/M88k/GISel/M88kInstructionSelector.cpp
+++ b/llvm/lib/Target/M88k/GISel/M88kInstructionSelector.cpp
@@ -90,11 +90,21 @@ private:
MachineRegisterInfo &MRI) const;
bool selectIntrinsic(MachineInstr &I, MachineBasicBlock &MBB,
MachineRegisterInfo &MRI);
+ bool selectDiv(MachineInstr &I, MachineBasicBlock &MBB,
+ MachineRegisterInfo &MRI) const;
bool isMC88110() const {
return TII.getSubtarget().isMC88110();
}
+ bool useDivInstr() const {
+ return TII.getSubtarget().useDivInstr();
+ }
+
+ bool noZeroDivCheck() const {
+ return TII.getSubtarget().noZeroDivCheck();
+ }
+
//const M88kTargetMachine &TM;
const M88kInstrInfo &TII;
const M88kRegisterInfo &TRI;
@@ -903,6 +913,45 @@ bool M88kInstructionSelector::selectIntrinsic(MachineInstr &I,
return false;
}
+bool M88kInstructionSelector::selectDiv(MachineInstr &I, MachineBasicBlock &MBB,
+ MachineRegisterInfo &MRI) const {
+ assert(I.getOpcode() == TargetOpcode::G_UDIV ||
+ I.getOpcode() == TargetOpcode::G_SDIV && "Unexpected G code");
+
+ bool Signed = I.getOpcode() == TargetOpcode::G_SDIV;
+ MachineInstr *MI = nullptr;
+ Register DstReg = I.getOperand(0).getReg();
+ Register DividendReg = I.getOperand(1).getReg();
+ Register DivisorReg = I.getOperand(2).getReg();
+
+ int64_t Divisor;
+ if (mi_match(DivisorReg, MRI, m_ICst(Divisor)) && isUInt<16>(Divisor)) {
+ const unsigned NewOpc = Signed ? M88k::DIVSri : M88k::DIVUri;
+ MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc), DstReg)
+ .addReg(DividendReg)
+ .addImm(Divisor);
+ } else {
+ const unsigned NewOpc = Signed ? M88k::DIVSrr : M88k::DIVUrr;
+ MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc), DstReg)
+ .addReg(DividendReg)
+ .addReg(DivisorReg);
+
+ if (!noZeroDivCheck() && !isMC88110()) {
+ if (!constrainSelectedInstRegOperands(*MI, TII, TRI, RBI))
+ return false;
+
+ // Generate trap with exception number 503 if divisor is zero.
+ // TODO It may be good to bundle both instructions.
+ MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(M88k::TCND))
+ .addImm(static_cast<int64_t>(CC0::EQ0))
+ .addReg(DivisorReg)
+ .addImm(503);
+ }
+ }
+ I.eraseFromParent();
+ return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
+}
+
bool M88kInstructionSelector::earlySelect(MachineInstr &I) {
assert(I.getParent() && "Instruction should be in a basic block!");
assert(I.getParent()->getParent() && "Instruction should be in a function!");
@@ -1031,6 +1080,9 @@ bool M88kInstructionSelector::select(MachineInstr &I) {
return true;
switch (I.getOpcode()) {
+ case TargetOpcode::G_UDIV:
+ case TargetOpcode::G_SDIV:
+ return selectDiv(I, MBB, MRI);
case TargetOpcode::G_INTRINSIC:
return selectIntrinsic(I, MBB, MRI);
case TargetOpcode::G_GLOBAL_VALUE:
diff --git a/llvm/lib/Target/M88k/GISel/M88kLegalizerInfo.cpp b/llvm/lib/Target/M88k/GISel/M88kLegalizerInfo.cpp
index f50b489..69c89ad 100644
--- a/llvm/lib/Target/M88k/GISel/M88kLegalizerInfo.cpp
+++ b/llvm/lib/Target/M88k/GISel/M88kLegalizerInfo.cpp
@@ -10,10 +10,13 @@
//===----------------------------------------------------------------------===//
#include "M88kLegalizerInfo.h"
+#include "M88kSubtarget.h"
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
-#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/Constants.h"
@@ -21,6 +24,7 @@
#include "llvm/IR/Type.h"
using namespace llvm;
+using namespace LegalityPredicates;
M88kLegalizerInfo::M88kLegalizerInfo(const M88kSubtarget &ST) {
using namespace TargetOpcode;
@@ -69,8 +73,23 @@ M88kLegalizerInfo::M88kLegalizerInfo(const M88kSubtarget &ST) {
getActionDefinitionsBuilder(G_ADD).legalFor({S32});
getActionDefinitionsBuilder(G_SUB).legalFor({S32});
getActionDefinitionsBuilder(G_MUL).legalFor({S32});
- getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
+ getActionDefinitionsBuilder(G_UDIV).legalFor({S32}).libcallFor({S64});
+ getActionDefinitionsBuilder(G_SDIV)
+#if 0
+ // The only problem with these 2 rules is that the custom code requires
+ // inserting new basic blocks. This is currently not supported by the
+ // Legalizer.
+ .legalIf(all(typeInSet(0, {S32}),
+ LegalityPredicate(([=, &ST](const LegalityQuery &Query) {
+ return ST.useDivInstr() || ST.isMC88110();
+ }))))
+ .customIf(all(typeInSet(0, {S32}),
+ LegalityPredicate(([=, &ST](const LegalityQuery &Query) {
+ return !ST.useDivInstr();
+ }))))
+#else
.legalFor({S32})
+#endif
.libcallFor({S64});
getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
.legalFor({S32})
@@ -197,6 +216,103 @@ bool M88kLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
MI.eraseFromParent();
break;
}
+#if 0
+ // This is a first attempt to lower G_SDIV to G_UDIV.
+ // It does not work because the Legalizer currently does not support inserting
+ // new basic blocks.
+ case G_SDIV: {
+ // The instruction
+ // %3:_ = G_SDIV %1:_, %2:_
+ // is lowered to G_UDIV. This is done by making both operands non-negative,
+ // and correcting the sign of the result. All 4 cases need to be
+ // considered. The code is a bit lengthy, but not complicated.
+ Register Dst = MI.getOperand(0).getReg();
+ Register Dividend = MI.getOperand(1).getReg();
+ Register Divisor = MI.getOperand(2).getReg();
+
+ if (MRI.getType(Dst) != S32 || MRI.getType(Dividend) != S32 ||
+ MRI.getType(Divisor) != S32)
+ return false;
+
+ MachineBasicBlock *CurBB = MI.getParent();
+ MachineFunction *MF = CurBB->getParent();
+
+ // First split the current basic block. Move all instructions after MI into
+ // the new block.
+ MachineFunction::iterator BBI(CurBB);
+ MachineBasicBlock *TailBB =
+ MF->CreateMachineBasicBlock(CurBB->getBasicBlock());
+ MF->insert(++BBI, TailBB);
+ MachineBasicBlock::iterator MII(&MI);
+ TailBB->splice(TailBB->begin(), CurBB, ++MII, CurBB->end());
+
+ // Create basic blocks.
+ MachineBasicBlock *DivisorNotPosBB =
+ MF->CreateMachineBasicBlock(CurBB->getBasicBlock());
+ MachineBasicBlock *DividendNegDivisorPosBB =
+ MF->CreateMachineBasicBlock(CurBB->getBasicBlock());
+ MachineBasicBlock *DividendNegDivisorNotPosBB =
+ MF->CreateMachineBasicBlock(CurBB->getBasicBlock());
+
+ MF->insert(--BBI, DivisorNotPosBB);
+ MF->insert(BBI, DividendNegDivisorPosBB);
+ MF->insert(BBI, DividendNegDivisorNotPosBB);
+
+ // Compare dividend and divisor against zero, and branch accordingly.
+ // Handle case 1: dividend zero or positiv, divisor positiv.
+ auto Zero = MIRBuilder.buildConstant(S32, 0);
+ auto Cmp1 = MIRBuilder.buildICmp(CmpInst::ICMP_SLE, S1, Divisor, Zero);
+ MIRBuilder.buildBrCond(Cmp1, *DivisorNotPosBB);
+ auto Cmp2 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, Dividend, Zero);
+ MIRBuilder.buildBrCond(Cmp2, *DividendNegDivisorPosBB);
+ auto Div1 =
+ MIRBuilder.buildInstr(TargetOpcode::G_UDIV, {S32}, {Dividend, Divisor});
+ MIRBuilder.buildBr(*TailBB);
+
+ // Handle case 2: dividend zero or positiv, divisor negativ.
+ // Result is negativ.
+ MIRBuilder.setMBB(*DivisorNotPosBB);
+ auto AbsDivisor = MIRBuilder.buildNeg(S32, Divisor);
+ auto Cmp3 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, Dividend, Zero);
+ MIRBuilder.buildBrCond(Cmp2, *DividendNegDivisorNotPosBB);
+ auto Div2 = MIRBuilder.buildNeg(
+ S32, MIRBuilder.buildInstr(TargetOpcode::G_UDIV, {S32},
+ {Dividend, AbsDivisor}));
+ MIRBuilder.buildBr(*TailBB);
+
+ // Handle case 3: dividend negativ, divisor negativ.
+ // Result is positiv.
+ MIRBuilder.setMBB(*DividendNegDivisorNotPosBB);
+ auto AbsDividend = MIRBuilder.buildNeg(S32, Dividend);
+ auto Cmp4 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, Dividend, Zero);
+ MIRBuilder.buildBrCond(Cmp4, *DividendNegDivisorNotPosBB);
+ auto Div3 = MIRBuilder.buildInstr(TargetOpcode::G_UDIV, {S32},
+ {AbsDividend, AbsDivisor});
+ MIRBuilder.buildBr(*TailBB);
+
+ // Handle case 4: dividend negativ, divisor zero or positiv.
+ // Result is negativ.
+ MIRBuilder.setMBB(*DividendNegDivisorPosBB);
+ auto AbsDividend2 = MIRBuilder.buildNeg(S32, Dividend);
+ auto Cmp5 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, Dividend, Zero);
+ MIRBuilder.buildBrCond(Cmp5, *DividendNegDivisorNotPosBB);
+ auto Div4 = MIRBuilder.buildNeg(
+ S32, MIRBuilder.buildInstr(TargetOpcode::G_UDIV, {S32},
+ {AbsDividend, Divisor}));
+ MIRBuilder.buildBr(*TailBB);
+
+ // Collect the results.
+ MIRBuilder.setInsertPt(*TailBB, TailBB->begin());
+ auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI, {Dst}, {});
+ Phi.addUse(Div1.getReg(0)).addMBB(CurBB);
+ Phi.addUse(Div2.getReg(0)).addMBB(DivisorNotPosBB);
+ Phi.addUse(Div3.getReg(0)).addMBB(DividendNegDivisorNotPosBB);
+ Phi.addUse(Div4.getReg(0)).addMBB(DividendNegDivisorPosBB);
+
+ MI.eraseFromParent();
+ break;
+ }
+#endif
default:
return false;
}
diff --git a/llvm/lib/Target/M88k/M88kInstrInfo.td b/llvm/lib/Target/M88k/M88kInstrInfo.td
index ecb832d..a735c27 100644
--- a/llvm/lib/Target/M88k/M88kInstrInfo.td
+++ b/llvm/lib/Target/M88k/M88kInstrInfo.td
@@ -430,7 +430,10 @@ let Predicates = [IsMC88110] in {
defm : BinaryOpPat<"ADDU", add>;
defm : BinaryOpPat<"SUBU", sub>;
defm : BinaryOpPat<"MULU", mul>;
-defm : BinaryOpPat<"DIVS", sdiv>; // TODO Correct?
+// DIVU and DIVS require some special handling.
+// For now, don#t add patterns for both instructions.
+// TODO The trap could be inserted in a later path.
+//defm : BinaryOpPat<"DIVS", sdiv>;
//def : Pat<(umullohi GPR:$rs1, GPR:$rs2), (MULUrrd GPR:$rs1, GPR:$rs2)>;
diff --git a/llvm/lib/Target/M88k/M88kSubtarget.cpp b/llvm/lib/Target/M88k/M88kSubtarget.cpp
index f786aeb..b8ba86f 100644
--- a/llvm/lib/Target/M88k/M88kSubtarget.cpp
+++ b/llvm/lib/Target/M88k/M88kSubtarget.cpp
@@ -23,6 +23,17 @@ using namespace llvm;
#define DEBUG_TYPE "m88k-subtarget"
+static cl::opt<bool>
+ NoZeroDivCheck("m88k-no-check-zero-division", cl::Hidden,
+ cl::desc("M88k: Don't trap on integer division by zero."),
+ cl::init(false));
+
+static cl::opt<bool> UseDivInstr(
+ "m88k-use-div-instruction", cl::Hidden,
+ cl::desc("M88k: Use the div instruction for signed integer division."),
+ cl::init(false));
+
+
#define GET_SUBTARGETINFO_TARGET_DESC
#define GET_SUBTARGETINFO_CTOR
#include "M88kGenSubtargetInfo.inc"
@@ -93,3 +104,6 @@ Optional<unsigned> M88kSubtarget::getCacheLineSize(unsigned Level) const {
return Optional<unsigned>();
}
}
+
+bool M88kSubtarget::useDivInstr() const { return UseDivInstr; }
+bool M88kSubtarget::noZeroDivCheck() const { return NoZeroDivCheck; }
diff --git a/llvm/lib/Target/M88k/M88kSubtarget.h b/llvm/lib/Target/M88k/M88kSubtarget.h
index 146e01e..2268af7 100644
--- a/llvm/lib/Target/M88k/M88kSubtarget.h
+++ b/llvm/lib/Target/M88k/M88kSubtarget.h
@@ -81,6 +81,9 @@ public:
bool isMC88100() const { return M88kProc == MC88100; }
bool isMC88110() const { return M88kProc == MC88110; }
+ bool useDivInstr() const;
+ bool noZeroDivCheck() const;
+
const TargetFrameLowering *getFrameLowering() const override {
return &FrameLowering;
}