Skip to content

[HEXAGON] Inlining Division #79021

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,98 @@ void HexagonDAGToDAGISel::SelectQ2V(SDNode *N) {
ReplaceNode(N, T);
}

void HexagonDAGToDAGISel::FDiv(SDNode *N) {
const SDLoc &dl(N);
ArrayRef<EVT> ResultType(N->value_begin(), N->value_end());
SmallVector<SDValue, 2> Ops;
Ops = {N->getOperand(0), N->getOperand(1)};
SDVTList VTs;
VTs = CurDAG->getVTList(MVT::f32, MVT::f32);
SDNode *ResScale = CurDAG->getMachineNode(Hexagon::F2_sfrecipa, dl, VTs, Ops);
SDNode *D = CurDAG->getMachineNode(Hexagon::F2_sffixupd, dl, MVT::f32, Ops);

SDValue C = CurDAG->getTargetConstant(0x3f800000, dl, MVT::i32);
SDNode *constNode =
CurDAG->getMachineNode(Hexagon::A2_tfrsi, dl, MVT::f32, C);

SDNode *n = CurDAG->getMachineNode(Hexagon::F2_sffixupn, dl, MVT::f32, Ops);
SDNode *Err = CurDAG->getMachineNode(Hexagon::F2_sffms_lib, dl, MVT::f32,
SDValue(constNode, 0), SDValue(D, 0),
SDValue(ResScale, 0));
SDNode *NewRec = CurDAG->getMachineNode(Hexagon::F2_sffma_lib, dl, MVT::f32,
SDValue(ResScale, 0), SDValue(Err, 0),
SDValue(ResScale, 0));
SDNode *newErr = CurDAG->getMachineNode(Hexagon::F2_sffms_lib, dl, MVT::f32,
SDValue(constNode, 0), SDValue(D, 0),
SDValue(NewRec, 0));
SDNode *q = CurDAG->getMachineNode(
Hexagon::A2_andir, dl, MVT::f32, SDValue(n, 0),
CurDAG->getTargetConstant(0x80000000, dl, MVT::i32));
SDNode *NewQ =
CurDAG->getMachineNode(Hexagon::F2_sffma_lib, dl, MVT::f32, SDValue(q, 0),
SDValue(n, 0), SDValue(NewRec, 0));
SDNode *NNewRec = CurDAG->getMachineNode(
Hexagon::F2_sffma_lib, dl, MVT::f32, SDValue(NewRec, 0),
SDValue(newErr, 0), SDValue(NewRec, 0));
SDNode *qErr =
CurDAG->getMachineNode(Hexagon::F2_sffms_lib, dl, MVT::f32, SDValue(n, 0),
SDValue(D, 0), SDValue(NewQ, 0));
SDNode *NNewQ = CurDAG->getMachineNode(Hexagon::F2_sffma_lib, dl, MVT::f32,
SDValue(NewQ, 0), SDValue(qErr, 0),
SDValue(NNewRec, 0));

SDNode *NqErr =
CurDAG->getMachineNode(Hexagon::F2_sffms_lib, dl, MVT::f32, SDValue(n, 0),
SDValue(NNewQ, 0), SDValue(D, 0));
std::array<SDValue, 4> temp1 = {SDValue(NNewQ, 0), SDValue(NqErr, 0),
SDValue(NNewRec, 0), SDValue(ResScale, 1)};
ArrayRef<SDValue> OpValue1(temp1);
SDNode *FinalNewQ =
CurDAG->getMachineNode(Hexagon::F2_sffma_sc, dl, MVT::f32, OpValue1);
ReplaceNode(N, FinalNewQ);
}

void HexagonDAGToDAGISel::FastFDiv(SDNode *N) {
const SDLoc &dl(N);
ArrayRef<EVT> ResultType(N->value_begin(), N->value_end());
SmallVector<SDValue, 2> Ops;
Ops = {N->getOperand(0), N->getOperand(1)};
SDVTList VTs;
VTs = CurDAG->getVTList(MVT::f32, MVT::f32);
SDNode *ResScale = CurDAG->getMachineNode(Hexagon::F2_sfrecipa, dl, VTs, Ops);
SDNode *D = CurDAG->getMachineNode(Hexagon::F2_sffixupd, dl, MVT::f32, Ops);

SDValue C = CurDAG->getTargetConstant(0x3f800000, dl, MVT::i32);
SDNode *constNode =
CurDAG->getMachineNode(Hexagon::A2_tfrsi, dl, MVT::f32, C);

SDNode *n = CurDAG->getMachineNode(Hexagon::F2_sffixupn, dl, MVT::f32, Ops);
SDNode *Err = CurDAG->getMachineNode(Hexagon::F2_sffms_lib, dl, MVT::f32,
SDValue(constNode, 0), SDValue(D, 0),
SDValue(ResScale, 0));
SDNode *NewRec = CurDAG->getMachineNode(Hexagon::F2_sffma_lib, dl, MVT::f32,
SDValue(ResScale, 0), SDValue(Err, 0),
SDValue(ResScale, 0));
SDNode *newErr = CurDAG->getMachineNode(Hexagon::F2_sffms_lib, dl, MVT::f32,
SDValue(constNode, 0), SDValue(D, 0),
SDValue(NewRec, 0));

SDNode *NNewRec = CurDAG->getMachineNode(
Hexagon::F2_sffma_lib, dl, MVT::f32, SDValue(NewRec, 0),
SDValue(newErr, 0), SDValue(NewRec, 0));
SDNode *FinalNewQ = CurDAG->getMachineNode(
Hexagon::F2_sfmpy, dl, MVT::f32, SDValue(NNewRec, 0), SDValue(n, 0));
ReplaceNode(N, FinalNewQ);
}

