Index: include/llvm/ADT/Triple.h =================================================================== --- include/llvm/ADT/Triple.h +++ include/llvm/ADT/Triple.h @@ -174,7 +174,8 @@ Cygnus, AMDOpenCL, CoreCLR, - LastEnvironmentType = CoreCLR + ELFIAMCU, + LastEnvironmentType = ELFIAMCU }; enum ObjectFormatType { UnknownObjectFormat, @@ -431,6 +432,10 @@ return getOS() == Triple::Bitrig; } + bool isEnvironmentIAMCU() const { + return getEnvironment() == Triple::ELFIAMCU; + } + bool isWindowsMSVCEnvironment() const { return getOS() == Triple::Win32 && (getEnvironment() == Triple::UnknownEnvironment || Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -2435,6 +2435,13 @@ }; + // Mark inreg arguments for lib-calls. For normal calls this is done by + // the frontend ABI code. + virtual void markInRegArguments(SelectionDAG &DAG, + TargetLowering::ArgListTy &Args) const { + return; + } + /// This function lowers an abstract call to a function into an actual call. /// This returns a pair of operands. The first element is the return value /// for the function (if RetTy is not VoidTy). The second element is the Index: lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -100,6 +100,9 @@ Entry.isZExt = !shouldSignExtendTypeInLibCall(Ops[i].getValueType(), isSigned); Args.push_back(Entry); } + + markInRegArguments(DAG, Args); + if (LC == RTLIB::UNKNOWN_LIBCALL) report_fatal_error("Unsupported library call operation!"); SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC), Index: lib/Support/Triple.cpp =================================================================== --- lib/Support/Triple.cpp +++ lib/Support/Triple.cpp @@ -202,6 +202,7 @@ case Cygnus: return "cygnus"; case AMDOpenCL: return "amdopencl"; case CoreCLR: return "coreclr"; + case ELFIAMCU: return "elfiamcu"; } llvm_unreachable("Invalid EnvironmentType!"); @@ -453,6 +454,7 @@ .StartsWith("cygnus", Triple::Cygnus) .StartsWith("amdopencl", Triple::AMDOpenCL) .StartsWith("coreclr", Triple::CoreCLR) + .StartsWith("elfiamcu", Triple::ELFIAMCU) .Default(Triple::UnknownEnvironment); } Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -917,6 +917,9 @@ bool isIntDivCheap(EVT VT, AttributeSet Attr) const override; + void markInRegArguments(SelectionDAG &DAG, TargetLowering::ArgListTy& Args) + const override; + protected: std::pair findRepresentativeClass(const TargetRegisterInfo *TRI, Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -27508,3 +27508,27 @@ Attribute::MinSize); return OptSize && !VT.isVector(); } + +void X86TargetLowering::markInRegArguments(SelectionDAG &DAG, + TargetLowering::ArgListTy& Args) const { + // The MCU psABI requires some arguments to be passed in-register. + // For regular calls, the inreg arguments are marked by the front-end. + // However, for compiler generated library calls, we have to patch this + // up here. + if (!Subtarget->isTargetMCU() || !Args.size()) + return; + + unsigned FreeRegs = 3; + for (auto &Arg : Args) { + // For library functions, we do not expect any fancy types. + unsigned Size = DAG.getDataLayout().getTypeSizeInBits(Arg.Ty); + unsigned SizeInRegs = (Size + 31) / 32; + if (SizeInRegs > 2 || SizeInRegs > FreeRegs) + continue; + + Arg.isInReg = true; + FreeRegs -= SizeInRegs; + if (!FreeRegs) + break; + } +} Index: lib/Target/X86/X86Subtarget.h =================================================================== --- lib/Target/X86/X86Subtarget.h +++ lib/Target/X86/X86Subtarget.h @@ -418,6 +418,7 @@ bool isTargetNaCl() const { return TargetTriple.isOSNaCl(); } bool isTargetNaCl32() const { return isTargetNaCl() && !is64Bit(); } bool isTargetNaCl64() const { return isTargetNaCl() && is64Bit(); } + bool isTargetMCU() const { return TargetTriple.isEnvironmentIAMCU(); } bool isTargetWindowsMSVC() const { return TargetTriple.isWindowsMSVCEnvironment(); Index: test/CodeGen/X86/mcu-abi.ll =================================================================== --- test/CodeGen/X86/mcu-abi.ll +++ test/CodeGen/X86/mcu-abi.ll @@ -0,0 +1,11 @@ +; RUN: llc < %s -mtriple=i686-pc-linux-elfiamcu | FileCheck %s + +; CHECK-LABEL: test_lib_args: +; CHECK: movl %edx, %eax +; CHECK: calll __fixsfsi +define i32 @test_lib_args(float inreg %a, float inreg %b) #0 { + %ret = fptosi float %b to i32 + ret i32 %ret +} + +attributes #0 = { nounwind "use-soft-float"="true"} Index: unittests/ADT/TripleTest.cpp =================================================================== --- unittests/ADT/TripleTest.cpp +++ unittests/ADT/TripleTest.cpp @@ -81,6 +81,12 @@ EXPECT_EQ(Triple::Darwin, T.getOS()); EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + T = Triple("i386-pc-linux-elfiamcu"); + EXPECT_EQ(Triple::x86, T.getArch()); + EXPECT_EQ(Triple::PC, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::ELFIAMCU, T.getEnvironment()); + T = Triple("x86_64-pc-linux-gnu"); EXPECT_EQ(Triple::x86_64, T.getArch()); EXPECT_EQ(Triple::PC, T.getVendor());