Index: llvm/lib/Target/RISCV/RISCVCallLowering.h =================================================================== --- llvm/lib/Target/RISCV/RISCVCallLowering.h +++ llvm/lib/Target/RISCV/RISCVCallLowering.h @@ -21,6 +21,8 @@ namespace llvm { class RISCVTargetLowering; +class MachineInstrBuilder; +class MachineIRBuilder; class RISCVCallLowering : public CallLowering { @@ -35,6 +37,27 @@ bool lowerCall(MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info) const override; + +private: + bool lowerReturnVal(MachineIRBuilder &MIRBuilder, const Value *Val, + ArrayRef VRegs, MachineInstrBuilder &Ret) const; + + /// A function of this type is used to perform value split action. + using SplitArgTy = std::function, int)>; + + template + void setISDArgsForCallingConv(const Function &F, const ArgInfo &OrigArg, + SmallVectorImpl &SplitVTs, + SmallVectorImpl &ISDArgs, bool isRet) const; + + void splitToValueTypes(const ArgInfo &OrigArg, + SmallVectorImpl &SplitArgs, + SmallVectorImpl &SplitVTs, MachineFunction &MF, + SplitArgTy PerformArgSplit) const; + + template + void updateArgLocInfo(SmallVectorImpl &ArgLocs, + const SmallVectorImpl &Arguments) const; }; } // end namespace llvm Index: llvm/lib/Target/RISCV/RISCVCallLowering.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVCallLowering.cpp +++ llvm/lib/Target/RISCV/RISCVCallLowering.cpp @@ -14,22 +14,106 @@ #include "RISCVCallLowering.h" #include "RISCVISelLowering.h" +#include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" using namespace llvm; +namespace { + +struct OutgoingValueHandler : public CallLowering::ValueHandler { + OutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI, + MachineInstrBuilder MIB, CCAssignFn *AssignFn) + : ValueHandler(B, MRI, AssignFn), MIB(MIB) {} + + MachineInstrBuilder MIB; + + bool isIncomingArgumentHandler() const override { return false; } + + Register getStackAddress(uint64_t Size, int64_t Offset, + MachinePointerInfo &MPO) override { + llvm_unreachable("not implemented"); + } + + void assignValueToAddress(Register ValVReg, Register Addr, uint64_t Size, + MachinePointerInfo &MPO, CCValAssign &VA) override { + llvm_unreachable("not implemented"); + } + + void assignValueToReg(Register ValVReg, Register PhysReg, + CCValAssign &VA) override { + Register ExtReg = extendRegister(ValVReg, VA); + MIRBuilder.buildCopy(PhysReg, ExtReg); + MIB.addUse(PhysReg, RegState::Implicit); + } + + bool assignArg(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, + const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags, + CCState &State) override { + if (AssignFn) + return AssignFn(ValNo, ValVT, LocVT, LocInfo, Flags, State); + return false; + } +}; + +} // namespace + RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI) : CallLowering(&TLI) {} +bool RISCVCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder, + const Value *Val, + ArrayRef VRegs, + MachineInstrBuilder &Ret) const { + if (!Val) + return true; + + // TODO: Only integer, pointer and aggregate types are supported now. + if (!Val->getType()->isIntOrPtrTy() && !Val->getType()->isAggregateType()) + return false; + + MachineFunction &MF = MIRBuilder.getMF(); + const Function &F = MF.getFunction(); + const DataLayout &DL = MF.getDataLayout(); + const RISCVTargetLowering &TLI = *getTLI(); + + SmallVector SplitEVTs; + ComputeValueVTs(TLI, DL, Val->getType(), SplitEVTs); + assert(VRegs.size() == SplitEVTs.size() && + "For each split Type there should be exactly one VReg."); + + ArgInfo OrigRetInfo(VRegs, Val->getType()); + setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F); + + SmallVector SplitRetInfos; + splitToValueTypes(OrigRetInfo, SplitRetInfos, SplitEVTs, MF, + [&](ArrayRef Regs, int SplitIdx) { + MIRBuilder.buildUnmerge(Regs, VRegs[SplitIdx]); + }); + + SmallVector Outs; + setISDArgsForCallingConv(F, OrigRetInfo, SplitEVTs, Outs, true); + + SmallVector ArgLocs; + CCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, F.getContext()); + + TLI.analyzeOutputArgs(MF, CCInfo, Outs, /*IsRet=*/true, nullptr); + updateArgLocInfo(ArgLocs, Outs); + + OutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret, nullptr); + return handleAssignments(CCInfo, ArgLocs, MIRBuilder, SplitRetInfos, Handler); +} + bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, ArrayRef VRegs) const { + assert(!Val == VRegs.empty() && "Return value without a vreg"); MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET); - - if (Val != nullptr) { + if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret)) return false; - } + MIRBuilder.insertInstr(Ret); return true; } @@ -48,3 +132,107 @@ CallLoweringInfo &Info) const { return false; } + +template +void RISCVCallLowering::setISDArgsForCallingConv(const Function &F, + const ArgInfo &OrigArg, + SmallVectorImpl &SplitVTs, + SmallVectorImpl &ISDArgs, + bool isRet) const { + const DataLayout &DL = F.getParent()->getDataLayout(); + LLVMContext &Ctx = F.getContext(); + CallingConv::ID CC = F.getCallingConv(); + const RISCVTargetLowering &TLI = *getTLI(); + + for (unsigned i = 0, e = SplitVTs.size(); i != e; ++i) { + EVT VT = SplitVTs[i]; + Type *SplitTy = VT.getTypeForEVT(Ctx); + MVT RegisterVT = TLI.getRegisterTypeForCallingConv(Ctx, CC, VT); + unsigned NumParts = TLI.getNumRegistersForCallingConv(Ctx, CC, VT); + + for (unsigned j = 0; j < NumParts; ++j) { + auto Flags = OrigArg.Flags[0]; + + if (j == 0) + Flags.setOrigAlign(TLI.getABIAlignmentForCallingConv(SplitTy, DL)); + else + Flags.setOrigAlign(Align(1)); + + ISDArgs.emplace_back(Flags, RegisterVT, VT, true, isRet ? 0 : i, 0); + } + } +} + +void RISCVCallLowering::splitToValueTypes(const ArgInfo &OrigArg, + SmallVectorImpl &SplitArgs, + SmallVectorImpl &SplitVTs, + MachineFunction &MF, + SplitArgTy PerformArgSplit) const { + const RISCVTargetLowering &TLI = *getTLI(); + LLVMContext &Ctx = OrigArg.Ty->getContext(); + CallingConv::ID CC = MF.getFunction().getCallingConv(); + const DataLayout &DL = MF.getDataLayout(); + + // Create one ArgInfo for each virtual register in the original ArgInfo. + for (unsigned i = 0, e = SplitVTs.size(); i != e; ++i) { + EVT VT = SplitVTs[i]; + Type *SplitTy = VT.getTypeForEVT(Ctx); + auto Flags = OrigArg.Flags[0]; + Flags.setOrigAlign(Align(DL.getABITypeAlignment(SplitTy))); + + unsigned NumParts = TLI.getNumRegistersForCallingConv(Ctx, CC, VT); + if (NumParts == 1) { + SplitArgs.emplace_back(OrigArg.Regs[i], VT.getTypeForEVT(Ctx), Flags, + OrigArg.IsFixed); + continue; + } + + SmallVector SplitRegs; + + EVT PartVT = TLI.getRegisterTypeForCallingConv(Ctx, CC, VT); + Type *PartTy = PartVT.getTypeForEVT(Ctx); + + for (unsigned j = 0; j < NumParts; ++j) { + ArgInfo Info = ArgInfo{MF.getRegInfo().createGenericVirtualRegister( + getLLTForType(*PartTy, DL)), + PartTy, Flags}; + SplitArgs.push_back(Info); + SplitRegs.push_back(Info.Regs[0]); + } + + PerformArgSplit(SplitRegs, i); + } +} + +template +void RISCVCallLowering::updateArgLocInfo( + SmallVectorImpl &ArgLocs, + const SmallVectorImpl &Arguments) const { + for (unsigned i = 0; i < ArgLocs.size(); ++i) { + const CCValAssign &VA = ArgLocs[i]; + CCValAssign::LocInfo LocInfo = VA.getLocInfo(); + // TODO: LocInfo type for BCvt and Indirect need be changed? + if (LocInfo == CCValAssign::BCvt || LocInfo == CCValAssign::Indirect) + continue; + + if (Arguments[i].ArgVT.getSizeInBits() >= Arguments[i].VT.getSizeInBits()) { + assert(LocInfo == CCValAssign::Full && "Unexpected CCValAssign::LocInfo"); + continue; + } + + if (Arguments[i].Flags.isSExt()) + LocInfo = CCValAssign::LocInfo::SExt; + else if (Arguments[i].Flags.isZExt()) + LocInfo = CCValAssign::LocInfo::ZExt; + else + LocInfo = CCValAssign::LocInfo::AExt; + + if (VA.isMemLoc()) + ArgLocs[i] = + CCValAssign::getMem(VA.getValNo(), VA.getValVT(), + VA.getLocMemOffset(), VA.getLocVT(), LocInfo); + else + ArgLocs[i] = CCValAssign::getReg(VA.getValNo(), VA.getValVT(), + VA.getLocReg(), VA.getLocVT(), LocInfo); + } +} Index: llvm/lib/Target/RISCV/RISCVISelLowering.h =================================================================== --- llvm/lib/Target/RISCV/RISCVISelLowering.h +++ llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -154,13 +154,14 @@ Register getRegisterByName(const char *RegName, LLT VT, const MachineFunction &MF) const override; -private: void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo, const SmallVectorImpl &Ins, bool IsRet) const; void analyzeOutputArgs(MachineFunction &MF, CCState &CCInfo, const SmallVectorImpl &Outs, bool IsRet, CallLoweringInfo *CLI) const; + +private: // Lower incoming arguments, copy physregs into vregs SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, Index: llvm/test/CodeGen/RISCV/GlobalISel/irtranslator-calllowering.ll =================================================================== --- llvm/test/CodeGen/RISCV/GlobalISel/irtranslator-calllowering.ll +++ llvm/test/CodeGen/RISCV/GlobalISel/irtranslator-calllowering.ll @@ -1,17 +1,143 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=riscv32 -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \ ; RUN: | FileCheck -check-prefix=RV32I %s ; RUN: llc -mtriple=riscv64 -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \ ; RUN: | FileCheck -check-prefix=RV64I %s -define void @foo() { - ; RV32I-LABEL: name: foo +define void @test_ret_void() { + ; RV32I-LABEL: name: test_ret_void ; RV32I: bb.1.entry: ; RV32I-NEXT: PseudoRET - ; RV64I-LABEL: name: foo + ; RV64I-LABEL: name: test_ret_void ; RV64I: bb.1.entry: ; RV64I-NEXT: PseudoRET entry: ret void } + +define i8 @test_ret_i8() { + ; RV32I-LABEL: name: test_ret_i8 + ; RV32I: bb.1.entry: + ; RV32I-NEXT: [[CST:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 + ; RV32I-NEXT: [[AEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[CST]](s8) + ; RV32I-NEXT: $x10 = COPY [[AEXT]](s32) + ; RV32I-NEXT: PseudoRET implicit $x10 + + ; RV64I-LABEL: name: test_ret_i8 + ; RV64I: bb.1.entry: + ; RV64I-NEXT: [[CST:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 + ; RV64I-NEXT: [[AEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[CST]](s8) + ; RV64I-NEXT: $x10 = COPY [[AEXT]](s64) + ; RV64I-NEXT: PseudoRET implicit $x10 +entry: + ret i8 1 +} + +define zeroext i8 @test_ret_i8_zext() { + ; RV32I-LABEL: name: test_ret_i8_zext + ; RV32I: bb.1.entry: + ; RV32I-NEXT: [[CST:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 + ; RV32I-NEXT: [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[CST]](s8) + ; RV32I-NEXT: $x10 = COPY [[ZEXT]](s32) + ; RV32I-NEXT: PseudoRET implicit $x10 + + ; RV64I-LABEL: name: test_ret_i8_zext + ; RV64I: bb.1.entry: + ; RV64I-NEXT: [[CST:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 + ; RV64I-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[CST]](s8) + ; RV64I-NEXT: $x10 = COPY [[ZEXT]](s64) + ; RV64I-NEXT: PseudoRET implicit $x10 +entry: + ret i8 1 +} + +define signext i16 @test_ret_i16_sext() { + ; RV32I-LABEL: name: test_ret_i16_sext + ; RV32I: bb.1.entry: + ; RV32I-NEXT: [[CST:%[0-9]+]]:_(s16) = G_CONSTANT i16 1 + ; RV32I-NEXT: [[SEXT:%[0-9]+]]:_(s32) = G_SEXT [[CST]](s16) + ; RV32I-NEXT: $x10 = COPY [[SEXT]](s32) + ; RV32I-NEXT: PseudoRET implicit $x10 + + ; RV64I-LABEL: name: test_ret_i16_sext + ; RV64I: bb.1.entry: + ; RV64I-NEXT: [[CST:%[0-9]+]]:_(s16) = G_CONSTANT i16 1 + ; RV64I-NEXT: [[SEXT:%[0-9]+]]:_(s64) = G_SEXT [[CST]](s16) + ; RV64I-NEXT: $x10 = COPY [[SEXT]](s64) + ; RV64I-NEXT: PseudoRET implicit $x10 +entry: + ret i16 1 +} + +define i32 @test_ret_i32() { + ; RV32I-LABEL: name: test_ret_i32 + ; RV32I: bb.1.entry: + ; RV32I-NEXT: [[CST:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; RV32I-NEXT: $x10 = COPY [[CST]](s32) + ; RV32I-NEXT: PseudoRET implicit $x10 + + ; RV64I-LABEL: name: test_ret_i32 + ; RV64I: bb.1.entry: + ; RV64I-NEXT: [[CST:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; RV64I-NEXT: [[AEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[CST]](s32) + ; RV64I-NEXT: $x10 = COPY [[AEXT]](s64) + ; RV64I-NEXT: PseudoRET implicit $x10 +entry: + ret i32 1 +} + +define i64 @test_ret_i64() { + ; RV32I-LABEL: name: test_ret_i64 + ; RV32I: bb.1.entry: + ; RV32I-NEXT: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4294967296 + ; RV32I-NEXT: [[CST1:%[0-9]+]]:_(s32), [[CST2:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[CST]](s64) + ; RV32I-NEXT: $x10 = COPY [[CST1]](s32) + ; RV32I-NEXT: $x11 = COPY [[CST2]](s32) + ; RV32I-NEXT: PseudoRET implicit $x10, implicit $x11 + + ; RV64I-LABEL: name: test_ret_i64 + ; RV64I: bb.1.entry: + ; RV64I-NEXT: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4294967296 + ; RV64I-NEXT: $x10 = COPY [[CST]](s64) + ; RV64I-NEXT: PseudoRET implicit $x10 +entry: + ret i64 4294967296 +} + +define i32* @test_ret_i32_ptr() { + ; RV32I-LABEL: name: test_ret_i32_ptr + ; RV32I: bb.1.entry: + ; RV32I-NEXT: [[UDEF:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF + ; RV32I-NEXT: $x10 = COPY [[UDEF]](p0) + ; RV32I-NEXT: PseudoRET implicit $x10 + + ; RV64I-LABEL: name: test_ret_i32_ptr + ; RV64I: bb.1.entry: + ; RV64I-NEXT: [[UDEF:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF + ; RV64I-NEXT: $x10 = COPY [[UDEF]](p0) + ; RV64I-NEXT: PseudoRET implicit $x10 +entry: + ret i32* undef +} + +define [2 x i32] @test_ret_2xi32() { + ; RV32I-LABEL: name: test_ret_2xi32 + ; RV32I: bb.1.entry: + ; RV32I-NEXT: [[CST1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; RV32I-NEXT: [[CST2:%[0-9]+]]:_(s32) = G_CONSTANT i32 2 + ; RV32I-NEXT: $x10 = COPY [[CST1]](s32) + ; RV32I-NEXT: $x11 = COPY [[CST2]](s32) + ; RV32I-NEXT: PseudoRET implicit $x10, implicit $x11 + + ; RV64I-LABEL: name: test_ret_2xi32 + ; RV64I: bb.1.entry: + ; RV64I-NEXT: [[CST1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; RV64I-NEXT: [[CST2:%[0-9]+]]:_(s32) = G_CONSTANT i32 2 + ; RV64I-NEXT: [[AEXT1:%[0-9]+]]:_(s64) = G_ANYEXT [[CST1]](s32) + ; RV64I-NEXT: $x10 = COPY [[AEXT1]](s64) + ; RV64I-NEXT: [[AEXT2:%[0-9]+]]:_(s64) = G_ANYEXT [[CST2]](s32) + ; RV64I-NEXT: $x11 = COPY [[AEXT2]](s64) + ; RV64I-NEXT: PseudoRET implicit $x10, implicit $x11 +entry: + ret [2 x i32] [i32 1, i32 2] +}