Index: lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp |
diff --git a/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp b/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp |
index c1c909cc46618e6880b0df260b08ecdf8d173fa6..1ef3ec45f72dcc5d01781f9e9811f7ff025fe567 100644 |
--- a/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp |
+++ b/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp |
@@ -93,13 +93,15 @@ bool PNaClABIVerifyFunctions::IsWhitelistedMetadata(unsigned MDKind) { |
// i1 is disallowed so that all loads and stores are a whole number of |
// bytes, and so that we do not need to define whether a store of i1 |
// zero-extends. |
+// |
+// Vector pointer types aren't currently allowed because vector memory |
+// accesses go through their scalar elements. |
static bool isValidPointerType(Type *Ty) { |
if (PointerType *PtrTy = dyn_cast<PointerType>(Ty)) { |
if (PtrTy->getAddressSpace() != 0) |
return false; |
Type *EltTy = PtrTy->getElementType(); |
- if (PNaClABITypeChecker::isValidScalarType(EltTy) && |
- !EltTy->isIntegerTy(1)) |
+ if (PNaClABITypeChecker::isValidScalarType(EltTy) && !EltTy->isIntegerTy(1)) |
return true; |
if (FunctionType *FTy = dyn_cast<FunctionType>(EltTy)) |
return PNaClABITypeChecker::isValidFunctionType(FTy); |
@@ -152,6 +154,16 @@ static bool isValidScalarOperand(const Value *Val) { |
isa<UndefValue>(Val)); |
} |
+static bool isValidVectorOperand(const Value *Val) { |
+ // The types of Instructions and Arguments are checked elsewhere. |
+ if (isa<Instruction>(Val) || isa<Argument>(Val)) |
+ return true; |
+ // Contrary to scalars, constant vector values aren't allowed on |
+ // instructions, except for aggregate zero and undefined. |
+ return PNaClABITypeChecker::isValidVectorType(Val->getType()) && |
+ (isa<ConstantAggregateZero>(Val) || isa<UndefValue>(Val)); |
+} |
+ |
static bool isAllowedAlignment(unsigned Alignment, Type *Ty) { |
// Non-atomic integer operations must always use "align 1", since we |
// do not want the backend to generate code with non-portable |
@@ -163,6 +175,9 @@ static bool isAllowedAlignment(unsigned Alignment, Type *Ty) { |
// To reduce the set of alignment values that need to be encoded in |
// pexes, we disallow other alignment values. We require alignments |
// to be explicit by disallowing Alignment == 0. |
+ // |
+ // Vector memory accesses go through their scalar elements, there is |
+ // therefore no such thing as vector alignment. |
return Alignment == 1 || |
(Ty->isDoubleTy() && Alignment == 8) || |
(Ty->isFloatTy() && Alignment == 4); |
@@ -253,9 +268,7 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { |
case Instruction::Resume: |
// indirectbr may interfere with streaming |
case Instruction::IndirectBr: |
- // No vector instructions yet |
- case Instruction::ExtractElement: |
- case Instruction::InsertElement: |
+ // TODO(jfb) Figure out ShuffleVector. |
case Instruction::ShuffleVector: |
// ExtractValue and InsertValue operate on struct values. |
case Instruction::ExtractValue: |
@@ -312,10 +325,32 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { |
case Instruction::SRem: |
case Instruction::Shl: |
case Instruction::LShr: |
- case Instruction::AShr: |
- if (Inst->getOperand(0)->getType()->isIntegerTy(1)) |
+ case Instruction::AShr: { |
+ Type *Op0Ty = Inst->getOperand(0)->getType(); |
+ if (Op0Ty->isIntegerTy(1)) |
return "arithmetic on i1"; |
+ if (VectorType *Op0VTy = dyn_cast<VectorType>(Op0Ty)) |
+ if (Op0VTy->getElementType()->isIntegerTy(1)) |
+ return "arithmetic on vector of i1"; |
break; |
+ } |
+ |
+ // Vector. |
+ case Instruction::ExtractElement: |
+ case Instruction::InsertElement: { |
+ // Insert and extract element are restricted to constant indices |
+ // that are in range to prevent undefined behavior. |
+ Value *Vec = Inst->getOperand(0); |
+ Value *Idx = Inst->getOperand( |
+ Instruction::InsertElement == Inst->getOpcode() ? 2 : 1); |
+ if (!isa<ConstantInt>(Idx)) |
+ return "non-constant vector insert/extract index"; |
+ const APInt &I = cast<ConstantInt>(Idx)->getValue(); |
+ unsigned NumElements = cast<VectorType>(Vec->getType())->getNumElements(); |
+ if (!I.ult(NumElements)) |
+ return "out of range vector insert/extract index"; |
+ break; |
+ } |
// Memory accesses. |
case Instruction::Load: { |
@@ -325,11 +360,11 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { |
return "atomic load"; |
if (Load->isVolatile()) |
return "volatile load"; |
+ if (!isNormalizedPtr(Inst->getOperand(PtrOperandIndex))) |
+ return "bad pointer"; |
if (!isAllowedAlignment(Load->getAlignment(), |
Load->getType())) |
return "bad alignment"; |
- if (!isNormalizedPtr(Inst->getOperand(PtrOperandIndex))) |
- return "bad pointer"; |
break; |
} |
case Instruction::Store: { |
@@ -339,11 +374,11 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { |
return "atomic store"; |
if (Store->isVolatile()) |
return "volatile store"; |
+ if (!isNormalizedPtr(Inst->getOperand(PtrOperandIndex))) |
+ return "bad pointer"; |
if (!isAllowedAlignment(Store->getAlignment(), |
Store->getValueOperand()->getType())) |
return "bad alignment"; |
- if (!isNormalizedPtr(Inst->getOperand(PtrOperandIndex))) |
- return "bad pointer"; |
break; |
} |
@@ -392,6 +427,7 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { |
ArgNum < E; ++ArgNum) { |
const Value *Arg = Call->getArgOperand(ArgNum); |
if (!(isValidScalarOperand(Arg) || |
+ isValidVectorOperand(Arg) || |
isNormalizedPtr(Arg) || |
isa<MDNode>(Arg))) |
return "bad intrinsic operand"; |
@@ -476,10 +512,11 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { |
} |
// Check the instruction's operands. We have already checked any |
- // pointer operands. Any remaining operands must be scalars. |
+ // pointer operands. Any remaining operands must be scalars or vectors. |
for (unsigned OpNum = 0, E = Inst->getNumOperands(); OpNum < E; ++OpNum) { |
if (OpNum != PtrOperandIndex && |
- !isValidScalarOperand(Inst->getOperand(OpNum))) |
+ !(isValidScalarOperand(Inst->getOperand(OpNum)) || |
+ isValidVectorOperand(Inst->getOperand(OpNum)))) |
return "bad operand"; |
} |
@@ -516,14 +553,19 @@ bool PNaClABIVerifyFunctions::runOnFunction(Function &F) { |
// check the reason for rejection. |
const char *Error = checkInstruction(BBI); |
// Check the instruction's result type. |
+ bool BadResult = false; |
if (!Error && !(PNaClABITypeChecker::isValidScalarType(Inst->getType()) || |
+ PNaClABITypeChecker::isValidVectorType(Inst->getType()) || |
isNormalizedPtr(Inst) || |
isa<AllocaInst>(Inst))) { |
Error = "bad result type"; |
+ BadResult = true; |
} |
if (Error) { |
- Reporter->addError() << "Function " << F.getName() << |
- " disallowed: " << Error << ": " << *BBI << "\n"; |
+ Reporter->addError() |
+ << "Function " << F.getName() << " disallowed: " << Error << ": " |
+ << (BadResult ? PNaClABITypeChecker::getTypeName(BBI->getType()) |
+ : "") << " " << *BBI << "\n"; |
} |
// Check instruction attachment metadata. |