Skip to content
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
78 changes: 64 additions & 14 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8347,6 +8347,10 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Lo.getValue(1),
Hi.getValue(1));

// For big-endian, swap the order of Lo and Hi.
if (!Subtarget.isLittleEndian())
std::swap(Lo, Hi);

SDValue Pair = DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, Lo, Hi);
return DAG.getMergeValues({Pair, Chain}, DL);
}
Expand Down Expand Up @@ -8419,15 +8423,21 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
SDValue Split = DAG.getNode(RISCVISD::SplitF64, DL,
DAG.getVTList(MVT::i32, MVT::i32), StoredVal);

SDValue Lo = DAG.getStore(Chain, DL, Split.getValue(0), BasePtr,
Store->getPointerInfo(), Store->getBaseAlign(),
Store->getMemOperand()->getFlags());
SDValue Lo = Split.getValue(0);
SDValue Hi = Split.getValue(1);

// For big-endian, swap the order of Lo and Hi before storing.
if (!Subtarget.isLittleEndian())
std::swap(Lo, Hi);

SDValue LoStore = DAG.getStore(
Chain, DL, Lo, BasePtr, Store->getPointerInfo(),
Store->getBaseAlign(), Store->getMemOperand()->getFlags());
BasePtr = DAG.getObjectPtrOffset(DL, BasePtr, TypeSize::getFixed(4));
SDValue Hi = DAG.getStore(Chain, DL, Split.getValue(1), BasePtr,
Store->getPointerInfo().getWithOffset(4),
Store->getBaseAlign(),
Store->getMemOperand()->getFlags());
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi);
SDValue HiStore = DAG.getStore(
Chain, DL, Hi, BasePtr, Store->getPointerInfo().getWithOffset(4),
Store->getBaseAlign(), Store->getMemOperand()->getFlags());
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, LoStore, HiStore);
}
if (VT == MVT::i64) {
assert(Subtarget.hasStdExtZilsd() && !Subtarget.is64Bit() &&
Expand Down Expand Up @@ -15160,8 +15170,12 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
Subtarget.hasStdExtDOrZdinx()) {
SDValue NewReg = DAG.getNode(RISCVISD::SplitF64, DL,
DAG.getVTList(MVT::i32, MVT::i32), Op0);
SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
NewReg.getValue(0), NewReg.getValue(1));
SDValue Lo = NewReg.getValue(0);
SDValue Hi = NewReg.getValue(1);
// For big-endian, swap the order when building the i64 pair.
if (!Subtarget.isLittleEndian())
std::swap(Lo, Hi);
SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Lo, Hi);
Results.push_back(RetReg);
} else if (!VT.isVector() && Op0VT.isFixedLengthVector() &&
isTypeLegal(Op0VT)) {
Expand Down Expand Up @@ -22538,6 +22552,11 @@ static MachineBasicBlock *emitSplitF64Pseudo(MachineInstr &MI,
MF.getMachineMemOperand(MPI, MachineMemOperand::MOLoad, 4, Align(8));
MachineMemOperand *MMOHi = MF.getMachineMemOperand(
MPI.getWithOffset(4), MachineMemOperand::MOLoad, 4, Align(8));

// For big-endian, the high part is at offset 0 and the low part at offset 4.
if (!Subtarget.isLittleEndian())
std::swap(LoReg, HiReg);

BuildMI(*BB, MI, DL, TII.get(RISCV::LW), LoReg)
.addFrameIndex(FI)
.addImm(0)
Expand All @@ -22562,6 +22581,8 @@ static MachineBasicBlock *emitBuildPairF64Pseudo(MachineInstr &MI,
Register DstReg = MI.getOperand(0).getReg();
Register LoReg = MI.getOperand(1).getReg();
Register HiReg = MI.getOperand(2).getReg();
bool KillLo = MI.getOperand(1).isKill();
bool KillHi = MI.getOperand(2).isKill();

const TargetRegisterClass *DstRC = &RISCV::FPR64RegClass;
int FI = MF.getInfo<RISCVMachineFunctionInfo>()->getMoveF64FrameIndex(MF);
Expand All @@ -22571,13 +22592,21 @@ static MachineBasicBlock *emitBuildPairF64Pseudo(MachineInstr &MI,
MF.getMachineMemOperand(MPI, MachineMemOperand::MOStore, 4, Align(8));
MachineMemOperand *MMOHi = MF.getMachineMemOperand(
MPI.getWithOffset(4), MachineMemOperand::MOStore, 4, Align(8));

// For big-endian, store the high part at offset 0 and the low part at
// offset 4.
if (!Subtarget.isLittleEndian()) {
std::swap(LoReg, HiReg);
std::swap(KillLo, KillHi);
}

BuildMI(*BB, MI, DL, TII.get(RISCV::SW))
.addReg(LoReg, getKillRegState(MI.getOperand(1).isKill()))
.addReg(LoReg, getKillRegState(KillLo))
.addFrameIndex(FI)
.addImm(0)
.addMemOperand(MMOLo);
BuildMI(*BB, MI, DL, TII.get(RISCV::SW))
.addReg(HiReg, getKillRegState(MI.getOperand(2).isKill()))
.addReg(HiReg, getKillRegState(KillHi))
.addFrameIndex(FI)
.addImm(4)
.addMemOperand(MMOHi);
Expand Down Expand Up @@ -23407,6 +23436,12 @@ static SDValue unpackF64OnRV32DSoftABI(SelectionDAG &DAG, SDValue Chain,
RegInfo.addLiveIn(HiVA.getLocReg(), HiVReg);
Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32);
}

// For big-endian, swap the order of Lo and Hi when building the pair.
const RISCVSubtarget &Subtarget = DAG.getSubtarget<RISCVSubtarget>();
if (!Subtarget.isLittleEndian())
std::swap(Lo, Hi);

return DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, Lo, Hi);
}

Expand Down Expand Up @@ -23778,6 +23813,10 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI,
SDValue Lo = SplitF64.getValue(0);
SDValue Hi = SplitF64.getValue(1);

// For big-endian, swap the order of Lo and Hi when passing.
if (!Subtarget.isLittleEndian())
std::swap(Lo, Hi);

Register RegLo = VA.getLocReg();
RegsToPass.push_back(std::make_pair(RegLo, Lo));

Expand Down Expand Up @@ -24005,8 +24044,14 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI,
MVT::i32, Glue);
Chain = RetValue2.getValue(1);
Glue = RetValue2.getValue(2);
RetValue = DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, RetValue,
RetValue2);

