//===- ExpandI64.cpp - Expand i64 and wider integer types -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===------------------------------------------------------------------===//
//
// This pass expands and lowers all operations on integers i64 and wider
// into 32-bit operations that can be handled by JS in a natural way.
//
// 64-bit variables become pairs of 2 32-bit variables, for the low and
// high 32 bit chunks. This happens for both registers and function
// arguments. Function return values become a return of the low 32 bits
// and a store of the high 32-bits in tempRet0, a global helper variable.
// Larger values become more chunks of 32 bits. Currently we require that
// types be a multiple of 32 bits.
//
// Many operations then become simple pairs of operations, for example
// bitwise AND becomes and AND of each 32-bit chunk. More complex operations
// like addition are lowered into calls into library support code in
// Emscripten (i64Add for example).
//
//===------------------------------------------------------------------===//
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CFG.h"
#include "llvm/Transforms/NaCl.h"
#include <map>
#include "llvm/Support/raw_ostream.h"
#ifdef NDEBUG
#undef assert
#define assert(x) { if (!(x)) report_fatal_error(#x); }
#endif
using namespace llvm;
namespace {
typedef SmallVector<Value*, 2> ChunksVec;
typedef std::map<Value*, ChunksVec> SplitsMap;
typedef SmallVector<PHINode *, 8> PHIVec;
typedef SmallVector<Instruction *, 8> DeadVec;
// This is a ModulePass because the pass recreates functions in
// order to expand i64 arguments to pairs of i32s.
class ExpandI64 : public ModulePass {
bool Changed;
DataLayout *DL;
Module *TheModule;
SplitsMap Splits; // old illegal value to new insts
PHIVec Phis;
// If the function has an illegal return or argument, create a legal version
void ensureLegalFunc(Function *F);
// If a function is illegal, remove it
void removeIllegalFunc(Function *F);
// splits an illegal instruction into 32-bit chunks. We do
// not yet have the values yet, as they depend on other
// splits, so store the parts in Splits, for FinalizeInst.
bool splitInst(Instruction *I);
// For an illegal value, returns the split out chunks
// representing the low and high parts, that splitInst
// generated.
// The value can also be a constant, in which case we just
// split it, or a function argument, in which case we
// map to the proper legalized new arguments
ChunksVec getChunks(Value *V);
Function *Add, *Sub, *Mul, *SDiv, *UDiv, *SRem, *URem, *LShr, *AShr, *Shl, *GetHigh, *SetHigh, *FtoILow, *FtoIHigh, *DtoILow, *DtoIHigh, *SItoF, *UItoF, *SItoD, *UItoD, *BItoD, *BDtoILow, *BDtoIHigh;
void ensureFuncs();
unsigned getNumChunks(Type *T);
public:
static char ID;
ExpandI64() : ModulePass(ID) {
initializeExpandI64Pass(*PassRegistry::getPassRegistry());
Add = Sub = Mul = SDiv = UDiv = SRem = URem = LShr = AShr = Shl = GetHigh = SetHigh = NULL;
}
virtual bool runOnModule(Module &M);
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
char ExpandI64::ID = 0;
INITIALIZE_PASS(ExpandI64, "expand-illegal-ints",
"Expand and lower illegal >i32 operations into 32-bit chunks",
false, false)
// Utilities
static bool isIllegal(Type *T) {
return T->isIntegerTy() && T->getIntegerBitWidth() > 32;
}
static FunctionType *getLegalizedFunctionType(FunctionType *FT) {
SmallVector<Type*, 0> ArgTypes; // XXX
int Num = FT->getNumParams();
for (int i = 0; i < Num; i++) {
Type *T = FT->getParamType(i);
if (!isIllegal(T)) {
ArgTypes.push_back(T);
} else {
Type *i32 = Type::getInt32Ty(FT->getContext());
ArgTypes.push_back(i32);
ArgTypes.push_back(i32);
}
}
Type *RT = FT->getReturnType();
Type *NewRT;
if (!isIllegal(