mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-24 20:29:53 +00:00
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:
parent
04ded924f3
commit
16e4ed5879
@ -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:
|
||||
""""""""
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 }
|
11
test/Verifier/bitcast-address-space-nested-global.ll
Normal file
11
test/Verifier/bitcast-address-space-nested-global.ll
Normal 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 }
|
@ -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
|
||||
}
|
||||
|
@ -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)*) }
|
||||
|
||||
|
17
test/Verifier/bitcast-address-space-through-gep-2.ll
Normal file
17
test/Verifier/bitcast-address-space-through-gep-2.ll
Normal 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)*) }
|
||||
|
13
test/Verifier/bitcast-address-space-through-gep.ll
Normal file
13
test/Verifier/bitcast-address-space-through-gep.ll
Normal 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)*) }
|
||||
|
||||
|
9
test/Verifier/bitcast-address-space-through-inttoptr.ll
Normal file
9
test/Verifier/bitcast-address-space-through-inttoptr.ll
Normal 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
|
||||
}
|
||||
|
9
test/Verifier/bitcast-address-spaces.ll
Normal file
9
test/Verifier/bitcast-address-spaces.ll
Normal 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
|
||||
}
|
||||
|
9
test/Verifier/bitcast-vector-pointer-as.ll
Normal file
9
test/Verifier/bitcast-vector-pointer-as.ll
Normal 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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user