// For big-endian, swap the order when building the pair.
SDValue Lo = RetValue;
SDValue Hi = RetValue2;
if (!Subtarget.isLittleEndian())
std::swap(Lo, Hi);

RetValue = DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, Lo, Hi);
} else
RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL, Subtarget);

Expand Down Expand Up @@ -24071,6 +24116,11 @@ RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
DAG.getVTList(MVT::i32, MVT::i32), Val);
SDValue Lo = SplitF64.getValue(0);
SDValue Hi = SplitF64.getValue(1);

// For big-endian, swap the order of Lo and Hi when returning.
if (!Subtarget.isLittleEndian())
std::swap(Lo, Hi);

Register RegLo = VA.getLocReg();
Register RegHi = RVLocs[++i].getLocReg();

Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/RISCV/RISCVSubtarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ RISCVSubtarget::RISCVSubtarget(const Triple &TT, StringRef CPU,
unsigned RVVVectorBitsMax,
const TargetMachine &TM)
: RISCVGenSubtargetInfo(TT, CPU, TuneCPU, FS),
RVVVectorBitsMin(RVVVectorBitsMin), RVVVectorBitsMax(RVVVectorBitsMax),
IsLittleEndian(TT.isLittleEndian()), RVVVectorBitsMin(RVVVectorBitsMin),
RVVVectorBitsMax(RVVVectorBitsMax),
FrameLowering(
initializeSubtargetDependencies(TT, CPU, TuneCPU, FS, ABIName)),
InstrInfo(*this), TLInfo(TM, *this) {
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/RISCV/RISCVSubtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
RISCVProcFamilyEnum RISCVProcFamily = Others;
RISCVVRGatherCostModelEnum RISCVVRGatherCostModel = Quadratic;

bool IsLittleEndian = true;

#define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \
bool ATTRIBUTE = DEFAULT;
#include "RISCVGenSubtargetInfo.inc"
Expand Down Expand Up @@ -220,6 +222,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
}

bool is64Bit() const { return IsRV64; }
bool isLittleEndian() const { return IsLittleEndian; }
MVT getXLenVT() const {
return is64Bit() ? MVT::i64 : MVT::i32;
}
Expand Down
78 changes: 78 additions & 0 deletions llvm/test/CodeGen/RISCV/bigendian-double-bitmanip.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -target-abi=ilp32 -mattr=+d -verify-machineinstrs < %s | FileCheck -check-prefix=RV32IFD-LE %s
; RUN: llc -mtriple=riscv32be -target-abi=ilp32 -mattr=+d -verify-machineinstrs < %s | FileCheck -check-prefix=RV32IFD-BE %s

