Index: llvm/lib/Target/RISCV/CMakeLists.txt =================================================================== --- llvm/lib/Target/RISCV/CMakeLists.txt +++ llvm/lib/Target/RISCV/CMakeLists.txt @@ -22,6 +22,7 @@ RISCVAsmPrinter.cpp RISCVCallLowering.cpp RISCVExpandAtomicPseudoInsts.cpp + RISCVCompressInstrs.cpp RISCVExpandPseudoInsts.cpp RISCVFrameLowering.cpp RISCVInstrInfo.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 *createRISCVCompressInstrsOptPass(); +void initializeRISCVCompressInstrsOptPass(PassRegistry &); + FunctionPass *createRISCVMergeBaseOffsetOptPass(); void initializeRISCVMergeBaseOffsetOptPass(PassRegistry &); Index: llvm/lib/Target/RISCV/RISCVCompressInstrs.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/RISCV/RISCVCompressInstrs.cpp @@ -0,0 +1,334 @@ +//===-- RISCVCompressInstrs.cpp - Make 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/Support/Debug.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "riscv-compress-instrs" +#define RISCV_COMPRESS_INSTRS_NAME "RISCV Compress Instructions" + +namespace { + +struct RISCVCompressInstrsOpt : public MachineFunctionPass { + static char ID; + + bool runOnMachineFunction(MachineFunction &Fn) override; + + RISCVCompressInstrsOpt() : MachineFunctionPass(ID) { + initializeRISCVCompressInstrsOptPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return RISCV_COMPRESS_INSTRS_NAME; } +}; +} // namespace + +char RISCVCompressInstrsOpt::ID = 0; +INITIALIZE_PASS(RISCVCompressInstrsOpt, "riscv-compress-instrs", + RISCV_COMPRESS_INSTRS_NAME, false, false) + +static const uint8_t CSWOffsetMask = 0b1111100; + +// 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. +// Return 0 if the offset is already compressible. +static int64_t getBaseAdjustForCompression(int64_t Offset) { + if (isShiftedUInt<5, 2>(Offset)) + return 0; + // Return the excess bits that do not fit in a compressible offset. + return Offset & ~(CSWOffsetMask); +} + +// 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). +// {Register(0), 0} - No suitable optimization found for this instruction. +static RegImmPair getRegImmPairPreventingCompression(const MachineInstr &MI) { + int64_t NewBaseAdjust = 0; + + switch (MI.getOpcode()) { + default: + break; + case RISCV::LW: { + const MachineOperand &MOImm = MI.getOperand(2); + if (!MOImm.isImm()) + break; + + int64_t Offset = MOImm.getImm(); + + NewBaseAdjust = getBaseAdjustForCompression(Offset); + + Register Base = MI.getOperand(1).getReg(); + // Load from stack pointer does not have a requirement for either of the + // registers to be compressible and the offset can be a 6 bit immediate + // scaled by 4. + if (RISCV::SPRegClass.contains(Base)) { + if (!isShiftedUInt<6, 2>(Offset) && NewBaseAdjust) + return RegImmPair(Base, NewBaseAdjust); + break; + } + + Register Dest = MI.getOperand(0).getReg(); + bool DestCompressed = RISCV::GPRCRegClass.contains(Dest); + bool BaseCompressed = RISCV::GPRCRegClass.contains(Base); + + // For loads we can only change the base register since dest is defined + // rather than used. + if ((!BaseCompressed || NewBaseAdjust) && DestCompressed) + return RegImmPair(Base, NewBaseAdjust); + + break; + } + case RISCV::SW: { + const MachineOperand &MOImm = MI.getOperand(2); + if (!MOImm.isImm()) + break; + + int64_t Offset = MOImm.getImm(); + + NewBaseAdjust = getBaseAdjustForCompression(Offset); + + Register Base = MI.getOperand(1).getReg(); + // Store to stack pointer does not have a requirement for either of the + // registers to be compressible and the offset can be a 6 bit immediate + // scaled by 4. + if (RISCV::SPRegClass.contains(Base)) { + if (!isShiftedUInt<6, 2>(Offset) && NewBaseAdjust) + return RegImmPair(Base, NewBaseAdjust); + break; + } + + Register Src = MI.getOperand(0).getReg(); + bool SrcCompressed = RISCV::GPRCRegClass.contains(Src); + bool BaseCompressed = RISCV::GPRCRegClass.contains(Base); + + // Cannot resolve uncompressible offset if we are resolving src reg + if (!SrcCompressed && (BaseCompressed || Src == Base) && !NewBaseAdjust) + return RegImmPair(Src, NewBaseAdjust); + if ((!BaseCompressed || NewBaseAdjust) && SrcCompressed) + return RegImmPair(Base, NewBaseAdjust); + + break; + } + } + return RegImmPair(Register(0), 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(MachineBasicBlock &MBB, + MachineInstr &FirstMI, + RegImmPair RegImm, + SmallVector &MIs) { + 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 Register(0); + + // Find a compressible register which will be available from the first + // instruction we care about to the last. + return RS.scavengeRegisterBackwards(RISCV::GPRCRegClass, + FirstMI.getIterator(), + /*RestoreAfter=*/false, /*SPAdj=*/0, + /*AllowSpill=*/false); +} + +// Update uses of the old register in the given instruction to the new register. +// Return false if no further instructions should be updated. +static bool updateOperands(MachineInstr &MI, RegImmPair OldRegImm, + Register NewReg) { + bool UpdatesAllowed = true; + + // If this pass is extended to support more instructions, the check for + // definedness may need to be strengthened. + assert((MI.getOpcode() == RISCV::LW || MI.getOpcode() == RISCV::SW) && + "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. + if (MO.isDef()) { + assert(MI.getOpcode() == RISCV::LW); + // Don't allow any more updates after optimizing LW where OldRegImm.Reg + // is defined and don't update this register. + UpdatesAllowed = false; + continue; + } + // Update reg + MO.setReg(NewReg); + } + + // Update offset + if (MI.getOpcode() == RISCV::LW || MI.getOpcode() == RISCV::SW) { + MachineOperand &MOImm = MI.getOperand(2); + int64_t NewOffset = MOImm.getImm() & CSWOffsetMask; + MOImm.setImm(NewOffset); + } + + return UpdatesAllowed; +} + +bool RISCVCompressInstrsOpt::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(MBB, 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. + for (MachineInstr *UpdateMI : MIs) + if (!updateOperands(*UpdateMI, RegImm, NewReg)) + break; + } + } + return true; +} + +/// Returns an instance of the Compress Instructions Optimization pass. +FunctionPass *llvm::createRISCVCompressInstrsOptPass() { + return new RISCVCompressInstrsOpt(); +} Index: llvm/lib/Target/RISCV/RISCVTargetMachine.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -37,6 +37,7 @@ RegisterTargetMachine Y(getTheRISCV64Target()); auto PR = PassRegistry::getPassRegistry(); initializeGlobalISel(*PR); + initializeRISCVCompressInstrsOptPass(*PR); initializeRISCVExpandPseudoPass(*PR); } @@ -171,7 +172,10 @@ void RISCVPassConfig::addPreSched2() {} -void RISCVPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); } +void RISCVPassConfig::addPreEmitPass() { + addPass(&BranchRelaxationPassID); + addPass(createRISCVCompressInstrsOptPass()); +} void RISCVPassConfig::addPreEmitPass2() { addPass(createRISCVExpandPseudoPass()); Index: llvm/test/CodeGen/RISCV/compress-instrs.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/RISCV/compress-instrs.mir @@ -0,0 +1,255 @@ +# RUN: llc -o - %s -mtriple=riscv32 -mattr=+c -simplify-mir \ +# RUN: -run-pass=riscv-compress-instrs | FileCheck %s +# RUN: llc -o - %s -mtriple=riscv64 -mattr=+c -simplify-mir \ +# RUN: -run-pass=riscv-compress-instrs | FileCheck %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_ptr() #0 { + entry: + store volatile i32 1, i32* null, align 4 + store volatile i32 3, i32* null, align 4 + store volatile i32 5, i32* null, align 4 + ret void + } + + define void @load_common_ptr() #0 { + entry: + %a = load volatile i32, i32* null, align 4 + %b = load volatile i32, i32* null, align 4 + %c = load volatile i32, i32* null, align 4 + ret void + } + + define void @store_large_offset() #0 { + entry: + store volatile i32 1, i32* inttoptr (i32 305421696 to i32*), align 4 + store volatile i32 3, i32* inttoptr (i32 305421700 to i32*), align 4 + store volatile i32 5, i32* inttoptr (i32 305421704 to i32*), align 4 + store volatile i32 7, i32* inttoptr (i32 305421708 to i32*), align 4 + ret void + } + + define void @load_large_offset() #0 { + entry: + %a = load volatile i32, i32* inttoptr (i32 305421696 to i32*), align 4 + %b = load volatile i32, i32* inttoptr (i32 305421700 to i32*), align 4 + %c = load volatile i32, i32* inttoptr (i32 305421704 to i32*), align 4 + %d = load volatile i32, i32* inttoptr (i32 305421708 to i32*), align 4 + ret void + } + + define void @store_common_value_no_opt(i32* %a, i32* %b, i32* %c) #0 { + entry: + store i32 0, i32* %a, align 4 + ret void + } + + define void @store_common_ptr_no_opt() #0 { + entry: + store volatile i32 1, i32* null, align 4 + ret void + } + + define void @load_common_ptr_no_opt() #0 { + entry: + %a = load volatile i32, i32* null, align 4 + ret void + } + + define void @store_large_offset_no_opt() #0 { + entry: + store volatile i32 1, i32* inttoptr (i32 305421696 to i32*), align 4 + store volatile i32 3, i32* inttoptr (i32 305421700 to i32*), align 4 + ret void + } + + define void @load_large_offset_no_opt() #0 { + entry: + %a = load volatile i32, i32* inttoptr (i32 305421696 to i32*), align 4 + %b = load volatile i32, i32* inttoptr (i32 305421700 to i32*), align 4 + 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: $x13 = ADDI $x0, 0 + ; CHECK-NEXT: SW $x13, killed renamable $x10, 0 :: (store 4 into %ir.a) + ; CHECK-NEXT: SW $x13, killed renamable $x11, 0 :: (store 4 into %ir.b) + ; CHECK-NEXT: SW $x13, killed renamable $x12, 0 :: (store 4 into %ir.c) + SW $x0, killed renamable $x10, 0 :: (store 4 into %ir.a) + SW $x0, killed renamable $x11, 0 :: (store 4 into %ir.b) + SW $x0, killed renamable $x12, 0 :: (store 4 into %ir.c) + PseudoRET + +... +--- +name: store_common_ptr +tracksRegLiveness: true +body: | + bb.0.entry: + ; CHECK-LABEL: name: store_common_ptr + ; CHECK: renamable $x10 = ADDI $x0, 1 + ; CHECK-NEXT: $x11 = ADDI $x0, 0 + ; CHECK-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store 4 into `i32* null`) + ; CHECK-NEXT: renamable $x10 = ADDI $x0, 3 + ; CHECK-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store 4 into `i32* null`) + ; CHECK-NEXT: renamable $x10 = ADDI $x0, 5 + ; CHECK-NEXT: SW killed renamable $x10, $x11, 0 :: (volatile store 4 into `i32* null`) + renamable $x10 = ADDI $x0, 1 + SW killed renamable $x10, $x0, 0 :: (volatile store 4 into `i32* null`) + renamable $x10 = ADDI $x0, 3 + SW killed renamable $x10, $x0, 0 :: (volatile store 4 into `i32* null`) + renamable $x10 = ADDI $x0, 5 + SW killed renamable $x10, $x0, 0 :: (volatile store 4 into `i32* null`) + PseudoRET + +... +--- +name: load_common_ptr +tracksRegLiveness: true +body: | + bb.0.entry: + ; CHECK-LABEL: name: load_common_ptr + ; CHECK: $x11 = ADDI $x0, 0 + ; CHECK-NEXT: dead renamable $x10 = LW $x11, 0 :: (volatile load 4 from `i32* null`) + ; CHECK-NEXT: dead renamable $x10 = LW $x11, 0 :: (volatile load 4 from `i32* null`) + ; CHECK-NEXT: dead renamable $x10 = LW $x11, 0 :: (volatile load 4 from `i32* null`) + dead renamable $x10 = LW $x0, 0 :: (volatile load 4 from `i32* null`) + dead renamable $x10 = LW $x0, 0 :: (volatile load 4 from `i32* null`) + dead renamable $x10 = LW $x0, 0 :: (volatile load 4 from `i32* null`) + PseudoRET + +... +--- +name: store_large_offset +tracksRegLiveness: true +body: | + bb.0.entry: + ; CHECK-LABEL: name: store_large_offset + ; CHECK: renamable $x10 = LUI 74566 + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 1 + ; CHECK-NEXT: $x12 = ADDI $x10, -640 + ; CHECK-NEXT: SW killed renamable $x11, $x12, 0 :: (volatile store 4 into `i32* inttoptr (i32 305421696 to i32*)`) + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 3 + ; CHECK-NEXT: SW killed renamable $x11, $x12, 4 :: (volatile store 4 into `i32* inttoptr (i32 305421700 to i32*)`) + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 5 + ; CHECK-NEXT: SW killed renamable $x11, $x12, 8 :: (volatile store 4 into `i32* inttoptr (i32 305421704 to i32*)`) + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 7 + ; CHECK-NEXT: SW killed renamable $x11, killed $x12, 12 :: (volatile store 4 into `i32* inttoptr (i32 305421708 to i32*)`) + renamable $x10 = LUI 74566 + renamable $x11 = ADDI $x0, 1 + SW killed renamable $x11, renamable $x10, -640 :: (volatile store 4 into `i32* inttoptr (i32 305421696 to i32*)`) + renamable $x11 = ADDI $x0, 3 + SW killed renamable $x11, renamable $x10, -636 :: (volatile store 4 into `i32* inttoptr (i32 305421700 to i32*)`) + renamable $x11 = ADDI $x0, 5 + SW killed renamable $x11, renamable $x10, -632 :: (volatile store 4 into `i32* inttoptr (i32 305421704 to i32*)`) + renamable $x11 = ADDI $x0, 7 + SW killed renamable $x11, killed renamable $x10, -628 :: (volatile store 4 into `i32* inttoptr (i32 305421708 to i32*)`) + PseudoRET + +... +--- +name: load_large_offset +tracksRegLiveness: true +body: | + bb.0.entry: + ; CHECK-LABEL: name: load_large_offset + ; CHECK: renamable $x10 = LUI 74566 + ; CHECK-NEXT: $x12 = ADDI $x10, -640 + ; CHECK-NEXT: dead renamable $x11 = LW $x12, 0 :: (volatile load 4 from `i32* inttoptr (i32 305421696 to i32*)`) + ; CHECK-NEXT: dead renamable $x11 = LW $x12, 4 :: (volatile load 4 from `i32* inttoptr (i32 305421700 to i32*)`) + ; CHECK-NEXT: dead renamable $x11 = LW $x12, 8 :: (volatile load 4 from `i32* inttoptr (i32 305421704 to i32*)`) + ; CHECK-NEXT: dead renamable $x10 = LW killed $x12, 12 :: (volatile load 4 from `i32* inttoptr (i32 305421708 to i32*)`) + renamable $x10 = LUI 74566 + dead renamable $x11 = LW renamable $x10, -640 :: (volatile load 4 from `i32* inttoptr (i32 305421696 to i32*)`) + dead renamable $x11 = LW renamable $x10, -636 :: (volatile load 4 from `i32* inttoptr (i32 305421700 to i32*)`) + dead renamable $x11 = LW renamable $x10, -632 :: (volatile load 4 from `i32* inttoptr (i32 305421704 to i32*)`) + dead renamable $x10 = LW killed renamable $x10, -628 :: (volatile load 4 from `i32* inttoptr (i32 305421708 to i32*)`) + PseudoRET + +... +--- +name: store_common_value_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $x10 + ; CHECK-LABEL: name: store_common_value_no_opt + ; CHECK: SW $x0, killed renamable $x10, 0 :: (store 4 into %ir.a) + SW $x0, killed renamable $x10, 0 :: (store 4 into %ir.a) + PseudoRET + +... +--- +name: store_common_ptr_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + ; CHECK-LABEL: name: store_common_ptr_no_opt + ; CHECK: renamable $x10 = ADDI $x0, 1 + ; CHECK-NEXT: SW killed renamable $x10, $x0, 0 :: (volatile store 4 into `i32* null`) + renamable $x10 = ADDI $x0, 1 + SW killed renamable $x10, $x0, 0 :: (volatile store 4 into `i32* null`) + PseudoRET + +... +--- +name: load_common_ptr_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + ; CHECK-LABEL: name: load_common_ptr_no_opt + ; CHECK: dead renamable $x10 = LW $x0, 0 :: (volatile load 4 from `i32* null`) + dead renamable $x10 = LW $x0, 0 :: (volatile load 4 from `i32* null`) + PseudoRET + +... +--- +name: store_large_offset_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + ; CHECK-LABEL: name: store_large_offset_no_opt + ; CHECK: renamable $x10 = LUI 74566 + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 1 + ; CHECK-NEXT: SW killed renamable $x11, renamable $x10, -640 :: (volatile store 4 into `i32* inttoptr (i32 305421696 to i32*)`) + ; CHECK-NEXT: renamable $x11 = ADDI $x0, 3 + ; CHECK-NEXT: SW killed renamable $x11, killed renamable $x10, -636 :: (volatile store 4 into `i32* inttoptr (i32 305421700 to i32*)`) + renamable $x10 = LUI 74566 + renamable $x11 = ADDI $x0, 1 + SW killed renamable $x11, renamable $x10, -640 :: (volatile store 4 into `i32* inttoptr (i32 305421696 to i32*)`) + renamable $x11 = ADDI $x0, 3 + SW killed renamable $x11, killed renamable $x10, -636 :: (volatile store 4 into `i32* inttoptr (i32 305421700 to i32*)`) + PseudoRET + +... +--- +name: load_large_offset_no_opt +tracksRegLiveness: true +body: | + bb.0.entry: + ; CHECK-LABEL: name: load_large_offset_no_opt + ; CHECK: renamable $x10 = LUI 74566 + ; CHECK-NEXT: dead renamable $x11 = LW renamable $x10, -640 :: (volatile load 4 from `i32* inttoptr (i32 305421696 to i32*)`) + ; CHECK-NEXT: dead renamable $x10 = LW killed renamable $x10, -636 :: (volatile load 4 from `i32* inttoptr (i32 305421700 to i32*)`) + renamable $x10 = LUI 74566 + dead renamable $x11 = LW renamable $x10, -640 :: (volatile load 4 from `i32* inttoptr (i32 305421696 to i32*)`) + dead renamable $x10 = LW killed renamable $x10, -636 :: (volatile load 4 from `i32* inttoptr (i32 305421700 to i32*)`) + PseudoRET + +...