blob: 08b3ddbaa57b07674f93dcd6156163b66469a07a [file] [log] [blame] [edit]
//===--- Util.cpp ---------------------------------------------------------===//
//
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
//===----------------------------------------------------------------------===//
//
// Helper functions.
//
//===----------------------------------------------------------------------===//
#include "GollvmPasses.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
using namespace llvm;
using namespace gollvm::passes;
// Whether a type contains pointer.
bool
gollvm::passes::hasPointer(Type *T) {
switch (T->getTypeID()) {
case Type::PointerTyID:
return true;
case Type::ArrayTyID:
return hasPointer(T->getArrayElementType());
case Type::FixedVectorTyID:
case Type::ScalableVectorTyID:
return hasPointer(T->getScalarType());
case Type::StructTyID: {
for (unsigned i = 0, e = T->getStructNumElements(); i < e; ++i)
if (hasPointer(T->getStructElementType(i)))
return true;
return false;
}
default:
return false;
}
}
static void
getPtrBitmapForTypeHelper(Type *T, const DataLayout &DL, uint64_t BaseOffset, BitVector &BV) {
if (!hasPointer(T))
return;
const unsigned PtrSize = DL.getPointerSize();
Type *Int32Ty = Type::getInt32Ty(T->getContext());
switch (T->getTypeID()) {
case Type::PointerTyID:
BV.set(BaseOffset / PtrSize);
break;;
case Type::ArrayTyID: {
Type *ET = T->getArrayElementType();
for (unsigned i = 0, n = T->getArrayNumElements(); i < n; ++i) {
Value *ivals[2] = { ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, i) };
ArrayRef<Value*> Idx = makeArrayRef(ivals, 2);
uint64_t Offset = DL.getIndexedOffsetInType(T, Idx);
getPtrBitmapForTypeHelper(ET, DL, BaseOffset+Offset, BV);
}
break;
}
case Type::FixedVectorTyID: {
auto *VT = llvm::cast<llvm::FixedVectorType>(T);
Type *ET = T->getScalarType();
for (unsigned i = 0, n = VT->getNumElements(); i < n; ++i) {
Value *ivals[2] = { ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, i) };
ArrayRef<Value*> Idx = makeArrayRef(ivals, 2);
uint64_t Offset = DL.getIndexedOffsetInType(T, Idx);
getPtrBitmapForTypeHelper(ET, DL, BaseOffset+Offset, BV);
}
break;
}
case Type::StructTyID: {
for (unsigned i = 0, n = T->getStructNumElements(); i < n; ++i) {
Type *ET = T->getStructElementType(i);
if (!hasPointer(ET))
continue;
Value *ivals[2] = { ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, i) };
ArrayRef<Value*> Idx = makeArrayRef(ivals, 2);
uint64_t Offset = DL.getIndexedOffsetInType(T, Idx);
getPtrBitmapForTypeHelper(ET, DL, BaseOffset+Offset, BV);
}
break;
}
case Type::ScalableVectorTyID:
assert(false && "not expecting ScalableVectorTyID");
default:
break;
}
}
// Compute the pointer bitmap for type T, stored into Words.
void
gollvm::passes::getPtrBitmapForType(Type *T, const DataLayout &DL,
SmallVectorImpl<Value *> &Words) {
// TODO: this function is silly -- BitVector internally has
// a bitmap storage, but it is private. Can we do better?
const unsigned PtrSize = DL.getPointerSize();
Type *Int32Ty = Type::getInt32Ty(T->getContext());
uint64_t Size = DL.getTypeStoreSize(T);
BitVector BV(Size/PtrSize);
getPtrBitmapForTypeHelper(T, DL, 0, BV);
if (BV.none())
return;
unsigned last = BV.find_last();
if (last == 0) // a single pointer field, no need of a bitmap
return;
//Words.reserve(last/32 + 1);
for (unsigned i = 0; i <= last; i += 32) {
uint32_t w = 0;
for (unsigned j = 0; j < 32 && i+j <= last; j++)
w |= BV[i+j] ? 1<<j : 0;
Words.push_back(ConstantInt::get(Int32Ty, w));
}
}