aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/LangRef.rst34
-rw-r--r--lib/IR/Verifier.cpp124
-rw-r--r--test/Verifier/bitcast-address-space-nested-global-cycle.ll8
-rw-r--r--test/Verifier/bitcast-address-space-nested-global.ll11
-rw-r--r--test/Verifier/bitcast-address-space-through-constant-inttoptr-inside-gep-instruction.ll10
-rw-r--r--test/Verifier/bitcast-address-space-through-constant-inttoptr.ll11
-rw-r--r--test/Verifier/bitcast-address-space-through-gep-2.ll17
-rw-r--r--test/Verifier/bitcast-address-space-through-gep.ll13
-rw-r--r--test/Verifier/bitcast-address-space-through-inttoptr.ll9
-rw-r--r--test/Verifier/bitcast-address-spaces.ll9
-rw-r--r--test/Verifier/bitcast-vector-pointer-as.ll9
11 files changed, 219 insertions, 36 deletions
diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index 91f2289..dc96d8f 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -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:
""""""""
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp
index b22d211..d523e42 100644
--- a/lib/IR/Verifier.cpp
+++ b/lib/IR/Verifier.cpp
@@ -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);
+ }
+ }
+ }
}
}
diff --git a/test/Verifier/bitcast-address-space-nested-global-cycle.ll b/test/Verifier/bitcast-address-space-nested-global-cycle.ll
new file mode 100644
index 0000000..0cee726
--- /dev/null
+++ b/test/Verifier/bitcast-address-space-nested-global-cycle.ll
@@ -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 }
diff --git a/test/Verifier/bitcast-address-space-nested-global.ll b/test/Verifier/bitcast-address-space-nested-global.ll
new file mode 100644
index 0000000..abe9d94
--- /dev/null
+++ b/test/Verifier/bitcast-address-space-nested-global.ll
@@ -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 }
diff --git a/test/Verifier/bitcast-address-space-through-constant-inttoptr-inside-gep-instruction.ll b/test/Verifier/bitcast-address-space-through-constant-inttoptr-inside-gep-instruction.ll
new file mode 100644
index 0000000..ed71afa
--- /dev/null
+++ b/test/Verifier/bitcast-address-space-through-constant-inttoptr-inside-gep-instruction.ll
@@ -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
+}
+
diff --git a/test/Verifier/bitcast-address-space-through-constant-inttoptr.ll b/test/Verifier/bitcast-address-space-through-constant-inttoptr.ll
new file mode 100644
index 0000000..e65c71e
--- /dev/null
+++ b/test/Verifier/bitcast-address-space-through-constant-inttoptr.ll
@@ -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)*) }
+
+
diff --git a/test/Verifier/bitcast-address-space-through-gep-2.ll b/test/Verifier/bitcast-address-space-through-gep-2.ll
new file mode 100644
index 0000000..3b77d9a
--- /dev/null
+++ b/test/Verifier/bitcast-address-space-through-gep-2.ll
@@ -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)*) }
+
diff --git a/test/Verifier/bitcast-address-space-through-gep.ll b/test/Verifier/bitcast-address-space-through-gep.ll
new file mode 100644
index 0000000..8e950dc
--- /dev/null
+++ b/test/Verifier/bitcast-address-space-through-gep.ll
@@ -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)*) }
+
+
diff --git a/test/Verifier/bitcast-address-space-through-inttoptr.ll b/test/Verifier/bitcast-address-space-through-inttoptr.ll
new file mode 100644
index 0000000..bec4048
--- /dev/null
+++ b/test/Verifier/bitcast-address-space-through-inttoptr.ll
@@ -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
+}
+
diff --git a/test/Verifier/bitcast-address-spaces.ll b/test/Verifier/bitcast-address-spaces.ll
new file mode 100644
index 0000000..4508417
--- /dev/null
+++ b/test/Verifier/bitcast-address-spaces.ll
@@ -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
+}
+
diff --git a/test/Verifier/bitcast-vector-pointer-as.ll b/test/Verifier/bitcast-vector-pointer-as.ll
new file mode 100644
index 0000000..89070e5
--- /dev/null
+++ b/test/Verifier/bitcast-vector-pointer-as.ll
@@ -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
+}
+