Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/Sparc.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ class LLVM_LIBRARY_VISIBILITY SparcV8TargetInfo : public SparcTargetInfo {
PtrDiffType = SignedLong;
break;
}

// The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit
// aligned.
LongDoubleWidth = 128;
LongDoubleAlign = 64;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably also need to fix the datalayout

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It already has the f128:64 part, so I think I'm good here?

LongDoubleFormat = &llvm::APFloat::IEEEquad();

// Up to 32 bits (V8) or 64 bits (V9) are lock-free atomic, but we're
// willing to do atomic ops on up to 64 bits.
MaxAtomicPromoteWidth = 64;
Expand Down
23 changes: 16 additions & 7 deletions clang/lib/CodeGen/Targets/Sparc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,32 @@ class SparcV8ABIInfo : public DefaultABIInfo {

private:
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType Ty) const;
void computeInfo(CGFunctionInfo &FI) const override;
};
} // end anonymous namespace

ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
if (const auto *BT = Ty->getAs<BuiltinType>();
BT && BT->getKind() == BuiltinType::LongDouble)
return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());

ABIArgInfo
SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
if (Ty->isAnyComplexType()) {
return ABIArgInfo::getDirect();
}
else {
return DefaultABIInfo::classifyReturnType(Ty);
return ABIArgInfo::getDirectInReg();
}

return DefaultABIInfo::classifyReturnType(Ty);
}

void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const {
ABIArgInfo SparcV8ABIInfo::classifyArgumentType(QualType Ty) const {
if (const auto *BT = Ty->getAs<BuiltinType>();
BT && BT->getKind() == BuiltinType::LongDouble)
return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());

return DefaultABIInfo::classifyArgumentType(Ty);
}

void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (auto &Arg : FI.arguments())
Arg.info = classifyArgumentType(Arg.type);
Expand Down
14 changes: 14 additions & 0 deletions clang/test/CodeGen/Sparc/sparcv8-abi.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,17 @@ r (long long __complex__ a, long long __complex__ b)
{
return 0;
}

// CHECK-LABEL: define{{.*}} void @s(ptr dead_on_unwind noalias writable sret(fp128) align 8 %agg.result, ptr noundef byval(fp128) align 8 %0) #0
long double
s(long double a)
{
return 0;
}

// CHECK-LABEL: define{{.*}}inreg{{.*}} { fp128, fp128 } @t(ptr noundef byval({ fp128, fp128 }) align 8 %a) #0
long double _Complex
t(long double _Complex a)
{
return 0;
}
22 changes: 11 additions & 11 deletions clang/test/Preprocessor/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1106,19 +1106,19 @@
// SPARC:#define __INT_LEAST8_MAX__ 127
// SPARC:#define __INT_LEAST8_TYPE__ signed char
// SPARC:#define __INT_MAX__ 2147483647
// SPARC:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
// SPARC:#define __LDBL_DIG__ 15
// SPARC:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
// SPARC:#define __LDBL_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966L
// SPARC:#define __LDBL_DIG__ 33
// SPARC:#define __LDBL_EPSILON__ 1.92592994438723585305597794258492732e-34L
// SPARC:#define __LDBL_HAS_DENORM__ 1
// SPARC:#define __LDBL_HAS_INFINITY__ 1
// SPARC:#define __LDBL_HAS_QUIET_NAN__ 1
// SPARC:#define __LDBL_MANT_DIG__ 53
// SPARC:#define __LDBL_MAX_10_EXP__ 308
// SPARC:#define __LDBL_MAX_EXP__ 1024
// SPARC:#define __LDBL_MAX__ 1.7976931348623157e+308L
// SPARC:#define __LDBL_MIN_10_EXP__ (-307)
// SPARC:#define __LDBL_MIN_EXP__ (-1021)
// SPARC:#define __LDBL_MIN__ 2.2250738585072014e-308L
// SPARC:#define __LDBL_MANT_DIG__ 113
// SPARC:#define __LDBL_MAX_10_EXP__ 4932
// SPARC:#define __LDBL_MAX_EXP__ 16384
// SPARC:#define __LDBL_MAX__ 1.18973149535723176508575932662800702e+4932L
// SPARC:#define __LDBL_MIN_10_EXP__ (-4931)
// SPARC:#define __LDBL_MIN_EXP__ (-16381)
// SPARC:#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L
// SPARC:#define __LONG_LONG_MAX__ 9223372036854775807LL
// SPARC:#define __LONG_MAX__ 2147483647L
// SPARC-NOT:#define __LP64__
Expand All @@ -1134,7 +1134,7 @@
// SPARC:#define __SIZEOF_DOUBLE__ 8
// SPARC:#define __SIZEOF_FLOAT__ 4
// SPARC:#define __SIZEOF_INT__ 4
// SPARC:#define __SIZEOF_LONG_DOUBLE__ 8
// SPARC:#define __SIZEOF_LONG_DOUBLE__ 16
// SPARC:#define __SIZEOF_LONG_LONG__ 8
// SPARC:#define __SIZEOF_LONG__ 4
// SPARC:#define __SIZEOF_POINTER__ 4
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/builtins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1009,9 +1009,9 @@ else ()
list(APPEND BUILTIN_CFLAGS_${arch} -fomit-frame-pointer -DCOMPILER_RT_ARMHF_TARGET)
endif()

