mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 21:32:10 +00:00
4ee451de36
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@45418 91177308-0d34-0410-b5e6-96231b3b80d8
449 lines
16 KiB
C++
449 lines
16 KiB
C++
//===- LowerPacked.cpp - Implementation of LowerPacked Transform ---------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements lowering vector datatypes into more primitive
|
|
// vector datatypes, and finally to scalar operations.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Transforms/Scalar.h"
|
|
#include "llvm/Argument.h"
|
|
#include "llvm/Constants.h"
|
|
#include "llvm/DerivedTypes.h"
|
|
#include "llvm/Function.h"
|
|
#include "llvm/Instructions.h"
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/InstVisitor.h"
|
|
#include "llvm/Support/Streams.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include <algorithm>
|
|
#include <map>
|
|
#include <functional>
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
/// This pass converts packed operators to an
|
|
/// equivalent operations on smaller packed data, to possibly
|
|
/// scalar operations. Currently it supports lowering
|
|
/// to scalar operations.
|
|
///
|
|
/// @brief Transforms packed instructions to simpler instructions.
|
|
///
|
|
class VISIBILITY_HIDDEN LowerPacked
|
|
: public FunctionPass, public InstVisitor<LowerPacked> {
|
|
public:
|
|
static char ID; // Pass identification, replacement for typeid
|
|
LowerPacked() : FunctionPass((intptr_t)&ID) {}
|
|
|
|
/// @brief Lowers packed operations to scalar operations.
|
|
/// @param F The fuction to process
|
|
virtual bool runOnFunction(Function &F);
|
|
|
|
/// @brief Lowers packed load instructions.
|
|
/// @param LI the load instruction to convert
|
|
void visitLoadInst(LoadInst& LI);
|
|
|
|
/// @brief Lowers packed store instructions.
|
|
/// @param SI the store instruction to convert
|
|
void visitStoreInst(StoreInst& SI);
|
|
|
|
/// @brief Lowers packed binary operations.
|
|
/// @param BO the binary operator to convert
|
|
void visitBinaryOperator(BinaryOperator& BO);
|
|
|
|
/// @brief Lowers packed icmp operations.
|
|
/// @param IC the icmp operator to convert
|
|
void visitICmpInst(ICmpInst& IC);
|
|
|
|
/// @brief Lowers packed select instructions.
|
|
/// @param SELI the select operator to convert
|
|
void visitSelectInst(SelectInst& SELI);
|
|
|
|
/// @brief Lowers packed extractelement instructions.
|
|
/// @param EE the extractelement operator to convert
|
|
void visitExtractElementInst(ExtractElementInst& EE);
|
|
|
|
/// @brief Lowers packed insertelement instructions.
|
|
/// @param IE the insertelement operator to convert
|
|
void visitInsertElementInst(InsertElementInst& IE);
|
|
|
|
/// This function asserts that the given instruction does not have
|
|
/// vector type. Instructions with vector type should be handled by
|
|
/// the other functions in this class.
|
|
///
|
|
/// @brief Asserts if VectorType instruction is not handled elsewhere.
|
|
/// @param I the unhandled instruction
|
|
void visitInstruction(Instruction &I) {
|
|
assert(!isa<VectorType>(I.getType()) &&
|
|
"Unhandled Instruction with Packed ReturnType!");
|
|
}
|
|
private:
|
|
/// @brief Retrieves lowered values for a packed value.
|
|
/// @param val the packed value
|
|
/// @return the lowered values
|
|
std::vector<Value*>& getValues(Value* val);
|
|
|
|
/// @brief Sets lowered values for a packed value.
|
|
/// @param val the packed value
|
|
/// @param values the corresponding lowered values
|
|
void setValues(Value* val,const std::vector<Value*>& values);
|
|
|
|
// Data Members
|
|
/// @brief whether we changed the function or not
|
|
bool Changed;
|
|
|
|
/// @brief a map from old packed values to new smaller packed values
|
|
std::map<Value*,std::vector<Value*> > packedToScalarMap;
|
|
|
|
/// Instructions in the source program to get rid of
|
|
/// after we do a pass (the old packed instructions)
|
|
std::vector<Instruction*> instrsToRemove;
|
|
};
|
|
|
|
char LowerPacked::ID = 0;
|
|
RegisterPass<LowerPacked>
|
|
X("lower-packed",
|
|
"lowers packed operations to operations on smaller packed datatypes");
|
|
|
|
} // end namespace
|
|
|
|
FunctionPass *llvm::createLowerPackedPass() { return new LowerPacked(); }
|
|
|
|
|
|
// This function sets lowered values for a corresponding
|
|
// packed value. Note, in the case of a forward reference
|
|
// getValues(Value*) will have already been called for
|
|
// the packed parameter. This function will then replace
|
|
// all references in the in the function of the "dummy"
|
|
// value the previous getValues(Value*) call
|
|
// returned with actual references.
|
|
void LowerPacked::setValues(Value* value,const std::vector<Value*>& values)
|
|
{
|
|
std::map<Value*,std::vector<Value*> >::iterator it =
|
|
packedToScalarMap.lower_bound(value);
|
|
if (it == packedToScalarMap.end() || it->first != value) {
|
|
// there was not a forward reference to this element
|
|
packedToScalarMap.insert(it,std::make_pair(value,values));
|
|
}
|
|
else {
|
|
// replace forward declarations with actual definitions
|
|
assert(it->second.size() == values.size() &&
|
|
"Error forward refences and actual definition differ in size");
|
|
for (unsigned i = 0, e = values.size(); i != e; ++i) {
|
|
// replace and get rid of old forward references
|
|
it->second[i]->replaceAllUsesWith(values[i]);
|
|
delete it->second[i];
|
|
it->second[i] = values[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// This function will examine the packed value parameter
|
|
// and if it is a packed constant or a forward reference
|
|
// properly create the lowered values needed. Otherwise
|
|
// it will simply retreive values from a
|
|
// setValues(Value*,const std::vector<Value*>&)
|
|
// call. Failing both of these cases, it will abort
|
|
// the program.
|
|
std::vector<Value*>& LowerPacked::getValues(Value* value)
|
|
{
|
|
assert(isa<VectorType>(value->getType()) &&
|
|
"Value must be VectorType");
|
|
|
|
// reject further processing if this one has
|
|
// already been handled
|
|
std::map<Value*,std::vector<Value*> >::iterator it =
|
|
packedToScalarMap.lower_bound(value);
|
|
if (it != packedToScalarMap.end() && it->first == value) {
|
|
return it->second;
|
|
}
|
|
|
|
if (ConstantVector* CP = dyn_cast<ConstantVector>(value)) {
|
|
// non-zero constant case
|
|
std::vector<Value*> results;
|
|
results.reserve(CP->getNumOperands());
|
|
for (unsigned i = 0, e = CP->getNumOperands(); i != e; ++i) {
|
|
results.push_back(CP->getOperand(i));
|
|
}
|
|
return packedToScalarMap.insert(it,
|
|
std::make_pair(value,results))->second;
|
|
}
|
|
else if (ConstantAggregateZero* CAZ =
|
|
dyn_cast<ConstantAggregateZero>(value)) {
|
|
// zero constant
|
|
const VectorType* PKT = cast<VectorType>(CAZ->getType());
|
|
std::vector<Value*> results;
|
|
results.reserve(PKT->getNumElements());
|
|
|
|
Constant* C = Constant::getNullValue(PKT->getElementType());
|
|
for (unsigned i = 0, e = PKT->getNumElements(); i != e; ++i) {
|
|
results.push_back(C);
|
|
}
|
|
return packedToScalarMap.insert(it,
|
|
std::make_pair(value,results))->second;
|
|
}
|
|
else if (isa<Instruction>(value)) {
|
|
// foward reference
|
|
const VectorType* PKT = cast<VectorType>(value->getType());
|
|
std::vector<Value*> results;
|
|
results.reserve(PKT->getNumElements());
|
|
|
|
for (unsigned i = 0, e = PKT->getNumElements(); i != e; ++i) {
|
|
results.push_back(new Argument(PKT->getElementType()));
|
|
}
|
|
return packedToScalarMap.insert(it,
|
|
std::make_pair(value,results))->second;
|
|
}
|
|
else {
|
|
// we don't know what it is, and we are trying to retrieve
|
|
// a value for it
|
|
assert(false && "Unhandled VectorType value");
|
|
abort();
|
|
}
|
|
}
|
|
|
|
void LowerPacked::visitLoadInst(LoadInst& LI)
|
|
{
|
|
// Make sure what we are dealing with is a vector type
|
|
if (const VectorType* PKT = dyn_cast<VectorType>(LI.getType())) {
|
|
// Initialization, Idx is needed for getelementptr needed later
|
|
Value *Idx[2];
|
|
Idx[0] = ConstantInt::get(Type::Int32Ty, 0);
|
|
|
|
// Convert this load into num elements number of loads
|
|
std::vector<Value*> values;
|
|
values.reserve(PKT->getNumElements());
|
|
|
|
for (unsigned i = 0, e = PKT->getNumElements(); i != e; ++i) {
|
|
// Calculate the second index we will need
|
|
Idx[1] = ConstantInt::get(Type::Int32Ty,i);
|
|
|
|
// Get the pointer
|
|
Value* val = new GetElementPtrInst(LI.getPointerOperand(),
|
|
Idx, array_endof(Idx),
|
|
LI.getName() +
|
|
".ge." + utostr(i),
|
|
&LI);
|
|
|
|
// generate the new load and save the result in packedToScalar map
|
|
values.push_back(new LoadInst(val, LI.getName()+"."+utostr(i),
|
|
LI.isVolatile(), &LI));
|
|
}
|
|
|
|
setValues(&LI,values);
|
|
Changed = true;
|
|
instrsToRemove.push_back(&LI);
|
|
}
|
|
}
|
|
|
|
void LowerPacked::visitBinaryOperator(BinaryOperator& BO)
|
|
{
|
|
// Make sure both operands are VectorTypes
|
|
if (isa<VectorType>(BO.getOperand(0)->getType())) {
|
|
std::vector<Value*>& op0Vals = getValues(BO.getOperand(0));
|
|
std::vector<Value*>& op1Vals = getValues(BO.getOperand(1));
|
|
std::vector<Value*> result;
|
|
assert((op0Vals.size() == op1Vals.size()) &&
|
|
"The two packed operand to scalar maps must be equal in size.");
|
|
|
|
result.reserve(op0Vals.size());
|
|
|
|
// generate the new binary op and save the result
|
|
for (unsigned i = 0; i != op0Vals.size(); ++i) {
|
|
result.push_back(BinaryOperator::create(BO.getOpcode(),
|
|
op0Vals[i],
|
|
op1Vals[i],
|
|
BO.getName() +
|
|
"." + utostr(i),
|
|
&BO));
|
|
}
|
|
|
|
setValues(&BO,result);
|
|
Changed = true;
|
|
instrsToRemove.push_back(&BO);
|
|
}
|
|
}
|
|
|
|
void LowerPacked::visitICmpInst(ICmpInst& IC)
|
|
{
|
|
// Make sure both operands are VectorTypes
|
|
if (isa<VectorType>(IC.getOperand(0)->getType())) {
|
|
std::vector<Value*>& op0Vals = getValues(IC.getOperand(0));
|
|
std::vector<Value*>& op1Vals = getValues(IC.getOperand(1));
|
|
std::vector<Value*> result;
|
|
assert((op0Vals.size() == op1Vals.size()) &&
|
|
"The two packed operand to scalar maps must be equal in size.");
|
|
|
|
result.reserve(op0Vals.size());
|
|
|
|
// generate the new binary op and save the result
|
|
for (unsigned i = 0; i != op0Vals.size(); ++i) {
|
|
result.push_back(CmpInst::create(IC.getOpcode(),
|
|
IC.getPredicate(),
|
|
op0Vals[i],
|
|
op1Vals[i],
|
|
IC.getName() +
|
|
"." + utostr(i),
|
|
&IC));
|
|
}
|
|
|
|
setValues(&IC,result);
|
|
Changed = true;
|
|
instrsToRemove.push_back(&IC);
|
|
}
|
|
}
|
|
|
|
void LowerPacked::visitStoreInst(StoreInst& SI)
|
|
{
|
|
if (const VectorType* PKT =
|
|
dyn_cast<VectorType>(SI.getOperand(0)->getType())) {
|
|
// We will need this for getelementptr
|
|
Value *Idx[2];
|
|
Idx[0] = ConstantInt::get(Type::Int32Ty, 0);
|
|
|
|
std::vector<Value*>& values = getValues(SI.getOperand(0));
|
|
|
|
assert((values.size() == PKT->getNumElements()) &&
|
|
"Scalar must have the same number of elements as Vector Type");
|
|
|
|
for (unsigned i = 0, e = PKT->getNumElements(); i != e; ++i) {
|
|
// Generate the indices for getelementptr
|
|
Idx[1] = ConstantInt::get(Type::Int32Ty,i);
|
|
Value* val = new GetElementPtrInst(SI.getPointerOperand(),
|
|
Idx, array_endof(Idx),
|
|
"store.ge." +
|
|
utostr(i) + ".",
|
|
&SI);
|
|
new StoreInst(values[i], val, SI.isVolatile(),&SI);
|
|
}
|
|
|
|
Changed = true;
|
|
instrsToRemove.push_back(&SI);
|
|
}
|
|
}
|
|
|
|
void LowerPacked::visitSelectInst(SelectInst& SELI)
|
|
{
|
|
// Make sure both operands are VectorTypes
|
|
if (isa<VectorType>(SELI.getType())) {
|
|
std::vector<Value*>& op0Vals = getValues(SELI.getTrueValue());
|
|
std::vector<Value*>& op1Vals = getValues(SELI.getFalseValue());
|
|
std::vector<Value*> result;
|
|
|
|
assert((op0Vals.size() == op1Vals.size()) &&
|
|
"The two packed operand to scalar maps must be equal in size.");
|
|
|
|
for (unsigned i = 0; i != op0Vals.size(); ++i) {
|
|
result.push_back(new SelectInst(SELI.getCondition(),
|
|
op0Vals[i],
|
|
op1Vals[i],
|
|
SELI.getName()+ "." + utostr(i),
|
|
&SELI));
|
|
}
|
|
|
|
setValues(&SELI,result);
|
|
Changed = true;
|
|
instrsToRemove.push_back(&SELI);
|
|
}
|
|
}
|
|
|
|
void LowerPacked::visitExtractElementInst(ExtractElementInst& EI)
|
|
{
|
|
std::vector<Value*>& op0Vals = getValues(EI.getOperand(0));
|
|
const VectorType *PTy = cast<VectorType>(EI.getOperand(0)->getType());
|
|
Value *op1 = EI.getOperand(1);
|
|
|
|
if (ConstantInt *C = dyn_cast<ConstantInt>(op1)) {
|
|
EI.replaceAllUsesWith(op0Vals[C->getZExtValue()]);
|
|
} else {
|
|
AllocaInst *alloca =
|
|
new AllocaInst(PTy->getElementType(),
|
|
ConstantInt::get(Type::Int32Ty, PTy->getNumElements()),
|
|
EI.getName() + ".alloca",
|
|
EI.getParent()->getParent()->getEntryBlock().begin());
|
|
for (unsigned i = 0; i < PTy->getNumElements(); ++i) {
|
|
GetElementPtrInst *GEP =
|
|
new GetElementPtrInst(alloca, ConstantInt::get(Type::Int32Ty, i),
|
|
"store.ge", &EI);
|
|
new StoreInst(op0Vals[i], GEP, &EI);
|
|
}
|
|
GetElementPtrInst *GEP =
|
|
new GetElementPtrInst(alloca, op1, EI.getName() + ".ge", &EI);
|
|
LoadInst *load = new LoadInst(GEP, EI.getName() + ".load", &EI);
|
|
EI.replaceAllUsesWith(load);
|
|
}
|
|
|
|
Changed = true;
|
|
instrsToRemove.push_back(&EI);
|
|
}
|
|
|
|
void LowerPacked::visitInsertElementInst(InsertElementInst& IE)
|
|
{
|
|
std::vector<Value*>& Vals = getValues(IE.getOperand(0));
|
|
Value *Elt = IE.getOperand(1);
|
|
Value *Idx = IE.getOperand(2);
|
|
std::vector<Value*> result;
|
|
result.reserve(Vals.size());
|
|
|
|
if (ConstantInt *C = dyn_cast<ConstantInt>(Idx)) {
|
|
unsigned idxVal = C->getZExtValue();
|
|
for (unsigned i = 0; i != Vals.size(); ++i) {
|
|
result.push_back(i == idxVal ? Elt : Vals[i]);
|
|
}
|
|
} else {
|
|
for (unsigned i = 0; i != Vals.size(); ++i) {
|
|
ICmpInst *icmp =
|
|
new ICmpInst(ICmpInst::ICMP_EQ, Idx,
|
|
ConstantInt::get(Type::Int32Ty, i),
|
|
"icmp", &IE);
|
|
SelectInst *select =
|
|
new SelectInst(icmp, Elt, Vals[i], "select", &IE);
|
|
result.push_back(select);
|
|
}
|
|
}
|
|
|
|
setValues(&IE, result);
|
|
Changed = true;
|
|
instrsToRemove.push_back(&IE);
|
|
}
|
|
|
|
bool LowerPacked::runOnFunction(Function& F)
|
|
{
|
|
// initialize
|
|
Changed = false;
|
|
|
|
// Does three passes:
|
|
// Pass 1) Converts Packed Operations to
|
|
// new Packed Operations on smaller
|
|
// datatypes
|
|
visit(F);
|
|
|
|
// Pass 2) Drop all references
|
|
std::for_each(instrsToRemove.begin(),
|
|
instrsToRemove.end(),
|
|
std::mem_fun(&Instruction::dropAllReferences));
|
|
|
|
// Pass 3) Delete the Instructions to remove aka packed instructions
|
|
for (std::vector<Instruction*>::iterator i = instrsToRemove.begin(),
|
|
e = instrsToRemove.end();
|
|
i != e; ++i) {
|
|
(*i)->getParent()->getInstList().erase(*i);
|
|
}
|
|
|
|
// clean-up
|
|
packedToScalarMap.clear();
|
|
instrsToRemove.clear();
|
|
|
|
return Changed;
|
|
}
|
|
|