Author: Lucas Chollet Date: 2026-06-11T00:11:23-07:00 New Revision: 685a4702e8f0f7a0d8db0643227c6569ad391c09
URL: https://github.com/llvm/llvm-project/commit/685a4702e8f0f7a0d8db0643227c6569ad391c09 DIFF: https://github.com/llvm/llvm-project/commit/685a4702e8f0f7a0d8db0643227c6569ad391c09.diff LOG: [RISCV] Add partial support for -fzero-call-used-regs (#194883) This implements the "-fzero-call-used-regs" option on RISCV for the "skip" and "*gpr*" arguments. Zeroing floating points and vector registers will be implemented later. Added: llvm/test/CodeGen/RISCV/zero-call-used-regs.ll Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Options/Options.td clang/lib/Driver/ToolChains/Clang.cpp llvm/lib/Target/RISCV/RISCVFrameLowering.cpp llvm/lib/Target/RISCV/RISCVFrameLowering.h llvm/lib/Target/RISCV/RISCVInstrInfo.cpp llvm/lib/Target/RISCV/RISCVInstrInfo.h llvm/lib/Target/RISCV/RISCVInstrInfo.td llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp llvm/lib/Target/RISCV/RISCVRegisterInfo.h llvm/lib/Target/RISCV/RISCVRegisterInfo.td Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a0a1daeb3caa2..78accb48547e5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -401,6 +401,9 @@ Modified Compiler Flags - The `-mno-outline` and `-moutline` compiler flags are now allowed on RISC-V and X86, which both support the machine outliner. - The `-mno-outline` flag will now add the `nooutline` IR attribute, so that `-mno-outline` and `-moutline` objects can be mixed correctly during LTO. +- The `-fzero-call-used-regs` compiler flag is now allowed on RISC-V, only the + "skip", "used-gpr", "used-gpr-arg", "all-gpr" and "all-gpr-arg" options are + supported for the moment. - Slightly changed hash id generation to get the unique linkage symbols names by ``-unique-internal-linkage-names`` option. Now it uses a path that diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 58af5ce45610b..44718600ea071 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4977,7 +4977,7 @@ defm raw_string_literals : BoolFOption<"raw-string-literals", def fzero_call_used_regs_EQ : Joined<["-"], "fzero-call-used-regs=">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>, - HelpText<"Clear call-used registers upon function return (AArch64/x86 only)">, + HelpText<"Clear call-used registers upon function return (AArch64/RISC-V/x86 only)">, Values<"skip,used-gpr-arg,used-gpr,used-arg,used,all-gpr-arg,all-gpr,all-arg,all">, NormalizedValues<["Skip", "UsedGPRArg", "UsedGPR", "UsedArg", "Used", "AllGPRArg", "AllGPR", "AllArg", "All"]>, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index b25bddf5a94e8..b6bab8f58a160 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6879,10 +6879,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_check_new); if (Arg *A = Args.getLastArg(options::OPT_fzero_call_used_regs_EQ)) { - // FIXME: There's no reason for this to be restricted to X86. The backend - // code needs to be changed to include the appropriate function calls - // automatically. - if (!Triple.isX86() && !Triple.isAArch64()) + // FIXME: There's no reason for this to be restricted to some backend. + // The backend code needs to be changed to include the appropriate function + // calls automatically. + StringRef Value = A->getValue(); + if (!Triple.isX86() && !Triple.isAArch64() && + !(Triple.isRISCV() && (Value == "skip" || Value.contains("gpr")))) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; } diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp index 9dac6de887f4a..7facdb1b4d548 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -1433,6 +1433,27 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, emitSiFiveCLICStackSwap(MF, MBB, MBBI, DL); } +void RISCVFrameLowering::emitZeroCallUsedRegs(BitVector RegsToZero, + MachineBasicBlock &MBB) const { + // Insertion point. + MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); + + // Fake a debug loc. + DebugLoc DL; + if (MBBI != MBB.end()) + DL = MBBI->getDebugLoc(); + + const MachineFunction &MF = *MBB.getParent(); + const RISCVSubtarget &STI = MF.getSubtarget<RISCVSubtarget>(); + const RISCVRegisterInfo &TRI = *STI.getRegisterInfo(); + const RISCVInstrInfo &TII = *STI.getInstrInfo(); + + for (MCRegister Reg : RegsToZero.set_bits()) { + if (TRI.isGeneralPurposeRegister(MF, Reg)) + TII.buildClearRegister(Reg, MBB, MBBI, DL); + } +} + StackOffset RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg) const { diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h index 84e48dbc05d67..496af9b9fd9cc 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h @@ -115,6 +115,10 @@ class RISCVFrameLowering : public TargetFrameLowering { const DebugLoc &DL, int64_t Amount, MachineInstr::MIFlag Flag, bool EmitCFI, bool DynAllocation) const; + + /// Emit target zero call-used regs. + void emitZeroCallUsedRegs(BitVector RegsToZero, + MachineBasicBlock &MBB) const override; }; } // namespace llvm #endif diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index fc9aea14d83a2..9076cbbc82ed9 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -3943,6 +3943,22 @@ MachineBasicBlock::iterator RISCVInstrInfo::insertOutlinedCall( return It; } +void RISCVInstrInfo::buildClearRegister(Register Reg, MachineBasicBlock &MBB, + MachineBasicBlock::iterator Iter, + DebugLoc &DL, + bool AllowSideEffects) const { + + const MachineFunction &MF = *MBB.getParent(); + const RISCVRegisterInfo &TRI = *STI.getRegisterInfo(); + + if (TRI.isGeneralPurposeRegister(MF, Reg)) { + BuildMI(MBB, Iter, DL, get(RISCV::PseudoClearGPR), Reg); + } else { + llvm::reportFatalInternalError( + "buildClearRegister is not implemented for non-GPR registers"); + } +} + std::optional<RegImmPair> RISCVInstrInfo::isAddImmediate(const MachineInstr &MI, Register Reg) const { // TODO: Handle cases where Reg is a super- or sub-register of the diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h index 273ed5248f7cd..c75335ba7d145 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h @@ -257,6 +257,10 @@ class RISCVInstrInfo : public RISCVGenInstrInfo { MachineBasicBlock::iterator &It, MachineFunction &MF, outliner::Candidate &C) const override; + void buildClearRegister(Register Reg, MachineBasicBlock &MBB, + MachineBasicBlock::iterator Iter, DebugLoc &DL, + bool AllowSideEffects = true) const override; + std::optional<RegImmPair> isAddImmediate(const MachineInstr &MI, Register Reg) const override; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index ffb0d5eeae0f9..2f58b43dfacbf 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -2161,6 +2161,12 @@ def SetFCSRImm : SetSysRegImm<SysRegFCSR, [FRM, FFLAGS]>; /// Other pseudo-instructions +// Used by -fzero-call-used-regs to zero out registers. +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8, + isCodeGenOnly = true in +def PseudoClearGPR : Pseudo<(outs GPR:$rd), (ins), []>, + PseudoInstExpansion<(ADDI GPR:$rd, X0, 0)>; + // Pessimistically assume the stack pointer will be clobbered let Defs = [X2], Uses = [X2] in { def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp index 7ee3542b05458..59ddedc26a466 100644 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -824,6 +824,16 @@ Register RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const { return TFI->hasFP(MF) ? RISCV::X8 : RISCV::X2; } +bool RISCVRegisterInfo::isArgumentRegister(const MachineFunction &MF, + MCRegister Reg) const { + auto const &STI = MF.getSubtarget<RISCVSubtarget>(); + if (!STI.getRegisterInfo()->isGeneralPurposeRegister(MF, Reg)) + llvm::reportFatalInternalError( + "isArgumentRegister is not implemented for non-GPR registers"); + + return llvm::is_contained(RISCV::getArgGPRs(STI.getTargetABI()), Reg); +} + StringRef RISCVRegisterInfo::getRegAsmName(MCRegister Reg) const { if (Reg == RISCV::SF_VCIX_STATE) return "sf.vcix_state"; diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h index 3a77820d28bbd..df203dc073786 100644 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.h +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.h @@ -125,6 +125,9 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo { Register getFrameRegister(const MachineFunction &MF) const override; + bool isArgumentRegister(const MachineFunction &MF, + MCRegister Reg) const override; + StringRef getRegAsmName(MCRegister Reg) const override; bool requiresRegisterScavenging(const MachineFunction &MF) const override { diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td index 58af1f863f7bf..bd2f3bb4b411e 100644 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td @@ -1018,3 +1018,11 @@ def MR : RISCVRegisterClass<[i8, v8i1], 8, } def MR0 : RISCVRegisterClass<[i8, v8i1], 8, (add M0)>; + +//===----------------------------------------------------------------------===// +// Register categories. +// + +def GeneralPurposeRegisters : RegisterCategory<[GPR]>; + +def FixedRegisters : RegisterCategory<[GPRX0]>; diff --git a/llvm/test/CodeGen/RISCV/zero-call-used-regs.ll b/llvm/test/CodeGen/RISCV/zero-call-used-regs.ll new file mode 100644 index 0000000000000..28e6c792b9dfd --- /dev/null +++ b/llvm/test/CodeGen/RISCV/zero-call-used-regs.ll @@ -0,0 +1,284 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc < %s -verify-machineinstrs -mtriple=riscv64-unknown-unknown | FileCheck %s --check-prefixes=CHECK,64-BITS +; RUN: llc < %s -verify-machineinstrs -mtriple=riscv32-unknown-unknown | FileCheck %s --check-prefixes=CHECK,32-BITS + +define i32 @skip(i32 noundef %a, i32 noundef %b, i32 noundef %c) #0 "zero-call-used-regs"="skip" { +; 64-BITS-LABEL: skip: +; 64-BITS: # %bb.0: # %entry +; 64-BITS-NEXT: mulw a0, a1, a0 +; 64-BITS-NEXT: or a0, a0, a2 +; 64-BITS-NEXT: ret +; +; 32-BITS-LABEL: skip: +; 32-BITS: # %bb.0: # %entry +; 32-BITS-NEXT: mul a0, a1, a0 +; 32-BITS-NEXT: or a0, a0, a2 +; 32-BITS-NEXT: ret + +entry: + %mul = mul nsw i32 %b, %a + %or = or i32 %mul, %c + ret i32 %or +} + +define i32 @used_gpr_arg(i32 noundef %a, i32 noundef %b, i32 noundef %c) #0 "zero-call-used-regs"="used-gpr-arg" { +; 64-BITS-LABEL: used_gpr_arg: +; 64-BITS: # %bb.0: # %entry +; 64-BITS-NEXT: mulw a0, a1, a0 +; 64-BITS-NEXT: or a0, a0, a2 +; 64-BITS-NEXT: li a1, 0 +; 64-BITS-NEXT: li a2, 0 +; 64-BITS-NEXT: ret +; +; 32-BITS-LABEL: used_gpr_arg: +; 32-BITS: # %bb.0: # %entry +; 32-BITS-NEXT: mul a0, a1, a0 +; 32-BITS-NEXT: or a0, a0, a2 +; 32-BITS-NEXT: li a1, 0 +; 32-BITS-NEXT: li a2, 0 +; 32-BITS-NEXT: ret + +entry: + %mul = mul nsw i32 %b, %a + %or = or i32 %mul, %c + ret i32 %or +} + +define i32 @used_gpr(i32 noundef %a, i32 noundef %b, i32 noundef %c) #0 "zero-call-used-regs"="used-gpr" { +; 64-BITS-LABEL: used_gpr: +; 64-BITS: # %bb.0: # %entry +; 64-BITS-NEXT: mulw a0, a1, a0 +; 64-BITS-NEXT: or a0, a0, a2 +; 64-BITS-NEXT: li a1, 0 +; 64-BITS-NEXT: li a2, 0 +; 64-BITS-NEXT: ret +; +; 32-BITS-LABEL: used_gpr: +; 32-BITS: # %bb.0: # %entry +; 32-BITS-NEXT: mul a0, a1, a0 +; 32-BITS-NEXT: or a0, a0, a2 +; 32-BITS-NEXT: li a1, 0 +; 32-BITS-NEXT: li a2, 0 +; 32-BITS-NEXT: ret + +entry: + %mul = mul nsw i32 %b, %a + %or = or i32 %mul, %c + ret i32 %or +} + +define i32 @used_arg(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d) #0 "zero-call-used-regs"="used-arg" { +; 64-BITS-LABEL: used_arg: +; 64-BITS: # %bb.0: # %entry +; 64-BITS-NEXT: mulw a0, a1, a0 +; 64-BITS-NEXT: or a0, a0, a2 +; 64-BITS-NEXT: li a1, 0 +; 64-BITS-NEXT: li a2, 0 +; 64-BITS-NEXT: ret +; +; 32-BITS-LABEL: used_arg: +; 32-BITS: # %bb.0: # %entry +; 32-BITS-NEXT: mul a0, a1, a0 +; 32-BITS-NEXT: or a0, a0, a2 +; 32-BITS-NEXT: li a1, 0 +; 32-BITS-NEXT: li a2, 0 +; 32-BITS-NEXT: ret + +entry: + %mul = mul nsw i32 %b, %a + %or = or i32 %mul, %c + ret i32 %or +} + +define i32 @used(i32 noundef %a, i32 noundef %b, i32 noundef %c) #0 "zero-call-used-regs"="used" { +; 64-BITS-LABEL: used: +; 64-BITS: # %bb.0: # %entry +; 64-BITS-NEXT: mulw a0, a1, a0 +; 64-BITS-NEXT: or a0, a0, a2 +; 64-BITS-NEXT: li a1, 0 +; 64-BITS-NEXT: li a2, 0 +; 64-BITS-NEXT: ret +; +; 32-BITS-LABEL: used: +; 32-BITS: # %bb.0: # %entry +; 32-BITS-NEXT: mul a0, a1, a0 +; 32-BITS-NEXT: or a0, a0, a2 +; 32-BITS-NEXT: li a1, 0 +; 32-BITS-NEXT: li a2, 0 +; 32-BITS-NEXT: ret + +entry: + %mul = mul nsw i32 %b, %a + %or = or i32 %mul, %c + ret i32 %or +} + +define i32 @all_gpr_arg(i32 noundef %a, i32 noundef %b, i32 noundef %c) #0 "zero-call-used-regs"="all-gpr-arg" { +; 64-BITS-LABEL: all_gpr_arg: +; 64-BITS: # %bb.0: # %entry +; 64-BITS-NEXT: mulw a0, a1, a0 +; 64-BITS-NEXT: or a0, a0, a2 +; 64-BITS-NEXT: li a1, 0 +; 64-BITS-NEXT: li a2, 0 +; 64-BITS-NEXT: li a3, 0 +; 64-BITS-NEXT: li a4, 0 +; 64-BITS-NEXT: li a5, 0 +; 64-BITS-NEXT: li a6, 0 +; 64-BITS-NEXT: li a7, 0 +; 64-BITS-NEXT: ret +; +; 32-BITS-LABEL: all_gpr_arg: +; 32-BITS: # %bb.0: # %entry +; 32-BITS-NEXT: mul a0, a1, a0 +; 32-BITS-NEXT: or a0, a0, a2 +; 32-BITS-NEXT: li a1, 0 +; 32-BITS-NEXT: li a2, 0 +; 32-BITS-NEXT: li a3, 0 +; 32-BITS-NEXT: li a4, 0 +; 32-BITS-NEXT: li a5, 0 +; 32-BITS-NEXT: li a6, 0 +; 32-BITS-NEXT: li a7, 0 +; 32-BITS-NEXT: ret + +entry: + %mul = mul nsw i32 %b, %a + %or = or i32 %mul, %c + ret i32 %or +} + +define i32 @all_gpr(i32 noundef %a, i32 noundef %b, i32 noundef %c) #0 "zero-call-used-regs"="all-gpr" { +; 64-BITS-LABEL: all_gpr: +; 64-BITS: # %bb.0: # %entry +; 64-BITS-NEXT: mulw a0, a1, a0 +; 64-BITS-NEXT: or a0, a0, a2 +; 64-BITS-NEXT: li t0, 0 +; 64-BITS-NEXT: li t1, 0 +; 64-BITS-NEXT: li t2, 0 +; 64-BITS-NEXT: li a1, 0 +; 64-BITS-NEXT: li a2, 0 +; 64-BITS-NEXT: li a3, 0 +; 64-BITS-NEXT: li a4, 0 +; 64-BITS-NEXT: li a5, 0 +; 64-BITS-NEXT: li a6, 0 +; 64-BITS-NEXT: li a7, 0 +; 64-BITS-NEXT: li t3, 0 +; 64-BITS-NEXT: li t4, 0 +; 64-BITS-NEXT: li t5, 0 +; 64-BITS-NEXT: li t6, 0 +; 64-BITS-NEXT: ret +; +; 32-BITS-LABEL: all_gpr: +; 32-BITS: # %bb.0: # %entry +; 32-BITS-NEXT: mul a0, a1, a0 +; 32-BITS-NEXT: or a0, a0, a2 +; 32-BITS-NEXT: li t0, 0 +; 32-BITS-NEXT: li t1, 0 +; 32-BITS-NEXT: li t2, 0 +; 32-BITS-NEXT: li a1, 0 +; 32-BITS-NEXT: li a2, 0 +; 32-BITS-NEXT: li a3, 0 +; 32-BITS-NEXT: li a4, 0 +; 32-BITS-NEXT: li a5, 0 +; 32-BITS-NEXT: li a6, 0 +; 32-BITS-NEXT: li a7, 0 +; 32-BITS-NEXT: li t3, 0 +; 32-BITS-NEXT: li t4, 0 +; 32-BITS-NEXT: li t5, 0 +; 32-BITS-NEXT: li t6, 0 +; 32-BITS-NEXT: ret + +entry: + %mul = mul nsw i32 %b, %a + %or = or i32 %mul, %c + ret i32 %or +} + +define double @skip_float(double noundef %a, float noundef %b) #0 "zero-call-used-regs"="skip" { +; CHECK-LABEL: skip_float: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fcvt.d.s fa5, fa1 +; CHECK-NEXT: fmul.d fa0, fa5, fa0 +; CHECK-NEXT: ret + +entry: + %conv = fpext float %b to double + %mul = fmul double %conv, %a + ret double %mul +} + +define double @used_gpr_arg_float(double noundef %a, float noundef %b) #0 "zero-call-used-regs"="used-gpr-arg" { +; CHECK-LABEL: used_gpr_arg_float: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fcvt.d.s fa5, fa1 +; CHECK-NEXT: fmul.d fa0, fa5, fa0 +; CHECK-NEXT: ret + +entry: + %conv = fpext float %b to double + %mul = fmul double %conv, %a + ret double %mul +} + +define double @used_gpr_float(double noundef %a, float noundef %b) #0 "zero-call-used-regs"="used-gpr" { +; CHECK-LABEL: used_gpr_float: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fcvt.d.s fa5, fa1 +; CHECK-NEXT: fmul.d fa0, fa5, fa0 +; CHECK-NEXT: ret + +entry: + %conv = fpext float %b to double + %mul = fmul double %conv, %a + ret double %mul +} + +define double @all_gpr_arg_float(double noundef %a, float noundef %b) #0 "zero-call-used-regs"="all-gpr-arg" { +; CHECK-LABEL: all_gpr_arg_float: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fcvt.d.s fa5, fa1 +; CHECK-NEXT: fmul.d fa0, fa5, fa0 +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: li a1, 0 +; CHECK-NEXT: li a2, 0 +; CHECK-NEXT: li a3, 0 +; CHECK-NEXT: li a4, 0 +; CHECK-NEXT: li a5, 0 +; CHECK-NEXT: li a6, 0 +; CHECK-NEXT: li a7, 0 +; CHECK-NEXT: ret + +entry: + %conv = fpext float %b to double + %mul = fmul double %conv, %a + ret double %mul +} + +define double @all_gpr_float(double noundef %a, float noundef %b) #0 "zero-call-used-regs"="all-gpr" { +; CHECK-LABEL: all_gpr_float: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: fcvt.d.s fa5, fa1 +; CHECK-NEXT: fmul.d fa0, fa5, fa0 +; CHECK-NEXT: li t0, 0 +; CHECK-NEXT: li t1, 0 +; CHECK-NEXT: li t2, 0 +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: li a1, 0 +; CHECK-NEXT: li a2, 0 +; CHECK-NEXT: li a3, 0 +; CHECK-NEXT: li a4, 0 +; CHECK-NEXT: li a5, 0 +; CHECK-NEXT: li a6, 0 +; CHECK-NEXT: li a7, 0 +; CHECK-NEXT: li t3, 0 +; CHECK-NEXT: li t4, 0 +; CHECK-NEXT: li t5, 0 +; CHECK-NEXT: li t6, 0 +; CHECK-NEXT: ret + +entry: + %conv = fpext float %b to double + %mul = fmul double %conv, %a + ret double %mul +} + +attributes #0 = { "target-cpu"="generic" "target-features"="+m,+f,+d" } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
