diff options
| author | Mark Seaborn <mseaborn@chromium.org> | 2013-06-25 07:57:02 -0700 |
|---|---|---|
| committer | Mark Seaborn <mseaborn@chromium.org> | 2013-06-25 07:57:02 -0700 |
| commit | d32f2f27e9bed303ce454ec48608204fba1e1194 (patch) | |
| tree | bbcf1b66bea25bb80bebe741a3f5111ec92b4899 /lib/Analysis | |
| parent | 29faec27f780be4336e0f210e8dd96582c989d3a (diff) | |
PNaCl ABI: Disallow various operations on the i1 type
Disallow i1 on loads/stores and require the conversions to i8 to be
explicit. Add a pass, PromoteI1Ops, that adds the conversions.
(Load/store on i1 occur in practice in small_tests for some boolean
globals.)
Disallow i1 for most arithmetic/comparison operations since these
aren't very useful and it's a nuisance for a code generator to have to
support these. I haven't seen these occur in practice, but
PromoteI1Ops nevertheless expands them.
We still allow and/or/xor on i1 because these do occur in practice,
and they're less of a nuisance to handle because they never overflow:
no truncation to 1 bit is required, unlike with adds.
Restrict the type of alloca's argument. Clang always uses i32 here.
Disallow i1 in switch instructions. Clang doesn't generate i1
switches for booleans.
Move CopyLoadOrStoreAttrs() helper into a header to reuse.
BUG=https://code.google.com/p/nativeclient/issues/detail?id=3490
TEST=PNaCl toolchain trybots + GCC torture tests + Spec2k
Review URL: https://codereview.chromium.org/17356011
Diffstat (limited to 'lib/Analysis')
| -rw-r--r-- | lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp b/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp index 9a96d19ed4..80d7da3f19 100644 --- a/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp +++ b/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp @@ -79,15 +79,21 @@ bool PNaClABIVerifyFunctions::IsWhitelistedMetadata(unsigned MDKind) { } // A valid pointer type is either: -// * a pointer to a valid PNaCl scalar type, or +// * a pointer to a valid PNaCl scalar type (except i1), or // * a function pointer (with valid argument and return types). +// +// 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. static bool isValidPointerType(Type *Ty) { if (PointerType *PtrTy = dyn_cast<PointerType>(Ty)) { if (PtrTy->getAddressSpace() != 0) return false; - if (PNaClABITypeChecker::isValidScalarType(PtrTy->getElementType())) + Type *EltTy = PtrTy->getElementType(); + if (PNaClABITypeChecker::isValidScalarType(EltTy) && + !EltTy->isIntegerTy(1)) return true; - if (FunctionType *FTy = dyn_cast<FunctionType>(PtrTy->getElementType())) + if (FunctionType *FTy = dyn_cast<FunctionType>(EltTy)) return PNaClABITypeChecker::isValidFunctionType(FTy); } return false; @@ -201,22 +207,12 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { case Instruction::Br: case Instruction::Unreachable: // Binary operations - case Instruction::Add: case Instruction::FAdd: - case Instruction::Sub: case Instruction::FSub: - case Instruction::Mul: case Instruction::FMul: - case Instruction::UDiv: - case Instruction::SDiv: case Instruction::FDiv: - case Instruction::URem: - case Instruction::SRem: case Instruction::FRem: // Bitwise binary operations - case Instruction::Shl: - case Instruction::LShr: - case Instruction::AShr: case Instruction::And: case Instruction::Or: case Instruction::Xor: @@ -233,12 +229,30 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { case Instruction::UIToFP: case Instruction::SIToFP: // Other operations - case Instruction::ICmp: case Instruction::FCmp: case Instruction::PHI: case Instruction::Select: break; + // The following operations are of dubious usefulness on 1-bit + // values. Use of the i1 type is disallowed here so that code + // generators do not need to support these corner cases. + case Instruction::ICmp: + // Binary operations + case Instruction::Add: + case Instruction::Sub: + case Instruction::Mul: + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::URem: + case Instruction::SRem: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + if (Inst->getOperand(0)->getType()->isIntegerTy(1)) + return "arithmetic on i1"; + break; + // Memory accesses. case Instruction::Load: { const LoadInst *Load = cast<LoadInst>(Inst); @@ -290,8 +304,11 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { break; case Instruction::Alloca: { - if (!cast<AllocaInst>(Inst)->getAllocatedType()->isIntegerTy(8)) + const AllocaInst *Alloca = cast<AllocaInst>(Inst); + if (!Alloca->getAllocatedType()->isIntegerTy(8)) return "non-i8 alloca"; + if (!Alloca->getArraySize()->getType()->isIntegerTy(32)) + return "alloca array size is not i32"; break; } @@ -345,6 +362,8 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) { const SwitchInst *Switch = cast<SwitchInst>(Inst); if (!isValidScalarOperand(Switch->getCondition())) return "bad switch condition"; + if (Switch->getCondition()->getType()->isIntegerTy(1)) + return "switch on i1"; // SwitchInst requires the cases to be ConstantInts, but it // doesn't require their types to be the same as the condition |
