Index: cfe/trunk/lib/CodeGen/TargetInfo.cpp =================================================================== --- cfe/trunk/lib/CodeGen/TargetInfo.cpp +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp @@ -841,7 +841,13 @@ Class classify(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const; ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; - bool shouldUseInReg(QualType Ty, CCState &State, bool &NeedsPadding) const; + /// \brief Updates the number of available free registers, returns + /// true if any registers were allocated. + bool updateFreeRegs(QualType Ty, CCState &State) const; + + bool shouldAggregateUseDirect(QualType Ty, CCState &State, bool &InReg, + bool &NeedsPadding) const; + bool shouldPrimitiveUseInReg(QualType Ty, CCState &State) const; /// \brief Rewrite the function info so that all memory arguments use /// inalloca. @@ -1003,9 +1009,10 @@ ASTContext &Context) const { uint64_t Size = Context.getTypeSize(Ty); - // Type must be register sized. - if (!isRegisterSize(Size)) - return false; + // For i386, type must be register sized. + // For the MCU ABI, it only needs to be <= 8-byte + if ((IsMCUABI && Size > 64) || (!IsMCUABI && !isRegisterSize(Size))) + return false; if (Ty->isVectorType()) { // 64- and 128- bit vectors inside structures are not returned in @@ -1052,7 +1059,8 @@ // integer register. if (State.FreeRegs) { --State.FreeRegs; - return getNaturalAlignIndirectInReg(RetTy); + if (!IsMCUABI) + return getNaturalAlignIndirectInReg(RetTy); } return getNaturalAlignIndirect(RetTy, /*ByVal=*/false); } @@ -1192,7 +1200,8 @@ if (!ByVal) { if (State.FreeRegs) { --State.FreeRegs; // Non-byval indirects just use one pointer. - return getNaturalAlignIndirectInReg(Ty); + if (!IsMCUABI) + return getNaturalAlignIndirectInReg(Ty); } return getNaturalAlignIndirect(Ty, false); } @@ -1223,9 +1232,7 @@ return Integer; } -bool X86_32ABIInfo::shouldUseInReg(QualType Ty, CCState &State, - bool &NeedsPadding) const { - NeedsPadding = false; +bool X86_32ABIInfo::updateFreeRegs(QualType Ty, CCState &State) const { if (!IsSoftFloatABI) { Class C = classify(Ty); if (C == Float) @@ -1253,25 +1260,46 @@ } State.FreeRegs -= SizeInRegs; + return true; +} + +bool X86_32ABIInfo::shouldAggregateUseDirect(QualType Ty, CCState &State, + bool &InReg, + bool &NeedsPadding) const { + NeedsPadding = false; + InReg = !IsMCUABI; + + if (!updateFreeRegs(Ty, State)) + return false; + + if (IsMCUABI) + return true; if (State.CC == llvm::CallingConv::X86_FastCall || State.CC == llvm::CallingConv::X86_VectorCall) { - if (Size > 32) - return false; - - if (Ty->isIntegralOrEnumerationType()) - return true; + if (getContext().getTypeSize(Ty) <= 32 && State.FreeRegs) + NeedsPadding = true; - if (Ty->isPointerType()) - return true; + return false; + } - if (Ty->isReferenceType()) - return true; + return true; +} - if (State.FreeRegs) - NeedsPadding = true; +bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const { + if (!updateFreeRegs(Ty, State)) + return false; + if (IsMCUABI) return false; + + if (State.CC == llvm::CallingConv::X86_FastCall || + State.CC == llvm::CallingConv::X86_VectorCall) { + if (getContext().getTypeSize(Ty) > 32) + return false; + + return (Ty->isIntegralOrEnumerationType() || Ty->isPointerType() || + Ty->isReferenceType()); } return true; @@ -1327,12 +1355,15 @@ llvm::LLVMContext &LLVMContext = getVMContext(); llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); - bool NeedsPadding; - if (shouldUseInReg(Ty, State, NeedsPadding)) { + bool NeedsPadding, InReg; + if (shouldAggregateUseDirect(Ty, State, InReg, NeedsPadding)) { unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; SmallVector Elements(SizeInRegs, Int32); llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); - return ABIArgInfo::getDirectInReg(Result); + if (InReg) + return ABIArgInfo::getDirectInReg(Result); + else + return ABIArgInfo::getDirect(Result); } llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : nullptr; @@ -1340,8 +1371,11 @@ // of those arguments will match the struct. This is important because the // LLVM backend isn't smart enough to remove byval, which inhibits many // optimizations. + // Don't do this for the MCU if there are still free integer registers + // (see X86_64 ABI for full explanation). if (getContext().getTypeSize(Ty) <= 4*32 && - canExpandIndirectArgument(Ty, getContext())) + canExpandIndirectArgument(Ty, getContext()) && + (!IsMCUABI || State.FreeRegs == 0)) return ABIArgInfo::getExpandWithPadding( State.CC == llvm::CallingConv::X86_FastCall || State.CC == llvm::CallingConv::X86_VectorCall, @@ -1371,14 +1405,14 @@ if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); - bool NeedsPadding; - bool InReg = shouldUseInReg(Ty, State, NeedsPadding); + bool InReg = shouldPrimitiveUseInReg(Ty, State); if (Ty->isPromotableIntegerType()) { if (InReg) return ABIArgInfo::getExtendInReg(); return ABIArgInfo::getExtend(); } + if (InReg) return ABIArgInfo::getDirectInReg(); return ABIArgInfo::getDirect(); @@ -1386,15 +1420,15 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { CCState State(FI.getCallingConvention()); - if (State.CC == llvm::CallingConv::X86_FastCall) + if (IsMCUABI) + State.FreeRegs = 3; + else if (State.CC == llvm::CallingConv::X86_FastCall) State.FreeRegs = 2; else if (State.CC == llvm::CallingConv::X86_VectorCall) { State.FreeRegs = 2; State.FreeSSERegs = 6; } else if (FI.getHasRegParm()) State.FreeRegs = FI.getRegParm(); - else if (IsMCUABI) - State.FreeRegs = 3; else State.FreeRegs = DefaultNumRegisterParameters; @@ -1405,7 +1439,8 @@ // return value was sret and put it in a register ourselves if appropriate. if (State.FreeRegs) { --State.FreeRegs; // The sret parameter consumes a register. - FI.getReturnInfo().setInReg(true); + if (!IsMCUABI) + FI.getReturnInfo().setInReg(true); } } Index: cfe/trunk/test/CodeGen/x86_32-arguments-iamcu.c =================================================================== --- cfe/trunk/test/CodeGen/x86_32-arguments-iamcu.c +++ cfe/trunk/test/CodeGen/x86_32-arguments-iamcu.c @@ -1,20 +1,24 @@ // RUN: %clang_cc1 -w -triple i386-pc-elfiamcu -mfloat-abi soft -emit-llvm -o - %s | FileCheck %s -// CHECK-LABEL: define void @ints(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 %d) +// CHECK-LABEL: define void @ints(i32 %a, i32 %b, i32 %c, i32 %d) void ints(int a, int b, int c, int d) {} -// CHECK-LABEL: define void @floats(float inreg %a, float inreg %b, float inreg %c, float %d) +// CHECK-LABEL: define void @floats(float %a, float %b, float %c, float %d) void floats(float a, float b, float c, float d) {} -// CHECK-LABEL: define void @mixed(i32 inreg %a, float inreg %b, i32 inreg %c, float %d) +// CHECK-LABEL: define void @mixed(i32 %a, float %b, i32 %c, float %d) void mixed(int a, float b, int c, float d) {} -// CHECK-LABEL: define void @doubles(double inreg %d1, double %d2) +// CHECK-LABEL: define void @doubles(double %d1, double %d2) void doubles(double d1, double d2) {} -// CHECK-LABEL: define void @mixedDoubles(i32 inreg %a, double inreg %d1) +// CHECK-LABEL: define void @mixedDoubles(i32 %a, double %d1) void mixedDoubles(int a, double d1) {} +typedef struct st3_t { + char a[3]; +} st3_t; + typedef struct st4_t { int a; } st4_t; @@ -30,33 +34,36 @@ int c; } st12_t; -// CHECK-LABEL: define void @smallStructs(i32 inreg %st1.coerce, i32 inreg %st2.coerce, i32 inreg %st3.coerce) +// CHECK-LABEL: define void @smallStructs(i32 %st1.coerce, i32 %st2.coerce, i32 %st3.coerce) void smallStructs(st4_t st1, st4_t st2, st4_t st3) {} -// CHECK-LABEL: define void @paddedStruct(i32 inreg %i1, i32 inreg %st.coerce0, i32 inreg %st.coerce1, i32 %st4.0) +// CHECK-LABEL: define void @paddedStruct(i32 %i1, i32 %st.coerce0, i32 %st.coerce1, i32 %st4.0) void paddedStruct(int i1, st5_t st, st4_t st4) {} -// CHECK-LABEL: define void @largeStruct(i32 %st.0, i32 %st.1, i32 %st.2) -void largeStruct(st12_t st) {} +// CHECK-LABEL: define void @largeStructBegin(%struct.st12_t* byval align 4 %st) +void largeStructBegin(st12_t st) {} -// CHECK-LABEL: define void @largeStructMiddle(i32 inreg %i1, i32 %st.0, i32 %st.1, i32 %st.2, i32 inreg %i2, i32 inreg %i3) +// CHECK-LABEL: define void @largeStructMiddle(i32 %i1, %struct.st12_t* byval align 4 %st, i32 %i2, i32 %i3) void largeStructMiddle(int i1, st12_t st, int i2, int i3) {} -// CHECK-LABEL: define i32 @retSmallStruct(i32 inreg %r.coerce) +// CHECK-LABEL: define void @largeStructEnd(i32 %i1, i32 %i2, i32 %i3, i32 %st.0, i32 %st.1, i32 %st.2) +void largeStructEnd(int i1, int i2, int i3, st12_t st) {} + +// CHECK-LABEL: define i24 @retNonPow2Struct(i32 %r.coerce) +st3_t retNonPow2Struct(st3_t r) { return r; } + +// CHECK-LABEL: define i32 @retSmallStruct(i32 %r.coerce) st4_t retSmallStruct(st4_t r) { return r; } -// CHECK-LABEL: define i64 @retPaddedStruct(i32 inreg %r.coerce0, i32 inreg %r.coerce1) +// CHECK-LABEL: define i64 @retPaddedStruct(i32 %r.coerce0, i32 %r.coerce1) st5_t retPaddedStruct(st5_t r) { return r; } -// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* inreg noalias sret %agg.result, i32 inreg %i1, i32 %r.0, i32 %r.1, i32 %r.2) +// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* noalias sret %agg.result, i32 %i1, %struct.st12_t* byval align 4 %r) st12_t retLargeStruct(int i1, st12_t r) { return r; } -// FIXME: We really shouldn't be marking this inreg. Right now the -// inreg gets ignored by the CG for varargs functions, but that's -// insane. -// CHECK-LABEL: define i32 @varArgs(i32 inreg %i1, ...) +// CHECK-LABEL: define i32 @varArgs(i32 %i1, ...) int varArgs(int i1, ...) { return i1; } -// CHECK-LABEL: define double @longDoubleArg(double inreg %ld1) +// CHECK-LABEL: define double @longDoubleArg(double %ld1) long double longDoubleArg(long double ld1) { return ld1; }