diff --git a/llvm/lib/Target/M68k/GISel/M68kCallLowering.h b/llvm/lib/Target/M68k/GISel/M68kCallLowering.h --- a/llvm/lib/Target/M68k/GISel/M68kCallLowering.h +++ b/llvm/lib/Target/M68k/GISel/M68kCallLowering.h @@ -22,6 +22,7 @@ namespace llvm { class M68kTargetLowering; +class MachineInstrBuilder; class M68kCallLowering : public CallLowering { // TODO: We are only supporting return instruction with no value at this time @@ -67,6 +68,17 @@ : M68kIncomingValueHandler(MIRBuilder, MRI) {} }; +struct CallReturnHandler : public M68kIncomingValueHandler { + CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI, + MachineInstrBuilder &MIB) + : M68kIncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {} + +private: + void assignValueToReg(Register ValVReg, Register PhysReg, + CCValAssign VA) override; + + MachineInstrBuilder &MIB; +}; } // end namespace llvm #endif // LLVM_LIB_TARGET_M68K_GLSEL_M68KCALLLOWERING_H diff --git a/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp b/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp --- a/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp +++ b/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp @@ -27,10 +27,12 @@ M68kCallLowering::M68kCallLowering(const M68kTargetLowering &TLI) : CallLowering(&TLI) {} -struct OutgoingArgHandler : public CallLowering::OutgoingValueHandler { - OutgoingArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI, - MachineInstrBuilder MIB) - : OutgoingValueHandler(MIRBuilder, MRI), MIB(MIB) {} +struct M68kOutgoingArgHandler : public CallLowering::OutgoingValueHandler { + M68kOutgoingArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI, + MachineInstrBuilder MIB) + : OutgoingValueHandler(MIRBuilder, MRI), MIB(MIB), + DL(MIRBuilder.getMF().getDataLayout()), + STI(MIRBuilder.getMF().getSubtarget()) {} void assignValueToReg(Register ValVReg, Register PhysReg, CCValAssign VA) override { @@ -41,16 +43,29 @@ void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, MachinePointerInfo &MPO, CCValAssign &VA) override { - llvm_unreachable("unimplemented"); + MachineFunction &MF = MIRBuilder.getMF(); + Register ExtReg = extendRegister(ValVReg, VA); + + auto *MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOStore, MemTy, + inferAlignFromPtrInfo(MF, MPO)); + MIRBuilder.buildStore(ExtReg, Addr, *MMO); } Register getStackAddress(uint64_t Size, int64_t Offset, MachinePointerInfo &MPO, ISD::ArgFlagsTy Flags) override { - llvm_unreachable("unimplemented"); + LLT p0 = LLT::pointer(0, DL.getPointerSizeInBits(0)); + LLT SType = LLT::scalar(DL.getPointerSizeInBits(0)); + Register StackReg = STI.getRegisterInfo()->getStackRegister(); + auto SPReg = MIRBuilder.buildCopy(p0, StackReg).getReg(0); + auto OffsetReg = MIRBuilder.buildConstant(SType, Offset); + auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg); + MPO = MachinePointerInfo::getStack(MIRBuilder.getMF(), Offset); + return AddrReg.getReg(0); } - MachineInstrBuilder MIB; + const DataLayout &DL; + const M68kSubtarget &STI; }; bool M68kCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, ArrayRef VRegs, @@ -72,7 +87,7 @@ setArgFlags(OrigArg, AttributeList::ReturnIndex, DL, F); splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv()); OutgoingValueAssigner ArgAssigner(AssignFn); - OutgoingArgHandler ArgHandler(MIRBuilder, MRI, MIB); + M68kOutgoingArgHandler ArgHandler(MIRBuilder, MRI, MIB); Success = determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgs, MIRBuilder, F.getCallingConv(), F.isVarArg()); @@ -144,9 +159,74 @@ return AddrReg.getReg(0); } +void CallReturnHandler::assignValueToReg(Register ValVReg, Register PhysReg, + CCValAssign VA) { + MIB.addDef(PhysReg, RegState::Implicit); + MIRBuilder.buildCopy(ValVReg, PhysReg); +} + bool M68kCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info) const { - return false; + MachineFunction &MF = MIRBuilder.getMF(); + Function &F = MF.getFunction(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + auto &DL = F.getParent()->getDataLayout(); + const M68kTargetLowering &TLI = *getTLI(); + const M68kSubtarget &STI = MF.getSubtarget(); + const TargetInstrInfo &TII = *STI.getInstrInfo(); + const M68kRegisterInfo *TRI = STI.getRegisterInfo(); + + SmallVector OutArgs; + for (auto &OrigArg : Info.OrigArgs) + splitToValueTypes(OrigArg, OutArgs, DL, Info.CallConv); + + SmallVector InArgs; + if (!Info.OrigRet.Ty->isVoidTy()) + splitToValueTypes(Info.OrigRet, InArgs, DL, Info.CallConv); + + unsigned AdjStackDown = TII.getCallFrameSetupOpcode(); + auto CallSeqStart = MIRBuilder.buildInstr(AdjStackDown); + + unsigned Opc = TLI.getTargetMachine().isPositionIndependent() ? M68k::CALLq + : Info.Callee.isReg() ? M68k::CALLj + : M68k::CALLb; + + auto MIB = MIRBuilder.buildInstrNoInsert(Opc) + .add(Info.Callee) + .addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv)); + + CCAssignFn *AssignFn = + TLI.getCCAssignFn(F.getCallingConv(), false, F.isVarArg()); + OutgoingValueAssigner Assigner(AssignFn); + M68kOutgoingArgHandler Handler(MIRBuilder, MRI, MIB); + if (!determineAndHandleAssignments(Handler, Assigner, OutArgs, MIRBuilder, + Info.CallConv, Info.IsVarArg)) + return false; + + if (Info.Callee.isReg()) + constrainOperandRegClass(MF, *TRI, MRI, *STI.getInstrInfo(), + *STI.getRegBankInfo(), *MIB, MIB->getDesc(), + Info.Callee, 0); + + MIRBuilder.insertInstr(MIB); + + if (!Info.OrigRet.Ty->isVoidTy()) { + CCAssignFn *RetAssignFn = + TLI.getCCAssignFn(F.getCallingConv(), true, F.isVarArg()); + + OutgoingValueAssigner Assigner(RetAssignFn, RetAssignFn); + CallReturnHandler Handler(MIRBuilder, MRI, MIB); + if (!determineAndHandleAssignments(Handler, Assigner, InArgs, MIRBuilder, + Info.CallConv, Info.IsVarArg)) + return false; + } + + CallSeqStart.addImm(Assigner.StackOffset).addImm(0); + + unsigned AdjStackUp = TII.getCallFrameDestroyOpcode(); + MIRBuilder.buildInstr(AdjStackUp).addImm(Assigner.StackOffset).addImm(0); + + return true; } bool M68kCallLowering::enableBigEndian() const { return true; } diff --git a/llvm/lib/Target/M68k/GISel/M68kInstructionSelector.cpp b/llvm/lib/Target/M68k/GISel/M68kInstructionSelector.cpp --- a/llvm/lib/Target/M68k/GISel/M68kInstructionSelector.cpp +++ b/llvm/lib/Target/M68k/GISel/M68kInstructionSelector.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "M68kRegisterBankInfo.h" +#include "M68kRegisterInfo.h" #include "M68kSubtarget.h" #include "M68kTargetMachine.h" #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" @@ -31,8 +32,26 @@ bool select(MachineInstr &I) override; static const char *getName() { return DEBUG_TYPE; } + // Address Register Indirect + ComplexRendererFns selectARI(MachineOperand &Root) const; + // Address Register Indirect with PostIncrement + ComplexRendererFns selectARIPI(MachineOperand &Root) const; + // Address Register Indirect with PreDecrement + ComplexRendererFns selectARIPD(MachineOperand &Root) const; + // Address Register Indirect with Displacement + ComplexRendererFns selectARID(MachineOperand &Root) const; + // Address Register Indirect with Index + ComplexRendererFns selectARII(MachineOperand &Root) const; + // Absolute Long Address Mode + ComplexRendererFns selectAL(MachineOperand &Root) const; + // Program Counter with Displacement + ComplexRendererFns selectPCD(MachineOperand &Root) const; + // Program Counter with Index + ComplexRendererFns selectPCI(MachineOperand &Root) const; + private: bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; + bool constrainCopy(MachineInstr &I) const; const M68kTargetMachine &TM; const M68kInstrInfo &TII; @@ -69,11 +88,130 @@ { } +InstructionSelector::ComplexRendererFns +M68kInstructionSelector::selectARI(MachineOperand &Root) const { + return None; +} + +InstructionSelector::ComplexRendererFns +M68kInstructionSelector::selectARIPI(MachineOperand &Root) const { + return None; +} + +InstructionSelector::ComplexRendererFns +M68kInstructionSelector::selectARIPD(MachineOperand &Root) const { + return None; +} + +InstructionSelector::ComplexRendererFns +M68kInstructionSelector::selectARID(MachineOperand &Root) const { + LLVM_DEBUG(dbgs() << "GISel: Selecting ARID\n"); + + MachineRegisterInfo &MRI = Root.getParent()->getMF()->getRegInfo(); + + MachineInstr *RootDef = MRI.getVRegDef(Root.getReg()); + + switch (RootDef->getOpcode()) { + default: + break; + case TargetOpcode::G_PTR_ADD: { + auto ValAndVReg = getIConstantVRegValWithLookThrough( + RootDef->getOperand(2).getReg(), MRI); + + if (!ValAndVReg) + break; + + int64_t Imm = ValAndVReg->Value.getSExtValue(); + Register Reg = RootDef->getOperand(1).getReg(); + + return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Imm).addUse(Reg); }}}; + } + case TargetOpcode::G_FRAME_INDEX: + return {{[=](MachineInstrBuilder &MIB) { + MIB.addImm(0).add(RootDef->getOperand(1)); + }}}; + } + + return None; +} + +InstructionSelector::ComplexRendererFns +M68kInstructionSelector::selectARII(MachineOperand &Root) const { + return None; +} + +InstructionSelector::ComplexRendererFns +M68kInstructionSelector::selectAL(MachineOperand &Root) const { + return None; +} + +InstructionSelector::ComplexRendererFns +M68kInstructionSelector::selectPCD(MachineOperand &Root) const { + return None; +} + +InstructionSelector::ComplexRendererFns +M68kInstructionSelector::selectPCI(MachineOperand &Root) const { + return None; +} + +bool M68kInstructionSelector::constrainCopy(MachineInstr &I) const { + MachineOperand &Dst = I.getOperand(0); + MachineOperand &Src = I.getOperand(1); + MachineRegisterInfo &MRI = I.getMF()->getRegInfo(); + + if (Dst.getReg().isVirtual() && Src.getReg().isPhysical()) { + auto &RegBankOrClass = MRI.getRegClassOrRegBank(Dst.getReg()); + if (RegBankOrClass.is()) + return true; + + LLT Ty = MRI.getType(Dst.getReg()); + const TargetRegisterClass *TRI = nullptr; + if (Ty.getSizeInBits() <= 8) { + TRI = &M68k::DR8RegClass; + } else if (Ty.getSizeInBits() == 16) { + TRI = &M68k::XR16RegClass; + } else { + TRI = &M68k::XR32RegClass; + } + + assert(TRI && "No register class ??"); + return RBI.constrainGenericRegister(Dst.getReg(), *TRI, MRI) != nullptr; + } + + return true; +} + bool M68kInstructionSelector::select(MachineInstr &I) { + if (I.isCopy()) + return constrainCopy(I); + // Certain non-generic instructions also need some special handling. if (!isPreISelGenericOpcode(I.getOpcode())) return true; + // GlobalISel does not support p0 very well. + // For example, we need to change: + // ``` + // %0:_(p0) = G_LOAD ... + // ``` + // into this: + // ``` + // %0_(s32) = G_LOAD + // ``` + switch (I.getOpcode()) { + case TargetOpcode::G_LOAD: { + MachineRegisterInfo &MRI = I.getMF()->getRegInfo(); + + Register Reg = I.getOperand(0).getReg(); + LLT Ty = MRI.getType(Reg); + if (Ty.isPointer()) { + MRI.setType(Reg, LLT::scalar(32)); + } + break; + } + } + if (selectImpl(I, *CoverageInfo)) return true; diff --git a/llvm/lib/Target/M68k/GISel/M68kLegalizerInfo.cpp b/llvm/lib/Target/M68k/GISel/M68kLegalizerInfo.cpp --- a/llvm/lib/Target/M68k/GISel/M68kLegalizerInfo.cpp +++ b/llvm/lib/Target/M68k/GISel/M68kLegalizerInfo.cpp @@ -21,13 +21,17 @@ M68kLegalizerInfo::M68kLegalizerInfo(const M68kSubtarget &ST) { using namespace TargetOpcode; - const LLT S32 = LLT::scalar(32); - const LLT P0 = LLT::pointer(0, 32); - getActionDefinitionsBuilder(G_LOAD).legalFor({S32}); - getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({P0}); - getActionDefinitionsBuilder(G_ADD).legalFor({S32}); - getActionDefinitionsBuilder(G_SUB).legalFor({S32}); - getActionDefinitionsBuilder(G_MUL).legalFor({S32}); - getActionDefinitionsBuilder(G_UDIV).legalFor({S32}); + const LLT s32 = LLT::scalar(32); + const LLT p0 = LLT::pointer(0, 32); + getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL, G_UDIV, G_CONSTANT}) + .legalFor({s32}); + getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0}); + + getActionDefinitionsBuilder({G_STORE, G_LOAD}) + .legalForTypesWithMemDesc({{s32, p0, s32, 4}}) + .legalForTypesWithMemDesc({{p0, p0, s32, 4}}); + + getActionDefinitionsBuilder(G_PTR_ADD).legalFor({{p0, s32}}); + getLegacyLegalizerInfo().computeTables(); } diff --git a/llvm/lib/Target/M68k/GISel/M68kRegisterBankInfo.cpp b/llvm/lib/Target/M68k/GISel/M68kRegisterBankInfo.cpp --- a/llvm/lib/Target/M68k/GISel/M68kRegisterBankInfo.cpp +++ b/llvm/lib/Target/M68k/GISel/M68kRegisterBankInfo.cpp @@ -86,7 +86,8 @@ case G_SDIV: case G_UDIV: case G_LOAD: - case G_STORE: { + case G_STORE: + case G_PTR_ADD: { OperandsMapping = &M68k::ValueMappings[M68k::GPR3OpsIdx]; break; } diff --git a/llvm/lib/Target/M68k/M68kInstrData.td b/llvm/lib/Target/M68k/M68kInstrData.td --- a/llvm/lib/Target/M68k/M68kInstrData.td +++ b/llvm/lib/Target/M68k/M68kInstrData.td @@ -68,12 +68,12 @@ class MxMove_MR : MxMove; + [(store REG.VT:$src, (MEMPat MEMOpd:$dst))], ENC>; class MxMove_MI : MxMove; + [(store TYPE.IPat:$src, (MEMPat MEMOpd:$dst))], ENC>; } // let mayStore = 1 class MxMove_RI @@ -87,7 +87,7 @@ MxEncEA SRCEA, MxEncExt SRCEXT, MxEncEA DSTEA, MxEncExt DSTEXT> : MxMove>; multiclass MMxMove_RM { @@ -133,7 +133,7 @@ MxEncEA SRCEA, MxEncExt SRCEXT, MxEncEA DSTEA, MxEncExt DSTEXT> : MxMove>; } // let mayLoad = 1, mayStore = 1 diff --git a/llvm/lib/Target/M68k/M68kInstrInfo.td b/llvm/lib/Target/M68k/M68kInstrInfo.td --- a/llvm/lib/Target/M68k/M68kInstrInfo.td +++ b/llvm/lib/Target/M68k/M68kInstrInfo.td @@ -488,6 +488,29 @@ def MxCP_PCI : ComplexPattern; +def gi_MxCP_ARI : GIComplexOperandMatcher, + GIComplexPatternEquiv; + +def gi_MxCP_ARIPI : GIComplexOperandMatcher, + GIComplexPatternEquiv; + +def gi_MxCP_ARIPD : GIComplexOperandMatcher, + GIComplexPatternEquiv; + +def gi_MxCP_ARID : GIComplexOperandMatcher, + GIComplexPatternEquiv; + +def gi_MxCP_ARII : GIComplexOperandMatcher, + GIComplexPatternEquiv; + +def gi_MxCP_AL : GIComplexOperandMatcher, + GIComplexPatternEquiv; + +def gi_MxCP_PCD : GIComplexOperandMatcher, + GIComplexPatternEquiv; + +def gi_MxCP_PCI : GIComplexOperandMatcher, + GIComplexPatternEquiv; //===----------------------------------------------------------------------===// // Pattern Fragments @@ -518,7 +541,11 @@ if (ExtType == ISD::EXTLOAD) return LD->getAlignment() >= 2 && !LD->isSimple(); return false; -}]>; +}]> { + let GISelPredicateCode = [{ + return (*MI.memoperands_begin())->getSize() == 2; + }]; +} def Mxloadi32 : PatFrag<(ops node:$ptr), (i32 (unindexedload node:$ptr)), [{ LoadSDNode *LD = cast(N); @@ -528,7 +555,11 @@ if (ExtType == ISD::EXTLOAD) return LD->getAlignment() >= 4 && !LD->isSimple(); return false; -}]>; +}]> { + let GISelPredicateCode = [{ + return (*MI.memoperands_begin())->getSize() == 4; + }]; +} def Mxloadi8 : PatFrag<(ops node:$ptr), (i8 (load node:$ptr))>; diff --git a/llvm/lib/Target/M68k/M68kTargetMachine.cpp b/llvm/lib/Target/M68k/M68kTargetMachine.cpp --- a/llvm/lib/Target/M68k/M68kTargetMachine.cpp +++ b/llvm/lib/Target/M68k/M68kTargetMachine.cpp @@ -19,6 +19,7 @@ #include "llvm/CodeGen/GlobalISel/IRTranslator.h" #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" #include "llvm/CodeGen/GlobalISel/Legalizer.h" +#include "llvm/CodeGen/GlobalISel/Localizer.h" #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetPassConfig.h" @@ -147,6 +148,7 @@ bool addIRTranslator() override; bool addLegalizeMachineIR() override; bool addRegBankSelect() override; + void addPreGlobalInstructionSelect() override; bool addGlobalInstructionSelect() override; bool addInstSelector() override; void addPreSched2() override; @@ -180,6 +182,10 @@ return false; } +void M68kPassConfig::addPreGlobalInstructionSelect() { + addPass(new Localizer()); +} + bool M68kPassConfig::addGlobalInstructionSelect() { addPass(new InstructionSelect()); return false; diff --git a/llvm/test/CodeGen/M68k/GlobalISel/c-call.ll b/llvm/test/CodeGen/M68k/GlobalISel/c-call.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/M68k/GlobalISel/c-call.ll @@ -0,0 +1,46 @@ +; RUN: llc -mtriple=m68k -global-isel -verify-machineinstrs %s -o - | FileCheck %s + +define i32 @test1() nounwind { +; CHECK-LABEL: test1: +; CHECK: ; %bb.0 +; CHECK-NEXT: suba.l #4, %sp +; CHECK-NEXT: jsr callee1 +; CHECK-NEXT: move.l #0, %d0 +; CHECK-NEXT: adda.l #4, %sp +; CHECK-NEXT: rts + call void @callee1() nounwind + ret i32 0 +} +declare void @callee1(); + +define i32 @test2() nounwind { +; CHECK-LABEL: test2: +; CHECK: ; %bb.0: +; CHECK-NEXT: suba.l #12, %sp +; CHECK-NEXT: move.l #12, (0,%sp) +; CHECK-NEXT: move.l #18, (4,%sp) +; CHECK-NEXT: move.l #-4, (8,%sp) +; CHECK-NEXT: jsr callee2 +; CHECK-NEXT: move.l #0, %d0 +; CHECK-NEXT: adda.l #12, %sp +; CHECK-NEXT: rts + call void @callee2(i32 12, i32 18, i32 -4) nounwind + ret i32 0 +} +declare void @callee2(i32, i32, i32); + +define i32 @test3(i32 %0, i32 %1) nounwind { +; CHECK-LABEL: test3: +; CHECK: ; %bb.0: +; CHECK-NEXT: suba.l #12, %sp +; CHECK-NEXT: move.l (16,%sp), %d0 +; CHECK-NEXT: move.l (20,%sp), %d1 +; CHECK-NEXT: move.l %d0, (0,%sp) +; CHECK-NEXT: move.l %d1, (4,%sp) +; CHECK-NEXT: jsr callee3 +; CHECK-NEXT: adda.l #12, %sp +; CHECK-NEXT: rts + %3 = call i32 @callee3(i32 %0, i32 %1) + ret i32 %3 +} +declare i32 @callee3(i32, i32) \ No newline at end of file diff --git a/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-call.ll b/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-call.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-call.ll @@ -0,0 +1,41 @@ +; RUN: llc -mtriple=m68k -O0 -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - 2>&1 | FileCheck %s + +; CHECK-LABEL: name: test_trivial_call +; CHECK: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp +; CHECK: CALLb @trivial_callee, csr_std, implicit $sp +; CHECK: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp +; CHECK: RTS +declare void @trivial_callee() +define void @test_trivial_call() { + call void @trivial_callee() + ret void +} + +; CHECK-LABEL: name: test_simple_return +; CHECK: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp +; CHECK: CALLb @simple_return_callee, csr_std, implicit $sp, implicit-def $d0 +; CHECK: [[RES:%[0-9]+]]:_(s32) = COPY $d0 +; CHECK: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp +; CHECK $d0 = COPY [[RES]] +; CHECK RTS implicit $d0 +declare i32 @simple_return_callee() +define i32 @test_simple_return() { + %res = call i32 @simple_return_callee() + ret i32 %res +} + +; CHECK-LABEL: name: test_simple_arg +; CHECK: [[ARG:%[0-9]+]]:_(s32) = G_CONSTANT i32 1048596 +; CHECK: ADJCALLSTACKDOWN 4, 0, implicit-def $sp, implicit-def $ccr, implicit $sp +; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp +; CHECK: [[OFFSET:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 +; CHECK: [[PTR:%[0-9]+]]:_(p0) = G_PTR_ADD [[SP]], [[OFFSET]](s32) +; CHECK: G_STORE [[ARG]](s32), [[PTR]](p0) +; CHECK: CALLb @simple_arg_callee, csr_std, implicit $sp +; CHECK: ADJCALLSTACKUP 4, 0, implicit-def $sp, implicit-def $ccr, implicit $sp +; CHECK: RTS +declare void @simple_arg_callee(i32 %0) +define void @test_simple_arg() { + call void @simple_arg_callee(i32 1048596) + ret void +}