Use llvm TargetData to find object sizes, offsets.
Previously, to compute the size of objects and the offsets of struct elements within structs, we were using the trick of using getelementpointer with a NULL base pointer and then casting the result to an int32/64. However, since we actually know the target we're compiling for at compile time, we can use corresponding methods from TargetData to get these values directly. This mostly cleans up code, but may make some of the gather/scatter lowering to loads/stores optimizations work better in the presence of structures.
This commit is contained in:
24
ctx.cpp
24
ctx.cpp
@@ -799,28 +799,6 @@ FunctionEmitContext::I1VecToBoolVec(llvm::Value *b) {
|
||||
}
|
||||
|
||||
|
||||
llvm::Value *
|
||||
FunctionEmitContext::SizeOf(LLVM_TYPE_CONST llvm::Type *ty) {
|
||||
// Emit code to compute the size of the given type using a GEP with a
|
||||
// NULL base pointer, indexing one element of the given type, and
|
||||
// casting the resulting 'pointer' to an int giving its size.
|
||||
LLVM_TYPE_CONST llvm::Type *ptrType = llvm::PointerType::get(ty, 0);
|
||||
llvm::Value *nullPtr = llvm::Constant::getNullValue(ptrType);
|
||||
llvm::Value *index[1] = { LLVMInt32(1) };
|
||||
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
|
||||
llvm::ArrayRef<llvm::Value *> arrayRef(&index[0], &index[1]);
|
||||
llvm::Value *poffset = llvm::GetElementPtrInst::Create(nullPtr, arrayRef,
|
||||
"offset_ptr", bblock);
|
||||
#else
|
||||
llvm::Value *poffset = llvm::GetElementPtrInst::Create(nullPtr, &index[0], &index[1],
|
||||
"offset_ptr", bblock);
|
||||
#endif
|
||||
AddDebugPos(poffset);
|
||||
llvm::Value *sizeOf = PtrToIntInst(poffset, LLVMTypes::Int64Type, "offset_int");
|
||||
return sizeOf;
|
||||
}
|
||||
|
||||
|
||||
static llvm::Value *
|
||||
lGetStringAsValue(llvm::BasicBlock *bblock, const char *s) {
|
||||
llvm::Constant *sConstant = llvm::ConstantArray::get(*g->ctx, s);
|
||||
@@ -2266,7 +2244,7 @@ FunctionEmitContext::LaunchInst(llvm::Value *callee,
|
||||
int align = 4 * RoundUpPow2(g->target.nativeVectorWidth);
|
||||
std::vector<llvm::Value *> allocArgs;
|
||||
allocArgs.push_back(launchGroupHandlePtr);
|
||||
allocArgs.push_back(SizeOf(argStructType));
|
||||
allocArgs.push_back(g->target.SizeOf(argStructType));
|
||||
allocArgs.push_back(LLVMInt32(align));
|
||||
llvm::Value *voidmem = CallInst(falloc, NULL, allocArgs, "args_ptr");
|
||||
llvm::Value *argmem = BitCastInst(voidmem, pt);
|
||||
|
||||
3
ctx.h
3
ctx.h
@@ -226,9 +226,6 @@ public:
|
||||
i32. */
|
||||
llvm::Value *I1VecToBoolVec(llvm::Value *b);
|
||||
|
||||
/** Returns the size of the given type. */
|
||||
llvm::Value *SizeOf(LLVM_TYPE_CONST llvm::Type *ty);
|
||||
|
||||
/** If the user has asked to compile the program with instrumentation,
|
||||
this inserts a callback to the user-supplied instrumentation
|
||||
function at the current point in the code. */
|
||||
|
||||
23
ispc.cpp
23
ispc.cpp
@@ -38,6 +38,7 @@
|
||||
#include "ispc.h"
|
||||
#include "module.h"
|
||||
#include "util.h"
|
||||
#include "llvmutil.h"
|
||||
#include <stdio.h>
|
||||
#ifdef ISPC_IS_WINDOWS
|
||||
#include <windows.h>
|
||||
@@ -279,6 +280,28 @@ Target::GetISAString() const {
|
||||
}
|
||||
|
||||
|
||||
llvm::Value *
|
||||
Target::SizeOf(LLVM_TYPE_CONST llvm::Type *type) {
|
||||
const llvm::TargetData *td = GetTargetMachine()->getTargetData();
|
||||
assert(td != NULL);
|
||||
return is32bit ? LLVMInt32(td->getTypeSizeInBits(type) / 8) :
|
||||
LLVMInt64(td->getTypeSizeInBits(type) / 8);
|
||||
}
|
||||
|
||||
|
||||
llvm::Value *
|
||||
Target::StructOffset(LLVM_TYPE_CONST llvm::Type *type, int element) {
|
||||
const llvm::TargetData *td = GetTargetMachine()->getTargetData();
|
||||
assert(td != NULL);
|
||||
LLVM_TYPE_CONST llvm::StructType *structType =
|
||||
llvm::dyn_cast<LLVM_TYPE_CONST llvm::StructType>(type);
|
||||
assert(structType != NULL);
|
||||
const llvm::StructLayout *sl = td->getStructLayout(structType);
|
||||
assert(sl != NULL);
|
||||
return LLVMInt32(sl->getElementOffset(element));
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Opt
|
||||
|
||||
|
||||
8
ispc.h
8
ispc.h
@@ -160,6 +160,14 @@ struct Target {
|
||||
/** Returns a string like "avx" encoding the target. */
|
||||
const char *GetISAString() const;
|
||||
|
||||
/** Returns the size of the given type */
|
||||
llvm::Value *SizeOf(LLVM_TYPE_CONST llvm::Type *type);
|
||||
/** Given a structure type and an element number in the structure,
|
||||
returns a value corresponding to the number of bytes from the start
|
||||
of the structure where the element is located. */
|
||||
llvm::Value *StructOffset(LLVM_TYPE_CONST llvm::Type *type,
|
||||
int element);
|
||||
|
||||
/** llvm Target object representing this target. */
|
||||
const llvm::Target *target;
|
||||
|
||||
|
||||
158
opt.cpp
158
opt.cpp
@@ -759,128 +759,6 @@ lGetIntValue(llvm::Value *offset) {
|
||||
}
|
||||
|
||||
|
||||
/** Returns the size of the given llvm::Type as an llvm::Value, if the size
|
||||
can be easily determined at compile type. If it's not easy to figure
|
||||
out the size, this just returns NULL and we handle finding its size
|
||||
differently.
|
||||
*/
|
||||
static bool
|
||||
lSizeOfIfKnown(const llvm::Type *type, uint64_t *size) {
|
||||
if (type == LLVMTypes::Int8Type) {
|
||||
*size = 1;
|
||||
return true;
|
||||
}
|
||||
if (type == LLVMTypes::Int8VectorType) {
|
||||
*size = g->target.vectorWidth * 1;
|
||||
return true;
|
||||
}
|
||||
else if (type == LLVMTypes::Int16Type) {
|
||||
*size = 2;
|
||||
return true;
|
||||
}
|
||||
if (type == LLVMTypes::Int16VectorType) {
|
||||
*size = g->target.vectorWidth * 2;
|
||||
return true;
|
||||
}
|
||||
else if (type == LLVMTypes::FloatType || type == LLVMTypes::Int32Type) {
|
||||
*size = 4;
|
||||
return true;
|
||||
}
|
||||
else if (type == LLVMTypes::FloatVectorType || type == LLVMTypes::Int32VectorType) {
|
||||
*size = g->target.vectorWidth * 4;
|
||||
return true;
|
||||
}
|
||||
else if (type == LLVMTypes::DoubleType || type == LLVMTypes::Int64Type) {
|
||||
*size = 8;
|
||||
return true;
|
||||
}
|
||||
else if (type == LLVMTypes::DoubleVectorType || type == LLVMTypes::Int64VectorType) {
|
||||
*size = g->target.vectorWidth * 8;
|
||||
return true;
|
||||
}
|
||||
else if (llvm::isa<const llvm::ArrayType>(type)) {
|
||||
const llvm::ArrayType *at = llvm::dyn_cast<const llvm::ArrayType>(type);
|
||||
uint64_t eltSize;
|
||||
if (lSizeOfIfKnown(at->getElementType(), &eltSize)) {
|
||||
*size = eltSize * at->getNumElements();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** This function returns an llvm::Value giving the size of the given type.
|
||||
If any instructions need to be generated to compute the size, they are
|
||||
inserted before insertBefore.
|
||||
*/
|
||||
static llvm::Value *
|
||||
lSizeOf(LLVM_TYPE_CONST llvm::Type *type, llvm::Instruction *insertBefore) {
|
||||
// First try the easy case and see if we can get it as a simple
|
||||
// constant..
|
||||
uint64_t size;
|
||||
if (lSizeOfIfKnown(type, &size))
|
||||
return LLVMInt64(size);
|
||||
|
||||
// Otherwise use the trick of doing a GEP with a NULL pointer to get
|
||||
// the pointer to the second element of an array of items of this type.
|
||||
// Then convert that pointer to an int and we've got the offset to the
|
||||
// second element in the array, a.k.a. the size of the type.
|
||||
LLVM_TYPE_CONST llvm::Type *ptrType = llvm::PointerType::get(type, 0);
|
||||
llvm::Value *nullPtr = llvm::Constant::getNullValue(ptrType);
|
||||
llvm::Value *index[1] = { LLVMInt32(1) };
|
||||
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
|
||||
llvm::ArrayRef<llvm::Value *> arrayRef(&index[0], &index[1]);
|
||||
llvm::Value *poffset = llvm::GetElementPtrInst::Create(nullPtr, arrayRef,
|
||||
"offset_ptr", insertBefore);
|
||||
#else
|
||||
llvm::Value *poffset = llvm::GetElementPtrInst::Create(nullPtr, &index[0], &index[1],
|
||||
"offset_ptr", insertBefore);
|
||||
#endif
|
||||
lCopyMetadata(poffset, insertBefore);
|
||||
LLVM_TYPE_CONST llvm::Type *intPtrType = g->target.is32bit ?
|
||||
LLVMTypes::Int32Type : LLVMTypes::Int64Type;
|
||||
llvm::Instruction *inst = new llvm::PtrToIntInst(poffset, intPtrType,
|
||||
"offset_int", insertBefore);
|
||||
lCopyMetadata(inst, insertBefore);
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
/** This function returns a value that gives the offset in bytes from the
|
||||
start of the given structure type to the given struct member. The
|
||||
instructions that compute this value are inserted before insertBefore.
|
||||
*/
|
||||
static llvm::Value *
|
||||
lStructOffset(LLVM_TYPE_CONST llvm::Type *type, uint64_t member,
|
||||
llvm::Instruction *insertBefore) {
|
||||
// Do a similar trick to the one done in lSizeOf above; compute the
|
||||
// pointer to the member starting from a NULL base pointer and then
|
||||
// cast that 'pointer' to an int...
|
||||
assert(llvm::isa<const llvm::StructType>(type));
|
||||
LLVM_TYPE_CONST llvm::Type *ptrType = llvm::PointerType::get(type, 0);
|
||||
llvm::Value *nullPtr = llvm::Constant::getNullValue(ptrType);
|
||||
llvm::Value *index[2] = { LLVMInt32(0), LLVMInt32((int32_t)member) };
|
||||
#if defined(LLVM_3_0) || defined(LLVM_3_0svn) || defined(LLVM_3_1svn)
|
||||
llvm::ArrayRef<llvm::Value *> arrayRef(&index[0], &index[2]);
|
||||
llvm::Value *poffset = llvm::GetElementPtrInst::Create(nullPtr, arrayRef,
|
||||
"member_ptr", insertBefore);
|
||||
#else
|
||||
llvm::Value *poffset = llvm::GetElementPtrInst::Create(nullPtr, &index[0], &index[2],
|
||||
"member_ptr", insertBefore);
|
||||
#endif
|
||||
lCopyMetadata(poffset, insertBefore);
|
||||
LLVM_TYPE_CONST llvm::Type *intPtrType = g->target.is32bit ?
|
||||
LLVMTypes::Int32Type : LLVMTypes::Int64Type;
|
||||
llvm::Instruction *inst = new llvm::PtrToIntInst(poffset, intPtrType,
|
||||
"member_int", insertBefore);
|
||||
lCopyMetadata(inst, insertBefore);
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
static llvm::Value *
|
||||
lGetTypeSize(LLVM_TYPE_CONST llvm::Type *type, llvm::Instruction *insertBefore) {
|
||||
LLVM_TYPE_CONST llvm::ArrayType *arrayType =
|
||||
@@ -888,11 +766,13 @@ lGetTypeSize(LLVM_TYPE_CONST llvm::Type *type, llvm::Instruction *insertBefore)
|
||||
if (arrayType != NULL)
|
||||
type = arrayType->getElementType();
|
||||
|
||||
llvm::Value *scale = lSizeOf(type, insertBefore);
|
||||
llvm::Instruction *inst = new llvm::TruncInst(scale, LLVMTypes::Int32Type, "sizeof32",
|
||||
insertBefore);
|
||||
lCopyMetadata(inst, insertBefore);
|
||||
return inst;
|
||||
llvm::Value *scale = g->target.SizeOf(type);
|
||||
if (g->target.is32bit == false) {
|
||||
scale = new llvm::TruncInst(scale, LLVMTypes::Int32Type, "sizeof32",
|
||||
insertBefore);
|
||||
lCopyMetadata(scale, insertBefore);
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
|
||||
@@ -919,11 +799,8 @@ lTraverseConstantExpr(llvm::Constant *value, llvm::Value **offsetPtr,
|
||||
LLVM_TYPE_CONST llvm::Type *targetType = targetPtrType->getElementType();
|
||||
|
||||
if (llvm::isa<const llvm::StructType>(targetType)) {
|
||||
*offsetPtr = lStructOffset(targetType, lGetIntValue(ce->getOperand(2)),
|
||||
insertBefore);
|
||||
*offsetPtr = new llvm::TruncInst(*offsetPtr, LLVMTypes::Int32Type, "member32",
|
||||
insertBefore);
|
||||
//CO lCopyMetadata(*offset, insertBefore);
|
||||
*offsetPtr = g->target.StructOffset(targetType,
|
||||
lGetIntValue(ce->getOperand(2)));
|
||||
*scaleType = LLVMTypes::Int8Type; // aka char aka sizeof(1)
|
||||
}
|
||||
else {
|
||||
@@ -979,10 +856,7 @@ lGetOffsetForLane(int lane, llvm::Value *value, llvm::Value **offset,
|
||||
LLVM_TYPE_CONST llvm::Type *targetType = targetPtrType->getElementType();
|
||||
|
||||
if (llvm::isa<const llvm::StructType>(targetType)) {
|
||||
*offset = lStructOffset(targetType, lGetIntValue(gep->getOperand(2)),
|
||||
insertBefore);
|
||||
*offset = new llvm::TruncInst(*offset, LLVMTypes::Int32Type, "member32",
|
||||
insertBefore);
|
||||
*offset = g->target.StructOffset(targetType, lGetIntValue(gep->getOperand(2)));
|
||||
lCopyMetadata(*offset, insertBefore);
|
||||
*scaleType = LLVMTypes::Int8Type; // aka char aka sizeof(1)
|
||||
}
|
||||
@@ -1806,15 +1680,17 @@ lScalarizeVector(llvm::Value *vec, llvm::Value **scalarizedVector,
|
||||
llvm::dyn_cast<llvm::VectorType>(ptrType->getElementType());
|
||||
assert(vecType != NULL);
|
||||
LLVM_TYPE_CONST llvm::Type *elementType = vecType->getElementType();
|
||||
uint64_t elementSize;
|
||||
bool sizeKnown = lSizeOfIfKnown(elementType, &elementSize);
|
||||
assert(sizeKnown == true);
|
||||
|
||||
llvm::Value *elementSize = g->target.SizeOf(elementType);
|
||||
|
||||
LLVM_TYPE_CONST llvm::Type *eltPtrType = llvm::PointerType::get(elementType, 0);
|
||||
|
||||
for (int i = 0; i < vectorLength; ++i) {
|
||||
llvm::Value *offset = g->target.is32bit ? LLVMInt32(i * elementSize) :
|
||||
LLVMInt64(i * elementSize);
|
||||
llvm::Value *offset =
|
||||
llvm::BinaryOperator::Create(llvm::Instruction::Mul, elementSize,
|
||||
g->target.is32bit ? LLVMInt32(i) :
|
||||
LLVMInt64(i),
|
||||
"elt_offset", li);
|
||||
llvm::Value *intPtrOffset =
|
||||
llvm::BinaryOperator::Create(llvm::Instruction::Add, baseInt,
|
||||
offset, "baseoffset", li);
|
||||
|
||||
Reference in New Issue
Block a user