Reject bitcasts between address spaces with different sizes

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187506 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matt Arsenault 2013-07-31 17:49:08 +00:00
parent 04ded924f3
commit 16e4ed5879
11 changed files with 219 additions and 36 deletions

View File

@ -1061,7 +1061,9 @@ the specifications in the ``datalayout`` keyword. The default
specifications are given in this list:
- ``E`` - big endian
- ``p:64:64:64`` - 64-bit pointers with 64-bit alignment
- ``p:64:64:64`` - 64-bit pointers with 64-bit alignment.
- ``p[n]:64:64:64`` - Other address spaces are assumed to be the
same as the default address space.
- ``S0`` - natural stack alignment is unspecified
- ``i1:8:8`` - i1 is 8-bit (byte) aligned
- ``i8:8:8`` - i8 is 8-bit (byte) aligned
@ -2583,7 +2585,7 @@ Examples:
It is sometimes useful to attach information to loop constructs. Currently,
loop metadata is implemented as metadata attached to the branch instruction
in the loop latch block. This type of metadata refer to a metadata node that is
guaranteed to be separate for each loop. The loop identifier metadata is
guaranteed to be separate for each loop. The loop identifier metadata is
specified with the name ``llvm.loop``.
The loop identifier metadata is implemented using a metadata that refers to
@ -5613,24 +5615,24 @@ Arguments:
The '``bitcast``' instruction takes a value to cast, which must be a
non-aggregate first class value, and a type to cast it to, which must
also be a non-aggregate :ref:`first class <t_firstclass>` type. The bit
sizes of ``value`` and the destination type, ``ty2``, must be identical.
If the source type is a pointer, the destination type must also be a
pointer. This instruction supports bitwise conversion of vectors to
integers and to vectors of other types (as long as they have the same
size).
also be a non-aggregate :ref:`first class <t_firstclass>` type. The
bit sizes of ``value`` and the destination type, ``ty2``, must be
identical. If the source type is a pointer, the destination type must
also be a pointer of the same size. This instruction supports bitwise
conversion of vectors to integers and to vectors of other types (as
long as they have the same size).
Semantics:
""""""""""
The '``bitcast``' instruction converts ``value`` to type ``ty2``. It is
always a *no-op cast* because no bits change with this conversion. The
conversion is done as if the ``value`` had been stored to memory and
read back as type ``ty2``. Pointer (or vector of pointers) types may
only be converted to other pointer (or vector of pointers) types with
this instruction. To convert pointers to other types, use the
:ref:`inttoptr <i_inttoptr>` or :ref:`ptrtoint <i_ptrtoint>` instructions
first.
The '``bitcast``' instruction converts ``value`` to type ``ty2``. It
is always a *no-op cast* because no bits change with this
conversion. The conversion is done as if the ``value`` had been stored
to memory and read back as type ``ty2``. Pointer (or vector of
pointers) types may only be converted to other pointer (or vector of
pointers) types with this instruction if the pointer sizes are
equal. To convert pointers to other types, use the :ref:`inttoptr
<i_inttoptr>` or :ref:`ptrtoint <i_ptrtoint>` instructions first.
Example:
""""""""

View File

@ -56,6 +56,7 @@
#include "llvm/DebugInfo.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/IntrinsicInst.h"
@ -128,6 +129,7 @@ namespace {
Module *Mod; // Module we are verifying right now
LLVMContext *Context; // Context within which we are verifying
DominatorTree *DT; // Dominator Tree, caution can be null!
const DataLayout *DL;
std::string Messages;
raw_string_ostream MessagesStr;
@ -152,13 +154,13 @@ namespace {
Verifier()
: FunctionPass(ID), Broken(false),
action(AbortProcessAction), Mod(0), Context(0), DT(0),
action(AbortProcessAction), Mod(0), Context(0), DT(0), DL(0),
MessagesStr(Messages), PersonalityFn(0) {
initializeVerifierPass(*PassRegistry::getPassRegistry());
}
explicit Verifier(VerifierFailureAction ctn)
: FunctionPass(ID), Broken(false), action(ctn), Mod(0),
Context(0), DT(0), MessagesStr(Messages), PersonalityFn(0) {
Context(0), DT(0), DL(0), MessagesStr(Messages), PersonalityFn(0) {
initializeVerifierPass(*PassRegistry::getPassRegistry());
}
@ -167,6 +169,8 @@ namespace {
Context = &M.getContext();
Finder.reset();
DL = getAnalysisIfAvailable<DataLayout>();
// We must abort before returning back to the pass manager, or else the
// pass manager may try to run other passes on the broken module.
return abortIfBroken();
@ -321,6 +325,9 @@ namespace {
void VerifyFunctionAttrs(FunctionType *FT, AttributeSet Attrs,
const Value *V);
void VerifyBitcastType(const Value *V, Type *DestTy, Type *SrcTy);
void VerifyConstantExprBitcastType(const ConstantExpr *CE);
void verifyDebugInfo(Module &M);
void WriteValue(const Value *V) {
@ -487,6 +494,33 @@ void Verifier::visitGlobalVariable(GlobalVariable &GV) {
}
}
if (!GV.hasInitializer()) {
visitGlobalValue(GV);
return;
}
// Walk any aggregate initializers looking for bitcasts between address spaces
SmallPtrSet<const Value *, 4> Visited;
SmallVector<const Value *, 4> WorkStack;
WorkStack.push_back(cast<Value>(GV.getInitializer()));
while (!WorkStack.empty()) {
const Value *V = WorkStack.pop_back_val();
if (!Visited.insert(V))
continue;
if (const User *U = dyn_cast<User>(V)) {
for (unsigned I = 0, N = U->getNumOperands(); I != N; ++I)
WorkStack.push_back(U->getOperand(I));
}
if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
VerifyConstantExprBitcastType(CE);
if (Broken)
return;
}
}
visitGlobalValue(GV);
}
@ -865,6 +899,52 @@ void Verifier::VerifyFunctionAttrs(FunctionType *FT, AttributeSet Attrs,
"Attributes 'noinline and alwaysinline' are incompatible!", V);
}
void Verifier::VerifyBitcastType(const Value *V, Type *DestTy, Type *SrcTy) {
// Get the size of the types in bits, we'll need this later
unsigned SrcBitSize = SrcTy->getPrimitiveSizeInBits();
unsigned DestBitSize = DestTy->getPrimitiveSizeInBits();
// BitCast implies a no-op cast of type only. No bits change.
// However, you can't cast pointers to anything but pointers.
Assert1(SrcTy->isPointerTy() == DestTy->isPointerTy(),
"Bitcast requires both operands to be pointer or neither", V);
Assert1(SrcBitSize == DestBitSize,
"Bitcast requires types of same width", V);
// Disallow aggregates.
Assert1(!SrcTy->isAggregateType(),
"Bitcast operand must not be aggregate", V);
Assert1(!DestTy->isAggregateType(),
"Bitcast type must not be aggregate", V);
// Without datalayout, assume all address spaces are the same size.
// Don't check if both types are not pointers.
// Skip casts between scalars and vectors.
if (!DL ||
!SrcTy->isPtrOrPtrVectorTy() ||
!DestTy->isPtrOrPtrVectorTy() ||
SrcTy->isVectorTy() != DestTy->isVectorTy()) {
return;
}
unsigned SrcAS = SrcTy->getPointerAddressSpace();
unsigned DstAS = DestTy->getPointerAddressSpace();
unsigned SrcASSize = DL->getPointerSizeInBits(SrcAS);
unsigned DstASSize = DL->getPointerSizeInBits(DstAS);
Assert1(SrcASSize == DstASSize,
"Bitcasts between pointers of different address spaces must have "
"the same size pointers, otherwise use PtrToInt/IntToPtr.", V);
}
void Verifier::VerifyConstantExprBitcastType(const ConstantExpr *CE) {
if (CE->getOpcode() == Instruction::BitCast) {
Type *SrcTy = CE->getOperand(0)->getType();
Type *DstTy = CE->getType();
VerifyBitcastType(CE, DstTy, SrcTy);
}
}
bool Verifier::VerifyAttributeCount(AttributeSet Attrs, unsigned Params) {
if (Attrs.getNumSlots() == 0)
return true;
@ -1349,26 +1429,9 @@ void Verifier::visitIntToPtrInst(IntToPtrInst &I) {
}
void Verifier::visitBitCastInst(BitCastInst &I) {
// Get the source and destination types
Type *SrcTy = I.getOperand(0)->getType();
Type *DestTy = I.getType();
// Get the size of the types in bits, we'll need this later
unsigned SrcBitSize = SrcTy->getPrimitiveSizeInBits();
unsigned DestBitSize = DestTy->getPrimitiveSizeInBits();
// BitCast implies a no-op cast of type only. No bits change.
// However, you can't cast pointers to anything but pointers.
Assert1(SrcTy->isPointerTy() == DestTy->isPointerTy(),
"Bitcast requires both operands to be pointer or neither", &I);
Assert1(SrcBitSize == DestBitSize, "Bitcast requires types of same width",&I);
// Disallow aggregates.
Assert1(!SrcTy->isAggregateType(),
"Bitcast operand must not be aggregate", &I);
Assert1(!DestTy->isAggregateType(),
"Bitcast type must not be aggregate", &I);
VerifyBitcastType(&I, DestTy, SrcTy);
visitInstruction(I);
}
@ -1992,6 +2055,27 @@ void Verifier::visitInstruction(Instruction &I) {
Assert1((i + 1 == e && isa<CallInst>(I)) ||
(i + 3 == e && isa<InvokeInst>(I)),
"Cannot take the address of an inline asm!", &I);
} else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(I.getOperand(i))) {
if (CE->getType()->isPtrOrPtrVectorTy()) {
// If we have a ConstantExpr pointer, we need to see if it came from an
// illegal bitcast (inttoptr <constant int> )
SmallVector<const ConstantExpr *, 4> Stack;
SmallPtrSet<const ConstantExpr *, 4> Visited;
Stack.push_back(CE);
while (!Stack.empty()) {
const ConstantExpr *V = Stack.pop_back_val();
if (!Visited.insert(V))
continue;
VerifyConstantExprBitcastType(V);
for (unsigned I = 0, N = V->getNumOperands(); I != N; ++I) {
if (ConstantExpr *Op = dyn_cast<ConstantExpr>(V->getOperand(I)))
Stack.push_back(Op);
}
}
}
}
}

View File

@ -0,0 +1,8 @@
; RUN: not llvm-as -verify -disable-output %s
target datalayout = "e-p:32:32:32-p1:16:16:16-p2:8:8:8-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32"
%struct.Self1 = type { %struct.Self1 addrspace(1)* }
@cycle1 = addrspace(1) constant %struct.Self1 { %struct.Self1 addrspace(1)* bitcast (%struct.Self1 addrspace(0)* @cycle0 to %struct.Self1 addrspace(1)*) }
@cycle0 = addrspace(0) constant %struct.Self1 { %struct.Self1 addrspace(1)* @cycle1 }

View File

@ -0,0 +1,11 @@
; RUN: not llvm-as -verify -disable-output %s
target datalayout = "e-p:32:32:32-p1:16:16:16-p2:8:8:8-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32"
%struct.Self1 = type { %struct.Self1 addrspace(1)* }
@nestedD = constant %struct.Self1 { %struct.Self1 addrspace(1)* bitcast (%struct.Self1 addrspace(0)* @nestedC to %struct.Self1 addrspace(1)*) }
@nestedC = constant %struct.Self1 { %struct.Self1 addrspace(1)* bitcast (%struct.Self1 addrspace(0)* @nestedB to %struct.Self1 addrspace(1)*) }
@nestedB = constant %struct.Self1 { %struct.Self1 addrspace(1)* bitcast (%struct.Self1 addrspace(0)* @nestedA to %struct.Self1 addrspace(1)*) }
@nestedA = constant %struct.Self1 { %struct.Self1 addrspace(1)* null }

View File

@ -0,0 +1,10 @@
; RUN: not llvm-as -verify -disable-output < %s
target datalayout = "e-p:32:32:32-p1:16:16:16-p2:8:8:8-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32"
; Check that we can find inttoptr -> illegal bitcasts when hidden
; inside constantexpr pointer operands
define i32 addrspace(2)* @illegal_bitcast_inttoptr_as_1_to_2_inside_gep() {
%cast = getelementptr i32 addrspace(2)* bitcast (i32 addrspace(1)* inttoptr (i32 1234 to i32 addrspace(1)*) to i32 addrspace(2)*), i32 3
ret i32 addrspace(2)* %cast
}

View File

@ -0,0 +1,11 @@
; RUN: not llvm-as -verify -disable-output %s
target datalayout = "e-p:32:32:32-p1:16:16:16-p2:8:8:8-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32"
%struct.Foo = type { i32 addrspace(1)* }
; Make sure we still reject the bitcast when the source is a inttoptr (constant int) in a global initializer
@bitcast_after_constant_inttoptr_initializer = global %struct.Foo { i32 addrspace(1)* bitcast (i32 addrspace(2)* inttoptr (i8 7 to i32 addrspace(2)*) to i32 addrspace(1)*) }

View File

@ -0,0 +1,17 @@
; RUN: not llvm-as -verify -disable-output %s
target datalayout = "e-p:32:32:32-p1:16:16:16-p2:8:8:8-p3:8:8:8-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32"
%struct.Foo1 = type { i32 addrspace(1)* }
@as2_array = addrspace(2) global [32 x i32] zeroinitializer
; gep -> legal bitcast (2 -> 3) -> gep -> illegal bitcast (3 -> 1)
@bitcast_after_gep_bitcast_gep =
global %struct.Foo1 { i32 addrspace(1)* bitcast
(i32 addrspace(3)* getelementptr
(i32 addrspace(3)* bitcast
(i32 addrspace(2)* getelementptr
([32 x i32] addrspace(2)* @as2_array, i32 0, i32 8) to i32 addrspace(3)*), i32 3) to i32 addrspace(1)*) }

View File

@ -0,0 +1,13 @@
; RUN: not llvm-as -verify -disable-output %s
target datalayout = "e-p:32:32:32-p1:16:16:16-p2:8:8:8-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32"
%struct.Foo = type { i32 addrspace(1)* }
@as2_array = addrspace(2) global [32 x i32] zeroinitializer
; Make sure we still reject the bitcast after the value is accessed through a GEP
@bitcast_after_gep = global %struct.Foo { i32 addrspace(1)* bitcast (i32 addrspace(2)* getelementptr ([32 x i32] addrspace(2)* @as2_array, i32 0, i32 8) to i32 addrspace(1)*) }

View File

@ -0,0 +1,9 @@
; RUN: not llvm-as -verify -disable-output %s
target datalayout = "e-p:32:32:32-p1:16:16:16-p2:8:8:8-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32"
define i32 addrspace(2)* @illegal_bitcast_as_1_to_2_inttoptr() {
%cast = bitcast i32 addrspace(1)* inttoptr (i32 5 to i32 addrspace(1)*) to i32 addrspace(2)*
ret i32 addrspace(2)* %cast
}

View File

@ -0,0 +1,9 @@
; RUN: not llvm-as -verify -disable-output %s
target datalayout = "e-p:32:32:32-p1:16:16:16-p2:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32"
define i32 addrspace(1)* @illegal_bitcast_as_0_to_1(i32 addrspace(0) *%p) {
%cast = bitcast i32 addrspace(0)* %p to i32 addrspace(1)*
ret i32 addrspace(1)* %cast
}

View File

@ -0,0 +1,9 @@
; RUN: not llvm-as -verify -disable-output %s
target datalayout = "e-p:32:32:32-p1:16:16:16-p2:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n8:16:32"
define <4 x i32 addrspace(1)*> @vector_illegal_bitcast_as_0_to_1(<4 x i32 addrspace(0)*> %p) {
%cast = bitcast <4 x i32 addrspace(0)*> %p to <4 x i32 addrspace(1)*>
ret <4 x i32 addrspace(1)*> %cast
}