diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-02-14 14:51:06 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-02-14 14:51:06 -0800 |
commit | b3d5de7043272a13341ea7ae0ac176a5782f13a7 (patch) | |
tree | 4f9c9aeab4d4b8aa07a6428e21ceb89552c46d37 | |
parent | 9c0197b97dc9b5be2132f8e6ebe9737d0d7dd7c1 (diff) | |
parent | 8dd47ed0fe367f1d6c0f7cb404d58b24be8b6f5c (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.h | 28 | ||||
-rw-r--r-- | lib/Target/JSBackend/JSBackend.cpp | 84 | ||||
-rw-r--r-- | lib/Target/JSBackend/SimplifyAllocas.cpp | 9 | ||||
-rw-r--r-- | lib/Transforms/NaCl/ExpandI64.cpp | 10 | ||||
-rw-r--r-- | lib/Transforms/NaCl/PNaClABISimplify.cpp | 4 | ||||
-rw-r--r-- | lib/Transforms/NaCl/PromoteIntegers.cpp | 43 | ||||
-rw-r--r-- | test/Transforms/NaCl/expand-i64.ll | 29 | ||||
-rw-r--r-- | test/Transforms/NaCl/promote-integer-align.ll | 29 |
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 +} |