-
Notifications
You must be signed in to change notification settings - Fork 16.6k
[RISCV] Handle codegen for Big Endian #172668
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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); | ||
| } | ||
|
|
@@ -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() && | ||
|
|
@@ -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)) { | ||
|
|
@@ -22538,14 +22552,27 @@ 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)); | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::LW), LoReg) | ||
| .addFrameIndex(FI) | ||
| .addImm(0) | ||
| .addMemOperand(MMOLo); | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::LW), HiReg) | ||
| .addFrameIndex(FI) | ||
| .addImm(4) | ||
| .addMemOperand(MMOHi); | ||
|
|
||
| // For big-endian, the high part is at offset 0 and the low part at offset 4. | ||
| if (!Subtarget.isLittleEndian()) { | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::LW), HiReg) | ||
| .addFrameIndex(FI) | ||
| .addImm(0) | ||
| .addMemOperand(MMOLo); | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::LW), LoReg) | ||
| .addFrameIndex(FI) | ||
| .addImm(4) | ||
| .addMemOperand(MMOHi); | ||
| } else { | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::LW), LoReg) | ||
| .addFrameIndex(FI) | ||
| .addImm(0) | ||
| .addMemOperand(MMOLo); | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::LW), HiReg) | ||
| .addFrameIndex(FI) | ||
| .addImm(4) | ||
| .addMemOperand(MMOHi); | ||
| } | ||
| MI.eraseFromParent(); // The pseudo instruction is gone now. | ||
| return BB; | ||
| } | ||
|
|
@@ -22571,16 +22598,32 @@ 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)); | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::SW)) | ||
| .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill())) | ||
| .addFrameIndex(FI) | ||
| .addImm(0) | ||
| .addMemOperand(MMOLo); | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::SW)) | ||
| .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill())) | ||
| .addFrameIndex(FI) | ||
| .addImm(4) | ||
| .addMemOperand(MMOHi); | ||
|
|
||
| // For big-endian, store the high part at offset 0 and the low part at | ||
| // offset 4. | ||
| if (!Subtarget.isLittleEndian()) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a lot of code duplication here. Can we use more variables to reduce it?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, thanks for the suggestion. |
||
| BuildMI(*BB, MI, DL, TII.get(RISCV::SW)) | ||
| .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill())) | ||
| .addFrameIndex(FI) | ||
| .addImm(0) | ||
| .addMemOperand(MMOLo); | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::SW)) | ||
| .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill())) | ||
| .addFrameIndex(FI) | ||
| .addImm(4) | ||
| .addMemOperand(MMOHi); | ||
| } else { | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::SW)) | ||
| .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill())) | ||
| .addFrameIndex(FI) | ||
| .addImm(0) | ||
| .addMemOperand(MMOLo); | ||
| BuildMI(*BB, MI, DL, TII.get(RISCV::SW)) | ||
| .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill())) | ||
| .addFrameIndex(FI) | ||
| .addImm(4) | ||
| .addMemOperand(MMOHi); | ||
| } | ||
| TII.loadRegFromStackSlot(*BB, MI, DstReg, FI, DstRC, Register()); | ||
| MI.eraseFromParent(); // The pseudo instruction is gone now. | ||
| return BB; | ||
|
|
@@ -23407,6 +23450,13 @@ 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>(); | ||
| // TESTED with: CodeGen/RISCV/bigendian-double-bitmanip.ll | ||
topperc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (!Subtarget.isLittleEndian()) | ||
| std::swap(Lo, Hi); | ||
|
|
||
| return DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, Lo, Hi); | ||
| } | ||
|
|
||
|
|
@@ -23778,6 +23828,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)); | ||
|
|
||
|
|
@@ -24005,8 +24059,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); | ||
|
|
||
|
|
@@ -24071,6 +24131,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(); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -97,6 +97,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { | |
| RISCVProcFamilyEnum RISCVProcFamily = Others; | ||
| RISCVVRGatherCostModelEnum RISCVVRGatherCostModel = Quadratic; | ||
|
|
||
| Triple TargetTriple; | ||
|
||
|
|
||
| #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ | ||
| bool ATTRIBUTE = DEFAULT; | ||
| #include "RISCVGenSubtargetInfo.inc" | ||
|
|
@@ -220,6 +222,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { | |
| } | ||
|
|
||
| bool is64Bit() const { return IsRV64; } | ||
| bool isLittleEndian() const { return TargetTriple.isLittleEndian(); } | ||
|
||
| MVT getXLenVT() const { | ||
| return is64Bit() ? MVT::i64 : MVT::i32; | ||
| } | ||
|
|
||
| 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 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The PSABI doc riscv-non-isa/riscv-elf-psabi-doc#470 says Yet this code seems to be toggling the sign bit in a0. If the psabi doc is correct, isn't the sign bit in a1?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The thing is that riscv-non-isa/riscv-elf-psabi-doc#470 is not ready yet -- or at least not merged/accepted officially yet. Therefore, once psabi is ready, we can change both GCC and LLVM. Until then, we will emit a warning for |
||
| ; 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) | ||
| 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 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we swap LoReg and HiReg instead of mostly duplicating the code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes