diff options
author | Kai Nacke <kai@redstar.de> | 2022-07-17 20:57:41 -0400 |
---|---|---|
committer | Kai Nacke <kai@redstar.de> | 2022-11-13 11:07:36 -0500 |
commit | 8bd2415dfa4a024cfa7b9301ed8ddb1a03d23c4d (patch) | |
tree | 5f989ff564e0aae4086434ec47a0c197e0d2d776 | |
parent | f85f5b6f9d46958c2013a215ce4a6e651b10f2c5 (diff) | |
download | llvm-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.td | 6 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Clang.cpp | 28 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Clang.h | 2 | ||||
-rw-r--r-- | llvm/lib/Target/M88k/GISel/M88kInstructionSelector.cpp | 52 | ||||
-rw-r--r-- | llvm/lib/Target/M88k/GISel/M88kLegalizerInfo.cpp | 120 | ||||
-rw-r--r-- | llvm/lib/Target/M88k/M88kInstrInfo.td | 5 | ||||
-rw-r--r-- | llvm/lib/Target/M88k/M88kSubtarget.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/Target/M88k/M88kSubtarget.h | 3 |
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; } |