unsigned char AvailableArray[(NumLibFuncs+3)/4];
DenseMap<unsigned, std::string> CustomNames;
static StringLiteral const StandardNames[NumLibFuncs];
- bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param;
+ bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param, ShouldSignExtI32Return;
unsigned SizeOfInt;
enum AvailabilityState {
ShouldSignExtI32Param = Val;
}
+ /// Set to true iff i32 results from library functions should have signext
+ /// attribute if they correspond to C-level int or unsigned int.
+ void setShouldSignExtI32Return(bool Val) {
+ ShouldSignExtI32Return = Val;
+ }
+
/// Returns the size of the wchar_t type in bytes or 0 if the size is unknown.
/// This queries the 'wchar_size' metadata.
unsigned getWCharSize(const Module &M) const;
Attribute::AttrKind getExtAttrForI32Return(bool Signed = true) const {
if (Impl->ShouldExtI32Return)
return Signed ? Attribute::SExt : Attribute::ZExt;
+ if (Impl->ShouldSignExtI32Return)
+ return Attribute::SExt;
return Attribute::None;
}
TLI.setUnavailable(LibFunc_fgets_unlocked);
bool ShouldExtI32Param = false, ShouldExtI32Return = false,
- ShouldSignExtI32Param = false;
+ ShouldSignExtI32Param = false, ShouldSignExtI32Return = false;
// PowerPC64, Sparc64, SystemZ need signext/zeroext on i32 parameters and
// returns corresponding to C-level ints and unsigned ints.
if (T.isPPC64() || T.getArch() == Triple::sparcv9 ||
if (T.isMIPS() || T.isRISCV64()) {
ShouldSignExtI32Param = true;
}
+ // riscv64 needs signext on i32 returns corresponding to both signed and
+ // unsigned ints.
+ if (T.isRISCV64()) {
+ ShouldSignExtI32Return = true;
+ }
TLI.setShouldExtI32Param(ShouldExtI32Param);
TLI.setShouldExtI32Return(ShouldExtI32Return);
TLI.setShouldSignExtI32Param(ShouldSignExtI32Param);
+ TLI.setShouldSignExtI32Return(ShouldSignExtI32Return);
// Let's assume by default that the size of int is 32 bits, unless the target
// is a 16-bit architecture because then it most likely is 16 bits. If that
: CustomNames(TLI.CustomNames), ShouldExtI32Param(TLI.ShouldExtI32Param),
ShouldExtI32Return(TLI.ShouldExtI32Return),
ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
+ ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
SizeOfInt(TLI.SizeOfInt) {
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
VectorDescs = TLI.VectorDescs;
ShouldExtI32Param(TLI.ShouldExtI32Param),
ShouldExtI32Return(TLI.ShouldExtI32Return),
ShouldSignExtI32Param(TLI.ShouldSignExtI32Param),
+ ShouldSignExtI32Return(TLI.ShouldSignExtI32Return),
SizeOfInt(TLI.SizeOfInt) {
std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
AvailableArray);
ShouldExtI32Param = TLI.ShouldExtI32Param;
ShouldExtI32Return = TLI.ShouldExtI32Return;
ShouldSignExtI32Param = TLI.ShouldSignExtI32Param;
+ ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
SizeOfInt = TLI.SizeOfInt;
memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
return *this;
ShouldExtI32Param = TLI.ShouldExtI32Param;
ShouldExtI32Return = TLI.ShouldExtI32Return;
ShouldSignExtI32Param = TLI.ShouldSignExtI32Param;
+ ShouldSignExtI32Return = TLI.ShouldSignExtI32Return;
SizeOfInt = TLI.SizeOfInt;
std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
AvailableArray);
F.addParamAttr(ArgNo, ExtAttr);
}
+static void setRetExtAttr(Function &F,
+ const TargetLibraryInfo &TLI, bool Signed = true) {
+ Attribute::AttrKind ExtAttr = TLI.getExtAttrForI32Return(Signed);
+ if (ExtAttr != Attribute::None && !F.hasRetAttribute(ExtAttr))
+ F.addRetAttr(ExtAttr);
+}
+
// Modeled after X86TargetLowering::markLibCallAttributes.
static void markRegisterParameterAttributes(Function *F) {
if (!F->arg_size() || F->isVarArg())
// on any target: A size_t argument (which may be an i32 on some targets)
// should not trigger the assert below.
case LibFunc_bcmp:
+ setRetExtAttr(*F, TLI);
+ break;
case LibFunc_calloc:
case LibFunc_fwrite:
case LibFunc_malloc:
--- /dev/null
+; RUN: opt %s -passes=instcombine -mtriple=riscv64-unknown-linux-gnu -S | FileCheck %s
+
+declare signext i32 @memcmp(ptr, ptr, i64)
+
+; Make sure we use signext attribute for the bcmp result.
+define signext i32 @test_bcmp(ptr %mem1, ptr %mem2, i64 %size) {
+; CHECK-LABEL: define {{[^@]+}}@test_bcmp(
+; CHECK-NEXT: [[BCMP:%.*]] = call i32 @bcmp(ptr [[MEM1:%.*]], ptr [[MEM2:%.*]], i64 [[SIZE:%.*]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[BCMP]], 0
+; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT: ret i32 [[ZEXT]]
+;
+ %call = call signext i32 @memcmp(ptr %mem1, ptr %mem2, i64 %size)
+ %cmp = icmp eq i32 %call, 0
+ %zext = zext i1 %cmp to i32
+ ret i32 %zext
+}
+
+; CHECK: declare signext i32 @bcmp(ptr nocapture, ptr nocapture, i64)