# For RISCV32, we must force enable int128 for compiling long
# For RISCV32 and 32-bit SPARC, we must force enable int128 for compiling long
# double routines.
if(COMPILER_RT_ENABLE_SOFTWARE_INT128 OR "${arch}" STREQUAL "riscv32")
if(COMPILER_RT_ENABLE_SOFTWARE_INT128 OR "${arch}" STREQUAL "riscv32" OR ("${arch}" STREQUAL "sparc" AND NOT CMAKE_COMPILER_IS_GNUCC))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for going back and forth, I suppose -fforce-enable-in128 isn't supported by riscv-gcc either, so it should be the same as in the file below.


When compiled with gcc, how is the library supposed to link if int128 routines are not compiled in?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When compiled with gcc, how is the library supposed to link if int128 routines are not compiled in?

I suppose in that case the library will lack long double routines? @rorth probably know better about this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When compiled with gcc, how is the library supposed to link if int128 routines are not compiled in?

I suppose in that case the library will lack long double routines? @rorth probably know better about this.

I've no idea right now (have tried to forget all of this ;-). Besides, I'm so busy with the upcoming GCC 16 release that I've no time left for LLVM.

What I've done in the past is do build with both clang and gcc as build compiler, 2-stage builds with clang, 1-stage ones with gcc. And note that the compiler-rt tests still aren't run in runtime builds (which is the default these days), not even a target to do so manually, so I've always used

 -DLLVM_ENABLE_PROJECTS=compiler-rt

to avoid that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the hint! I tried running it and seems like I found some other long double related failures:

SanitizerCommon-asan-sparc-Linux :: printf-ldbl.c
SanitizerCommon-asan-sparc-Linux :: scanf-ldbl.c
SanitizerCommon-ubsan-sparc-Linux :: printf-ldbl.c                                                                                                                                                                                                                            
SanitizerCommon-ubsan-sparc-Linux :: scanf-ldbl.c

Because clang lowers the printf/scanf calls into something like __nldbl_snprintf and __nldbl___isoc99_sscanf...
Seems like I missed defining __LONG_DOUBLE_128__, lemme fix this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay seems like after __LONG_DOUBLE_128__ is added the issue is gone.

list(APPEND BUILTIN_CFLAGS_${arch} -fforce-enable-int128)
endif()

Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/builtins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ foreach(arch ${BUILTIN_TEST_ARCH})
string(REPLACE ";" " " BUILTINS_TEST_TARGET_CFLAGS "${BUILTINS_TEST_TARGET_CFLAGS}")
endif()

if (COMPILER_RT_ENABLE_SOFTWARE_INT128 OR ${arch} STREQUAL "riscv32")
if (COMPILER_RT_ENABLE_SOFTWARE_INT128 OR "${arch}" MATCHES "riscv32|sparc$" AND NOT CMAKE_COMPILER_IS_GNUCC)
list(APPEND BUILTINS_TEST_TARGET_CFLAGS -fforce-enable-int128)
string(REPLACE ";" " " BUILTINS_TEST_TARGET_CFLAGS "${BUILTINS_TEST_TARGET_CFLAGS}")
endif()
Expand Down
3 changes: 0 additions & 3 deletions compiler-rt/test/sanitizer_common/TestCases/printf-ldbl.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// RUN: %clang %s -o %t && %run %t 2>&1

// Issue #41838
// XFAIL: sparc-target-arch && target={{.*solaris.*}}

#include <assert.h>
#include <stdio.h>
#include <string.h>
Expand Down
3 changes: 0 additions & 3 deletions compiler-rt/test/sanitizer_common/TestCases/scanf-ldbl.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// RUN: %clang %s -o %t && %run %t 2>&1

// Issue #41838
// XFAIL: sparc-target-arch && target={{.*solaris.*}}

#include <assert.h>
#include <stdio.h>
#include <string.h>
Expand Down
3 changes: 0 additions & 3 deletions compiler-rt/test/ubsan/TestCases/Float/cast-overflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
// RUN: %run %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6
// RUN: %run %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7

// Issue #41838
// XFAIL: sparc-target-arch && target={{.*solaris.*}}

// This test assumes float and double are IEEE-754 single- and double-precision.

#if defined(__APPLE__)
Expand Down
3 changes: 0 additions & 3 deletions compiler-rt/test/ubsan/TestCases/Misc/log-path_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
// FIXME: log_path is not supported on Windows yet.
// XFAIL: target={{.*windows-msvc.*}}

// Issue #41838
// XFAIL: sparc-target-arch && target={{.*solaris.*}}

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Target/Sparc/SparcCallingConv.td
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def CC_Sparc32 : CallingConv<[
// As are v2i32 arguments (this would be the default behavior for
// v2i32 if it wasn't allocated to the IntPair register-class)
CCIfType<[v2i32], CCCustom<"CC_Sparc_Assign_Split_64">>,


// f128 arguments are passed indirectly.
CCIfType<[f128], CCPassIndirect<i32>>,
// Alternatively, they are assigned to the stack in 4-byte aligned units.
CCAssignToStack<4, 4>
]>;
Expand All @@ -34,6 +34,7 @@ def RetCC_Sparc32 : CallingConv<[
CCIfType<[i32], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>,
CCIfType<[f32], CCAssignToReg<[F0, F1, F2, F3]>>,
CCIfType<[f64], CCAssignToReg<[D0, D1]>>,
CCIfType<[f128], CCCustom<"CC_Sparc_Assign_Ret_F128">>,
CCIfType<[v2i32], CCCustom<"CC_Sparc_Assign_Ret_Split_64">>
]>;

Expand Down
110 changes: 98 additions & 12 deletions llvm/lib/Target/Sparc/SparcISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,23 @@ static bool CC_Sparc_Assign_Ret_Split_64(unsigned &ValNo, MVT &ValVT,
return true;
}

static bool CC_Sparc_Assign_Ret_F128(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
CCValAssign::LocInfo &LocInfo,
ISD::ArgFlagsTy &ArgFlags,
CCState &State) {
static const MCPhysReg RegList[] = {SP::Q0, SP::Q1};

if (!ArgFlags.isInReg())
return false;

if (Register Reg = State.AllocateReg(RegList))
State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
else
return false;

return true;
}

// Allocate a full-sized argument for the 64-bit ABI.
static bool Analyze_CC_Sparc64_Full(bool IsReturn, unsigned &ValNo, MVT &ValVT,
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
Expand Down Expand Up @@ -289,8 +306,7 @@ SparcTargetLowering::LowerReturn_32(SDValue Chain, CallingConv::ID CallConv,

SDValue Arg = OutVals[realRVLocIdx];

if (VA.needsCustom()) {
assert(VA.getLocVT() == MVT::v2i32);
if (VA.needsCustom() && VA.getLocVT() == MVT::v2i32) {
// Legalize ret v2i32 -> ret 2 x i32 (Basically: do what would
// happen by default if this wasn't a legal type)

Expand Down Expand Up @@ -555,20 +571,42 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
continue;
}

int FI = MF.getFrameInfo().CreateFixedObject(4,
Offset,
true);
SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
SDValue Load ;
if (VA.getLocInfo() == CCValAssign::Indirect) {
EVT LocVT = VA.getLocVT();
int FI = MF.getFrameInfo().CreateFixedObject(
LocVT.getFixedSizeInBits() / 8, Offset, true);
SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
SDValue ArgValue = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr,
MachinePointerInfo::getFixedStack(MF, FI));
InVals.push_back(ArgValue);

unsigned ArgIndex = Ins[InIdx].OrigArgIndex;
unsigned ArgPartOffset = Ins[InIdx].PartOffset;
assert(ArgPartOffset == 0);
while (i + 1 != e && Ins[InIdx + 1].OrigArgIndex == ArgIndex) {
CCValAssign &PartVA = ArgLocs[i + 1];
unsigned PartOffset = Ins[InIdx + 1].PartOffset - ArgPartOffset;
SDValue Offset = DAG.getIntPtrConstant(PartOffset, dl);
SDValue Address = DAG.getNode(ISD::ADD, dl, PtrVT, ArgValue, Offset);
InVals.push_back(DAG.getLoad(PartVA.getValVT(), dl, Chain, Address,
MachinePointerInfo()));
++i;
++InIdx;
}
continue;
}

int FI;
if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) {
Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo());
} else if (VA.getValVT() == MVT::f128) {
report_fatal_error("SPARCv8 does not handle f128 in calls; "
"pass indirectly");
FI = MF.getFrameInfo().CreateFixedObject(4, Offset, true);
} else {
// We shouldn't see any other value types here.
llvm_unreachable("Unexpected ValVT encountered in frame lowering.");
}

SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
SDValue Load =
DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo());
InVals.push_back(Load);
}

