This revision was automatically updated to reflect the committed changes. Closed by commit rG3d6c492d7a98: [RISCV] Fix ILP32D lowering for double+double/double+int return types (authored by jrtc27).
Changed prior to commit: https://reviews.llvm.org/D69590?vs=226981&id=237912#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D69590/new/ https://reviews.llvm.org/D69590 Files: clang/lib/CodeGen/TargetInfo.cpp clang/test/CodeGen/riscv32-ilp32d-abi.c Index: clang/test/CodeGen/riscv32-ilp32d-abi.c =================================================================== --- clang/test/CodeGen/riscv32-ilp32d-abi.c +++ clang/test/CodeGen/riscv32-ilp32d-abi.c @@ -280,3 +280,27 @@ union double_u f_ret_double_u() { return (union double_u){1.0}; } + +// Test that we don't incorrectly think double+int/double+double structs will +// be returned indirectly and thus have an off-by-one error for the number of +// GPRs available (this is an edge case when structs > 2*XLEN are still +// returned in registers). This includes complex doubles, which are treated as +// double+double structs by the ABI. + +// CHECK: define { double, i32 } @f_ret_double_int32_s_double_int32_s_just_sufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, double %0, i32 %1) +struct double_int32_s f_ret_double_int32_s_double_int32_s_just_sufficient_gprs( + int a, int b, int c, int d, int e, int f, int g, struct double_int32_s h) { + return (struct double_int32_s){1.0, 2}; +} + +// CHECK: define { double, double } @f_ret_double_double_s_double_int32_s_just_sufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, double %0, i32 %1) +struct double_double_s f_ret_double_double_s_double_int32_s_just_sufficient_gprs( + int a, int b, int c, int d, int e, int f, int g, struct double_int32_s h) { + return (struct double_double_s){1.0, 2.0}; +} + +// CHECK: define { double, double } @f_ret_doublecomplex_double_int32_s_just_sufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, double %0, i32 %1) +double __complex__ f_ret_doublecomplex_double_int32_s_just_sufficient_gprs( + int a, int b, int c, int d, int e, int f, int g, struct double_int32_s h) { + return 1.0; +} Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -9377,11 +9377,21 @@ FI.getReturnInfo() = classifyReturnType(RetTy); // IsRetIndirect is true if classifyArgumentType indicated the value should - // be passed indirect or if the type size is greater than 2*xlen. e.g. fp128 - // is passed direct in LLVM IR, relying on the backend lowering code to - // rewrite the argument list and pass indirectly on RV32. - bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect || - getContext().getTypeSize(RetTy) > (2 * XLen); + // be passed indirect, or if the type size is a scalar greater than 2*XLen + // and not a complex type with elements <= FLen. e.g. fp128 is passed direct + // in LLVM IR, relying on the backend lowering code to rewrite the argument + // list and pass indirectly on RV32. + bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect; + if (!IsRetIndirect && RetTy->isScalarType() && + getContext().getTypeSize(RetTy) > (2 * XLen)) { + if (RetTy->isComplexType() && FLen) { + QualType EltTy = RetTy->getAs<ComplexType>()->getElementType(); + IsRetIndirect = getContext().getTypeSize(EltTy) > FLen; + } else { + // This is a normal scalar > 2*XLen, such as fp128 on RV32. + IsRetIndirect = true; + } + } // We must track the number of GPRs used in order to conform to the RISC-V // ABI, as integer scalars passed in registers should have signext/zeroext
Index: clang/test/CodeGen/riscv32-ilp32d-abi.c =================================================================== --- clang/test/CodeGen/riscv32-ilp32d-abi.c +++ clang/test/CodeGen/riscv32-ilp32d-abi.c @@ -280,3 +280,27 @@ union double_u f_ret_double_u() { return (union double_u){1.0}; } + +// Test that we don't incorrectly think double+int/double+double structs will +// be returned indirectly and thus have an off-by-one error for the number of +// GPRs available (this is an edge case when structs > 2*XLEN are still +// returned in registers). This includes complex doubles, which are treated as +// double+double structs by the ABI. + +// CHECK: define { double, i32 } @f_ret_double_int32_s_double_int32_s_just_sufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, double %0, i32 %1) +struct double_int32_s f_ret_double_int32_s_double_int32_s_just_sufficient_gprs( + int a, int b, int c, int d, int e, int f, int g, struct double_int32_s h) { + return (struct double_int32_s){1.0, 2}; +} + +// CHECK: define { double, double } @f_ret_double_double_s_double_int32_s_just_sufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, double %0, i32 %1) +struct double_double_s f_ret_double_double_s_double_int32_s_just_sufficient_gprs( + int a, int b, int c, int d, int e, int f, int g, struct double_int32_s h) { + return (struct double_double_s){1.0, 2.0}; +} + +// CHECK: define { double, double } @f_ret_doublecomplex_double_int32_s_just_sufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, double %0, i32 %1) +double __complex__ f_ret_doublecomplex_double_int32_s_just_sufficient_gprs( + int a, int b, int c, int d, int e, int f, int g, struct double_int32_s h) { + return 1.0; +} Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -9377,11 +9377,21 @@ FI.getReturnInfo() = classifyReturnType(RetTy); // IsRetIndirect is true if classifyArgumentType indicated the value should - // be passed indirect or if the type size is greater than 2*xlen. e.g. fp128 - // is passed direct in LLVM IR, relying on the backend lowering code to - // rewrite the argument list and pass indirectly on RV32. - bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect || - getContext().getTypeSize(RetTy) > (2 * XLen); + // be passed indirect, or if the type size is a scalar greater than 2*XLen + // and not a complex type with elements <= FLen. e.g. fp128 is passed direct + // in LLVM IR, relying on the backend lowering code to rewrite the argument + // list and pass indirectly on RV32. + bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect; + if (!IsRetIndirect && RetTy->isScalarType() && + getContext().getTypeSize(RetTy) > (2 * XLen)) { + if (RetTy->isComplexType() && FLen) { + QualType EltTy = RetTy->getAs<ComplexType>()->getElementType(); + IsRetIndirect = getContext().getTypeSize(EltTy) > FLen; + } else { + // This is a normal scalar > 2*XLen, such as fp128 on RV32. + IsRetIndirect = true; + } + } // We must track the number of GPRs used in order to conform to the RISC-V // ABI, as integer scalars passed in registers should have signext/zeroext
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits