Index: llvm/lib/Target/RISCV/CMakeLists.txt =================================================================== --- llvm/lib/Target/RISCV/CMakeLists.txt +++ llvm/lib/Target/RISCV/CMakeLists.txt @@ -21,6 +21,7 @@ add_llvm_target(RISCVCodeGen RISCVAsmPrinter.cpp RISCVCallLowering.cpp + RISCVMakeCompressible.cpp RISCVExpandAtomicPseudoInsts.cpp RISCVExpandPseudoInsts.cpp RISCVFrameLowering.cpp Index: llvm/lib/Target/RISCV/RISCV.h =================================================================== --- llvm/lib/Target/RISCV/RISCV.h +++ llvm/lib/Target/RISCV/RISCV.h @@ -37,6 +37,9 @@ FunctionPass *createRISCVISelDag(RISCVTargetMachine &TM); +FunctionPass *createRISCVMakeCompressibleOptPass(); +void initializeRISCVMakeCompressibleOptPass(PassRegistry &); + FunctionPass *createRISCVGatherScatterLoweringPass(); void initializeRISCVGatherScatterLoweringPass(PassRegistry &); Index: llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp @@ -0,0 +1,358 @@ +//===-- RISCVMakeCompressible.cpp - Make more instructions compressible ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This pass searches for instructions that are prevented from being compressed +// by one of the following: +// +// 1. The use of a single uncompressed register. +// 2. A base register + offset where the offset is too large to be compressed +// and the base register may or may not be compressed. +// +// +// For case 1, if a compressed register is available, then the uncompressed +// register is copied to the compressed register and its uses are replaced. +// +// For example, storing zero uses the uncompressible zero register: +// sw zero, 0(a0) # if zero +// sw zero, 8(a0) # if zero +// sw zero, 4(a0) # if zero +// sw zero, 24(a0) # if zero +// +// If a compressed register (e.g. a1) is available, the above can be transformed +// to the following to improve code size: +// li a1, 0 +// c.sw a1, 0(a0) +// c.sw a1, 8(a0) +// c.sw a1, 4(a0) +// c.sw a1, 24(a0) +// +// +// For case 2, if a compressed register is available, then the original base +// is copied and adjusted such that: +// +// new_base_register = base_register + adjustment +// base_register + large_offset = new_base_register + small_offset +// +// For example, the following offsets are too large for c.sw: +// lui a2, 983065 +// sw a1, -236(a2) +// sw a1, -240(a2) +// sw a1, -244(a2) +// sw a1, -248(a2) +// sw a1, -252(a2) +// sw a0, -256(a2) +// +// If a compressed register is available (e.g. a3), a new base could be created +// such that the addresses can accessed with a compressible offset, thus +// improving code size: +// lui a2, 983065 +// addi a3, a2, -256 +// c.sw a1, 20(a3) +// c.sw a1, 16(a3) +// c.sw a1, 12(a3) +// c.sw a1, 8(a3) +// c.sw a1, 4(a3) +// c.sw a0, 0(a3) +// +// +// This optimization is only applied if there are enough uses of the copied +// register for code size to be reduced. +// +//===----------------------------------------------------------------------===// + +#include "RISCV.h" +#include "RISCVSubtarget.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Debug.h" + +using namespace llvm; + +#define DEBUG_TYPE "riscv-make-compressible" +#define RISCV_COMPRESS_INSTRS_NAME "RISCV Make Compressible" + +namespace { + +struct RISCVMakeCompressibleOpt : public MachineFunctionPass { + static char ID; + + bool runOnMachineFunction(MachineFunction &Fn) override; + + RISCVMakeCompressibleOpt() : MachineFunctionPass(ID) { + initializeRISCVMakeCompressibleOptPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return RISCV_COMPRESS_INSTRS_NAME; } +}; +} // namespace + +char RISCVMakeCompressibleOpt::ID = 0; +INITIALIZE_PASS(RISCVMakeCompressibleOpt, "riscv-make-compressible", + RISCV_COMPRESS_INSTRS_NAME, false, false) + +// Return log2(widthInBytes) of load/store done by Opcode. +static unsigned log2LdstWidth(unsigned Opcode) { + switch (Opcode) { + default: + llvm_unreachable("Unexpected opcode"); + case RISCV::LW: + case RISCV::SW: + case RISCV::FLW: + case RISCV::FSW: + return 2; + case RISCV::LD: + case RISCV::SD: + case RISCV::FLD: + case RISCV::FSD: + return 3; + } +} + +// Return a mask for the offset bits of a non-stack-pointer based compressed +// load/store. +static uint8_t compressedLDSTOffsetMask(unsigned Opcode) { + return 0x1f << log2LdstWidth(Opcode); +} + +// Return true if Offset fits within a compressed stack-pointer based +// load/store. +static bool compressibleSPOffset(int64_t Offset, unsigned Opcode) { + return isShiftedUIntN(6, log2LdstWidth(Opcode), Offset); +} + +// Given an offset for a load/store, return the adjustment required to the base +// register such that the address can be accessed with a compressible offset. +// This will return 0 if the offset is already compressible. +static int64_t getBaseAdjustForCompression(int64_t Offset, unsigned Opcode) { + // Return the excess bits that do not fit in a compressible offset. + return Offset & ~compressedLDSTOffsetMask(Opcode); +} + +// Return true if Reg is in a compressed register class. +static bool isCompressedReg(Register Reg) { + return RISCV::GPRCRegClass.contains(Reg) || + RISCV::FPR32CRegClass.contains(Reg) || + RISCV::FPR64CRegClass.contains(Reg); +} + +// Return true if Opcode is a load for which there exists a compressed version. +static bool isCompressibleLoad(const unsigned Opcode) { + return Opcode == RISCV::LW || Opcode == RISCV::FLW || Opcode == RISCV::LD || + Opcode == RISCV::FLD; +} + +// Return true if Opcode is a store for which there exists a compressed version. +static bool isCompressibleStore(const unsigned Opcode) { + return Opcode == RISCV::SW || Opcode == RISCV::FSW || Opcode == RISCV::SD || + Opcode == RISCV::FSD; +} + +// Find a single register and/or large offset which, if compressible, would +// allow the given instruction to be compressed. +// +// Possible return values: +// {Reg, 0} - Uncompressed Reg needs replacing with a compressed register. +// {Reg, N} - Reg needs replacing with a compressed register and N needs +// adding to the new register. (Reg may be compressed or +// uncompressed). +// {RISCV::NoRegister, 0} - No suitable optimization found for this +// instruction. +static RegImmPair getRegImmPairPreventingCompression(const MachineInstr &MI) { + const unsigned Opcode = MI.getOpcode(); + + if (isCompressibleLoad(Opcode) || isCompressibleStore(Opcode)) { + const MachineOperand &MOImm = MI.getOperand(2); + if (!MOImm.isImm()) + return RegImmPair(RISCV::NoRegister, 0); + + int64_t Offset = MOImm.getImm(); + int64_t NewBaseAdjust = getBaseAdjustForCompression(Offset, Opcode); + Register Base = MI.getOperand(1).getReg(); + + // Memory accesses via the stack pointer do not have a requirement for + // either of the registers to be compressible and can take a larger offset. + if (RISCV::SPRegClass.contains(Base)) { + if (!compressibleSPOffset(Offset, Opcode) && NewBaseAdjust) + return RegImmPair(Base, NewBaseAdjust); + } else { + Register SrcDest = MI.getOperand(0).getReg(); + bool SrcDestCompressed = isCompressedReg(SrcDest); + bool BaseCompressed = isCompressedReg(Base); + + // If only Base and/or offset prevent compression, then return Base and + // any adjustment required to make the offset compressible. + if ((!BaseCompressed || NewBaseAdjust) && SrcDestCompressed) + return RegImmPair(Base, NewBaseAdjust); + + // For loads, we can only change the base register since dest is defined + // rather than used. + // + // For stores, we can change SrcDest (and Base if SrcDest == Base) but + // cannot resolve an uncompressible offset in this case. + if (isCompressibleStore(Opcode)) { + if (!SrcDestCompressed && (BaseCompressed || SrcDest == Base) && + !NewBaseAdjust) + return RegImmPair(SrcDest, NewBaseAdjust); + } + } + } + return RegImmPair(RISCV::NoRegister, 0); +} + +// Check all uses after FirstMI of the given register, keeping a vector of +// instructions that would be compressible if the given register (and offset if +// applicable) were compressible. +// +// If there are enough uses for this optimization to improve code size and a +// compressed register is available, return that compressed register. +static Register analyzeCompressibleUses(MachineInstr &FirstMI, + RegImmPair RegImm, + SmallVectorImpl &MIs) { + MachineBasicBlock &MBB = *FirstMI.getParent(); + const TargetRegisterInfo *TRI = + MBB.getParent()->getSubtarget().getRegisterInfo(); + + RegScavenger RS; + RS.enterBasicBlock(MBB); + + for (MachineBasicBlock::instr_iterator I = FirstMI.getIterator(), + E = MBB.instr_end(); + I != E; ++I) { + MachineInstr &MI = *I; + + // Determine if this is an instruction which would benefit from using the + // new register. + RegImmPair CandidateRegImm = getRegImmPairPreventingCompression(MI); + if (CandidateRegImm.Reg == RegImm.Reg && + CandidateRegImm.Imm == RegImm.Imm) { + // Advance tracking since the value in the new register must be live for + // this instruction too. + RS.forward(I); + + MIs.push_back(&MI); + } + + // If RegImm.Reg is modified by this instruction, then we cannot optimize + // past this instruction. If the register is already compressed, then it may + // possible to optimize a large offset in the current instruction - this + // will have been detected by the preceeding call to + // getRegImmPairPreventingCompression. + if (MI.modifiesRegister(RegImm.Reg, TRI)) + break; + } + + // Adjusting the base costs one new uncompressed addi and therefore three uses + // are required for a code size reduction. If no base adjustment is required, + // then copying the register costs one new c.mv (or c.li Rd, 0 for "copying" + // the zero register) and therefore two uses are required for a code size + // reduction. + if (MIs.size() < 2 || (RegImm.Imm != 0 && MIs.size() < 3)) + return RISCV::NoRegister; + + // Find a compressible register which will be available from the first + // instruction we care about to the last. + const TargetRegisterClass *RCToScavenge; + + // Work out the compressed register class from which to scavenge. + if (RISCV::GPRRegClass.contains(RegImm.Reg)) + RCToScavenge = &RISCV::GPRCRegClass; + else if (RISCV::FPR32RegClass.contains(RegImm.Reg)) + RCToScavenge = &RISCV::FPR32CRegClass; + else if (RISCV::FPR64RegClass.contains(RegImm.Reg)) + RCToScavenge = &RISCV::FPR64CRegClass; + else + return RISCV::NoRegister; + + return RS.scavengeRegisterBackwards(*RCToScavenge, FirstMI.getIterator(), + /*RestoreAfter=*/false, /*SPAdj=*/0, + /*AllowSpill=*/false); +} + +// Update uses of the old register in the given instruction to the new register. +static void updateOperands(MachineInstr &MI, RegImmPair OldRegImm, + Register NewReg) { + unsigned Opcode = MI.getOpcode(); + + // If this pass is extended to support more instructions, the check for + // definedness may need to be strengthened. + assert((isCompressibleLoad(Opcode) || isCompressibleStore(Opcode)) && + "Unsupported instruction for this optimization."); + + // Update registers + for (MachineOperand &MO : MI.operands()) + if (MO.isReg() && MO.getReg() == OldRegImm.Reg) { + // Do not update operands that define the old register. + // + // The new register was scavenged for the range of instructions that are + // being updated, therefore it should not be defined within this range + // except possibly in the final instruction. + if (MO.isDef()) { + assert(isCompressibleLoad(Opcode)); + continue; + } + // Update reg + MO.setReg(NewReg); + } + + // Update offset + MachineOperand &MOImm = MI.getOperand(2); + int64_t NewOffset = MOImm.getImm() & compressedLDSTOffsetMask(Opcode); + MOImm.setImm(NewOffset); +} + +bool RISCVMakeCompressibleOpt::runOnMachineFunction(MachineFunction &Fn) { + // This is a size optimization. + if (skipFunction(Fn.getFunction()) || !Fn.getFunction().hasOptSize()) + return false; + + const RISCVSubtarget &STI = Fn.getSubtarget(); + const RISCVInstrInfo &TII = *STI.getInstrInfo(); + + // This optimization only makes sense if compressed instructions are emitted. + if (!STI.hasStdExtC()) + return false; + + for (MachineBasicBlock &MBB : Fn) { + LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n"); + for (MachineInstr &MI : MBB) { + // Determine if this instruction would otherwise be compressed if not for + // an uncompressible register or offset. + RegImmPair RegImm = getRegImmPairPreventingCompression(MI); + if (!RegImm.Reg && RegImm.Imm == 0) + continue; + + // Determine if there is a set of instructions for which replacing this + // register with a compressed register (and compressible offset if + // applicable) is possible and will allow compression. + SmallVector MIs; + Register NewReg = analyzeCompressibleUses(MI, RegImm, MIs); + if (!NewReg) + continue; + + assert(isInt<12>(RegImm.Imm)); + BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(RISCV::ADDI), NewReg) + .addReg(RegImm.Reg) + .addImm(RegImm.Imm); + + // Update the set of instructions to use the compressed register and + // compressible offset instead. These instructions should now be + // compressible. + // TODO: Update all uses if RegImm.Imm == 0? Not just those that are + // expected to become compressible. + for (MachineInstr *UpdateMI : MIs) + updateOperands(*UpdateMI, RegImm, NewReg); + } + } + return true; +} + +/// Returns an instance of the Make Compressible Optimization pass. +FunctionPass *llvm::createRISCVMakeCompressibleOptPass() { + return new RISCVMakeCompressibleOpt(); +} Index: llvm/lib/Target/RISCV/RISCVTargetMachine.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -42,6 +42,7 @@ RegisterTargetMachine Y(getTheRISCV64Target()); auto *PR = PassRegistry::getPassRegistry(); initializeGlobalISel(*PR); + initializeRISCVMakeCompressibleOptPass(*PR); initializeRISCVGatherScatterLoweringPass(*PR); initializeRISCVMergeBaseOffsetOptPass(*PR); initializeRISCVSExtWRemovalPass(*PR); @@ -192,7 +193,10 @@ void RISCVPassConfig::addPreSched2() {} -void RISCVPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); } +void RISCVPassConfig::addPreEmitPass() { + addPass(&BranchRelaxationPassID); + addPass(createRISCVMakeCompressibleOptPass()); +} void RISCVPassConfig::addPreEmitPass2() { addPass(createRISCVExpandPseudoPass()); Index: llvm/test/CodeGen/RISCV/make-compressible-i32-f-d.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/RISCV/make-compressible-i32-f-d.mir @@ -0,0 +1,1138 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -o - %s -mtriple=riscv32 -mattr=+c,+f,+d -simplify-mir \ +# RUN: -run-pass=riscv-make-compressible | FileCheck --check-prefix=RV32 %s +# RUN: llc -o - %s -mtriple=riscv64 -mattr=+c,+f,+d -simplify-mir \ +# RUN: -run-pass=riscv-make-compressible | FileCheck --check-prefix=RV64 %s +--- | + + define void @store_common_value(i32* %a, i32* %b, i32* %c) #0 { + entry: + store i32 0, i32* %a, align 4 + store i32 0, i32* %b, align 4 + store i32 0, i32* %c, align 4 + ret void + } + + define void @store_common_value_float(float* %a, float* %b, float* %c, float %d, float %e, float %f, float %g, float %h, float %i, float %j) #0 { + entry: + store float %j, float* %a, align 4 + store float %j, float* %b, align 4 + store float %j, float* %c, align 4 + ret void + } + + define void @store_common_value_double(double* %a, double* %b, double* %c, double %d, double %e, double %f, double %g, double %h, double %i, double %j) #0 { + entry: + store double %j, double* %a, align 8 + store double %j, double* %b, align 8 + store double %j, double* %c, align 8 + ret void + } + + define void @store_common_ptr(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32* %p) #0 { + entry: + store volatile i32 1, i32* %p, align 4 + store volatile i32 3, i32* %p, align 4 + store volatile i32 5, i32* %p, align 4 + ret void + } + + define void @store_common_ptr_self(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32* %p) #0 { + entry: + %g = ptrtoint i32* %p to i32 + store volatile i32 1, i32* %p, align 4 + store volatile i32 3, i32* %p, align 4 + store volatile i32 %g, i32* %p, align 4 + ret void + } + + define void @store_common_ptr_float(float %a, float %b, float %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i, float* %p) #0 { + entry: + store volatile float %a, float* %p, align 4 + store volatile float %b, float* %p, align 4 + store volatile float %c, float* %p, align 4 + ret void + } + + define void @store_common_ptr_double(double %a, double %b, double %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i, double* %p) #0 { + entry: + store volatile double %a, double* %p, align 8 + store volatile double %b, double* %p, align 8 + store volatile double %c, double* %p, align 8 + ret void + } + + define void @load_common_ptr(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32* %p) #0 { + entry: + %g = load volatile i32, i32* %p, align 4 + %h = load volatile i32, i32* %p, align 4 + %i = load volatile i32, i32* %p, align 4 + ret void + } + + define void @load_common_ptr_float(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, float* %g) #0 { + entry: + %0 = load float, float* %g, align 4 + %arrayidx1 = getelementptr inbounds float, float* %g, i32 1 + %1 = load float, float* %arrayidx1, align 4 + %arrayidx2 = getelementptr inbounds float, float* %g, i32 2 + %2 = load float, float* %arrayidx2, align 4 + tail call void @load_common_ptr_float_1(float %0, float %1, float %2) + ret void + } + + declare void @load_common_ptr_float_1(float, float, float) #0 + + define void @load_common_ptr_double(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, double* %g) #0 { + entry: + %0 = load double, double* %g, align 8 + %arrayidx1 = getelementptr inbounds double, double* %g, i32 1 + %1 = load double, double* %arrayidx1, align 8 + %arrayidx2 = getelementptr inbounds double, double* %g, i32 2 + %2 = load double, double* %arrayidx2, align 8 + tail call void @load_common_ptr_double_1(double %0, double %1, double %2) + ret void + } + + declare void @load_common_ptr_double_1(double, double, double) #0 + + define void @store_large_offset(i32* %p) #0 { + entry: + %0 = getelementptr inbounds i32, i32* %p, i32 100 + store volatile i32 1, i32* %0, align 4 + %1 = getelementptr inbounds i32, i32* %p, i32 101 + store volatile i32 3, i32* %1, align 4 + %2 = getelementptr inbounds i32, i32* %p, i32 102 + store volatile i32 5, i32* %2, align 4 + %3 = getelementptr inbounds i32, i32* %p, i32 103 + store volatile i32 7, i32* %3, align 4 + ret void + } + + define void @store_large_offset_float(float* %p, float %a, float %b, float %c, float %d) #0 { + entry: + %0 = getelementptr inbounds float, float* %p, i32 100 + store volatile float %a, float* %0, align 4 + %1 = getelementptr inbounds float, float* %p, i32 101 + store volatile float %b, float* %1, align 4 + %2 = getelementptr inbounds float, float* %p, i32 102 + store volatile float %c, float* %2, align 4 + %3 = getelementptr inbounds float, float* %p, i32 103 + store volatile float %d, float* %3, align 4 + ret void + } + + define void @store_large_offset_double(double* %p, double %a, double %b, double %c, double %d) #0 { + entry: + %0 = getelementptr inbounds double, double* %p, i32 100 + store volatile double %a, double* %0, align 8 + %1 = getelementptr inbounds double, double* %p, i32 101 + store volatile double %b, double* %1, align 8 + %2 = getelementptr inbounds double, double* %p, i32 102 + store volatile double %c, double* %2, align 8 + %3 = getelementptr inbounds double, double* %p, i32 103 + store volatile double %d, double* %3, align 8 + ret void + } + + define void @load_large_offset(i32* %p) #0 { + entry: + %0 = getelementptr inbounds i32, i32* %p, i32 100 + %a = load volatile i32, i32* %0, align 4 + %1 = getelementptr inbounds i32, i32* %p, i32 101 + %b = load volatile i32, i32* %1, align 4 + %2 = getelementptr inbounds i32, i32* %p, i32 102 + %c = load volatile i32, i32* %2, align 4 + %3 = getelementptr inbounds i32, i32* %p, i32 103 + %d = load volatile i32, i32* %3, align 4 + ret void + } + + define void @load_large_offset_float(float* %p) #0 { + entry: + %arrayidx = getelementptr inbounds float, float* %p, i32 100 + %0 = load float, float* %arrayidx, align 4 + %arrayidx1 = getelementptr inbounds float, float* %p, i32 101 + %1 = load float, float* %arrayidx1, align 4 + %arrayidx2 = getelementptr inbounds float, float* %p, i32 102 + %2 = load float, float* %arrayidx2, align 4 + tail call void @load_large_offset_float_1(float %0, float %1, float %2) + ret void + } + + declare void @load_large_offset_float_1(float, float, float) #0 + + define void @load_large_offset_double(double* %p) #0 { + entry: + %arrayidx = getelementptr inbounds double, double* %p, i32 100 + %0 = load double, double* %arrayidx, align 8 + %arrayidx1 = getelementptr inbounds double, double* %p, i32 101 + %1 = load double, double* %arrayidx1, align 8 + %arrayidx2 = getelementptr inbounds double, double* %p, i32 102 + %2 = load double, double* %arrayidx2, align 8 + tail call void @load_large_offset_double_1(double %0, double %1, double %2) + ret void + } + + declare void @load_large_offset_double_1(double, double, double) #0 + + define void @store_common_value_no_opt(i32* %a) #0 { + entry: + store i32 0, i32* %a, align 4 + ret void + } + + define void @store_common_value_float_no_opt(float* %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h) #0 { + entry: + store float %h, float* %a, align 4 + ret void + } + + define void @store_common_value_double_no_opt(double* %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h) #0 { + entry: + store double %h, double* %a, align 8 + ret void + } + + define void @store_common_ptr_no_opt(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32* %p) #0 { + entry: + store volatile i32 1, i32* %p, align 4 + ret void + } + + define void @store_common_ptr_float_no_opt(float %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, float* %p) #0 { + entry: + store volatile float %a, float* %p, align 4 + ret void + } + + define void @store_common_ptr_double_no_opt(double %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, double* %p) #0 { + entry: + store volatile double %a, double* %p, align 8 + ret void + } + + define void @load_common_ptr_no_opt(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32* %p) #0 { + entry: + %g = load volatile i32, i32* %p, align 4 + ret void + } + + define float @load_common_ptr_float_no_opt(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, float* %g) #0 { + entry: + %0 = load float, float* %g, align 4 + ret float %0 + } + + define double @load_common_ptr_double_no_opt(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, double* %g) #0 { + entry: + %0 = load double, double* %g, align 8 + ret double %0 + } + + define void @store_large_offset_no_opt(i32* %p) #0 { + entry: + %0 = getelementptr inbounds i32, i32* %p, i32 100 + store volatile i32 1, i32* %0, align 4 + %1 = getelementptr inbounds i32, i32* %p, i32 101 + store volatile i32 3, i32* %1, align 4 + ret void + } + + define void @store_large_offset_float_no_opt(float* %p, float %a, float %b) #0 { + entry: + %0 = getelementptr inbounds float, float* %p, i32 100 + store volatile float %a, float* %0, align 4 + %1 = getelementptr inbounds float, float* %p, i32 101 + store volatile float %b, float* %1, align 4 + ret void + } + + define void @store_large_offset_double_no_opt(double* %p, double %a, double %b) #0 { + entry: + %0 = getelementptr inbounds double, double* %p, i32 100 + store volatile double %a, double* %0, align 8 + %1 = getelementptr inbounds double, double* %p, i32 101 + store volatile double %b, double* %1, align 8 + ret void + } + + define void @load_large_offset_no_opt(i32* %p) #0 { + entry: + %0 = getelementptr inbounds i32, i32* %p, i32 100 + %a = load volatile i32, i32* %0, align 4 + %1 = getelementptr inbounds i32, i32* %p, i32 101 + %b = load volatile i32, i32* %1, align 4 + ret void + } + + define { float, float } @load_large_offset_float_no_opt(float* %p) #0 { + entry: + %arrayidx = getelementptr inbounds float, float* %p, i32 100 + %0 = load float, float* %arrayidx, align 4 + %arrayidx1 = getelementptr inbounds float, float* %p, i32 101 + %1 = load float, float* %arrayidx1, align 4 + %2 = insertvalue { float, float } undef, float %0, 0 + %3 = insertvalue { float, float } %2, float %1, 1 + ret { float, float } %3 + } + + define { double, double } @load_large_offset_double_no_opt(double* %p) #0 { + entry: + %arrayidx = getelementptr inbounds double, double* %p, i32 100 + %0 = load double, double* %arrayidx, align 8 + %arrayidx1 = getelementptr inbounds double, double* %p, i32 101 + %1 = load double, double* %arrayidx1, align 8 + %2 = insertvalue { double, double } undef, double %0, 0 + %3 = insertvalue { double, double } %2, double %1, 1 + ret { double, double } %3 + } + + attributes #0 = { optsize "target-features"="+c,+f,+d" } + +... +--- +name: store_common_value +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $x11, $x12 + + ; RV32-LABEL: name: store_common_value + ; RV32: liveins: $x10, $x11, $x12 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x13 = ADDI $x0, 0 + ; RV32-NEXT: SW $x13, killed renamable $x10, 0 :: (store (s32) into %ir.a) + ; RV32-NEXT: SW $x13, killed renamable $x11, 0 :: (store (s32) into %ir.b) + ; RV32-NEXT: SW $x13, killed renamable $x12, 0 :: (store (s32) into %ir.c) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_value + ; RV64: liveins: $x10, $x11, $x12 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x13 = ADDI $x0, 0 + ; RV64-NEXT: SW $x13, killed renamable $x10, 0 :: (store (s32) into %ir.a) + ; RV64-NEXT: SW $x13, killed renamable $x11, 0 :: (store (s32) into %ir.b) + ; RV64-NEXT: SW $x13, killed renamable $x12, 0 :: (store (s32) into %ir.c) + ; RV64-NEXT: PseudoRET + SW $x0, killed renamable $x10, 0 :: (store (s32) into %ir.a) + SW $x0, killed renamable $x11, 0 :: (store (s32) into %ir.b) + SW $x0, killed renamable $x12, 0 :: (store (s32) into %ir.c) + PseudoRET + +... +--- +name: store_common_value_float +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $x11, $x12, $f16_f + + ; RV32-LABEL: name: store_common_value_float + ; RV32: liveins: $x10, $x11, $x12, $f16_f + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $f10_f = ADDI $f16_f, 0 + ; RV32-NEXT: FSW $f10_f, killed renamable $x10, 0 :: (store (s32) into %ir.a) + ; RV32-NEXT: FSW $f10_f, killed renamable $x11, 0 :: (store (s32) into %ir.b) + ; RV32-NEXT: FSW killed $f10_f, killed renamable $x12, 0 :: (store (s32) into %ir.c) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_value_float + ; RV64: liveins: $x10, $x11, $x12, $f16_f + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $f10_f = ADDI $f16_f, 0 + ; RV64-NEXT: FSW $f10_f, killed renamable $x10, 0 :: (store (s32) into %ir.a) + ; RV64-NEXT: FSW $f10_f, killed renamable $x11, 0 :: (store (s32) into %ir.b) + ; RV64-NEXT: FSW killed $f10_f, killed renamable $x12, 0 :: (store (s32) into %ir.c) + ; RV64-NEXT: PseudoRET + FSW renamable $f16_f, killed renamable $x10, 0 :: (store (s32) into %ir.a) + FSW renamable $f16_f, killed renamable $x11, 0 :: (store (s32) into %ir.b) + FSW killed renamable $f16_f, killed renamable $x12, 0 :: (store (s32) into %ir.c) + PseudoRET + +... +--- +name: store_common_value_double +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $x11, $x12, $f16_d + + ; RV32-LABEL: name: store_common_value_double + ; RV32: liveins: $x10, $x11, $x12, $f16_d + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $f10_d = ADDI $f16_d, 0 + ; RV32-NEXT: FSD $f10_d, killed renamable $x10, 0 :: (store (s64) into %ir.a) + ; RV32-NEXT: FSD $f10_d, killed renamable $x11, 0 :: (store (s64) into %ir.b) + ; RV32-NEXT: FSD killed $f10_d, killed renamable $x12, 0 :: (store (s64) into %ir.c) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_value_double + ; RV64: liveins: $x10, $x11, $x12, $f16_d + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $f10_d = ADDI $f16_d, 0 + ; RV64-NEXT: FSD $f10_d, killed renamable $x10, 0 :: (store (s64) into %ir.a) + ; RV64-NEXT: FSD $f10_d, killed renamable $x11, 0 :: (store (s64) into %ir.b) + ; RV64-NEXT: FSD killed $f10_d, killed renamable $x12, 0 :: (store (s64) into %ir.c) + ; RV64-NEXT: PseudoRET + FSD renamable $f16_d, killed renamable $x10, 0 :: (store (s64) into %ir.a) + FSD renamable $f16_d, killed renamable $x11, 0 :: (store (s64) into %ir.b) + FSD killed renamable $f16_d, killed renamable $x12, 0 :: (store (s64) into %ir.c) + PseudoRET + +... +--- +name: store_common_ptr +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; RV32-LABEL: name: store_common_ptr + ; RV32: liveins: $x16 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: renamable $x10 = ADDI $x0, 1 + ; RV32-NEXT: $x11 = ADDI $x16, 0 + ; RV32-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: renamable $x10 = ADDI $x0, 3 + ; RV32-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: renamable $x10 = ADDI $x0, 5 + ; RV32-NEXT: SW killed renamable $x10, killed $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_ptr + ; RV64: liveins: $x16 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: renamable $x10 = ADDI $x0, 1 + ; RV64-NEXT: $x11 = ADDI $x16, 0 + ; RV64-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: renamable $x10 = ADDI $x0, 3 + ; RV64-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: renamable $x10 = ADDI $x0, 5 + ; RV64-NEXT: SW killed renamable $x10, killed $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: PseudoRET + renamable $x10 = ADDI $x0, 1 + SW killed renamable $x10, renamable $x16, 0 :: (volatile store (s32) into %ir.p) + renamable $x10 = ADDI $x0, 3 + SW killed renamable $x10, renamable $x16, 0 :: (volatile store (s32) into %ir.p) + renamable $x10 = ADDI $x0, 5 + SW killed renamable $x10, killed renamable $x16, 0 :: (volatile store (s32) into %ir.p) + PseudoRET + +... +--- +name: store_common_ptr_self +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; RV32-LABEL: name: store_common_ptr_self + ; RV32: liveins: $x16 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: renamable $x10 = ADDI $x0, 1 + ; RV32-NEXT: $x11 = ADDI $x16, 0 + ; RV32-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: renamable $x10 = ADDI $x0, 3 + ; RV32-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: SW killed $x11, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_ptr_self + ; RV64: liveins: $x16 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: renamable $x10 = ADDI $x0, 1 + ; RV64-NEXT: $x11 = ADDI $x16, 0 + ; RV64-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: renamable $x10 = ADDI $x0, 3 + ; RV64-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: SW killed $x11, $x11, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: PseudoRET + renamable $x10 = ADDI $x0, 1 + SW killed renamable $x10, renamable $x16, 0 :: (volatile store (s32) into %ir.p) + renamable $x10 = ADDI $x0, 3 + SW killed renamable $x10, renamable $x16, 0 :: (volatile store (s32) into %ir.p) + SW killed renamable $x16, renamable $x16, 0 :: (volatile store (s32) into %ir.p) + PseudoRET + +... +--- +name: store_common_ptr_float +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16, $f10_f, $f11_f, $f12_f + + ; RV32-LABEL: name: store_common_ptr_float + ; RV32: liveins: $x16, $f10_f, $f11_f, $f12_f + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x10 = ADDI $x16, 0 + ; RV32-NEXT: FSW killed renamable $f10_f, $x10, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: FSW killed renamable $f11_f, $x10, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: FSW killed renamable $f12_f, killed $x10, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_ptr_float + ; RV64: liveins: $x16, $f10_f, $f11_f, $f12_f + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x10 = ADDI $x16, 0 + ; RV64-NEXT: FSW killed renamable $f10_f, $x10, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: FSW killed renamable $f11_f, $x10, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: FSW killed renamable $f12_f, killed $x10, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: PseudoRET + FSW killed renamable $f10_f, renamable $x16, 0 :: (volatile store (s32) into %ir.p) + FSW killed renamable $f11_f, renamable $x16, 0 :: (volatile store (s32) into %ir.p) + FSW killed renamable $f12_f, killed renamable $x16, 0 :: (volatile store (s32) into %ir.p) + PseudoRET + +... +--- +name: store_common_ptr_double +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16, $f10_d, $f11_d, $f12_d + + ; RV32-LABEL: name: store_common_ptr_double + ; RV32: liveins: $x16, $f10_d, $f11_d, $f12_d + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x10 = ADDI $x16, 0 + ; RV32-NEXT: FSD killed renamable $f10_d, $x10, 0 :: (volatile store (s64) into %ir.p) + ; RV32-NEXT: FSD killed renamable $f11_d, $x10, 0 :: (volatile store (s64) into %ir.p) + ; RV32-NEXT: FSD killed renamable $f12_d, killed $x10, 0 :: (volatile store (s64) into %ir.p) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_ptr_double + ; RV64: liveins: $x16, $f10_d, $f11_d, $f12_d + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x10 = ADDI $x16, 0 + ; RV64-NEXT: FSD killed renamable $f10_d, $x10, 0 :: (volatile store (s64) into %ir.p) + ; RV64-NEXT: FSD killed renamable $f11_d, $x10, 0 :: (volatile store (s64) into %ir.p) + ; RV64-NEXT: FSD killed renamable $f12_d, killed $x10, 0 :: (volatile store (s64) into %ir.p) + ; RV64-NEXT: PseudoRET + FSD killed renamable $f10_d, renamable $x16, 0 :: (volatile store (s64) into %ir.p) + FSD killed renamable $f11_d, renamable $x16, 0 :: (volatile store (s64) into %ir.p) + FSD killed renamable $f12_d, killed renamable $x16, 0 :: (volatile store (s64) into %ir.p) + PseudoRET + +... +--- +name: load_common_ptr +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; RV32-LABEL: name: load_common_ptr + ; RV32: liveins: $x16 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x11 = ADDI $x16, 0 + ; RV32-NEXT: dead renamable $x10 = LW $x11, 0 :: (volatile load (s32) from %ir.p) + ; RV32-NEXT: dead renamable $x10 = LW $x11, 0 :: (volatile load (s32) from %ir.p) + ; RV32-NEXT: dead renamable $x10 = LW killed $x11, 0 :: (volatile load (s32) from %ir.p) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: load_common_ptr + ; RV64: liveins: $x16 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x11 = ADDI $x16, 0 + ; RV64-NEXT: dead renamable $x10 = LW $x11, 0 :: (volatile load (s32) from %ir.p) + ; RV64-NEXT: dead renamable $x10 = LW $x11, 0 :: (volatile load (s32) from %ir.p) + ; RV64-NEXT: dead renamable $x10 = LW killed $x11, 0 :: (volatile load (s32) from %ir.p) + ; RV64-NEXT: PseudoRET + dead renamable $x10 = LW renamable $x16, 0 :: (volatile load (s32) from %ir.p) + dead renamable $x10 = LW renamable $x16, 0 :: (volatile load (s32) from %ir.p) + dead renamable $x10 = LW killed renamable $x16, 0 :: (volatile load (s32) from %ir.p) + PseudoRET + +... +--- +name: load_common_ptr_float +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; RV32-LABEL: name: load_common_ptr_float + ; RV32: liveins: $x16 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x10 = ADDI $x16, 0 + ; RV32-NEXT: renamable $f10_f = FLW $x10, 0 :: (load (s32) from %ir.g) + ; RV32-NEXT: renamable $f11_f = FLW $x10, 4 :: (load (s32) from %ir.arrayidx1) + ; RV32-NEXT: renamable $f12_f = FLW killed $x10, 8 :: (load (s32) from %ir.arrayidx2) + ; RV32-NEXT: PseudoTAIL target-flags(riscv-plt) @load_common_ptr_float_1, implicit $x2, implicit $f10_f, implicit $f11_f, implicit $f12_f + ; RV64-LABEL: name: load_common_ptr_float + ; RV64: liveins: $x16 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x10 = ADDI $x16, 0 + ; RV64-NEXT: renamable $f10_f = FLW $x10, 0 :: (load (s32) from %ir.g) + ; RV64-NEXT: renamable $f11_f = FLW $x10, 4 :: (load (s32) from %ir.arrayidx1) + ; RV64-NEXT: renamable $f12_f = FLW killed $x10, 8 :: (load (s32) from %ir.arrayidx2) + ; RV64-NEXT: PseudoTAIL target-flags(riscv-plt) @load_common_ptr_float_1, implicit $x2, implicit $f10_f, implicit $f11_f, implicit $f12_f + renamable $f10_f = FLW renamable $x16, 0 :: (load (s32) from %ir.g) + renamable $f11_f = FLW renamable $x16, 4 :: (load (s32) from %ir.arrayidx1) + renamable $f12_f = FLW killed renamable $x16, 8 :: (load (s32) from %ir.arrayidx2) + PseudoTAIL target-flags(riscv-plt) @load_common_ptr_float_1, implicit $x2, implicit $f10_f, implicit $f11_f, implicit $f12_f + +... +--- +name: load_common_ptr_double +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; RV32-LABEL: name: load_common_ptr_double + ; RV32: liveins: $x16 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x10 = ADDI $x16, 0 + ; RV32-NEXT: renamable $f10_d = FLD $x10, 0 :: (load (s64) from %ir.g) + ; RV32-NEXT: renamable $f11_d = FLD $x10, 8 :: (load (s64) from %ir.arrayidx1) + ; RV32-NEXT: renamable $f12_d = FLD killed $x10, 16 :: (load (s64) from %ir.arrayidx2) + ; RV32-NEXT: PseudoTAIL target-flags(riscv-plt) @load_common_ptr_double_1, implicit $x2, implicit $f10_d, implicit $f11_d, implicit $f12_d + ; RV64-LABEL: name: load_common_ptr_double + ; RV64: liveins: $x16 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x10 = ADDI $x16, 0 + ; RV64-NEXT: renamable $f10_d = FLD $x10, 0 :: (load (s64) from %ir.g) + ; RV64-NEXT: renamable $f11_d = FLD $x10, 8 :: (load (s64) from %ir.arrayidx1) + ; RV64-NEXT: renamable $f12_d = FLD killed $x10, 16 :: (load (s64) from %ir.arrayidx2) + ; RV64-NEXT: PseudoTAIL target-flags(riscv-plt) @load_common_ptr_double_1, implicit $x2, implicit $f10_d, implicit $f11_d, implicit $f12_d + renamable $f10_d = FLD renamable $x16, 0 :: (load (s64) from %ir.g) + renamable $f11_d = FLD renamable $x16, 8 :: (load (s64) from %ir.arrayidx1) + renamable $f12_d = FLD killed renamable $x16, 16 :: (load (s64) from %ir.arrayidx2) + PseudoTAIL target-flags(riscv-plt) @load_common_ptr_double_1, implicit $x2, implicit $f10_d, implicit $f11_d, implicit $f12_d + +... +--- +name: store_large_offset +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; RV32-LABEL: name: store_large_offset + ; RV32: liveins: $x10 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: renamable $x11 = ADDI $x0, 1 + ; RV32-NEXT: $x12 = ADDI $x10, 384 + ; RV32-NEXT: SW killed renamable $x11, $x12, 16 :: (volatile store (s32) into %ir.0) + ; RV32-NEXT: renamable $x11 = ADDI $x0, 3 + ; RV32-NEXT: SW killed renamable $x11, $x12, 20 :: (volatile store (s32) into %ir.1) + ; RV32-NEXT: renamable $x11 = ADDI $x0, 5 + ; RV32-NEXT: SW killed renamable $x11, $x12, 24 :: (volatile store (s32) into %ir.2) + ; RV32-NEXT: renamable $x11 = ADDI $x0, 7 + ; RV32-NEXT: SW killed renamable $x11, killed $x12, 28 :: (volatile store (s32) into %ir.3) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_large_offset + ; RV64: liveins: $x10 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: renamable $x11 = ADDI $x0, 1 + ; RV64-NEXT: $x12 = ADDI $x10, 384 + ; RV64-NEXT: SW killed renamable $x11, $x12, 16 :: (volatile store (s32) into %ir.0) + ; RV64-NEXT: renamable $x11 = ADDI $x0, 3 + ; RV64-NEXT: SW killed renamable $x11, $x12, 20 :: (volatile store (s32) into %ir.1) + ; RV64-NEXT: renamable $x11 = ADDI $x0, 5 + ; RV64-NEXT: SW killed renamable $x11, $x12, 24 :: (volatile store (s32) into %ir.2) + ; RV64-NEXT: renamable $x11 = ADDI $x0, 7 + ; RV64-NEXT: SW killed renamable $x11, killed $x12, 28 :: (volatile store (s32) into %ir.3) + ; RV64-NEXT: PseudoRET + renamable $x11 = ADDI $x0, 1 + SW killed renamable $x11, renamable $x10, 400 :: (volatile store (s32) into %ir.0) + renamable $x11 = ADDI $x0, 3 + SW killed renamable $x11, renamable $x10, 404 :: (volatile store (s32) into %ir.1) + renamable $x11 = ADDI $x0, 5 + SW killed renamable $x11, renamable $x10, 408 :: (volatile store (s32) into %ir.2) + renamable $x11 = ADDI $x0, 7 + SW killed renamable $x11, killed renamable $x10, 412 :: (volatile store (s32) into %ir.3) + PseudoRET + +... +--- +name: store_large_offset_float +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $f10_f, $f11_f, $f12_f, $f13_f + + ; RV32-LABEL: name: store_large_offset_float + ; RV32: liveins: $x10, $f10_f, $f11_f, $f12_f, $f13_f + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x11 = ADDI $x10, 384 + ; RV32-NEXT: FSW killed renamable $f10_f, $x11, 16 :: (volatile store (s32) into %ir.0) + ; RV32-NEXT: FSW killed renamable $f11_f, $x11, 20 :: (volatile store (s32) into %ir.1) + ; RV32-NEXT: FSW killed renamable $f12_f, $x11, 24 :: (volatile store (s32) into %ir.2) + ; RV32-NEXT: FSW killed renamable $f13_f, killed $x11, 28 :: (volatile store (s32) into %ir.3) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_large_offset_float + ; RV64: liveins: $x10, $f10_f, $f11_f, $f12_f, $f13_f + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x11 = ADDI $x10, 384 + ; RV64-NEXT: FSW killed renamable $f10_f, $x11, 16 :: (volatile store (s32) into %ir.0) + ; RV64-NEXT: FSW killed renamable $f11_f, $x11, 20 :: (volatile store (s32) into %ir.1) + ; RV64-NEXT: FSW killed renamable $f12_f, $x11, 24 :: (volatile store (s32) into %ir.2) + ; RV64-NEXT: FSW killed renamable $f13_f, killed $x11, 28 :: (volatile store (s32) into %ir.3) + ; RV64-NEXT: PseudoRET + FSW killed renamable $f10_f, renamable $x10, 400 :: (volatile store (s32) into %ir.0) + FSW killed renamable $f11_f, renamable $x10, 404 :: (volatile store (s32) into %ir.1) + FSW killed renamable $f12_f, renamable $x10, 408 :: (volatile store (s32) into %ir.2) + FSW killed renamable $f13_f, killed renamable $x10, 412 :: (volatile store (s32) into %ir.3) + PseudoRET + +... +--- +name: store_large_offset_double +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $f10_d, $f11_d, $f12_d, $f13_d + + ; RV32-LABEL: name: store_large_offset_double + ; RV32: liveins: $x10, $f10_d, $f11_d, $f12_d, $f13_d + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x11 = ADDI $x10, 768 + ; RV32-NEXT: FSD killed renamable $f10_d, $x11, 32 :: (volatile store (s64) into %ir.0) + ; RV32-NEXT: FSD killed renamable $f11_d, $x11, 40 :: (volatile store (s64) into %ir.1) + ; RV32-NEXT: FSD killed renamable $f12_d, $x11, 48 :: (volatile store (s64) into %ir.2) + ; RV32-NEXT: FSD killed renamable $f13_d, killed $x11, 56 :: (volatile store (s64) into %ir.3) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_large_offset_double + ; RV64: liveins: $x10, $f10_d, $f11_d, $f12_d, $f13_d + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x11 = ADDI $x10, 768 + ; RV64-NEXT: FSD killed renamable $f10_d, $x11, 32 :: (volatile store (s64) into %ir.0) + ; RV64-NEXT: FSD killed renamable $f11_d, $x11, 40 :: (volatile store (s64) into %ir.1) + ; RV64-NEXT: FSD killed renamable $f12_d, $x11, 48 :: (volatile store (s64) into %ir.2) + ; RV64-NEXT: FSD killed renamable $f13_d, killed $x11, 56 :: (volatile store (s64) into %ir.3) + ; RV64-NEXT: PseudoRET + FSD killed renamable $f10_d, renamable $x10, 800 :: (volatile store (s64) into %ir.0) + FSD killed renamable $f11_d, renamable $x10, 808 :: (volatile store (s64) into %ir.1) + FSD killed renamable $f12_d, renamable $x10, 816 :: (volatile store (s64) into %ir.2) + FSD killed renamable $f13_d, killed renamable $x10, 824 :: (volatile store (s64) into %ir.3) + PseudoRET + +... +--- +name: load_large_offset +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; RV32-LABEL: name: load_large_offset + ; RV32: liveins: $x10 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x12 = ADDI $x10, 384 + ; RV32-NEXT: dead renamable $x11 = LW $x12, 16 :: (volatile load (s32) from %ir.0) + ; RV32-NEXT: dead renamable $x11 = LW $x12, 20 :: (volatile load (s32) from %ir.1) + ; RV32-NEXT: dead renamable $x11 = LW $x12, 24 :: (volatile load (s32) from %ir.2) + ; RV32-NEXT: dead renamable $x10 = LW killed $x12, 28 :: (volatile load (s32) from %ir.3) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: load_large_offset + ; RV64: liveins: $x10 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x12 = ADDI $x10, 384 + ; RV64-NEXT: dead renamable $x11 = LW $x12, 16 :: (volatile load (s32) from %ir.0) + ; RV64-NEXT: dead renamable $x11 = LW $x12, 20 :: (volatile load (s32) from %ir.1) + ; RV64-NEXT: dead renamable $x11 = LW $x12, 24 :: (volatile load (s32) from %ir.2) + ; RV64-NEXT: dead renamable $x10 = LW killed $x12, 28 :: (volatile load (s32) from %ir.3) + ; RV64-NEXT: PseudoRET + dead renamable $x11 = LW renamable $x10, 400 :: (volatile load (s32) from %ir.0) + dead renamable $x11 = LW renamable $x10, 404 :: (volatile load (s32) from %ir.1) + dead renamable $x11 = LW renamable $x10, 408 :: (volatile load (s32) from %ir.2) + dead renamable $x10 = LW killed renamable $x10, 412 :: (volatile load (s32) from %ir.3) + PseudoRET + +... +--- +name: load_large_offset_float +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; RV32-LABEL: name: load_large_offset_float + ; RV32: liveins: $x10 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x11 = ADDI $x10, 384 + ; RV32-NEXT: renamable $f10_f = FLW $x11, 16 :: (load (s32) from %ir.arrayidx) + ; RV32-NEXT: renamable $f11_f = FLW $x11, 20 :: (load (s32) from %ir.arrayidx1) + ; RV32-NEXT: renamable $f12_f = FLW killed $x11, 24 :: (load (s32) from %ir.arrayidx2) + ; RV32-NEXT: PseudoTAIL target-flags(riscv-plt) @load_large_offset_float_1, implicit $x2, implicit $f10_f, implicit $f11_f, implicit $f12_f + ; RV64-LABEL: name: load_large_offset_float + ; RV64: liveins: $x10 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x11 = ADDI $x10, 384 + ; RV64-NEXT: renamable $f10_f = FLW $x11, 16 :: (load (s32) from %ir.arrayidx) + ; RV64-NEXT: renamable $f11_f = FLW $x11, 20 :: (load (s32) from %ir.arrayidx1) + ; RV64-NEXT: renamable $f12_f = FLW killed $x11, 24 :: (load (s32) from %ir.arrayidx2) + ; RV64-NEXT: PseudoTAIL target-flags(riscv-plt) @load_large_offset_float_1, implicit $x2, implicit $f10_f, implicit $f11_f, implicit $f12_f + renamable $f10_f = FLW renamable $x10, 400 :: (load (s32) from %ir.arrayidx) + renamable $f11_f = FLW renamable $x10, 404 :: (load (s32) from %ir.arrayidx1) + renamable $f12_f = FLW killed renamable $x10, 408 :: (load (s32) from %ir.arrayidx2) + PseudoTAIL target-flags(riscv-plt) @load_large_offset_float_1, implicit $x2, implicit $f10_f, implicit $f11_f, implicit $f12_f + +... +--- +name: load_large_offset_double +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; RV32-LABEL: name: load_large_offset_double + ; RV32: liveins: $x10 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: $x11 = ADDI $x10, 768 + ; RV32-NEXT: renamable $f10_d = FLD $x11, 32 :: (load (s64) from %ir.arrayidx) + ; RV32-NEXT: renamable $f11_d = FLD $x11, 40 :: (load (s64) from %ir.arrayidx1) + ; RV32-NEXT: renamable $f12_d = FLD killed $x11, 48 :: (load (s64) from %ir.arrayidx2) + ; RV32-NEXT: PseudoTAIL target-flags(riscv-plt) @load_large_offset_double_1, implicit $x2, implicit $f10_d, implicit $f11_d, implicit $f12_d + ; RV64-LABEL: name: load_large_offset_double + ; RV64: liveins: $x10 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: $x11 = ADDI $x10, 768 + ; RV64-NEXT: renamable $f10_d = FLD $x11, 32 :: (load (s64) from %ir.arrayidx) + ; RV64-NEXT: renamable $f11_d = FLD $x11, 40 :: (load (s64) from %ir.arrayidx1) + ; RV64-NEXT: renamable $f12_d = FLD killed $x11, 48 :: (load (s64) from %ir.arrayidx2) + ; RV64-NEXT: PseudoTAIL target-flags(riscv-plt) @load_large_offset_double_1, implicit $x2, implicit $f10_d, implicit $f11_d, implicit $f12_d + renamable $f10_d = FLD renamable $x10, 800 :: (load (s64) from %ir.arrayidx) + renamable $f11_d = FLD renamable $x10, 808 :: (load (s64) from %ir.arrayidx1) + renamable $f12_d = FLD killed renamable $x10, 816 :: (load (s64) from %ir.arrayidx2) + PseudoTAIL target-flags(riscv-plt) @load_large_offset_double_1, implicit $x2, implicit $f10_d, implicit $f11_d, implicit $f12_d + +... +--- +name: store_common_value_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; RV32-LABEL: name: store_common_value_no_opt + ; RV32: liveins: $x10 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: SW $x0, killed renamable $x10, 0 :: (store (s32) into %ir.a) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_value_no_opt + ; RV64: liveins: $x10 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: SW $x0, killed renamable $x10, 0 :: (store (s32) into %ir.a) + ; RV64-NEXT: PseudoRET + SW $x0, killed renamable $x10, 0 :: (store (s32) into %ir.a) + PseudoRET + +... +--- +name: store_common_value_float_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $f16_f + + ; RV32-LABEL: name: store_common_value_float_no_opt + ; RV32: liveins: $x10, $f16_f + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: FSW killed renamable $f16_f, killed renamable $x10, 0 :: (store (s32) into %ir.a) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_value_float_no_opt + ; RV64: liveins: $x10, $f16_f + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: FSW killed renamable $f16_f, killed renamable $x10, 0 :: (store (s32) into %ir.a) + ; RV64-NEXT: PseudoRET + FSW killed renamable $f16_f, killed renamable $x10, 0 :: (store (s32) into %ir.a) + PseudoRET + +... +--- +name: store_common_value_double_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $f16_d + + ; RV32-LABEL: name: store_common_value_double_no_opt + ; RV32: liveins: $x10, $f16_d + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: FSD killed renamable $f16_d, killed renamable $x10, 0 :: (store (s64) into %ir.a) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_value_double_no_opt + ; RV64: liveins: $x10, $f16_d + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: FSD killed renamable $f16_d, killed renamable $x10, 0 :: (store (s64) into %ir.a) + ; RV64-NEXT: PseudoRET + FSD killed renamable $f16_d, killed renamable $x10, 0 :: (store (s64) into %ir.a) + PseudoRET + +... +--- +name: store_common_ptr_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; RV32-LABEL: name: store_common_ptr_no_opt + ; RV32: liveins: $x16 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: renamable $x10 = ADDI $x0, 1 + ; RV32-NEXT: SW killed renamable $x10, killed renamable $x16, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_ptr_no_opt + ; RV64: liveins: $x16 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: renamable $x10 = ADDI $x0, 1 + ; RV64-NEXT: SW killed renamable $x10, killed renamable $x16, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: PseudoRET + renamable $x10 = ADDI $x0, 1 + SW killed renamable $x10, killed renamable $x16, 0 :: (volatile store (s32) into %ir.p) + PseudoRET + +... +--- +name: store_common_ptr_float_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16, $f10_f + + ; RV32-LABEL: name: store_common_ptr_float_no_opt + ; RV32: liveins: $x16, $f10_f + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: FSW killed renamable $f10_f, killed renamable $x16, 0 :: (volatile store (s32) into %ir.p) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_ptr_float_no_opt + ; RV64: liveins: $x16, $f10_f + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: FSW killed renamable $f10_f, killed renamable $x16, 0 :: (volatile store (s32) into %ir.p) + ; RV64-NEXT: PseudoRET + FSW killed renamable $f10_f, killed renamable $x16, 0 :: (volatile store (s32) into %ir.p) + PseudoRET + +... +--- +name: store_common_ptr_double_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16, $f10_d + + ; RV32-LABEL: name: store_common_ptr_double_no_opt + ; RV32: liveins: $x16, $f10_d + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: FSD killed renamable $f10_d, killed renamable $x16, 0 :: (volatile store (s64) into %ir.p) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_common_ptr_double_no_opt + ; RV64: liveins: $x16, $f10_d + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: FSD killed renamable $f10_d, killed renamable $x16, 0 :: (volatile store (s64) into %ir.p) + ; RV64-NEXT: PseudoRET + FSD killed renamable $f10_d, killed renamable $x16, 0 :: (volatile store (s64) into %ir.p) + PseudoRET + +... +--- +name: load_common_ptr_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; RV32-LABEL: name: load_common_ptr_no_opt + ; RV32: liveins: $x16 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: dead renamable $x10 = LW killed renamable $x16, 0 :: (volatile load (s32) from %ir.p) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: load_common_ptr_no_opt + ; RV64: liveins: $x16 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: dead renamable $x10 = LW killed renamable $x16, 0 :: (volatile load (s32) from %ir.p) + ; RV64-NEXT: PseudoRET + dead renamable $x10 = LW killed renamable $x16, 0 :: (volatile load (s32) from %ir.p) + PseudoRET + +... +--- +name: load_common_ptr_float_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; RV32-LABEL: name: load_common_ptr_float_no_opt + ; RV32: liveins: $x16 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: renamable $f10_f = FLW killed renamable $x16, 0 :: (load (s32) from %ir.g) + ; RV32-NEXT: PseudoRET implicit $f10_f + ; RV64-LABEL: name: load_common_ptr_float_no_opt + ; RV64: liveins: $x16 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: renamable $f10_f = FLW killed renamable $x16, 0 :: (load (s32) from %ir.g) + ; RV64-NEXT: PseudoRET implicit $f10_f + renamable $f10_f = FLW killed renamable $x16, 0 :: (load (s32) from %ir.g) + PseudoRET implicit $f10_f + +... +--- +name: load_common_ptr_double_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; RV32-LABEL: name: load_common_ptr_double_no_opt + ; RV32: liveins: $x16 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: renamable $f10_d = FLD killed renamable $x16, 0 :: (load (s64) from %ir.g) + ; RV32-NEXT: PseudoRET implicit $f10_d + ; RV64-LABEL: name: load_common_ptr_double_no_opt + ; RV64: liveins: $x16 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: renamable $f10_d = FLD killed renamable $x16, 0 :: (load (s64) from %ir.g) + ; RV64-NEXT: PseudoRET implicit $f10_d + renamable $f10_d = FLD killed renamable $x16, 0 :: (load (s64) from %ir.g) + PseudoRET implicit $f10_d + +... +--- +name: store_large_offset_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; RV32-LABEL: name: store_large_offset_no_opt + ; RV32: liveins: $x10 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: renamable $x11 = ADDI $x0, 1 + ; RV32-NEXT: SW killed renamable $x11, renamable $x10, 400 :: (volatile store (s32) into %ir.0) + ; RV32-NEXT: renamable $x11 = ADDI $x0, 3 + ; RV32-NEXT: SW killed renamable $x11, killed renamable $x10, 404 :: (volatile store (s32) into %ir.1) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_large_offset_no_opt + ; RV64: liveins: $x10 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: renamable $x11 = ADDI $x0, 1 + ; RV64-NEXT: SW killed renamable $x11, renamable $x10, 400 :: (volatile store (s32) into %ir.0) + ; RV64-NEXT: renamable $x11 = ADDI $x0, 3 + ; RV64-NEXT: SW killed renamable $x11, killed renamable $x10, 404 :: (volatile store (s32) into %ir.1) + ; RV64-NEXT: PseudoRET + renamable $x11 = ADDI $x0, 1 + SW killed renamable $x11, renamable $x10, 400 :: (volatile store (s32) into %ir.0) + renamable $x11 = ADDI $x0, 3 + SW killed renamable $x11, killed renamable $x10, 404 :: (volatile store (s32) into %ir.1) + PseudoRET + +... +--- +name: store_large_offset_float_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $f10_f, $f11_f + + ; RV32-LABEL: name: store_large_offset_float_no_opt + ; RV32: liveins: $x10, $f10_f, $f11_f + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: FSW killed renamable $f10_f, renamable $x10, 400 :: (volatile store (s32) into %ir.0) + ; RV32-NEXT: FSW killed renamable $f11_f, killed renamable $x10, 404 :: (volatile store (s32) into %ir.1) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_large_offset_float_no_opt + ; RV64: liveins: $x10, $f10_f, $f11_f + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: FSW killed renamable $f10_f, renamable $x10, 400 :: (volatile store (s32) into %ir.0) + ; RV64-NEXT: FSW killed renamable $f11_f, killed renamable $x10, 404 :: (volatile store (s32) into %ir.1) + ; RV64-NEXT: PseudoRET + FSW killed renamable $f10_f, renamable $x10, 400 :: (volatile store (s32) into %ir.0) + FSW killed renamable $f11_f, killed renamable $x10, 404 :: (volatile store (s32) into %ir.1) + PseudoRET + +... +--- +name: store_large_offset_double_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $f10_d, $f11_d + + ; RV32-LABEL: name: store_large_offset_double_no_opt + ; RV32: liveins: $x10, $f10_d, $f11_d + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: FSD killed renamable $f10_d, renamable $x10, 800 :: (volatile store (s64) into %ir.0) + ; RV32-NEXT: FSD killed renamable $f11_d, killed renamable $x10, 808 :: (volatile store (s64) into %ir.1) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: store_large_offset_double_no_opt + ; RV64: liveins: $x10, $f10_d, $f11_d + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: FSD killed renamable $f10_d, renamable $x10, 800 :: (volatile store (s64) into %ir.0) + ; RV64-NEXT: FSD killed renamable $f11_d, killed renamable $x10, 808 :: (volatile store (s64) into %ir.1) + ; RV64-NEXT: PseudoRET + FSD killed renamable $f10_d, renamable $x10, 800 :: (volatile store (s64) into %ir.0) + FSD killed renamable $f11_d, killed renamable $x10, 808 :: (volatile store (s64) into %ir.1) + PseudoRET + +... +--- +name: load_large_offset_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; RV32-LABEL: name: load_large_offset_no_opt + ; RV32: liveins: $x10 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: dead renamable $x11 = LW renamable $x10, 400 :: (volatile load (s32) from %ir.0) + ; RV32-NEXT: dead renamable $x10 = LW killed renamable $x10, 404 :: (volatile load (s32) from %ir.1) + ; RV32-NEXT: PseudoRET + ; RV64-LABEL: name: load_large_offset_no_opt + ; RV64: liveins: $x10 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: dead renamable $x11 = LW renamable $x10, 400 :: (volatile load (s32) from %ir.0) + ; RV64-NEXT: dead renamable $x10 = LW killed renamable $x10, 404 :: (volatile load (s32) from %ir.1) + ; RV64-NEXT: PseudoRET + dead renamable $x11 = LW renamable $x10, 400 :: (volatile load (s32) from %ir.0) + dead renamable $x10 = LW killed renamable $x10, 404 :: (volatile load (s32) from %ir.1) + PseudoRET + +... +--- +name: load_large_offset_float_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; RV32-LABEL: name: load_large_offset_float_no_opt + ; RV32: liveins: $x10 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: renamable $f10_f = FLW renamable $x10, 400 :: (load (s32) from %ir.arrayidx) + ; RV32-NEXT: renamable $f11_f = FLW killed renamable $x10, 404 :: (load (s32) from %ir.arrayidx1) + ; RV32-NEXT: PseudoRET implicit $f10_f, implicit $f11_f + ; RV64-LABEL: name: load_large_offset_float_no_opt + ; RV64: liveins: $x10 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: renamable $f10_f = FLW renamable $x10, 400 :: (load (s32) from %ir.arrayidx) + ; RV64-NEXT: renamable $f11_f = FLW killed renamable $x10, 404 :: (load (s32) from %ir.arrayidx1) + ; RV64-NEXT: PseudoRET implicit $f10_f, implicit $f11_f + renamable $f10_f = FLW renamable $x10, 400 :: (load (s32) from %ir.arrayidx) + renamable $f11_f = FLW killed renamable $x10, 404 :: (load (s32) from %ir.arrayidx1) + PseudoRET implicit $f10_f, implicit $f11_f + +... +--- +name: load_large_offset_double_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; RV32-LABEL: name: load_large_offset_double_no_opt + ; RV32: liveins: $x10 + ; RV32-NEXT: {{ $}} + ; RV32-NEXT: renamable $f10_d = FLD renamable $x10, 800 :: (load (s64) from %ir.arrayidx) + ; RV32-NEXT: renamable $f11_d = FLD killed renamable $x10, 808 :: (load (s64) from %ir.arrayidx1) + ; RV32-NEXT: PseudoRET implicit $f10_d, implicit $f11_d + ; RV64-LABEL: name: load_large_offset_double_no_opt + ; RV64: liveins: $x10 + ; RV64-NEXT: {{ $}} + ; RV64-NEXT: renamable $f10_d = FLD renamable $x10, 800 :: (load (s64) from %ir.arrayidx) + ; RV64-NEXT: renamable $f11_d = FLD killed renamable $x10, 808 :: (load (s64) from %ir.arrayidx1) + ; RV64-NEXT: PseudoRET implicit $f10_d, implicit $f11_d + renamable $f10_d = FLD renamable $x10, 800 :: (load (s64) from %ir.arrayidx) + renamable $f11_d = FLD killed renamable $x10, 808 :: (load (s64) from %ir.arrayidx1) + PseudoRET implicit $f10_d, implicit $f11_d + +... Index: llvm/test/CodeGen/RISCV/make-compressible-i64.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/RISCV/make-compressible-i64.mir @@ -0,0 +1,341 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -o - %s -mtriple=riscv64 -mattr=+c -simplify-mir \ +# RUN: -run-pass=riscv-make-compressible | FileCheck %s +--- | + + define void @store_common_value(i64* %a, i64* %b, i64* %c) #0 { + entry: + store i64 0, i64* %a, align 8 + store i64 0, i64* %b, align 8 + store i64 0, i64* %c, align 8 + ret void + } + + define void @store_common_ptr(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64* %p) #0 { + entry: + store volatile i64 1, i64* %p, align 8 + store volatile i64 3, i64* %p, align 8 + store volatile i64 5, i64* %p, align 8 + ret void + } + + define void @store_common_ptr_self(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64* %p) #0 { + entry: + %g = ptrtoint i64* %p to i64 + store volatile i64 1, i64* %p, align 8 + store volatile i64 3, i64* %p, align 8 + store volatile i64 %g, i64* %p, align 8 + ret void + } + + define void @load_common_ptr(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64* %p) #0 { + entry: + %g = load volatile i64, i64* %p, align 8 + %h = load volatile i64, i64* %p, align 8 + %i = load volatile i64, i64* %p, align 8 + ret void + } + + define void @store_large_offset(i64* %p) #0 { + entry: + %0 = getelementptr inbounds i64, i64* %p, i64 100 + store volatile i64 1, i64* %0, align 8 + %1 = getelementptr inbounds i64, i64* %p, i64 101 + store volatile i64 3, i64* %1, align 8 + %2 = getelementptr inbounds i64, i64* %p, i64 102 + store volatile i64 5, i64* %2, align 8 + %3 = getelementptr inbounds i64, i64* %p, i64 103 + store volatile i64 7, i64* %3, align 8 + ret void + } + + define void @load_large_offset(i64* %p) #0 { + entry: + %0 = getelementptr inbounds i64, i64* %p, i64 100 + %a = load volatile i64, i64* %0, align 8 + %1 = getelementptr inbounds i64, i64* %p, i64 101 + %b = load volatile i64, i64* %1, align 8 + %2 = getelementptr inbounds i64, i64* %p, i64 102 + %c = load volatile i64, i64* %2, align 8 + %3 = getelementptr inbounds i64, i64* %p, i64 103 + %d = load volatile i64, i64* %3, align 8 + ret void + } + + define void @store_common_value_no_opt(i64* %a) #0 { + entry: + store i64 0, i64* %a, align 8 + ret void + } + + define void @store_common_ptr_no_opt(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64* %p) #0 { + entry: + store volatile i64 1, i64* %p, align 8 + ret void + } + + define void @load_common_ptr_no_opt(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64* %p) #0 { + entry: + %g = load volatile i64, i64* %p, align 8 + ret void + } + + define void @store_large_offset_no_opt(i64* %p) #0 { + entry: + %0 = getelementptr inbounds i64, i64* %p, i64 100 + store volatile i64 1, i64* %0, align 8 + %1 = getelementptr inbounds i64, i64* %p, i64 101 + store volatile i64 3, i64* %1, align 8 + ret void + } + + define void @load_large_offset_no_opt(i64* %p) #0 { + entry: + %0 = getelementptr inbounds i64, i64* %p, i64 100 + %a = load volatile i64, i64* %0, align 8 + %1 = getelementptr inbounds i64, i64* %p, i64 101 + %b = load volatile i64, i64* %1, align 8 + ret void + } + + attributes #0 = { optsize "target-features"="+c" } + +... +--- +name: store_common_value +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10, $x11, $x12 + + ; CHECK-LABEL: name: store_common_value + ; CHECK: liveins: $x10, $x11, $x12 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x13 = ADDI $x0, 0 + ; CHECK-NEXT: SD $x13, killed renamable $x10, 0 :: (store (s64) into %ir.a) + ; CHECK-NEXT: SD $x13, killed renamable $x11, 0 :: (store (s64) into %ir.b) + ; CHECK-NEXT: SD $x13, killed renamable $x12, 0 :: (store (s64) into %ir.c) + ; CHECK-NEXT: PseudoRET + SD $x0, killed renamable $x10, 0 :: (store (s64) into %ir.a) + SD $x0, killed renamable $x11, 0 :: (store (s64) into %ir.b) + SD $x0, killed renamable $x12, 0 :: (store (s64) into %ir.c) + PseudoRET + +... +--- +name: store_common_ptr +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: store_common_ptr + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: renamable $x10 = ADDI $x0, 1 + ; CHECK-NEXT: $x11 = ADDI $x16, 0 + ; CHECK-NEXT: SD killed renamable $x10, $x11, 0 :: (volatile store (s64) into %ir.p) + ; CHECK-NEXT: renamable $x10 = ADDI $x0, 3 + ; CHECK-NEXT: SD killed renamable $x10, $x11, 0 :: (volatile store (s64) into %ir.p) + ; CHECK-NEXT: renamable $x10 = ADDI $x0, 5 + ; CHECK-NEXT: SD killed renamable $x10, killed $x11, 0 :: (volatile store (s64) into %ir.p) + ; CHECK-NEXT: PseudoRET + renamable $x10 = ADDI $x0, 1 + SD killed renamable $x10, renamable $x16, 0 :: (volatile store (s64) into %ir.p) + renamable $x10 = ADDI $x0, 3 + SD killed renamable $x10, renamable $x16, 0 :: (volatile store (s64) into %ir.p) + renamable $x10 = ADDI $x0, 5 + SD killed renamable $x10, killed renamable $x16, 0 :: (volatile store (s64) into %ir.p) + PseudoRET + +... +--- +name: store_common_ptr_self +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: store_common_ptr_self + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: renamable $x10 = ADDI $x0, 1 + ; CHECK-NEXT: $x11 = ADDI $x16, 0 + ; CHECK-NEXT: SD killed renamable $x10, $x11, 0 :: (volatile store (s64) into %ir.p) + ; CHECK-NEXT: renamable $x10 = ADDI $x0, 3 + ; CHECK-NEXT: SD killed renamable $x10, $x11, 0 :: (volatile store (s64) into %ir.p) + ; CHECK-NEXT: SD killed $x11, $x11, 0 :: (volatile store (s64) into %ir.p) + ; CHECK-NEXT: PseudoRET + renamable $x10 = ADDI $x0, 1 + SD killed renamable $x10, renamable $x16, 0 :: (volatile store (s64) into %ir.p) + renamable $x10 = ADDI $x0, 3 + SD killed renamable $x10, renamable $x16, 0 :: (volatile store (s64) into %ir.p) + SD killed renamable $x16, renamable $x16, 0 :: (volatile store (s64) into %ir.p) + PseudoRET + +... +--- +name: load_common_ptr +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: load_common_ptr + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x11 = ADDI $x16, 0 + ; CHECK-NEXT: dead renamable $x10 = LD $x11, 0 :: (volatile load (s64) from %ir.p) + ; CHECK-NEXT: dead renamable $x10 = LD $x11, 0 :: (volatile load (s64) from %ir.p) + ; CHECK-NEXT: dead renamable $x10 = LD killed $x11, 0 :: (volatile load (s64) from %ir.p) + ; CHECK-NEXT: PseudoRET + dead renamable $x10 = LD renamable $x16, 0 :: (volatile load (s64) from %ir.p) + dead renamable $x10 = LD renamable $x16, 0 :: (volatile load (s64) from %ir.p) + dead renamable $x10 = LD killed renamable $x16, 0 :: (volatile load (s64) from %ir.p) + PseudoRET + +... +--- +name: store_large_offset +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; CHECK-LABEL: name: store_large_offset + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 1 + ; CHECK-NEXT: $x12 = ADDI $x10, 768 + ; CHECK-NEXT: SD killed renamable $x11, $x12, 32 :: (volatile store (s64) into %ir.0) + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 3 + ; CHECK-NEXT: SD killed renamable $x11, $x12, 40 :: (volatile store (s64) into %ir.1) + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 5 + ; CHECK-NEXT: SD killed renamable $x11, $x12, 48 :: (volatile store (s64) into %ir.2) + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 7 + ; CHECK-NEXT: SD killed renamable $x11, killed $x12, 56 :: (volatile store (s64) into %ir.3) + ; CHECK-NEXT: PseudoRET + renamable $x11 = ADDI $x0, 1 + SD killed renamable $x11, renamable $x10, 800 :: (volatile store (s64) into %ir.0) + renamable $x11 = ADDI $x0, 3 + SD killed renamable $x11, renamable $x10, 808 :: (volatile store (s64) into %ir.1) + renamable $x11 = ADDI $x0, 5 + SD killed renamable $x11, renamable $x10, 816 :: (volatile store (s64) into %ir.2) + renamable $x11 = ADDI $x0, 7 + SD killed renamable $x11, killed renamable $x10, 824 :: (volatile store (s64) into %ir.3) + PseudoRET + +... +--- +name: load_large_offset +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; CHECK-LABEL: name: load_large_offset + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x12 = ADDI $x10, 768 + ; CHECK-NEXT: dead renamable $x11 = LD $x12, 32 :: (volatile load (s64) from %ir.0) + ; CHECK-NEXT: dead renamable $x11 = LD $x12, 40 :: (volatile load (s64) from %ir.1) + ; CHECK-NEXT: dead renamable $x11 = LD $x12, 48 :: (volatile load (s64) from %ir.2) + ; CHECK-NEXT: dead renamable $x10 = LD killed $x12, 56 :: (volatile load (s64) from %ir.3) + ; CHECK-NEXT: PseudoRET + dead renamable $x11 = LD renamable $x10, 800 :: (volatile load (s64) from %ir.0) + dead renamable $x11 = LD renamable $x10, 808 :: (volatile load (s64) from %ir.1) + dead renamable $x11 = LD renamable $x10, 816 :: (volatile load (s64) from %ir.2) + dead renamable $x10 = LD killed renamable $x10, 824 :: (volatile load (s64) from %ir.3) + PseudoRET + +... +--- +name: store_common_value_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; CHECK-LABEL: name: store_common_value_no_opt + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: SD $x0, killed renamable $x10, 0 :: (store (s64) into %ir.a) + ; CHECK-NEXT: PseudoRET + SD $x0, killed renamable $x10, 0 :: (store (s64) into %ir.a) + PseudoRET + +... +--- +name: store_common_ptr_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: store_common_ptr_no_opt + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: renamable $x10 = ADDI $x0, 1 + ; CHECK-NEXT: SD killed renamable $x10, killed renamable $x16, 0 :: (volatile store (s64) into %ir.p) + ; CHECK-NEXT: PseudoRET + renamable $x10 = ADDI $x0, 1 + SD killed renamable $x10, killed renamable $x16, 0 :: (volatile store (s64) into %ir.p) + PseudoRET + +... +--- +name: load_common_ptr_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x16 + + ; CHECK-LABEL: name: load_common_ptr_no_opt + ; CHECK: liveins: $x16 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: dead renamable $x10 = LD killed renamable $x16, 0 :: (volatile load (s64) from %ir.p) + ; CHECK-NEXT: PseudoRET + dead renamable $x10 = LD killed renamable $x16, 0 :: (volatile load (s64) from %ir.p) + PseudoRET + +... +--- +name: store_large_offset_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; CHECK-LABEL: name: store_large_offset_no_opt + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 1 + ; CHECK-NEXT: SD killed renamable $x11, renamable $x10, 800 :: (volatile store (s64) into %ir.0) + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 3 + ; CHECK-NEXT: SD killed renamable $x11, killed renamable $x10, 808 :: (volatile store (s64) into %ir.1) + ; CHECK-NEXT: PseudoRET + renamable $x11 = ADDI $x0, 1 + SD killed renamable $x11, renamable $x10, 800 :: (volatile store (s64) into %ir.0) + renamable $x11 = ADDI $x0, 3 + SD killed renamable $x11, killed renamable $x10, 808 :: (volatile store (s64) into %ir.1) + PseudoRET + +... +--- +name: load_large_offset_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + + ; CHECK-LABEL: name: load_large_offset_no_opt + ; CHECK: liveins: $x10 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: dead renamable $x11 = LD renamable $x10, 800 :: (volatile load (s64) from %ir.0) + ; CHECK-NEXT: dead renamable $x10 = LD killed renamable $x10, 808 :: (volatile load (s64) from %ir.1) + ; CHECK-NEXT: PseudoRET + dead renamable $x11 = LD renamable $x10, 800 :: (volatile load (s64) from %ir.0) + dead renamable $x10 = LD killed renamable $x10, 808 :: (volatile load (s64) from %ir.1) + PseudoRET + +...