Expand Down Expand Up @@ -836,6 +874,8 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
CallingConv::ID CallConv = CLI.CallConv;
bool isVarArg = CLI.IsVarArg;
MachineFunction &MF = DAG.getMachineFunction();
LLVMContext &Ctx = *DAG.getContext();
EVT PtrVT = getPointerTy(MF.getDataLayout());

// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
Expand Down Expand Up @@ -914,7 +954,9 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
// Promote the value if needed.
switch (VA.getLocInfo()) {
default: llvm_unreachable("Unknown loc info!");
case CCValAssign::Full: break;
case CCValAssign::Full:
case CCValAssign::Indirect:
break;
case CCValAssign::SExt:
Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
break;
Expand Down Expand Up @@ -1027,6 +1069,50 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,

assert(VA.isMemLoc());

if (VA.getLocInfo() == CCValAssign::Indirect) {
// Store the argument in a stack slot and pass its address.
unsigned ArgIndex = Outs[realArgIdx].OrigArgIndex;
unsigned ArgPartOffset = Outs[realArgIdx].PartOffset;
assert(ArgPartOffset == 0);

EVT SlotVT;
if (i + 1 != e && Outs[realArgIdx + 1].OrigArgIndex == ArgIndex) {
Type *OrigArgType = CLI.Args[ArgIndex].Ty;
EVT OrigArgVT = getValueType(MF.getDataLayout(), OrigArgType);
MVT PartVT =
getRegisterTypeForCallingConv(Ctx, CLI.CallConv, OrigArgVT);
unsigned N =
getNumRegistersForCallingConv(Ctx, CLI.CallConv, OrigArgVT);
SlotVT = EVT::getIntegerVT(Ctx, PartVT.getSizeInBits() * N);
} else {
SlotVT = Outs[realArgIdx].VT;
}

SDValue SpillSlot = DAG.CreateStackTemporary(SlotVT);
int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
MemOpChains.push_back(
DAG.getStore(Chain, dl, Arg, SpillSlot,
MachinePointerInfo::getFixedStack(MF, FI)));
// If the original argument was split (e.g. i128), we need
// to store all parts of it here (and pass just one address).
while (i + 1 != e && Outs[realArgIdx + 1].OrigArgIndex == ArgIndex) {
SDValue PartValue = OutVals[realArgIdx + 1];
unsigned PartOffset = Outs[realArgIdx + 1].PartOffset;
SDValue Address = DAG.getNode(ISD::ADD, dl, PtrVT, SpillSlot,
DAG.getIntPtrConstant(PartOffset, dl));
MemOpChains.push_back(
DAG.getStore(Chain, dl, PartValue, Address,
MachinePointerInfo::getFixedStack(MF, FI)));
assert((PartOffset + PartValue.getValueType().getStoreSize() <=
SlotVT.getStoreSize()) &&
"Not enough space for argument part!");
++i;
++realArgIdx;
}

Arg = SpillSlot;
}

// Create a store off the stack pointer for this argument.
SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset() + StackOffset,
Expand Down
30 changes: 30 additions & 0 deletions llvm/test/CodeGen/SPARC/fp128.ll
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,33 @@ entry:
store fp128 %1, ptr %scalar.result, align 8
ret void
}

define fp128 @f128_direct(fp128 %num) nounwind {
; CHECK-LABEL: f128_direct:
; CHECK: ! %bb.0:
; CHECK-NEXT: save %sp, -152, %sp
; CHECK-NEXT: ldd [%fp+92], %f0
; CHECK-NEXT: ldd [%fp+100], %f4
; CHECK-NEXT: ld [%fp+64], %i0
; CHECK-NEXT: add %fp, -48, %i1
; CHECK-NEXT: st %i1, [%sp+96]
; CHECK-NEXT: add %fp, -32, %i1
; CHECK-NEXT: st %i1, [%sp+92]
; CHECK-NEXT: add %fp, -16, %i1
; CHECK-NEXT: st %i1, [%sp+64]
; CHECK-NEXT: std %f4, [%fp+-40]
; CHECK-NEXT: std %f0, [%fp+-48]
; CHECK-NEXT: std %f4, [%fp+-24]
; CHECK-NEXT: call f128_callee
; CHECK-NEXT: std %f0, [%fp+-32]
; CHECK-NEXT: unimp 16
; CHECK-NEXT: ldd [%fp+-8], %f0
; CHECK-NEXT: ldd [%fp+-16], %f4
; CHECK-NEXT: std %f0, [%i0+8]
; CHECK-NEXT: std %f4, [%i0]
; CHECK-NEXT: ret
; CHECK-NEXT: restore
%ret = call fp128 @f128_callee(fp128 %num, fp128 %num)
ret fp128 %ret
}
declare fp128 @f128_callee(fp128 %a, fp128 %b)
Loading