[llvm] 503a935 - [PowerPC][GISel] support 64 bit load/store
Chen Zheng via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 12 04:23:05 PST 2022
Author: Chen Zheng
Date: 2022-12-12T12:20:54Z
New Revision: 503a935d895446a6fa238c412d8561f80d2a2a90
URL: https://github.com/llvm/llvm-project/commit/503a935d895446a6fa238c412d8561f80d2a2a90
DIFF: https://github.com/llvm/llvm-project/commit/503a935d895446a6fa238c412d8561f80d2a2a90.diff
LOG: [PowerPC][GISel] support 64 bit load/store
Reviewed By: arsenm
Differential Revision: https://reviews.llvm.org/D134792
Added:
llvm/test/CodeGen/PowerPC/GlobalISel/load-store-64bit.ll
Modified:
llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp
llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp
llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp
llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h
Removed:
################################################################################
diff --git a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp
index e3f4ccd9e9f60..172f403046c35 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp
+++ b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp
@@ -15,8 +15,11 @@
#include "PPCRegisterBankInfo.h"
#include "PPCSubtarget.h"
#include "PPCTargetMachine.h"
+#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/IR/IntrinsicsPowerPC.h"
#include "llvm/Support/Debug.h"
@@ -121,6 +124,32 @@ static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
return true;
}
+static unsigned selectLoadStoreOp(unsigned GenericOpc, unsigned RegBankID,
+ unsigned OpSize) {
+ const bool IsStore = GenericOpc == TargetOpcode::G_STORE;
+ switch (RegBankID) {
+ case PPC::GPRRegBankID:
+ switch (OpSize) {
+ case 64:
+ return IsStore ? PPC::STD : PPC::LD;
+ default:
+ llvm_unreachable("Unexpected size!");
+ }
+ break;
+ case PPC::FPRRegBankID:
+ switch (OpSize) {
+ case 64:
+ return IsStore ? PPC::STFD : PPC::LFD;
+ default:
+ llvm_unreachable("Unexpected size!");
+ }
+ break;
+ default:
+ llvm_unreachable("Unexpected register bank!");
+ }
+ return GenericOpc;
+}
+
bool PPCInstructionSelector::selectIntToFP(MachineInstr &I,
MachineBasicBlock &MBB,
MachineRegisterInfo &MRI) const {
@@ -198,6 +227,43 @@ bool PPCInstructionSelector::select(MachineInstr &I) {
switch (Opcode) {
default:
return false;
+ case TargetOpcode::G_LOAD:
+ case TargetOpcode::G_STORE: {
+ GLoadStore &LdSt = cast<GLoadStore>(I);
+ LLT PtrTy = MRI.getType(LdSt.getPointerReg());
+
+ if (PtrTy != LLT::pointer(0, 64)) {
+ LLVM_DEBUG(dbgs() << "Load/Store pointer has type: " << PtrTy
+ << ", expected: " << LLT::pointer(0, 64) << '\n');
+ return false;
+ }
+
+ auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
+ const unsigned NewOpc = selectLoadStoreOp(
+ I.getOpcode(), RBI.getRegBank(LdSt.getReg(0), MRI, TRI)->getID(),
+ LdSt.getMemSizeInBits());
+
+ if (NewOpc == I.getOpcode())
+ return nullptr;
+
+ // For now, simply use DForm with load/store addr as base and 0 as imm.
+ // FIXME: optimize load/store with some specific address patterns.
+ I.setDesc(TII.get(NewOpc));
+ Register AddrReg = I.getOperand(1).getReg();
+ bool IsKill = I.getOperand(1).isKill();
+ I.getOperand(1).ChangeToImmediate(0);
+ I.addOperand(*I.getParent()->getParent(),
+ MachineOperand::CreateReg(AddrReg, /* isDef */ false,
+ /* isImp */ false, IsKill));
+ return &I;
+ };
+
+ MachineInstr *LoadStore = SelectLoadStoreAddressingMode();
+ if (!LoadStore)
+ return false;
+
+ return constrainSelectedInstRegOperands(*LoadStore, TII, TRI, RBI);
+ }
case TargetOpcode::G_SITOFP:
case TargetOpcode::G_UITOFP:
return selectIntToFP(I, MBB, MRI);
diff --git a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp
index 2d30b38bddc63..b47f7b942d093 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp
+++ b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp
@@ -19,6 +19,7 @@ using namespace LegalizeActions;
PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) {
using namespace TargetOpcode;
+ const LLT P0 = LLT::pointer(0, 64);
const LLT S32 = LLT::scalar(32);
const LLT S64 = LLT::scalar(64);
getActionDefinitionsBuilder(G_IMPLICIT_DEF).legalFor({S64});
@@ -41,5 +42,10 @@ PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) {
getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
.legalForCartesianProduct({S32, S64}, {S64});
+ // For now only handle 64 bit, we only support 64 bit integer and zext/sext is
+ // not ready.
+ getActionDefinitionsBuilder({G_LOAD, G_STORE})
+ .legalForTypesWithMemDesc({{S64, P0, S64, 8}});
+
getLegacyLegalizerInfo().computeTables();
}
diff --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp
index a9154a451ab4c..cd67dd9de9be7 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp
+++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp
@@ -119,6 +119,37 @@ PPCRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
getValueMapping(PMI_GPR64)});
break;
}
+ case TargetOpcode::G_LOAD: {
+ // Check if that load feeds fp instructions.
+ if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),
+ [&](const MachineInstr &UseMI) {
+ // If we have at least one direct use in a FP instruction,
+ // assume this was a floating point load in the IR. If it was
+ // not, we would have had a bitcast before reaching that
+ // instruction.
+ //
+ // Int->FP conversion operations are also captured in
+ // onlyDefinesFP().
+ return onlyUsesFP(UseMI, MRI, TRI);
+ }))
+ OperandsMapping = getOperandsMapping(
+ {getValueMapping(PMI_FPR64), getValueMapping(PMI_GPR64)});
+ else
+ OperandsMapping = getOperandsMapping(
+ {getValueMapping(PMI_GPR64), getValueMapping(PMI_GPR64)});
+ break;
+ }
+ case TargetOpcode::G_STORE: {
+ // Check if the store is fed by fp instructions.
+ MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(0).getReg());
+ if (onlyDefinesFP(*DefMI, MRI, TRI))
+ OperandsMapping = getOperandsMapping(
+ {getValueMapping(PMI_FPR64), getValueMapping(PMI_GPR64)});
+ else
+ OperandsMapping = getOperandsMapping(
+ {getValueMapping(PMI_GPR64), getValueMapping(PMI_GPR64)});
+ break;
+ }
default:
return getInvalidInstructionMapping();
}
@@ -126,6 +157,128 @@ PPCRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
return getInstructionMapping(MappingID, Cost, OperandsMapping, NumOperands);
}
+/// Returns whether opcode \p Opc is a pre-isel generic floating-point opcode,
+/// having only floating-point operands.
+/// FIXME: this is copied from target AArch64. Needs some code refactor here to
+/// put this function in GlobalISel/Utils.cpp.
+static bool isPreISelGenericFloatingPointOpcode(unsigned Opc) {
+ switch (Opc) {
+ case TargetOpcode::G_FADD:
+ case TargetOpcode::G_FSUB:
+ case TargetOpcode::G_FMUL:
+ case TargetOpcode::G_FMA:
+ case TargetOpcode::G_FDIV:
+ case TargetOpcode::G_FCONSTANT:
+ case TargetOpcode::G_FPEXT:
+ case TargetOpcode::G_FPTRUNC:
+ case TargetOpcode::G_FCEIL:
+ case TargetOpcode::G_FFLOOR:
+ case TargetOpcode::G_FNEARBYINT:
+ case TargetOpcode::G_FNEG:
+ case TargetOpcode::G_FCOS:
+ case TargetOpcode::G_FSIN:
+ case TargetOpcode::G_FLOG10:
+ case TargetOpcode::G_FLOG:
+ case TargetOpcode::G_FLOG2:
+ case TargetOpcode::G_FSQRT:
+ case TargetOpcode::G_FABS:
+ case TargetOpcode::G_FEXP:
+ case TargetOpcode::G_FRINT:
+ case TargetOpcode::G_INTRINSIC_TRUNC:
+ case TargetOpcode::G_INTRINSIC_ROUND:
+ case TargetOpcode::G_FMAXNUM:
+ case TargetOpcode::G_FMINNUM:
+ case TargetOpcode::G_FMAXIMUM:
+ case TargetOpcode::G_FMINIMUM:
+ return true;
+ }
+ return false;
+}
+
+/// \returns true if a given intrinsic \p ID only uses and defines FPRs.
+static bool isFPIntrinsic(unsigned ID) {
+ // TODO: Add more intrinsics.
+ switch (ID) {
+ default:
+ return false;
+ }
+}
+
+/// FIXME: this is copied from target AArch64. Needs some code refactor here to
+/// put this function in class RegisterBankInfo.
+bool PPCRegisterBankInfo::hasFPConstraints(const MachineInstr &MI,
+ const MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI,
+ unsigned Depth) const {
+ unsigned Op = MI.getOpcode();
+ if (Op == TargetOpcode::G_INTRINSIC && isFPIntrinsic(MI.getIntrinsicID()))
+ return true;
+
+ // Do we have an explicit floating point instruction?
+ if (isPreISelGenericFloatingPointOpcode(Op))
+ return true;
+
+ // No. Check if we have a copy-like instruction. If we do, then we could
+ // still be fed by floating point instructions.
+ if (Op != TargetOpcode::COPY && !MI.isPHI() &&
+ !isPreISelGenericOptimizationHint(Op))
+ return false;
+
+ // Check if we already know the register bank.
+ auto *RB = getRegBank(MI.getOperand(0).getReg(), MRI, TRI);
+ if (RB == &PPC::FPRRegBank)
+ return true;
+ if (RB == &PPC::GPRRegBank)
+ return false;
+
+ // We don't know anything.
+ //
+ // If we have a phi, we may be able to infer that it will be assigned a FPR
+ // based off of its inputs.
+ if (!MI.isPHI() || Depth > MaxFPRSearchDepth)
+ return false;
+
+ return any_of(MI.explicit_uses(), [&](const MachineOperand &Op) {
+ return Op.isReg() &&
+ onlyDefinesFP(*MRI.getVRegDef(Op.getReg()), MRI, TRI, Depth + 1);
+ });
+}
+
+/// FIXME: this is copied from target AArch64. Needs some code refactor here to
+/// put this function in class RegisterBankInfo.
+bool PPCRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
+ const MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI,
+ unsigned Depth) const {
+ switch (MI.getOpcode()) {
+ case TargetOpcode::G_FPTOSI:
+ case TargetOpcode::G_FPTOUI:
+ case TargetOpcode::G_FCMP:
+ case TargetOpcode::G_LROUND:
+ case TargetOpcode::G_LLROUND:
+ return true;
+ default:
+ break;
+ }
+ return hasFPConstraints(MI, MRI, TRI, Depth);
+}
+
+/// FIXME: this is copied from target AArch64. Needs some code refactor here to
+/// put this function in class RegisterBankInfo.
+bool PPCRegisterBankInfo::onlyDefinesFP(const MachineInstr &MI,
+ const MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI,
+ unsigned Depth) const {
+ switch (MI.getOpcode()) {
+ case TargetOpcode::G_SITOFP:
+ case TargetOpcode::G_UITOFP:
+ return true;
+ default:
+ break;
+ }
+ return hasFPConstraints(MI, MRI, TRI, Depth);
+}
+
RegisterBankInfo::InstructionMappings
PPCRegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const {
// TODO Implement.
diff --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h
index 40959a3e625e9..b1a16dbb60f65 100644
--- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h
+++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h
@@ -69,6 +69,23 @@ class PPCRegisterBankInfo final : public PPCGenRegisterBankInfo {
InstructionMappings
getInstrAlternativeMappings(const MachineInstr &MI) const override;
+
+private:
+ /// Maximum recursion depth for hasFPConstraints.
+ const unsigned MaxFPRSearchDepth = 2;
+
+ /// \returns true if \p MI only uses and defines FPRs.
+ bool hasFPConstraints(const MachineInstr &MI, const MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI,
+ unsigned Depth = 0) const;
+
+ /// \returns true if \p MI only uses FPRs.
+ bool onlyUsesFP(const MachineInstr &MI, const MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI, unsigned Depth = 0) const;
+
+ /// \returns true if \p MI only defines FPRs.
+ bool onlyDefinesFP(const MachineInstr &MI, const MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI, unsigned Depth = 0) const;
};
} // namespace llvm
diff --git a/llvm/test/CodeGen/PowerPC/GlobalISel/load-store-64bit.ll b/llvm/test/CodeGen/PowerPC/GlobalISel/load-store-64bit.ll
new file mode 100644
index 0000000000000..ade1d63805360
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/GlobalISel/load-store-64bit.ll
@@ -0,0 +1,248 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -o - \
+; RUN: -ppc-vsr-nums-as-vr -ppc-asm-full-reg-names < %s | FileCheck %s
+
+define i64 @load_i64(ptr %p) {
+; CHECK-LABEL: load_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: ld r3, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %ret = load i64, ptr %p, align 8
+ ret i64 %ret
+}
+
+define i64 @load2_i64(ptr %p, i64 %a) {
+; CHECK-LABEL: load2_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: ld r3, 0(r3)
+; CHECK-NEXT: add r3, r3, r4
+; CHECK-NEXT: blr
+entry:
+ %load = load i64, ptr %p, align 8
+ %ret = add i64 %load, %a
+ ret i64 %ret
+}
+
+define float @load3_i64(ptr %p) {
+; CHECK-LABEL: load3_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: ld r3, 0(r3)
+; CHECK-NEXT: mtfprd f0, r3
+; CHECK-NEXT: xscvsxdsp f1, f0
+; CHECK-NEXT: blr
+entry:
+ %load = load i64, ptr %p, align 8
+ %ret = sitofp i64 %load to float
+ ret float %ret
+}
+
+define double @load4_i64(ptr %p) {
+; CHECK-LABEL: load4_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: ld r3, 0(r3)
+; CHECK-NEXT: mtfprd f0, r3
+; CHECK-NEXT: xscvsxddp f1, f0
+; CHECK-NEXT: blr
+entry:
+ %load = load i64, ptr %p, align 8
+ %ret = sitofp i64 %load to double
+ ret double %ret
+}
+
+define float @load5_i64(ptr %p) {
+; CHECK-LABEL: load5_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: ld r3, 0(r3)
+; CHECK-NEXT: mtfprd f0, r3
+; CHECK-NEXT: xscvuxdsp f1, f0
+; CHECK-NEXT: blr
+entry:
+ %load = load i64, ptr %p, align 8
+ %ret = uitofp i64 %load to float
+ ret float %ret
+}
+
+define double @load6_i64(ptr %p) {
+; CHECK-LABEL: load6_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: ld r3, 0(r3)
+; CHECK-NEXT: mtfprd f0, r3
+; CHECK-NEXT: xscvuxddp f1, f0
+; CHECK-NEXT: blr
+entry:
+ %load = load i64, ptr %p, align 8
+ %ret = uitofp i64 %load to double
+ ret double %ret
+}
+
+define double @load_f64(ptr %p) {
+; CHECK-LABEL: load_f64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: lfd f1, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %ret = load double, ptr %p, align 8
+ ret double %ret
+}
+
+define double @load2_f64(ptr %p, double %a) {
+; CHECK-LABEL: load2_f64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: lfd f0, 0(r3)
+; CHECK-NEXT: xsadddp f1, f0, f1
+; CHECK-NEXT: blr
+entry:
+ %load = load double, ptr %p, align 8
+ %ret = fadd double %load, %a
+ ret double %ret
+}
+
+define i64 @load3_f64(ptr %p) {
+; CHECK-LABEL: load3_f64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: lfd f0, 0(r3)
+; CHECK-NEXT: xscvdpsxds f0, f0
+; CHECK-NEXT: mffprd r3, f0
+; CHECK-NEXT: blr
+entry:
+ %load = load double, ptr %p, align 8
+ %ret = fptosi double %load to i64
+ ret i64 %ret
+}
+
+define i64 @load4_f64(ptr %p) {
+; CHECK-LABEL: load4_f64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: lfd f0, 0(r3)
+; CHECK-NEXT: xscvdpuxds f0, f0
+; CHECK-NEXT: mffprd r3, f0
+; CHECK-NEXT: blr
+entry:
+ %load = load double, ptr %p, align 8
+ %ret = fptoui double %load to i64
+ ret i64 %ret
+}
+
+define void @store_i64(ptr %p) {
+; CHECK-LABEL: store_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: li r4, 100
+; CHECK-NEXT: std r4, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ store i64 100, ptr %p, align 8
+ ret void
+}
+
+define void @store2_i64(ptr %p, i64 %a, i64 %b) {
+; CHECK-LABEL: store2_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: add r4, r4, r5
+; CHECK-NEXT: std r4, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %add = add i64 %a, %b
+ store i64 %add, ptr %p, align 8
+ ret void
+}
+
+define void @store3_i64(ptr %p, float %a) {
+; CHECK-LABEL: store3_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: xscvdpsxds f0, f1
+; CHECK-NEXT: mffprd r4, f0
+; CHECK-NEXT: std r4, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %conv = fptosi float %a to i64
+ store i64 %conv, ptr %p, align 8
+ ret void
+}
+
+define void @store4_i64(ptr %p, double %a) {
+; CHECK-LABEL: store4_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: xscvdpsxds f0, f1
+; CHECK-NEXT: mffprd r4, f0
+; CHECK-NEXT: std r4, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %conv = fptosi double %a to i64
+ store i64 %conv, ptr %p, align 8
+ ret void
+}
+
+define void @store5_i64(ptr %p, float %a) {
+; CHECK-LABEL: store5_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: xscvdpuxds f0, f1
+; CHECK-NEXT: mffprd r4, f0
+; CHECK-NEXT: std r4, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %conv = fptoui float %a to i64
+ store i64 %conv, ptr %p, align 8
+ ret void
+}
+
+define void @store6_i64(ptr %p, double %a) {
+; CHECK-LABEL: store6_i64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: xscvdpuxds f0, f1
+; CHECK-NEXT: mffprd r4, f0
+; CHECK-NEXT: std r4, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %conv = fptoui double %a to i64
+ store i64 %conv, ptr %p, align 8
+ ret void
+}
+
+define void @store_f64(ptr %p, double %a) {
+; CHECK-LABEL: store_f64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: stfd f1, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ store double %a, ptr %p, align 8
+ ret void
+}
+
+define void @store2_f64(ptr %p, double %a, double %b) {
+; CHECK-LABEL: store2_f64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: xsadddp f0, f1, f2
+; CHECK-NEXT: stfd f0, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %fadd = fadd double %a, %b
+ store double %fadd, ptr %p, align 8
+ ret void
+}
+
+define void @store3_f64(ptr %p, i64 %a) {
+; CHECK-LABEL: store3_f64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: mtfprd f0, r4
+; CHECK-NEXT: xscvsxddp f0, f0
+; CHECK-NEXT: stfd f0, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %conv = sitofp i64 %a to double
+ store double %conv, ptr %p, align 8
+ ret void
+}
+
+define void @store4_f64(ptr %p, i64 %a) {
+; CHECK-LABEL: store4_f64:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: mtfprd f0, r4
+; CHECK-NEXT: xscvuxddp f0, f0
+; CHECK-NEXT: stfd f0, 0(r3)
+; CHECK-NEXT: blr
+entry:
+ %conv = uitofp i64 %a to double
+ store double %conv, ptr %p, align 8
+ ret void
+}
More information about the llvm-commits
mailing list