aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST/ByteCode/InterpBuiltin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/ByteCode/InterpBuiltin.cpp')
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltin.cpp137
1 files changed, 137 insertions, 0 deletions
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index a2e97fc..6053237 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2773,6 +2773,50 @@ static bool interp__builtin_blend(InterpState &S, CodePtr OpPC,
return true;
}
+static bool interp__builtin_ia32_pshuf(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call, bool IsShufHW) {
+ assert(Call->getNumArgs() == 2 && "masked forms handled via select*");
+ APSInt ControlImm = popToAPSInt(S, Call->getArg(1));
+ const Pointer &Src = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+
+ unsigned NumElems = Dst.getNumElems();
+ PrimType ElemT = Dst.getFieldDesc()->getPrimType();
+
+ unsigned ElemBits = static_cast<unsigned>(primSize(ElemT) * 8);
+ if (ElemBits != 16 && ElemBits != 32)
+ return false;
+
+ unsigned LaneElts = 128u / ElemBits;
+ assert(LaneElts && (NumElems % LaneElts == 0));
+
+ uint8_t Ctl = static_cast<uint8_t>(ControlImm.getZExtValue());
+
+ for (unsigned Idx = 0; Idx != NumElems; Idx++) {
+ unsigned LaneBase = (Idx / LaneElts) * LaneElts;
+ unsigned LaneIdx = Idx % LaneElts;
+ unsigned SrcIdx = Idx;
+ unsigned Sel = (Ctl >> (2 * LaneIdx)) & 0x3;
+ if (ElemBits == 32) {
+ SrcIdx = LaneBase + Sel;
+ } else {
+ constexpr unsigned HalfSize = 4;
+ bool InHigh = LaneIdx >= HalfSize;
+ if (!IsShufHW && !InHigh) {
+ SrcIdx = LaneBase + Sel;
+ } else if (IsShufHW && InHigh) {
+ unsigned Rel = LaneIdx - HalfSize;
+ Sel = (Ctl >> (2 * Rel)) & 0x3;
+ SrcIdx = LaneBase + HalfSize + Sel;
+ }
+ }
+
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, { Dst.elem<T>(Idx) = Src.elem<T>(SrcIdx); });
+ }
+ Dst.initializeAllElements();
+ return true;
+}
+
static bool interp__builtin_elementwise_triop(
InterpState &S, CodePtr OpPC, const CallExpr *Call,
llvm::function_ref<APInt(const APSInt &, const APSInt &, const APSInt &)>
@@ -2878,6 +2922,61 @@ static bool interp__builtin_x86_insert_subvector(InterpState &S, CodePtr OpPC,
return true;
}
+static bool interp__builtin_vec_ext(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call, unsigned ID) {
+ assert(Call->getNumArgs() == 2);
+
+ APSInt ImmAPS = popToAPSInt(S, Call->getArg(1));
+ const Pointer &Vec = S.Stk.pop<Pointer>();
+ if (!Vec.getFieldDesc()->isPrimitiveArray())
+ return false;
+
+ unsigned NumElems = Vec.getNumElems();
+ unsigned Index =
+ static_cast<unsigned>(ImmAPS.getZExtValue() & (NumElems - 1));
+
+ PrimType ElemPT = Vec.getFieldDesc()->getPrimType();
+ // FIXME(#161685): Replace float+int split with a numeric-only type switch
+ if (ElemPT == PT_Float) {
+ S.Stk.push<Floating>(Vec.elem<Floating>(Index));
+ return true;
+ }
+ INT_TYPE_SWITCH_NO_BOOL(ElemPT, {
+ APSInt V = Vec.elem<T>(Index).toAPSInt();
+ pushInteger(S, V, Call->getType());
+ });
+
+ return true;
+}
+
+static bool interp__builtin_vec_set(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call, unsigned ID) {
+ assert(Call->getNumArgs() == 3);
+
+ APSInt ImmAPS = popToAPSInt(S, Call->getArg(2));
+ APSInt ValAPS = popToAPSInt(S, Call->getArg(1));
+
+ const Pointer &Base = S.Stk.pop<Pointer>();
+ if (!Base.getFieldDesc()->isPrimitiveArray())
+ return false;
+
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+
+ unsigned NumElems = Base.getNumElems();
+ unsigned Index =
+ static_cast<unsigned>(ImmAPS.getZExtValue() & (NumElems - 1));
+
+ PrimType ElemPT = Base.getFieldDesc()->getPrimType();
+ INT_TYPE_SWITCH_NO_BOOL(ElemPT, {
+ for (unsigned I = 0; I != NumElems; ++I)
+ Dst.elem<T>(I) = Base.elem<T>(I);
+ Dst.elem<T>(Index) = static_cast<T>(ValAPS);
+ });
+
+ Dst.initializeAllElements();
+ return true;
+}
+
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
uint32_t BuiltinID) {
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
@@ -3606,6 +3705,21 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case X86::BI__builtin_ia32_selectpd_512:
return interp__builtin_select(S, OpPC, Call);
+ case X86::BI__builtin_ia32_pshuflw:
+ case X86::BI__builtin_ia32_pshuflw256:
+ case X86::BI__builtin_ia32_pshuflw512:
+ return interp__builtin_ia32_pshuf(S, OpPC, Call, false);
+
+ case X86::BI__builtin_ia32_pshufhw:
+ case X86::BI__builtin_ia32_pshufhw256:
+ case X86::BI__builtin_ia32_pshufhw512:
+ return interp__builtin_ia32_pshuf(S, OpPC, Call, true);
+
+ case X86::BI__builtin_ia32_pshufd:
+ case X86::BI__builtin_ia32_pshufd256:
+ case X86::BI__builtin_ia32_pshufd512:
+ return interp__builtin_ia32_pshuf(S, OpPC, Call, false);
+
case X86::BI__builtin_ia32_kandqi:
case X86::BI__builtin_ia32_kandhi:
case X86::BI__builtin_ia32_kandsi:
@@ -3686,6 +3800,29 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case X86::BI__builtin_ia32_insert128i256:
return interp__builtin_x86_insert_subvector(S, OpPC, Call, BuiltinID);
+ case X86::BI__builtin_ia32_vec_ext_v4hi:
+ case X86::BI__builtin_ia32_vec_ext_v16qi:
+ case X86::BI__builtin_ia32_vec_ext_v8hi:
+ case X86::BI__builtin_ia32_vec_ext_v4si:
+ case X86::BI__builtin_ia32_vec_ext_v2di:
+ case X86::BI__builtin_ia32_vec_ext_v32qi:
+ case X86::BI__builtin_ia32_vec_ext_v16hi:
+ case X86::BI__builtin_ia32_vec_ext_v8si:
+ case X86::BI__builtin_ia32_vec_ext_v4di:
+ case X86::BI__builtin_ia32_vec_ext_v4sf:
+ return interp__builtin_vec_ext(S, OpPC, Call, BuiltinID);
+
+ case X86::BI__builtin_ia32_vec_set_v4hi:
+ case X86::BI__builtin_ia32_vec_set_v16qi:
+ case X86::BI__builtin_ia32_vec_set_v8hi:
+ case X86::BI__builtin_ia32_vec_set_v4si:
+ case X86::BI__builtin_ia32_vec_set_v2di:
+ case X86::BI__builtin_ia32_vec_set_v32qi:
+ case X86::BI__builtin_ia32_vec_set_v16hi:
+ case X86::BI__builtin_ia32_vec_set_v8si:
+ case X86::BI__builtin_ia32_vec_set_v4di:
+ return interp__builtin_vec_set(S, OpPC, Call, BuiltinID);
+
default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)