Skip to content

Commit b3e4686

Browse files
committed
[clang][Interp] Implement __builtin_{ctz,clz,bswap}
1 parent 1b12974 commit b3e4686

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

clang/lib/AST/Interp/InterpBuiltin.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,52 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC,
841841
return true;
842842
}
843843

844+
static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
845+
const InterpFrame *Frame, const Function *Func,
846+
const CallExpr *Call) {
847+
unsigned BuiltinOp = Func->getBuiltinID();
848+
PrimType ValT = *S.getContext().classify(Call->getArg(0));
849+
const APSInt &Val = peekToAPSInt(S.Stk, ValT);
850+
851+
// When the argument is 0, the result of GCC builtins is undefined, whereas
852+
// for Microsoft intrinsics, the result is the bit-width of the argument.
853+
bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 &&
854+
BuiltinOp != Builtin::BI__lzcnt &&
855+
BuiltinOp != Builtin::BI__lzcnt64;
856+
857+
if (ZeroIsUndefined && Val == 0)
858+
return false;
859+
860+
pushInt(S, Val.countl_zero());
861+
return true;
862+
}
863+
864+
static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC,
865+
const InterpFrame *Frame, const Function *Func,
866+
const CallExpr *Call) {
867+
PrimType ValT = *S.getContext().classify(Call->getArg(0));
868+
const APSInt &Val = peekToAPSInt(S.Stk, ValT);
869+
870+
if (Val == 0)
871+
return false;
872+
873+
pushInt(S, Val.countr_zero());
874+
return true;
875+
}
876+
877+
static bool interp__builtin_bswap(InterpState &S, CodePtr OpPC,
878+
const InterpFrame *Frame,
879+
const Function *Func, const CallExpr *Call) {
880+
PrimType ReturnT = *S.getContext().classify(Call->getType());
881+
PrimType ValT = *S.getContext().classify(Call->getArg(0));
882+
const APSInt &Val = peekToAPSInt(S.Stk, ValT);
883+
assert(Val.getActiveBits() <= 64);
884+
885+
INT_TYPE_SWITCH(ReturnT,
886+
{ S.Stk.push<T>(T::from(Val.byteSwap().getZExtValue())); });
887+
return true;
888+
}
889+
844890
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
845891
const CallExpr *Call) {
846892
InterpFrame *Frame = S.Current;
@@ -1114,6 +1160,32 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
11141160
return false;
11151161
break;
11161162

1163+
case Builtin::BI__builtin_clz:
1164+
case Builtin::BI__builtin_clzl:
1165+
case Builtin::BI__builtin_clzll:
1166+
case Builtin::BI__builtin_clzs:
1167+
case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes
1168+
case Builtin::BI__lzcnt:
1169+
case Builtin::BI__lzcnt64:
1170+
if (!interp__builtin_clz(S, OpPC, Frame, F, Call))
1171+
return false;
1172+
break;
1173+
1174+
case Builtin::BI__builtin_ctz:
1175+
case Builtin::BI__builtin_ctzl:
1176+
case Builtin::BI__builtin_ctzll:
1177+
case Builtin::BI__builtin_ctzs:
1178+
if (!interp__builtin_ctz(S, OpPC, Frame, F, Call))
1179+
return false;
1180+
break;
1181+
1182+
case Builtin::BI__builtin_bswap16:
1183+
case Builtin::BI__builtin_bswap32:
1184+
case Builtin::BI__builtin_bswap64:
1185+
if (!interp__builtin_bswap(S, OpPC, Frame, F, Call))
1186+
return false;
1187+
break;
1188+
11171189
default:
11181190
return false;
11191191
}

clang/test/AST/Interp/builtin-functions.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,3 +444,32 @@ void test_noexcept(int *i) {
444444
}
445445
#undef TEST_TYPE
446446
} // end namespace test_launder
447+
448+
namespace clz {
449+
char clz1[__builtin_clz(1) == BITSIZE(int) - 1 ? 1 : -1];
450+
char clz2[__builtin_clz(7) == BITSIZE(int) - 3 ? 1 : -1];
451+
char clz3[__builtin_clz(1 << (BITSIZE(int) - 1)) == 0 ? 1 : -1];
452+
int clz4 = __builtin_clz(0);
453+
char clz5[__builtin_clzl(0xFL) == BITSIZE(long) - 4 ? 1 : -1];
454+
char clz6[__builtin_clzll(0xFFLL) == BITSIZE(long long) - 8 ? 1 : -1];
455+
char clz7[__builtin_clzs(0x1) == BITSIZE(short) - 1 ? 1 : -1];
456+
char clz8[__builtin_clzs(0xf) == BITSIZE(short) - 4 ? 1 : -1];
457+
char clz9[__builtin_clzs(0xfff) == BITSIZE(short) - 12 ? 1 : -1];
458+
}
459+
460+
namespace ctz {
461+
char ctz1[__builtin_ctz(1) == 0 ? 1 : -1];
462+
char ctz2[__builtin_ctz(8) == 3 ? 1 : -1];
463+
char ctz3[__builtin_ctz(1 << (BITSIZE(int) - 1)) == BITSIZE(int) - 1 ? 1 : -1];
464+
int ctz4 = __builtin_ctz(0);
465+
char ctz5[__builtin_ctzl(0x10L) == 4 ? 1 : -1];
466+
char ctz6[__builtin_ctzll(0x100LL) == 8 ? 1 : -1];
467+
char ctz7[__builtin_ctzs(1 << (BITSIZE(short) - 1)) == BITSIZE(short) - 1 ? 1 : -1];
468+
}
469+
470+
namespace bswap {
471+
extern int f(void);
472+
int h3 = __builtin_bswap16(0x1234) == 0x3412 ? 1 : f();
473+
int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f();
474+
int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f();
475+
}

0 commit comments

Comments
 (0)