aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-02-14 14:51:06 -0800
committerAlon Zakai <alonzakai@gmail.com>2014-02-14 14:51:06 -0800
commitb3d5de7043272a13341ea7ae0ac176a5782f13a7 (patch)
tree4f9c9aeab4d4b8aa07a6428e21ceb89552c46d37
parent9c0197b97dc9b5be2132f8e6ebe9737d0d7dd7c1 (diff)
parent8dd47ed0fe367f1d6c0f7cb404d58b24be8b6f5c (diff)
Merge pull request #14 from sunfishcode/incoming
Instead of lowering pointers, teach the JSBackend how to handle them
-rw-r--r--lib/Target/JSBackend/CallHandlers.h28
-rw-r--r--lib/Target/JSBackend/JSBackend.cpp84
-rw-r--r--lib/Target/JSBackend/SimplifyAllocas.cpp9
-rw-r--r--lib/Transforms/NaCl/ExpandI64.cpp10
-rw-r--r--lib/Transforms/NaCl/PNaClABISimplify.cpp4
-rw-r--r--lib/Transforms/NaCl/PromoteIntegers.cpp43
-rw-r--r--test/Transforms/NaCl/expand-i64.ll29
-rw-r--r--test/Transforms/NaCl/promote-integer-align.ll29
8 files changed, 169 insertions, 67 deletions
diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h
index e88b781cb4..4a57bcddc2 100644
--- a/lib/Target/JSBackend/CallHandlers.h
+++ b/lib/Target/JSBackend/CallHandlers.h
@@ -10,28 +10,18 @@ CallHandlerMap *CallHandlers;
// Definitions
unsigned getNumArgOperands(const Instruction *I) {
- if (const CallInst *CI = dyn_cast<const CallInst>(I)) {
- return CI->getNumArgOperands();
- } else {
- return cast<const InvokeInst>(I)->getNumArgOperands();
- }
+ return ImmutableCallSite(I).arg_size();
}
const Value *getActuallyCalledValue(const Instruction *I) {
- const Value *CV = NULL;
- if (const CallInst *CI = dyn_cast<const CallInst>(I)) {
- CV = CI->getCalledValue();
- } else {
- CV = cast<const InvokeInst>(I)->getCalledValue();
- }
- if (const BitCastInst *B = dyn_cast<const BitCastInst>(CV)) {
- // if the called value is a bitcast of a function, then we just call it directly, properly
- // for example, extern void x() in C will turn into void x(...) in LLVM IR, then the IR bitcasts
- // it to the proper form right before the call. this both causes an unnecessary indirect
- // call, and it is done with the wrong type. TODO: don't even put it into the function table
- if (const Function *F = dyn_cast<const Function>(B->getOperand(0))) {
- CV = F;
- }
+ const Value *CV = ImmutableCallSite(I).getCalledValue();
+
+ // if the called value is a bitcast of a function, then we just call it directly, properly
+ // for example, extern void x() in C will turn into void x(...) in LLVM IR, then the IR bitcasts
+ // it to the proper form right before the call. this both causes an unnecessary indirect
+ // call, and it is done with the wrong type. TODO: don't even put it into the function table
+ if (const Function *F = dyn_cast<const Function>(CV->stripPointerCasts())) {
+ CV = F;
}
return CV;
}
diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp
index 0d83a6a319..dc2404866a 100644
--- a/lib/Target/JSBackend/JSBackend.cpp
+++ b/lib/Target/JSBackend/JSBackend.cpp
@@ -30,6 +30,7 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Pass.h"
#include "llvm/PassManager.h"
+#include "llvm/Support/CallSite.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
@@ -303,7 +304,7 @@ namespace {
}
std::string getPtrAsStr(const Value* Ptr) {
Ptr = Ptr->stripPointerCasts();
- if (isa<const ConstantPointerNull>(Ptr)) return "0";
+ if (isa<const ConstantPointerNull>(Ptr) || isa<UndefValue>(Ptr)) return "0";
if (const Function *F = dyn_cast<Function>(Ptr)) {
return utostr(getFunctionIndex(F));
} else if (const Constant *CV = dyn_cast<Constant>(Ptr)) {
@@ -344,13 +345,13 @@ namespace {
void printType(Type* Ty);
void printTypes(const Module* M);
- std::string getAssign(const StringRef &, const Type *);
- std::string getCast(const StringRef &, const Type *, AsmCast sign=ASM_SIGNED);
- std::string getParenCast(const StringRef &, const Type *, AsmCast sign=ASM_SIGNED);
+ std::string getAssign(const StringRef &, Type *);
+ std::string getCast(const StringRef &, Type *, AsmCast sign=ASM_SIGNED);
+ std::string getParenCast(const StringRef &, Type *, AsmCast sign=ASM_SIGNED);
std::string getDoubleToInt(const StringRef &);
std::string getIMul(const Value *, const Value *);
- std::string getLoad(const Instruction *I, const Value *P, const Type *T, unsigned Alignment, char sep=';');
- std::string getStore(const Instruction *I, const Value *P, const Type *T, const std::string& VS, unsigned Alignment, char sep=';');
+ std::string getLoad(const Instruction *I, const Value *P, Type *T, unsigned Alignment, char sep=';');
+ std::string getStore(const Instruction *I, const Value *P, Type *T, const std::string& VS, unsigned Alignment, char sep=';');
void printFunctionBody(const Function *F);
bool generateSIMDInstruction(const std::string &iName, const Instruction *I, raw_string_ostream& Code);
@@ -485,12 +486,12 @@ const std::string &JSWriter::getJSName(const Value* val) {
return ValueNames[val] = name;
}
-std::string JSWriter::getAssign(const StringRef &s, const Type *t) {
+std::string JSWriter::getAssign(const StringRef &s, Type *t) {
UsedVars[s] = t->getTypeID();
return (s + " = ").str();
}
-std::string JSWriter::getCast(const StringRef &s, const Type *t, AsmCast sign) {
+std::string JSWriter::getCast(const StringRef &s, Type *t, AsmCast sign) {
switch (t->getTypeID()) {
default: {
// some types we cannot cast, like vectors - ignore
@@ -517,11 +518,12 @@ std::string JSWriter::getCast(const StringRef &s, const Type *t, AsmCast sign) {
default: llvm_unreachable("Unsupported integer cast bitwidth");
}
}
- case Type::PointerTyID: return (s + "|0").str();
+ case Type::PointerTyID:
+ return (sign == ASM_SIGNED || (sign & ASM_NONSPECIFIC) ? s + "|0" : s + ">>>0").str();
}
}
-std::string JSWriter::getParenCast(const StringRef &s, const Type *t, AsmCast sign) {
+std::string JSWriter::getParenCast(const StringRef &s, Type *t, AsmCast sign) {
return getCast(("(" + s + ")").str(), t, sign);
}
@@ -555,15 +557,28 @@ std::string JSWriter::getIMul(const Value *V1, const Value *V2) {
return "Math_imul(" + getValueAsStr(V1) + ", " + getValueAsStr(V2) + ")|0"; // unknown or too large, emit imul
}
-std::string JSWriter::getLoad(const Instruction *I, const Value *P, const Type *T, unsigned Alignment, char sep) {
+// Test whether the given value is known to be a null pointer.
+static bool isAbsolute(const Value *P) {
+ if (const IntToPtrInst *ITP = dyn_cast<IntToPtrInst>(P)) {
+ return isa<ConstantInt>(ITP->getOperand(0));
+ }
+
+ if (isa<ConstantPointerNull>(P)) {
+ return true;
+ }
+
+ return false;
+}
+
+std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, unsigned Alignment, char sep) {
std::string Assign = getAssign(getJSName(I), I->getType());
unsigned Bytes = T->getPrimitiveSizeInBits()/8;
std::string text;
if (Bytes <= Alignment || Alignment == 0) {
text = Assign + getPtrLoad(P);
- if (const IntToPtrInst *ITP = dyn_cast<IntToPtrInst>(P)) {
+ if (isAbsolute(P)) {
// loads from an absolute constants are either intentional segfaults (int x = *((int*)0)), or code problems
- if (isa<ConstantInt>(ITP->getOperand(0))) text += "; abort() /* segfault, load from absolute addr */";
+ text += "; abort() /* segfault, load from absolute addr */";
}
} else {
// unaligned in some manner
@@ -605,7 +620,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, const Type *
break;
}
case 4: {
- if (T->isIntegerTy()) {
+ if (T->isIntegerTy() || T->isPointerTy()) {
switch (Alignment) {
case 2: {
text = Assign + "HEAPU16[" + PS + ">>1]|" +
@@ -622,6 +637,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, const Type *
default: assert(0 && "bad 4i store");
}
} else { // float
+ assert(T->isFloatingPointTy());
switch (Alignment) {
case 2: {
text = "HEAP16[tempDoublePtr>>1]=HEAP16[" + PS + ">>1]" + sep +
@@ -652,9 +668,9 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, const Type *
return text;
}
-std::string JSWriter::getStore(const Instruction *I, const Value *P, const Type *T, const std::string& VS, unsigned Alignment, char sep) {
+std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, const std::string& VS, unsigned Alignment, char sep) {
assert(sep == ';'); // FIXME when we need that
- unsigned Bytes = T->getPrimitiveSizeInBits()/8;
+ unsigned Bytes = DL->getTypeAllocSize(T);
std::string text;
if (Bytes <= Alignment || Alignment == 0) {
text = getPtrUse(P) + " = " + VS;
@@ -699,7 +715,7 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, const Type
break;
}
case 4: {
- if (T->isIntegerTy()) {
+ if (T->isIntegerTy() || T->isPointerTy()) {
switch (Alignment) {
case 2: {
text = "HEAP16[" + PS + ">>1]=" + VS + "&65535;" +
@@ -716,6 +732,7 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, const Type
default: assert(0 && "bad 4i store");
}
} else { // float
+ assert(T->isFloatingPointTy());
text = "HEAPF32[tempDoublePtr>>2]=" + VS + ';';
switch (Alignment) {
case 2: {
@@ -773,7 +790,7 @@ std::string JSWriter::getHeapAccess(const std::string& Name, unsigned Bytes, boo
std::string JSWriter::getPtrUse(const Value* Ptr) {
Type *t = cast<PointerType>(Ptr->getType())->getElementType();
- unsigned Bytes = t->getPrimitiveSizeInBits()/8;
+ unsigned Bytes = DL->getTypeAllocSize(t);
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) {
std::string text = "";
unsigned Addr = getGlobalAddress(GV->getName().str());
@@ -781,9 +798,10 @@ std::string JSWriter::getPtrUse(const Value* Ptr) {
default: llvm_unreachable("Unsupported type");
case 8: return "HEAPF64[" + utostr(Addr >> 3) + "]";
case 4: {
- if (t->isIntegerTy()) {
+ if (t->isIntegerTy() || t->isPointerTy()) {
return "HEAP32[" + utostr(Addr >> 2) + "]";
} else {
+ assert(t->isFloatingPointTy());
return "HEAPF32[" + utostr(Addr >> 2) + "]";
}
}
@@ -791,7 +809,7 @@ std::string JSWriter::getPtrUse(const Value* Ptr) {
case 1: return "HEAP8[" + utostr(Addr) + "]";
}
} else {
- return getHeapAccess(getOpName(Ptr), Bytes, t->isIntegerTy());
+ return getHeapAccess(getPtrAsStr(Ptr), Bytes, t->isIntegerTy() || t->isPointerTy());
}
}
@@ -870,7 +888,7 @@ std::string JSWriter::getConstant(const Constant* CV, AsmCast sign) {
}
return CI->getValue().toString(10, sign != ASM_UNSIGNED);
} else if (isa<UndefValue>(CV)) {
- return CV->getType()->isIntegerTy() ? "0" : getCast("0", CV->getType());
+ return CV->getType()->isIntegerTy() || CV->getType()->isPointerTy() ? "0" : getCast("0", CV->getType());
} else if (isa<ConstantAggregateZero>(CV)) {
if (VectorType *VT = dyn_cast<VectorType>(CV->getType())) {
if (VT->getElementType()->isIntegerTy()) {
@@ -1266,18 +1284,12 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
}
Type *T = AI->getAllocatedType();
std::string Size;
- if (T->isVectorTy()) {
- checkVectorType(T);
- Size = "16";
+ uint64_t BaseSize = DL->getTypeAllocSize(T);
+ const Value *AS = AI->getArraySize();
+ if (const ConstantInt *CI = dyn_cast<ConstantInt>(AS)) {
+ Size = Twine(memAlign(BaseSize * CI->getZExtValue())).str();
} else {
- assert(!isa<ArrayType>(T));
- const Value *AS = AI->getArraySize();
- unsigned BaseSize = T->getScalarSizeInBits()/8;
- if (const ConstantInt *CI = dyn_cast<ConstantInt>(AS)) {
- Size = Twine(memAlign(BaseSize * CI->getZExtValue())).str();
- } else {
- Size = memAlignStr("((" + utostr(BaseSize) + '*' + getValueAsStr(AS) + ")|0)");
- }
+ Size = memAlignStr("((" + utostr(BaseSize) + '*' + getValueAsStr(AS) + ")|0)");
}
Code << getAssign(iName, Type::getInt32Ty(I->getContext())) << "STACKTOP; STACKTOP = STACKTOP + " << Size << "|0;";
break;
@@ -1556,8 +1568,8 @@ void JSWriter::printFunctionBody(const Function *F) {
R.Render();
// Emit local variables
- UsedVars["sp"] = Type::getInt32Ty(F->getContext())->getTypeID();
- UsedVars["label"] = Type::getInt32Ty(F->getContext())->getTypeID();
+ UsedVars["sp"] = Type::IntegerTyID;
+ UsedVars["label"] = Type::IntegerTyID;
if (!UsedVars.empty()) {
unsigned Count = 0;
for (VarMap::const_iterator VI = UsedVars.begin(); VI != UsedVars.end(); ++VI) {
@@ -1670,9 +1682,8 @@ void JSWriter::printFunction(const Function *F) {
if (const AllocaInst* AI = dyn_cast<AllocaInst>(II)) {
Type *T = AI->getAllocatedType();
if (!T->isVectorTy()) {
- assert(!isa<ArrayType>(T));
const Value *AS = AI->getArraySize();
- unsigned BaseSize = T->getScalarSizeInBits()/8;
+ unsigned BaseSize = DL->getTypeAllocSize(T);
if (const ConstantInt *CI = dyn_cast<ConstantInt>(AS)) {
// TODO: group by alignment to avoid unnecessary padding
unsigned Size = memAlign(BaseSize * CI->getZExtValue());
@@ -2072,6 +2083,7 @@ void JSWriter::calculateNativizedVars(const Function *F) {
const Instruction *I = &*II;
if (const AllocaInst *AI = dyn_cast<const AllocaInst>(I)) {
if (AI->getAllocatedType()->isVectorTy()) continue; // we do not nativize vectors, we rely on the LLVM optimizer to avoid load/stores on them
+ if (AI->getAllocatedType()->isAggregateType()) continue; // we do not nativize aggregates either
// this is on the stack. if its address is never used nor escaped, we can nativize it
bool Fail = false;
for (Instruction::const_use_iterator UI = I->use_begin(), UE = I->use_end(); UI != UE && !Fail; ++UI) {
diff --git a/lib/Target/JSBackend/SimplifyAllocas.cpp b/lib/Target/JSBackend/SimplifyAllocas.cpp
index 2fda6be948..858ded32a1 100644
--- a/lib/Target/JSBackend/SimplifyAllocas.cpp
+++ b/lib/Target/JSBackend/SimplifyAllocas.cpp
@@ -72,12 +72,11 @@ bool SimplifyAllocas::runOnFunction(Function &Func) {
}
std::vector<Instruction*> Aliases; // the bitcasts of this alloca
for (Instruction::use_iterator UI = AI->use_begin(), UE = AI->use_end(); UI != UE && !Fail; ++UI) {
- Instruction *U = dyn_cast<Instruction>(*UI);
- if (!U || U->getOpcode() != Instruction::BitCast) { Fail = true; break; }
+ Instruction *U = cast<Instruction>(*UI);
+ if (U->getOpcode() != Instruction::BitCast) { Fail = true; break; }
// bitcasting just to do loads and stores is ok
for (Instruction::use_iterator BUI = U->use_begin(), BUE = U->use_end(); BUI != BUE && !Fail; ++BUI) {
- Instruction *BU = dyn_cast<Instruction>(*BUI);
- if (!BU) { Fail = true; break; }
+ Instruction *BU = cast<Instruction>(*BUI);
if (BU->getOpcode() == Instruction::Load) {
CHECK_TYPE(BU->getType());
break;
@@ -88,7 +87,7 @@ bool SimplifyAllocas::runOnFunction(Function &Func) {
}
if (!Fail) Aliases.push_back(U);
}
- if (!Fail && Aliases.size() > 0) {
+ if (!Fail && Aliases.size() > 0 && ActualType) {
// success, replace the alloca and the bitcast aliases with a single simple alloca
AllocaInst *NA = new AllocaInst(ActualType, ConstantInt::get(i32, 1), "", I);
NA->takeName(AI);
diff --git a/lib/Transforms/NaCl/ExpandI64.cpp b/lib/Transforms/NaCl/ExpandI64.cpp
index ae3b67e6e7..6034880613 100644
--- a/lib/Transforms/NaCl/ExpandI64.cpp
+++ b/lib/Transforms/NaCl/ExpandI64.cpp
@@ -389,7 +389,10 @@ bool ExpandI64::splitInst(Instruction *I) {
Instruction *Add = i == 0 ? AI : CopyDebug(BinaryOperator::Create(Instruction::Add, AI, ConstantInt::get(i32, 4*i), "", I), I);
Instruction *Ptr = CopyDebug(new IntToPtrInst(Add, i32P, "", I), I);
LoadInst *Chunk = new LoadInst(Ptr, "", I); CopyDebug(Chunk, I);
- Chunk->setAlignment(std::min(4U, LI->getAlignment()));
+ Chunk->setAlignment(MinAlign(LI->getAlignment() == 0 ?
+ DL->getABITypeAlignment(LI->getType()) :
+ LI->getAlignment(),
+ 4*i));
Chunk->setVolatile(LI->isVolatile());
Chunk->setOrdering(LI->getOrdering());
Chunk->setSynchScope(LI->getSynchScope());
@@ -406,7 +409,10 @@ bool ExpandI64::splitInst(Instruction *I) {
Instruction *Add = i == 0 ? AI : CopyDebug(BinaryOperator::Create(Instruction::Add, AI, ConstantInt::get(i32, 4*i), "", I), I);
Instruction *Ptr = CopyDebug(new IntToPtrInst(Add, i32P, "", I), I);
StoreInst *Chunk = new StoreInst(InputChunks[i], Ptr, I);
- Chunk->setAlignment(std::min(4U, SI->getAlignment()));
+ Chunk->setAlignment(MinAlign(SI->getAlignment() == 0 ?
+ DL->getABITypeAlignment(SI->getValueOperand()->getType()) :
+ SI->getAlignment(),
+ 4*i));
Chunk->setVolatile(SI->isVolatile());
Chunk->setOrdering(SI->getOrdering());
Chunk->setSynchScope(SI->getSynchScope());
diff --git a/lib/Transforms/NaCl/PNaClABISimplify.cpp b/lib/Transforms/NaCl/PNaClABISimplify.cpp
index 1cde8897f2..2b7ff9ca5d 100644
--- a/lib/Transforms/NaCl/PNaClABISimplify.cpp
+++ b/lib/Transforms/NaCl/PNaClABISimplify.cpp
@@ -106,9 +106,11 @@ void llvm::PNaClABISimplifyAddPostOptPasses(PassManager &PM) {
// This pass converts those arguments to 32-bit.
PM.add(createCanonicalizeMemIntrinsicsPass());
+#if 0 // XXX EMSCRIPTEN: PNaCl strips metadata to avoid making it ABI-exposed; empscripten doesn't need this.
// We place StripMetadata after optimization passes because
// optimizations depend on the metadata.
PM.add(createStripMetadataPass());
+#endif
// FlattenGlobals introduces ConstantExpr bitcasts of globals which
// are expanded out later.
@@ -131,9 +133,11 @@ void llvm::PNaClABISimplifyAddPostOptPasses(PassManager &PM) {
// atomics: a ``fence seq_cst`` surrounded by ``asm("":::"memory")``
// has special meaning and is translated differently.
PM.add(createRemoveAsmMemoryPass());
+#if 0 // XXX EMSCRIPTEN: PNaCl replaces pointers with ints to simplify their ABI; empscripten doesn't need this.
// ReplacePtrsWithInts assumes that getelementptr instructions and
// ConstantExprs have already been expanded out.
PM.add(createReplacePtrsWithIntsPass());
+#endif
// We place StripAttributes after optimization passes because many
// analyses add attributes to reflect their results.
diff --git a/lib/Transforms/NaCl/PromoteIntegers.cpp b/lib/Transforms/NaCl/PromoteIntegers.cpp
index d48bdfc37b..b8050b5ba2 100644
--- a/lib/Transforms/NaCl/PromoteIntegers.cpp
+++ b/lib/Transforms/NaCl/PromoteIntegers.cpp
@@ -43,13 +43,25 @@
using namespace llvm;
namespace {
+class ConversionState;
+
class PromoteIntegers : public FunctionPass {
+ DataLayout *DL;
+
+ Value *splitLoad(LoadInst *Inst, ConversionState &State);
+ Value *splitStore(StoreInst *Inst, ConversionState &State);
+ void convertInstruction(Instruction *Inst, ConversionState &State);
+
public:
static char ID;
PromoteIntegers() : FunctionPass(ID) {
initializePromoteIntegersPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnFunction(Function &F);
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<DataLayout>();
+ return FunctionPass::getAnalysisUsage(AU);
+ }
};
}
@@ -135,6 +147,8 @@ static Value *convertConstant(Constant *C, bool SignExt=false) {
}
}
+namespace {
+
// Holds the state for converting/replacing values. Conversion is done in one
// pass, with each value requiring conversion possibly having two stages. When
// an instruction needs to be replaced (i.e. it has illegal operands or result)
@@ -212,9 +226,11 @@ class ConversionState {
SmallVector<Instruction *, 8> ToErase;
};
+} // anonymous namespace
+
// Split an illegal load into multiple legal loads and return the resulting
// promoted value. The size of the load is assumed to be a multiple of 8.
-static Value *splitLoad(LoadInst *Inst, ConversionState &State) {
+Value *PromoteIntegers::splitLoad(LoadInst *Inst, ConversionState &State) {
if (Inst->isVolatile() || Inst->isAtomic())
report_fatal_error("Can't split volatile/atomic loads");
if (cast<IntegerType>(Inst->getType())->getBitWidth() % 8 != 0)
@@ -246,7 +262,15 @@ static Value *splitLoad(LoadInst *Inst, ConversionState &State) {
HiType->getPointerTo(),
OrigPtr->getName() + ".hity");
- Value *LoadHi = IRB.CreateAlignedLoad(BCHi, 1, Inst->getName() + ".hi"); // XXX EMSCRIPTEN: worst-case alignment assumption
+#if 0 // XXX EMSCRIPTEN: We want the full-strength alignment.
+ Value *LoadHi = IRB.CreateAlignedLoad(BCHi, 1, Inst->getName() + ".hi");
+#else
+ unsigned HiAlign = MinAlign(Inst->getAlignment() == 0 ?
+ DL->getABITypeAlignment(Inst->getType()) :
+ Inst->getAlignment(),
+ LoWidth / 8);
+ Value *LoadHi = IRB.CreateAlignedLoad(BCHi, HiAlign, Inst->getName() + ".hi");
+#endif
if (!isLegalSize(Width - LoWidth)) {
LoadHi = splitLoad(cast<LoadInst>(LoadHi), State);
#if 0 /// XXX EMSCRIPTEN: We don't need to convert pointers.
@@ -266,7 +290,7 @@ static Value *splitLoad(LoadInst *Inst, ConversionState &State) {
return Result;
}
-static Value *splitStore(StoreInst *Inst, ConversionState &State) {
+Value *PromoteIntegers::splitStore(StoreInst *Inst, ConversionState &State) {
if (Inst->isVolatile() || Inst->isAtomic())
report_fatal_error("Can't split volatile/atomic stores");
if (cast<IntegerType>(Inst->getValueOperand()->getType())->getBitWidth() % 8
@@ -305,7 +329,15 @@ static Value *splitStore(StoreInst *Inst, ConversionState &State) {
HiType->getPointerTo(),
OrigPtr->getName() + ".hity");
- Value *StoreHi = IRB.CreateAlignedStore(HiTrunc, BCHi, 1); // XXX EMSCRIPTEN: worst-case alignment assumption
+#if 0 // XXX EMSCRIPTEN: We want the full-strength alignment.
+ Value *StoreHi = IRB.CreateAlignedStore(HiTrunc, BCHi, 1);
+#else
+ unsigned HiAlign = MinAlign(Inst->getAlignment() == 0 ?
+ DL->getABITypeAlignment(Inst->getValueOperand()->getType()) :
+ Inst->getAlignment(),
+ LoWidth / 8);
+ Value *StoreHi = IRB.CreateAlignedStore(HiTrunc, BCHi, HiAlign);
+#endif
if (!isLegalSize(Width - LoWidth)) {
// HiTrunc is still illegal, and is redundant with the truncate in the
@@ -389,7 +421,7 @@ static Value *getSignExtend(Value *Operand, Value *OrigOperand,
InsertPt), Shl);
}
-static void convertInstruction(Instruction *Inst, ConversionState &State) {
+void PromoteIntegers::convertInstruction(Instruction *Inst, ConversionState &State) {
if (SExtInst *Sext = dyn_cast<SExtInst>(Inst)) {
Value *Op = Sext->getOperand(0);
Value *NewInst = NULL;
@@ -642,6 +674,7 @@ static void convertInstruction(Instruction *Inst, ConversionState &State) {
}
bool PromoteIntegers::runOnFunction(Function &F) {
+ DL = &getAnalysis<DataLayout>();
// Don't support changing the function arguments. This should not be
// generated by clang.
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) {
diff --git a/test/Transforms/NaCl/expand-i64.ll b/test/Transforms/NaCl/expand-i64.ll
index df4804d19b..fd468fc6d1 100644
--- a/test/Transforms/NaCl/expand-i64.ll
+++ b/test/Transforms/NaCl/expand-i64.ll
@@ -217,6 +217,21 @@ define i64 @load(i64 *%a) {
ret i64 %c
}
+; CHECK: define i32 @aligned_load(i64* %a) {
+; CHECK: %1 = ptrtoint i64* %a to i32
+; CHECK: %2 = inttoptr i32 %1 to i32*
+; CHECK: %3 = load i32* %2, align 16
+; CHECK: %4 = add i32 %1, 4
+; CHECK: %5 = inttoptr i32 %4 to i32*
+; CHECK: %6 = load i32* %5, align 4
+; CHECK: call void @setHigh32(i32 %6)
+; CHECK: ret i32 %3
+; CHECK: }
+define i64 @aligned_load(i64 *%a) {
+ %c = load i64* %a, align 16
+ ret i64 %c
+}
+
; CHECK: define void @store(i64* %a, i32, i32) {
; CHECK: %3 = ptrtoint i64* %a to i32
; CHECK: %4 = inttoptr i32 %3 to i32*
@@ -231,6 +246,20 @@ define void @store(i64 *%a, i64 %b) {
ret void
}
+; CHECK: define void @aligned_store(i64* %a, i32, i32) {
+; CHECK: %3 = ptrtoint i64* %a to i32
+; CHECK: %4 = inttoptr i32 %3 to i32*
+; CHECK: store i32 %0, i32* %4, align 16
+; CHECK: %5 = add i32 %3, 4
+; CHECK: %6 = inttoptr i32 %5 to i32*
+; CHECK: store i32 %1, i32* %6, align 4
+; CHECK: ret void
+; CHECK: }
+define void @aligned_store(i64 *%a, i64 %b) {
+ store i64 %b, i64* %a, align 16
+ ret void
+}
+
; CHECK: define i32 @call(i32, i32) {
; CHECK: %3 = call i32 @foo(i32 %0, i32 %1)
; CHECK: %4 = call i32 @getHigh32()
diff --git a/test/Transforms/NaCl/promote-integer-align.ll b/test/Transforms/NaCl/promote-integer-align.ll
new file mode 100644
index 0000000000..0866d99a72
--- /dev/null
+++ b/test/Transforms/NaCl/promote-integer-align.ll
@@ -0,0 +1,29 @@
+; RUN: opt -S -nacl-promote-ints < %s | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
+
+; CHECK: define void @aligned_copy(i24* %p, i24* %q) {
+; CHECK-NEXT: %p.loty = bitcast i24* %p to i16*
+; CHECK-NEXT: %t.lo = load i16* %p.loty, align 64
+; CHECK-NEXT: %t.lo.ext = zext i16 %t.lo to i32
+; CHECK-NEXT: %p.hi = getelementptr i16* %p.loty, i32 1
+; CHECK-NEXT: %p.hity = bitcast i16* %p.hi to i8*
+; CHECK-NEXT: %t.hi = load i8* %p.hity, align 1
+; CHECK-NEXT: %t.hi.ext = zext i8 %t.hi to i32
+; CHECK-NEXT: %t.hi.ext.sh = shl i32 %t.hi.ext, 16
+; CHECK-NEXT: %t = or i32 %t.lo.ext, %t.hi.ext.sh
+; CHECK-NEXT: %q.loty = bitcast i24* %q to i16*
+; CHECK-NEXT: %t.lo1 = trunc i32 %t to i16
+; CHECK-NEXT: store i16 %t.lo1, i16* %q.loty, align 64
+; CHECK-NEXT: %t.hi.sh = lshr i32 %t, 16
+; CHECK-NEXT: %q.hi = getelementptr i16* %q.loty, i32 1
+; CHECK-NEXT: %t.hi2 = trunc i32 %t.hi.sh to i8
+; CHECK-NEXT: %q.hity = bitcast i16* %q.hi to i8*
+; CHECK-NEXT: store i8 %t.hi2, i8* %q.hity, align 1
+; CHECK-NEXT: ret void
+; CHECK-NEXT:}
+define void @aligned_copy(i24* %p, i24* %q) {
+ %t = load i24* %p, align 64
+ store i24 %t, i24* %q, align 64
+ ret void
+}