; Test operations that involve SplitF64/BuildPairF64 on RV32 with D extension
; but soft-float ABI. This configuration triggers the special handling for
; big-endian.

define double @fneg(double %a) nounwind {
; RV32IFD-LE-LABEL: fneg:
; RV32IFD-LE: # %bb.0:
; RV32IFD-LE-NEXT: lui a2, 524288
; RV32IFD-LE-NEXT: xor a1, a1, a2
; RV32IFD-LE-NEXT: ret
;
; RV32IFD-BE-LABEL: fneg:
; RV32IFD-BE: # %bb.0:
; RV32IFD-BE-NEXT: lui a2, 524288
; RV32IFD-BE-NEXT: xor a0, a0, a2
; RV32IFD-BE-NEXT: ret
%1 = fneg double %a
ret double %1
}

define double @fabs(double %a) nounwind {
; RV32IFD-LE-LABEL: fabs:
; RV32IFD-LE: # %bb.0:
; RV32IFD-LE-NEXT: slli a1, a1, 1
; RV32IFD-LE-NEXT: srli a1, a1, 1
; RV32IFD-LE-NEXT: ret
;
; RV32IFD-BE-LABEL: fabs:
; RV32IFD-BE: # %bb.0:
; RV32IFD-BE-NEXT: slli a0, a0, 1
; RV32IFD-BE-NEXT: srli a0, a0, 1
; RV32IFD-BE-NEXT: ret
%1 = call double @llvm.fabs.f64(double %a)
ret double %1
}

define double @fcopysign(double %a, double %b) nounwind {
; RV32IFD-LE-LABEL: fcopysign:
; RV32IFD-LE: # %bb.0:
; RV32IFD-LE-NEXT: addi sp, sp, -16
; RV32IFD-LE-NEXT: sw a2, 8(sp)
; RV32IFD-LE-NEXT: sw a3, 12(sp)
; RV32IFD-LE-NEXT: fld fa5, 8(sp)
; RV32IFD-LE-NEXT: sw a0, 8(sp)
; RV32IFD-LE-NEXT: sw a1, 12(sp)
; RV32IFD-LE-NEXT: fld fa4, 8(sp)
; RV32IFD-LE-NEXT: fsgnj.d fa5, fa4, fa5
; RV32IFD-LE-NEXT: fsd fa5, 8(sp)
; RV32IFD-LE-NEXT: lw a0, 8(sp)
; RV32IFD-LE-NEXT: lw a1, 12(sp)
; RV32IFD-LE-NEXT: addi sp, sp, 16
; RV32IFD-LE-NEXT: ret
;
; RV32IFD-BE-LABEL: fcopysign:
; RV32IFD-BE: # %bb.0:
; RV32IFD-BE-NEXT: addi sp, sp, -16
; RV32IFD-BE-NEXT: sw a2, 8(sp)
; RV32IFD-BE-NEXT: sw a3, 12(sp)
; RV32IFD-BE-NEXT: fld fa5, 8(sp)
; RV32IFD-BE-NEXT: sw a0, 8(sp)
; RV32IFD-BE-NEXT: sw a1, 12(sp)
; RV32IFD-BE-NEXT: fld fa4, 8(sp)
; RV32IFD-BE-NEXT: fsgnj.d fa5, fa4, fa5
; RV32IFD-BE-NEXT: fsd fa5, 8(sp)
; RV32IFD-BE-NEXT: lw a0, 8(sp)
; RV32IFD-BE-NEXT: lw a1, 12(sp)
; RV32IFD-BE-NEXT: addi sp, sp, 16
; RV32IFD-BE-NEXT: ret
%1 = call double @llvm.copysign.f64(double %a, double %b)
ret double %1
}

declare double @llvm.fabs.f64(double)
declare double @llvm.copysign.f64(double, double)
94 changes: 94 additions & 0 deletions llvm/test/CodeGen/RISCV/bigendian-f64-call.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -target-abi=ilp32 -mattr=+d -verify-machineinstrs < %s | FileCheck -check-prefix=RV32LE %s
; RUN: llc -mtriple=riscv32be -target-abi=ilp32 -mattr=+d -verify-machineinstrs < %s | FileCheck -check-prefix=RV32BE %s

