[llvm] [Hexagon] Add XQFloat extraneous conversion removal pass (PR #207236)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 2 14:50:18 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-hexagon
Author: Fateme Hosseini (fhossein-quic)
<details>
<summary>Changes</summary>
Introduce VectorConvertRemove to remove extraneous qf->sf/hf conversions after XQFloat code generation. Off by default, enabled with -enable-rem-conv.
Co-authored-by: Santanu Das <quic_santdas@<!-- -->qti.qualcomm.com>
---
Patch is 74.45 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/207236.diff
12 Files Affected:
- (modified) llvm/lib/Target/Hexagon/HexagonXQFloatGenerator.cpp (+486)
- (modified) llvm/test/CodeGen/Hexagon/autohvx/xqf-assertion1.ll (+13-3)
- (modified) llvm/test/CodeGen/Hexagon/autohvx/xqf-check-qf-instrs.ll (+8-8)
- (added) llvm/test/CodeGen/Hexagon/autohvx/xqf-compliant-ieee-mul-qf16.ll (+86)
- (added) llvm/test/CodeGen/Hexagon/autohvx/xqf-compliant-ieee-mul-qf32.ll (+136)
- (added) llvm/test/CodeGen/Hexagon/autohvx/xqf-convert-elim.ll (+77)
- (added) llvm/test/CodeGen/Hexagon/autohvx/xqf-lossy-mul-qf16.ll (+74)
- (added) llvm/test/CodeGen/Hexagon/autohvx/xqf-lossy-mul-qf32.ll (+109)
- (added) llvm/test/CodeGen/Hexagon/autohvx/xqf-v81/xqf-v81-compliant-ieee-mul-qf32.ll (+109)
- (added) llvm/test/CodeGen/Hexagon/autohvx/xqf-v81/xqf-v81-lossy-mul-qf32.ll (+98)
- (added) llvm/test/CodeGen/Hexagon/autohvx/xqf-v81/xqf-v81-vsub.ll (+164)
- (added) llvm/test/CodeGen/Hexagon/autohvx/xqf-vsub.ll (+130)
``````````diff
diff --git a/llvm/lib/Target/Hexagon/HexagonXQFloatGenerator.cpp b/llvm/lib/Target/Hexagon/HexagonXQFloatGenerator.cpp
index 460976cdfd7ba..ce62f3430dd81 100644
--- a/llvm/lib/Target/Hexagon/HexagonXQFloatGenerator.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonXQFloatGenerator.cpp
@@ -155,6 +155,14 @@ extern cl::opt<QFloatMode> QFloatModeValue;
// Master flag to enable XQF generations
cl::opt<bool> EnableHVXXQFloat("enable-xqf-gen", cl::init(false),
cl::desc("Enable XQFloat generations"));
+// Master flag to remove extraneous qf to sf/hf conversions
+cl::opt<bool>
+ EnableConversionsRemoval("enable-rem-conv", cl::init(false),
+ cl::desc("Enable extraneous conversions removal"));
+
+// Diagnostic flags
+cl::opt<bool> PrintDebug("debug-print", cl::init(false),
+ cl::desc("Print function mir after transformation"));
// This vector contains the opcodes which generate qf32 from add/subtract
static constexpr unsigned XQFPAdd32[] = {
// vector add instructions
@@ -253,10 +261,478 @@ struct HexagonXQFloatGenerator : public MachineFunctionPass {
OriginalMI; // Hold the instructions to be deleted
};
+// Print machine function
+static void debug_print([[maybe_unused]] MachineFunction &MF) {
+ dbgs() << "\n=== Printing function ===\n";
+#ifndef NDEBUG
+ for (MachineBasicBlock &MBB : MF)
+ MBB.dump();
+#endif // NDEBUG
+}
+
// This class removes redundant vector convert instructions from qf to hf/sf.
// Additionally, it relaces use of sf/hf registers with qf types.
// The resulting code is complete without dangling instructions.
// FIXME: Liveness is not preserved.
+class VectorConvertRemove {
+
+public:
+ VectorConvertRemove(MachineFunction &_MF, MachineRegisterInfo *_MRI,
+ const HexagonSubtarget *_HST)
+ : MF(_MF), MRI(_MRI), HST(_HST) {
+ HII = HST->getInstrInfo();
+ }
+
+ void run();
+
+private:
+ MachineFunction &MF;
+ MachineRegisterInfo *MRI;
+ const HexagonSubtarget *HST;
+ const HexagonInstrInfo *HII;
+
+ enum Operation { Add16, Add32, Sub16, Sub32, Mul16, Mul32 };
+ // Helper functions
+ void handle_addsub_sf_sf(MachineInstr &, Register &, Register &, Register &,
+ bool);
+ void handle_addsub_qf_sf(MachineInstr &, Register &, Register &, Register &,
+ bool);
+ void handle_addsubmul_hf_hf(MachineInstr &, Register &, Register &,
+ Register &, Operation);
+ void handle_addsubmul_qf_hf(MachineInstr &, Register &, Register &,
+ Register &, Operation);
+ void handle_qf32_mul_sf_sf(MachineInstr &, Register &, Register &,
+ Register &);
+ void handle_qf16_mul_hf_hf(MachineInstr &, Register &, Register &,
+ Register &);
+ bool checkHVXUses32(MachineInstr *, MachineInstr *);
+ bool checkHVXUses16(MachineInstr *, MachineInstr *);
+ unsigned getOperation(Operation, bool, bool);
+
+ // List which holds conversion instructions
+ SmallPtrSet<MachineInstr *, 16> ConvInstrList;
+ // List which holds qf handling instructions
+ std::vector<MachineInstr *> SfHfInstrList;
+};
+
+// both : both operands are replaced
+unsigned VectorConvertRemove::getOperation(Operation Op, bool firstOpQf,
+ bool secOpQf) {
+ if (firstOpQf && secOpQf) {
+ switch (Op) {
+ case Add16:
+ return Hexagon::V6_vadd_qf16;
+ case Add32:
+ return Hexagon::V6_vadd_qf32;
+ case Sub16:
+ return Hexagon::V6_vsub_qf16;
+ case Sub32:
+ return Hexagon::V6_vsub_qf32;
+ case Mul16:
+ return Hexagon::V6_vmpy_qf16;
+ case Mul32:
+ return Hexagon::V6_vmpy_qf32_qf16;
+ }
+ } else if (firstOpQf) {
+ switch (Op) {
+ case Add16:
+ return Hexagon::V6_vadd_qf16_mix;
+ case Add32:
+ return Hexagon::V6_vadd_qf32_mix;
+ case Sub16:
+ return Hexagon::V6_vsub_qf16_mix;
+ case Sub32:
+ return Hexagon::V6_vsub_qf32_mix;
+ case Mul16:
+ return Hexagon::V6_vmpy_qf16_mix_hf;
+ case Mul32:
+ return Hexagon::V6_vmpy_qf32_mix_hf;
+ }
+ } else if (secOpQf) {
+ switch (Op) {
+ case Sub16:
+ return Hexagon::V6_vsub_hf_mix;
+ case Sub32:
+ return Hexagon::V6_vsub_sf_mix;
+ default:
+ break;
+ }
+ } else {
+ }
+ llvm_unreachable("Unknown opcode and operand combination!");
+}
+
+// Return false if there are multiple instructions where the qf32 is used
+// other than the instruction for which it is called
+bool VectorConvertRemove::checkHVXUses32(MachineInstr *MI,
+ MachineInstr *UseMI) {
+ Register convReg = MI->getOperand(0).getReg();
+ // Iterate over all uses of the Def we are analyzing
+ for (auto &MO : make_range(MRI->use_begin(convReg), MRI->use_end())) {
+ MachineInstr *UMI = MO.getParent();
+ if (UMI == UseMI)
+ continue;
+ // Since the convert cannot be deleted, we set the operand as NOT kill
+ MI->getOperand(1).setIsKill(false);
+ return false;
+ }
+ return true;
+}
+
+// Return false if there are multiple instructions where the qf16 is used
+// other than the instruction for which it is called
+bool VectorConvertRemove::checkHVXUses16(MachineInstr *MI,
+ MachineInstr *UseMI) {
+ Register convReg = MI->getOperand(0).getReg();
+ // Iterate over all uses of the Def we are analyzing
+ for (auto &MO : make_range(MRI->use_begin(convReg), MRI->use_end())) {
+ MachineInstr *UMI = MO.getParent();
+ if (UMI == UseMI)
+ continue;
+ // Since the convert cannot be deleted, we set the operand as NOT kill
+ MI->getOperand(1).setIsKill(false);
+ return false;
+ }
+ return true;
+}
+
+// Removes converts feeding to op(sf,sf), and replaces its sf operands with qf
+void VectorConvertRemove::handle_addsub_sf_sf(MachineInstr &MI, Register &Reg1,
+ Register &Reg2, Register &Dest,
+ bool isAdd) {
+
+ MachineBasicBlock &MBB = *MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+
+ bool firstConv = false, secConv = false;
+ bool DefOp1_del = false, DefOp2_del = false;
+ Register Src1, Src2;
+
+ MachineInstr *DefOp1 = MRI->getVRegDef(Reg1);
+ MachineInstr *DefOp2 = MRI->getVRegDef(Reg2);
+ // check if the first operand is from a convert operation
+ if (DefOp1->getOpcode() == Hexagon::V6_vconv_sf_qf32) {
+ if (checkHVXUses32(DefOp1, &MI))
+ DefOp1_del = true;
+ Src1 = DefOp1->getOperand(1).getReg();
+ firstConv = true;
+ }
+
+ // check if the second operand is from a convert operation
+ if (DefOp2->getOpcode() == Hexagon::V6_vconv_sf_qf32) {
+ if (checkHVXUses32(DefOp2, &MI))
+ DefOp2_del = true;
+ Src2 = DefOp2->getOperand(1).getReg();
+ secConv = true;
+ }
+
+ if (firstConv && secConv) {
+ BuildMI(MBB, MI, DL,
+ HII->get(getOperation(isAdd ? Operation::Add32 : Operation::Sub32,
+ true, true)),
+ Dest)
+ .addReg(Src1)
+ .addReg(Src2);
+ SfHfInstrList.push_back(&MI);
+ } else if (firstConv) {
+ BuildMI(MBB, MI, DL,
+ HII->get(getOperation(isAdd ? Operation::Add32 : Operation::Sub32,
+ true, false)),
+ Dest)
+ .addReg(Src1)
+ .addReg(Reg2);
+ SfHfInstrList.push_back(&MI);
+ } else if (secConv) {
+ // For v79, there is no provision for 2nd op being qf for add/sub
+ if (HST->useHVXV81Ops()) {
+ if (isAdd)
+ BuildMI(MBB, MI, DL, HII->get(Hexagon::V6_vadd_qf32_mix), Dest)
+ .addReg(Src2)
+ .addReg(Reg1);
+ else
+ BuildMI(MBB, MI, DL, HII->get(Hexagon::V6_vsub_sf_mix), Dest)
+ .addReg(Reg1)
+ .addReg(Src2);
+ SfHfInstrList.push_back(&MI);
+ // For v79, there is no provision for 2nd op being qf for add/sub. Since
+ // add is commutative, the ops can be rotated.
+ } else if (HST->useHVXV79Ops()) {
+ // for vadd we interchange the ops, for vsub we ignore
+ if (isAdd) {
+ BuildMI(MBB, MI, DL, HII->get(Hexagon::V6_vadd_qf32_mix), Dest)
+ .addReg(Src2)
+ .addReg(Reg1);
+ SfHfInstrList.push_back(&MI);
+ } else // don't delete the convert instruction for vsub
+ DefOp2_del = false;
+ }
+ } else { // none of the operands are from convert instructions
+ }
+
+ if (DefOp1_del)
+ ConvInstrList.insert(DefOp1);
+ if (DefOp2_del)
+ ConvInstrList.insert(DefOp2);
+}
+
+// Removes converts feeding to op(hf,hf), and replaces its hf operands with qf
+void VectorConvertRemove::handle_addsubmul_hf_hf(MachineInstr &MI,
+ Register &Reg1, Register &Reg2,
+ Register &Dest, Operation Op) {
+
+ MachineBasicBlock &MBB = *MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+
+ bool firstConv = false, secConv = false;
+ bool DefOp1_del = false, DefOp2_del = false;
+ bool isSub = Op == Operation::Sub16;
+ Register Src1, Src2;
+
+ MachineInstr *DefOp1 = MRI->getVRegDef(Reg1);
+ MachineInstr *DefOp2 = MRI->getVRegDef(Reg2);
+ // check if the first operand is from a convert operation
+ if (DefOp1->getOpcode() == Hexagon::V6_vconv_hf_qf16) {
+ if (checkHVXUses16(DefOp1, &MI))
+ DefOp1_del = true;
+ Src1 = DefOp1->getOperand(1).getReg();
+ firstConv = true;
+ }
+
+ // check if the second operand is from a convert operation
+ if (DefOp2->getOpcode() == Hexagon::V6_vconv_hf_qf16) {
+ if (checkHVXUses16(DefOp2, &MI))
+ DefOp2_del = true;
+ Src2 = DefOp2->getOperand(1).getReg();
+ secConv = true;
+ }
+
+ if (firstConv && secConv) {
+ BuildMI(MBB, MI, DL, HII->get(getOperation(Op, true, true)), Dest)
+ .addReg(Src1)
+ .addReg(Src2);
+ SfHfInstrList.push_back(&MI);
+ } else if (firstConv) {
+ BuildMI(MBB, MI, DL, HII->get(getOperation(Op, true, false)), Dest)
+ .addReg(Src1)
+ .addReg(Reg2);
+ SfHfInstrList.push_back(&MI);
+ } else if (secConv) {
+ // For v81, we interchange the ops for vadd/vmul
+ // for vsub we use qf as second operand
+ if (HST->useHVXV81Ops()) {
+ if (!isSub)
+ BuildMI(MBB, MI, DL, HII->get(getOperation(Op, true, false)), Dest)
+ .addReg(Src2)
+ .addReg(Reg1);
+ else
+ BuildMI(MBB, MI, DL, HII->get(getOperation(Op, false, true)), Dest)
+ .addReg(Reg1)
+ .addReg(Src2);
+ SfHfInstrList.push_back(&MI);
+ } else if (HST->useHVXV79Ops()) {
+ // for vadd/vmul we interchange the ops, for vsub we ignore
+ if (!isSub) {
+ BuildMI(MBB, MI, DL, HII->get(getOperation(Op, true, false)), Dest)
+ .addReg(Src2)
+ .addReg(Reg1);
+ SfHfInstrList.push_back(&MI);
+ } else // don't delete the convert instruction for vsub
+ DefOp2_del = false;
+ }
+ } else { // none of the operands are from convert instructions
+ }
+
+ if (DefOp1_del)
+ ConvInstrList.insert(DefOp1);
+ if (DefOp2_del)
+ ConvInstrList.insert(DefOp2);
+}
+
+// Removes converts feeding to op(qf,sf), and replaces its sf operands with qf
+void VectorConvertRemove::handle_addsub_qf_sf(MachineInstr &MI, Register &Reg1,
+ Register &Reg2, Register &Dest,
+ bool isAdd) {
+ MachineBasicBlock &MBB = *MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+ Register Src;
+ bool conv = false;
+
+ MachineInstr *DefOp = MRI->getVRegDef(Reg2);
+ // check if the second operand is from a convert operation
+ if (DefOp->getOpcode() == Hexagon::V6_vconv_sf_qf32) {
+ if (checkHVXUses32(DefOp, &MI))
+ ConvInstrList.insert(DefOp);
+ Src = DefOp->getOperand(1).getReg();
+ conv = true;
+ }
+
+ if (conv) {
+ BuildMI(MBB, MI, DL,
+ HII->get(isAdd ? Hexagon::V6_vadd_qf32 : Hexagon::V6_vsub_qf32),
+ Dest)
+ .addReg(Reg1)
+ .addReg(Src);
+ SfHfInstrList.push_back(&MI);
+ }
+}
+
+// Removes converts feeding to op(qf,hf), and replaces its hf operands with qf
+void VectorConvertRemove::handle_addsubmul_qf_hf(MachineInstr &MI,
+ Register &Reg1, Register &Reg2,
+ Register &Dest, Operation Op) {
+ MachineBasicBlock &MBB = *MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+ Register Src;
+ bool conv = false;
+
+ MachineInstr *DefOp = MRI->getVRegDef(Reg2);
+ // check if the second operand is from a convert operation
+ if (DefOp->getOpcode() == Hexagon::V6_vconv_hf_qf16) {
+ if (checkHVXUses16(DefOp, &MI))
+ ConvInstrList.insert(DefOp);
+ Src = DefOp->getOperand(1).getReg();
+ conv = true;
+ }
+
+ if (conv) {
+ BuildMI(MBB, MI, DL, HII->get(getOperation(Op, true, true)), Dest)
+ .addReg(Reg1)
+ .addReg(Src);
+ SfHfInstrList.push_back(&MI);
+ }
+}
+
+// Removes converts feeding to op(sf,sf), and replaces its sf operands with qf
+void VectorConvertRemove::handle_qf32_mul_sf_sf(MachineInstr &MI,
+ Register &Reg1, Register &Reg2,
+ Register &Dest) {
+ MachineBasicBlock &MBB = *MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+ Register Src1, Src2;
+ bool firstConv = false, secConv = false;
+
+ MachineInstr *DefOp1 = MRI->getVRegDef(Reg1);
+ MachineInstr *DefOp2 = MRI->getVRegDef(Reg2);
+
+ if (DefOp1->getOpcode() == Hexagon::V6_vconv_sf_qf32 &&
+ DefOp2->getOpcode() == Hexagon::V6_vconv_sf_qf32) {
+ // If yes, we can remove the convert
+ if (checkHVXUses32(DefOp1, &MI) && checkHVXUses32(DefOp2, &MI)) {
+ ConvInstrList.insert(DefOp1);
+ ConvInstrList.insert(DefOp2);
+ }
+ Src1 = DefOp1->getOperand(1).getReg();
+ Src2 = DefOp2->getOperand(1).getReg();
+ firstConv = true;
+ secConv = true;
+ }
+
+ // If both are true, then only replace with qf32 = vmpy(qf32, qf32)
+ if (firstConv && secConv) {
+ BuildMI(MBB, MI, DL, HII->get(Hexagon::V6_vmpy_qf32), Dest)
+ .addReg(Src1)
+ .addReg(Src2);
+ SfHfInstrList.push_back(&MI);
+ }
+}
+
+void VectorConvertRemove::run() {
+ for (auto &MBB : MF) {
+ for (auto &MI : MBB) {
+ // Skip if the instruction does not have two operands,
+ // or is a bundle instruction
+ // or is a debug instruction
+ if (MI.getNumOperands() != 3 || MI.isDebugInstr())
+ continue;
+
+ auto Op1 = MI.getOperand(1);
+ if (!Op1.isReg())
+ continue;
+ auto Op2 = MI.getOperand(2);
+ if (!Op2.isReg())
+ continue;
+ auto Op0 = MI.getOperand(0);
+ if (!Op0.isReg())
+ continue;
+ Register Reg1 = Op1.getReg();
+ Register Reg2 = Op2.getReg();
+ Register Dest = Op0.getReg();
+
+ switch (MI.getOpcode()) {
+ // TODO Handle the new vsub instructions
+ // qf32 = vadd(sf, sf)
+ case Hexagon::V6_vadd_sf:
+ handle_addsub_sf_sf(MI, Reg1, Reg2, Dest, true);
+ break;
+ // qf32 = vsub(sf, sf)
+ case Hexagon::V6_vsub_sf:
+ handle_addsub_sf_sf(MI, Reg1, Reg2, Dest, false);
+ break;
+ // qf32 = vadd(qf32, sf)
+ case Hexagon::V6_vadd_qf32_mix:
+ handle_addsub_qf_sf(MI, Reg1, Reg2, Dest, true);
+ break;
+ // qf32 = vsub(qf32, sf)
+ case Hexagon::V6_vsub_qf32_mix:
+ handle_addsub_qf_sf(MI, Reg1, Reg2, Dest, false);
+ break;
+ // qf16 = vadd(hf, hf)
+ case Hexagon::V6_vadd_hf:
+ handle_addsubmul_hf_hf(MI, Reg1, Reg2, Dest, Operation::Add16);
+ break;
+ // qf16 = vsub(hf, hf)
+ case Hexagon::V6_vsub_hf:
+ handle_addsubmul_hf_hf(MI, Reg1, Reg2, Dest, Operation::Sub16);
+ break;
+ // qf16 = vadd(qf16, hf)
+ case Hexagon::V6_vadd_qf16_mix:
+ handle_addsubmul_qf_hf(MI, Reg1, Reg2, Dest, Operation::Add16);
+ break;
+ // qf16 = vsub(qf16, hf)
+ case Hexagon::V6_vsub_qf16_mix:
+ handle_addsubmul_qf_hf(MI, Reg1, Reg2, Dest, Operation::Sub16);
+ break;
+ // qf32 = vmpy(sf, sf)
+ case Hexagon::V6_vmpy_qf32_sf:
+ handle_qf32_mul_sf_sf(MI, Reg1, Reg2, Dest);
+ break;
+ // qf32 = vmpy(hf, hf)
+ case Hexagon::V6_vmpy_qf32_hf:
+ handle_addsubmul_hf_hf(MI, Reg1, Reg2, Dest, Operation::Mul32);
+ break;
+ // qf32 = vmpy(qf16, hf)
+ case Hexagon::V6_vmpy_qf32_mix_hf:
+ handle_addsubmul_qf_hf(MI, Reg1, Reg2, Dest, Operation::Mul32);
+ break;
+ // qf16 = vmpy(hf, hf)
+ case Hexagon::V6_vmpy_qf16_hf:
+ handle_addsubmul_hf_hf(MI, Reg1, Reg2, Dest, Operation::Mul16);
+ break;
+ // qf16 = vmpy(qf16, hf)
+ case Hexagon::V6_vmpy_qf16_mix_hf:
+ handle_addsubmul_qf_hf(MI, Reg1, Reg2, Dest, Operation::Mul16);
+ ;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Delete the vadd/vsub/vmpy instructions
+ for (MachineInstr *sfhfMI : SfHfInstrList) {
+ LLVM_DEBUG(dbgs() << "deleting sf/hf instruction ");
+ LLVM_DEBUG(sfhfMI->dump());
+ sfhfMI->eraseFromParent();
+ }
+ // Delete conversion instructions
+ for (MachineInstr *convMI : ConvInstrList) {
+ LLVM_DEBUG(dbgs() << "deleting conversion instruction");
+ LLVM_DEBUG(convMI->dump());
+ convMI->eraseFromParent();
+ }
+}
+
char HexagonXQFloatGenerator::ID = 0;
} // namespace
@@ -1652,6 +2128,16 @@ bool HexagonXQFloatGenerator::runOnMachineFunction(MachineFunction &MF) {
HII = HST->getInstrInfo();
MRI = &MF.getRegInfo();
+ if (EnableConversionsRemoval &&
+ !(QFloatModeValue == QFloatMode::StrictIEEE)) {
+ VectorConvertRemove VCR(MF, MRI, HST);
+ VCR.run();
+ LLVM_DEBUG(dbgs() << "\nExtraneous conversion instructions removed for "
+ << MF.getName());
+ if (PrintDebug)
+ debug_print(MF);
+ }
+
switch (QFloatModeValue) {
case QFloatMode::StrictIEEE:
LLVM_DEBUG(dbgs() << "\nGenerating code for STRICT-IEEE mode.\n");
diff --git a/llvm/test/CodeGen/Hexagon/autohvx/xqf-assertion1.ll b/llvm/test/CodeGen/Hexagon/autohvx/xqf-assertion1.ll
index f73cfc9c83729..90d0790989388 100644
--- a/llvm/test/CodeGen/Hexagon/autohvx/xqf-assertion1.ll
+++ b/llvm/test/CodeGen/Hexagon/autohvx/xqf-assertion1.ll
@@ -1,9 +1,8 @@
; On v79 and above, checks for Assertion `isImm() && "Wrong MachineOperand accessor"' failed
-; REQUIRES: asserts
-; RUN: llc -march=hexagon -enable-xqf-gen=true \
+; RUN: llc -march=hexagon -enable-xqf-gen=true -enable-rem-conv=true \
; RUN: -mattr=+hvx-ieee-fp,+hvx-length128b,+hvxv79 -o /dev/null < %s
-; RUN: llc -march=hexagon -enable-xqf-gen=true \
+; RUN: llc -march=hexagon -enable-xqf-gen=true -enable-rem-conv=true \
; RUN: -mattr=+hvx-ieee-fp,+hvx-length128b,+hvxv81 -o /dev/null < %s
@@ -72,3 +71,14 @@ attributes #4 = { nocallback nofree nosync nounwind willreturn memory(none) }
attributes #5 = { nofree nounwind }
attributes #6 = { nounwind }
attributes #7 = { noreturn nounwind }
+
+!llvm.module.flags = !{!0, !1, !2}
+!llvm.ident = !{!6}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"frame-pointer", i32 2}
+!2 = !{i32 5, !"CG MDInfo", !3}
+!3 = !{!4, !5}
+!4 = !{!"F", !"no_filename_available", !"", !"", i1 false, !""}
+!5 = !{!"C", !"set_double_vector_mode", !"(void)", !"(...)", i1 true, !""}
+!6 = !{!"QuIC LLVM Hexagon Clang version 8.8-alpha3 Engineering Release: hexagon-clang-88"}
diff --git a/llvm/test/CodeGen/Hexagon/autohvx/xqf-check-qf-instrs.ll b/llvm/test/CodeGen/Hexagon/autohvx/xqf-check-qf-instrs.ll
index c3b22b77d533b..96e497a571cb5 100644
--- a/llvm/test/CodeGen/Hexagon/autohvx/xqf-check-qf-instrs.ll
+++ b/llvm/test/CodeGen/Hexagon/autohvx/xqf-check-qf-instrs.ll
@@ -5,29 +5,29 @@
; REQUIRES: asserts
; RUN: llc -mtriple=hexagon-unknown-elf -mhvx -mcpu=hexagonv79 -mattr=+hvxv79,+hvx-length128b,+hvx-qfloat -enable-xqf-gen=true \
-; RUN: -hexagon-qfloat-mode=ieee -debug-only=handle-qfp -o /dev/null < %s \
+; RUN: -enable-rem-conv=true -hexagon-qfloat-mode=ieee -debug-only=handle-qfp -o /dev/null < %s \
; RUN: 2>&1 | FileCheck %s --check-prefix=IEEE
; RUN: llc -mtriple=hexagon-unknown-...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/207236
More information about the llvm-commits
mailing list