From: Tim Northover Date: Wed, 12 Feb 2014 12:04:59 +0000 (+0000) Subject: ARM NEON: fix range checking on immediates. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a5f239932494936b269b158ec2d2e0aec912408c;p=clang ARM NEON: fix range checking on immediates. Previously, range checking on the __builtin_neon_XYZ_v Clang intrinsics didn't take account of the type actually passed to the call, which meant a request like "vext_s16(a, b, 7)" was allowed through (TableGen was conservative and allowed 0-7 for all types). This caused an assert in the backend because the lane doesn't make sense. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201232 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td index a1065d9f72..02d67084f7 100644 --- a/include/clang/Basic/arm_neon.td +++ b/include/clang/Basic/arm_neon.td @@ -148,6 +148,10 @@ class Inst { bit isVCVT_N = 0; bit isA64 = 0; bit isCrypto = 0; + // For immediate checks: the immediate will be assumed to specify the lane of + // a Q register. Only used for intrinsics which end up calling polymorphic + // builtins. + bit isLaneQ = 0; // Certain intrinsics have different names than their representative // instructions. This field allows us to handle this correctly when we @@ -909,7 +913,9 @@ def VMLS_LANEQ : IOpInst<"vmls_laneq", "dddji", "siUsUifQsQiQUsQUiQf", OP_MLS_LN>; def VFMA_LANE : IInst<"vfma_lane", "dddgi", "fdQfQd">; -def VFMA_LANEQ : IInst<"vfma_laneq", "dddji", "fdQfQd">; +def VFMA_LANEQ : IInst<"vfma_laneq", "dddji", "fdQfQd"> { + let isLaneQ = 1; +} def VFMS_LANE : IOpInst<"vfms_lane", "dddgi", "fdQfQd", OP_FMS_LN>; def VFMS_LANEQ : IOpInst<"vfms_laneq", "dddji", "fdQfQd", OP_FMS_LNQ>; @@ -1302,7 +1308,9 @@ def SCALAR_VMUL_N : IInst<"vmul_n", "dds", "d">; def SCALAR_VMUL_LANE : IInst<"vmul_lane", "ddgi", "d">; // VMUL_LANEQ d type implemented using scalar mul lane -def SCALAR_VMUL_LANEQ : IInst<"vmul_laneq", "ddji", "d">; +def SCALAR_VMUL_LANEQ : IInst<"vmul_laneq", "ddji", "d"> { + let isLaneQ = 1; +} // VMULX_LANE d type implemented using scalar vmulx_lane def SCALAR_VMULX_LANE : IOpInst<"vmulx_lane", "ddgi", "d", OP_SCALAR_VMULX_LN>; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 07f25c15fa..dfacba84ef 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -326,9 +326,9 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { } // Get the valid immediate range for the specified NEON type code. -static unsigned RFT(unsigned t, bool shift = false) { +static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) { NeonTypeFlags Type(t); - int IsQuad = Type.isQuad(); + int IsQuad = ForceQuad ? true : Type.isQuad(); switch (Type.getEltType()) { case NeonTypeFlags::Int8: case NeonTypeFlags::Poly8: diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp index ac9e22491e..e4c6cb3b1d 100644 --- a/utils/TableGen/NeonEmitter.cpp +++ b/utils/TableGen/NeonEmitter.cpp @@ -3007,6 +3007,14 @@ NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS, rangestr = "l = 1; "; rangestr += "u = RFT(TV" + shiftstr + ")"; + } else if (ck == ClassB) { + // ClassB intrinsics have a type (and hence lane number) that is only + // known at runtime. + assert(immPos > 0 && "unexpected immediate operand"); + if (R->getValueAsBit("isLaneQ")) + rangestr = "u = RFT(TV, false, true)"; + else + rangestr = "u = RFT(TV, false, false)"; } else { // The immediate generally refers to a lane in the preceding argument. assert(immPos > 0 && "unexpected immediate operand");