void HexagonDAGToDAGISel::SelectFDiv(SDNode *N) {
if (N->getFlags().hasAllowReassociation())
FastFDiv(N);
else
FDiv(N);
return;
}

void HexagonDAGToDAGISel::Select(SDNode *N) {
if (N->isMachineOpcode())
return N->setNodeId(-1); // Already selected.
Expand Down Expand Up @@ -949,6 +1041,8 @@ void HexagonDAGToDAGISel::Select(SDNode *N) {
case HexagonISD::D2P: return SelectD2P(N);
case HexagonISD::Q2V: return SelectQ2V(N);
case HexagonISD::V2Q: return SelectV2Q(N);
case ISD::FDIV:
return SelectFDiv(N);
}

SelectCode(N);
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ class HexagonDAGToDAGISel : public SelectionDAGISel {
void SelectD2P(SDNode *N);
void SelectQ2V(SDNode *N);
void SelectV2Q(SDNode *N);
void SelectFDiv(SDNode *N);
void FDiv(SDNode *N);
void FastFDiv(SDNode *N);

// Include the declarations autogenerated from the selection patterns.
#define GET_DAGISEL_DECL
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,13 @@ bool HexagonTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
return Subtarget.getInstrInfo()->isValidAutoIncImm(VT, V);
}

SDValue HexagonTargetLowering::LowerFDIV(SDValue Op, SelectionDAG &DAG) const {
if (DAG.getMachineFunction().getFunction().hasOptSize())
return SDValue();
else
return Op;
}

SDValue
HexagonTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
Expand Down Expand Up @@ -1765,6 +1772,7 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FADD, MVT::f64, Expand);
setOperationAction(ISD::FSUB, MVT::f64, Expand);
setOperationAction(ISD::FMUL, MVT::f64, Expand);
setOperationAction(ISD::FDIV, MVT::f32, Custom);

setOperationAction(ISD::FMINNUM, MVT::f32, Legal);
setOperationAction(ISD::FMAXNUM, MVT::f32, Legal);
Expand Down Expand Up @@ -3341,6 +3349,9 @@ HexagonTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
errs() << "Error: check for a non-legal type in this operation\n";
#endif
llvm_unreachable("Should not custom lower this!");

case ISD::FDIV:
return LowerFDIV(Op, DAG);
case ISD::CONCAT_VECTORS: return LowerCONCAT_VECTORS(Op, DAG);
case ISD::INSERT_SUBVECTOR: return LowerINSERT_SUBVECTOR(Op, DAG);
case ISD::INSERT_VECTOR_ELT: return LowerINSERT_VECTOR_ELT(Op, DAG);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/Hexagon/HexagonISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ class HexagonTargetLowering : public TargetLowering {

SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFDIV(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerPREFETCH(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerREADCYCLECOUNTER(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_LABEL(SDValue Op, SelectionDAG &DAG) const;
Expand Down
30 changes: 30 additions & 0 deletions llvm/test/CodeGen/Hexagon/inline-division-space.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
; Test for checking division is inlined or not in case of Os.
; RUN: llc -O2 -march=hexagon < %s | FileCheck %s

; Function Attrs: optsize
define dso_local i32 @testInt(i32 %a, i32 %b) local_unnamed_addr #0 {
entry:
;CHECK: call __hexagon_divsi3
%div = sdiv i32 %a, %b
%conv = sitofp i32 %div to float
%conv1 = fptosi float %conv to i32
ret i32 %conv1
}

; Function Attrs: optsize
define dso_local float @testFloat(float %a, float %b) local_unnamed_addr #0 {
entry:
;CHECK: call __hexagon_divsf3
%div = fdiv float %a, %b
ret float %div
}

; Function Attrs: optsize
define dso_local double @testDouble(double %a, double %b) local_unnamed_addr #0 {
entry:
;CHECK: call __hexagon_divdf3
%div = fdiv double %a, %b
ret double %div
}

attributes #0 = { optsize }
29 changes: 29 additions & 0 deletions llvm/test/CodeGen/Hexagon/inline-division.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
; Test for checking division is inlined or not in case of Os.
; RUN: llc -O2 -march=hexagon < %s | FileCheck %s

define dso_local i32 @testInt(i32 %a, i32 %b) local_unnamed_addr {
entry:
;CHECK: call __hexagon_divsi3
%div = sdiv i32 %a, %b
%conv = sitofp i32 %div to float
%conv1 = fptosi float %conv to i32
ret i32 %conv1
}

define dso_local float @testFloat(float %a, float %b) local_unnamed_addr {
entry:
;CHECK-NOT: call __hexagon_divsf3
;CHECK: sfrecipa
;CHECK: sffixupn
;CHEKC: and
;CHECK: sfmpy
%div = fdiv float %a, %b
ret float %div
}

define dso_local double @testDouble(double %a, double %b) local_unnamed_addr {
entry:
;CHECK: call __hexagon_divdf3
%div = fdiv double %a, %b
ret double %div
}