Skip to content

Commit 9e31f0a

Browse files
committedJan 24, 2018
IRGen: Emit an inline implementation of __builtin_wmemcmp on MSVCRT platforms.
The MSVC runtime library does not provide a definition of wmemcmp, so we need an inline implementation. Differential Revision: https://reviews.llvm.org/D42441 llvm-svn: 323362
1 parent 123ce97 commit 9e31f0a

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed
 

‎clang/lib/CodeGen/CGBuiltin.cpp

+57
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,63 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
17411741
Builder.CreateMemSet(Dest, ByteVal, SizeVal, false);
17421742
return RValue::get(Dest.getPointer());
17431743
}
1744+
case Builtin::BI__builtin_wmemcmp: {
1745+
// The MSVC runtime library does not provide a definition of wmemcmp, so we
1746+
// need an inline implementation.
1747+
if (!getTarget().getTriple().isOSMSVCRT())
1748+
break;
1749+
1750+
llvm::Type *WCharTy = ConvertType(getContext().WCharTy);
1751+
1752+
Value *Dst = EmitScalarExpr(E->getArg(0));
1753+
Value *Src = EmitScalarExpr(E->getArg(1));
1754+
Value *Size = EmitScalarExpr(E->getArg(2));
1755+
1756+
BasicBlock *Entry = Builder.GetInsertBlock();
1757+
BasicBlock *CmpGT = createBasicBlock("wmemcmp.gt");
1758+
BasicBlock *CmpLT = createBasicBlock("wmemcmp.lt");
1759+
BasicBlock *Next = createBasicBlock("wmemcmp.next");
1760+
BasicBlock *Exit = createBasicBlock("wmemcmp.exit");
1761+
Value *SizeEq0 = Builder.CreateICmpEQ(Size, ConstantInt::get(SizeTy, 0));
1762+
Builder.CreateCondBr(SizeEq0, Exit, CmpGT);
1763+
1764+
EmitBlock(CmpGT);
1765+
PHINode *DstPhi = Builder.CreatePHI(Dst->getType(), 2);
1766+
DstPhi->addIncoming(Dst, Entry);
1767+
PHINode *SrcPhi = Builder.CreatePHI(Src->getType(), 2);
1768+
SrcPhi->addIncoming(Src, Entry);
1769+
PHINode *SizePhi = Builder.CreatePHI(SizeTy, 2);
1770+
SizePhi->addIncoming(Size, Entry);
1771+
CharUnits WCharAlign =
1772+
getContext().getTypeAlignInChars(getContext().WCharTy);
1773+
Value *DstCh = Builder.CreateAlignedLoad(WCharTy, DstPhi, WCharAlign);
1774+
Value *SrcCh = Builder.CreateAlignedLoad(WCharTy, SrcPhi, WCharAlign);
1775+
Value *DstGtSrc = Builder.CreateICmpUGT(DstCh, SrcCh);
1776+
Builder.CreateCondBr(DstGtSrc, Exit, CmpLT);
1777+
1778+
EmitBlock(CmpLT);
1779+
Value *DstLtSrc = Builder.CreateICmpULT(DstCh, SrcCh);
1780+
Builder.CreateCondBr(DstLtSrc, Exit, Next);
1781+
1782+
EmitBlock(Next);
1783+
Value *NextDst = Builder.CreateConstInBoundsGEP1_32(WCharTy, DstPhi, 1);
1784+
Value *NextSrc = Builder.CreateConstInBoundsGEP1_32(WCharTy, SrcPhi, 1);
1785+
Value *NextSize = Builder.CreateSub(SizePhi, ConstantInt::get(SizeTy, 1));
1786+
Value *NextSizeEq0 =
1787+
Builder.CreateICmpEQ(NextSize, ConstantInt::get(SizeTy, 0));
1788+
Builder.CreateCondBr(NextSizeEq0, Exit, CmpGT);
1789+
DstPhi->addIncoming(NextDst, Next);
1790+
SrcPhi->addIncoming(NextSrc, Next);
1791+
SizePhi->addIncoming(NextSize, Next);
1792+
1793+
EmitBlock(Exit);
1794+
PHINode *Ret = Builder.CreatePHI(IntTy, 4);
1795+
Ret->addIncoming(ConstantInt::get(IntTy, 0), Entry);
1796+
Ret->addIncoming(ConstantInt::get(IntTy, 1), CmpGT);
1797+
Ret->addIncoming(ConstantInt::get(IntTy, -1), CmpLT);
1798+
Ret->addIncoming(ConstantInt::get(IntTy, 0), Next);
1799+
return RValue::get(Ret);
1800+
}
17441801
case Builtin::BI__builtin_dwarf_cfa: {
17451802
// The offset in bytes from the first argument to the CFA.
17461803
//

‎clang/test/CodeGen/wmemcmp.c

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -emit-llvm -o - | FileCheck %s
2+
3+
typedef __SIZE_TYPE__ size_t;
4+
typedef __WCHAR_TYPE__ wchar_t;
5+
6+
int wmemcmp_test(const wchar_t *s1, const wchar_t *s2, size_t n) {
7+
// CHECK: [[S1:%.*]] = load
8+
// CHECK: [[S2:%.*]] = load
9+
// CHECK: [[N:%.*]] = load
10+
// CHECK: [[N0:%.*]] = icmp eq i64 [[N]], 0
11+
// CHECK: br i1 [[N0]], label %[[EXIT:.*]], label %[[GT:.*]]
12+
13+
// CHECK: [[GT]]:
14+
// CHECK: [[S1P:%.*]] = phi i16* [ [[S1]], %[[ENTRY:.*]] ], [ [[S1N:.*]], %[[NEXT:.*]] ]
15+
// CHECK: [[S2P:%.*]] = phi i16* [ [[S2]], %[[ENTRY]] ], [ [[S2N:.*]], %[[NEXT]] ]
16+
// CHECK: [[NP:%.*]] = phi i64 [ [[N]], %[[ENTRY]] ], [ [[NN:.*]], %[[NEXT]] ]
17+
// CHECK: [[S1L:%.*]] = load i16, i16* [[S1P]], align 2
18+
// CHECK: [[S2L:%.*]] = load i16, i16* [[S2P]], align 2
19+
// CHECK: [[CMPGT:%.*]] = icmp ugt i16 [[S1L]], [[S2L]]
20+
// CHECK: br i1 [[CMPGT]], label %[[EXIT]], label %[[LT:.*]]
21+
22+
// CHECK: [[LT]]:
23+
// CHECK: [[CMPLT:%.*]] = icmp ult i16 [[S1L]], [[S2L]]
24+
// CHECK: br i1 [[CMPLT]], label %[[EXIT]], label %[[NEXT:.*]]
25+
26+
// CHECK: [[NEXT]]:
27+
// CHECK: [[S1N]] = getelementptr inbounds i16, i16* [[S1P]], i32 1
28+
// CHECK: [[S2N]] = getelementptr inbounds i16, i16* [[S2P]], i32 1
29+
// CHECK: [[NN]] = sub i64 [[NP]], 1
30+
// CHECK: [[NN0:%.*]] = icmp eq i64 [[NN]], 0
31+
// CHECK: br i1 [[NN0]], label %[[EXIT]], label %[[GT]]
32+
//
33+
// CHECK: [[EXIT]]:
34+
// CHECK: [[RV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ 1, %[[GT]] ], [ -1, %[[LT]] ], [ 0, %[[NEXT]] ]
35+
// CHECK: ret i32 [[RV]]
36+
return __builtin_wmemcmp(s1, s2, n);
37+
}

0 commit comments

Comments
 (0)
Please sign in to comment.