; Test f64 function calls with D extension and soft-float ABI
; This specifically tests the LowerCall path that needs to swap Lo/Hi for BE

declare double @external_func(double, double)

define double @test_f64_call(double %a, double %b) {
; RV32LE-LABEL: test_f64_call:
; RV32LE: # %bb.0:
; RV32LE-NEXT: addi sp, sp, -16
; RV32LE-NEXT: .cfi_def_cfa_offset 16
; RV32LE-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
; RV32LE-NEXT: .cfi_offset ra, -4
; RV32LE-NEXT: call external_func
; RV32LE-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
; RV32LE-NEXT: .cfi_restore ra
; RV32LE-NEXT: addi sp, sp, 16
; RV32LE-NEXT: .cfi_def_cfa_offset 0
; RV32LE-NEXT: ret
;
; RV32BE-LABEL: test_f64_call:
; RV32BE: # %bb.0:
; RV32BE-NEXT: addi sp, sp, -16
; RV32BE-NEXT: .cfi_def_cfa_offset 16
; RV32BE-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
; RV32BE-NEXT: .cfi_offset ra, -4
; RV32BE-NEXT: call external_func
; RV32BE-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
; RV32BE-NEXT: .cfi_restore ra
; RV32BE-NEXT: addi sp, sp, 16
; RV32BE-NEXT: .cfi_def_cfa_offset 0
; RV32BE-NEXT: ret
%result = call double @external_func(double %a, double %b)
ret double %result
}

; Test with a computation before the call to force SplitF64
define double @test_f64_call_with_fadd(double %a, double %b) {
; RV32LE-LABEL: test_f64_call_with_fadd:
; RV32LE: # %bb.0:
; RV32LE-NEXT: addi sp, sp, -16
; RV32LE-NEXT: .cfi_def_cfa_offset 16
; RV32LE-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
; RV32LE-NEXT: .cfi_offset ra, -4
; RV32LE-NEXT: sw a2, 0(sp)
; RV32LE-NEXT: sw a3, 4(sp)
; RV32LE-NEXT: fld fa5, 0(sp)
; RV32LE-NEXT: sw a0, 0(sp)
; RV32LE-NEXT: sw a1, 4(sp)
; RV32LE-NEXT: fld fa4, 0(sp)
; RV32LE-NEXT: fadd.d fa5, fa4, fa5
; RV32LE-NEXT: fsd fa5, 0(sp)
; RV32LE-NEXT: lw a0, 0(sp)
; RV32LE-NEXT: lw a1, 4(sp)
; RV32LE-NEXT: mv a2, a0
; RV32LE-NEXT: mv a3, a1
; RV32LE-NEXT: call external_func
; RV32LE-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
; RV32LE-NEXT: .cfi_restore ra
; RV32LE-NEXT: addi sp, sp, 16
; RV32LE-NEXT: .cfi_def_cfa_offset 0
; RV32LE-NEXT: ret
;
; RV32BE-LABEL: test_f64_call_with_fadd:
; RV32BE: # %bb.0:
; RV32BE-NEXT: addi sp, sp, -16
; RV32BE-NEXT: .cfi_def_cfa_offset 16
; RV32BE-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
; RV32BE-NEXT: .cfi_offset ra, -4
; RV32BE-NEXT: sw a2, 0(sp)
; RV32BE-NEXT: sw a3, 4(sp)
; RV32BE-NEXT: fld fa5, 0(sp)
; RV32BE-NEXT: sw a0, 0(sp)
; RV32BE-NEXT: sw a1, 4(sp)
; RV32BE-NEXT: fld fa4, 0(sp)
; RV32BE-NEXT: fadd.d fa5, fa4, fa5
; RV32BE-NEXT: fsd fa5, 0(sp)
; RV32BE-NEXT: lw a0, 0(sp)
; RV32BE-NEXT: lw a1, 4(sp)
; RV32BE-NEXT: mv a2, a0
; RV32BE-NEXT: mv a3, a1
; RV32BE-NEXT: call external_func
; RV32BE-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
; RV32BE-NEXT: .cfi_restore ra
; RV32BE-NEXT: addi sp, sp, 16
; RV32BE-NEXT: .cfi_def_cfa_offset 0
; RV32BE-NEXT: ret
%sum = fadd double %a, %b
%result = call double @external_func(double %sum, double %sum)
ret double %result
}
Loading