aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Gohman <sunfish@google.com>2014-02-13 19:24:56 -0800
committerDan Gohman <sunfish@google.com>2014-02-14 11:38:16 -0800
commit71fb6dcb87d2abd302080149d4a583a5e35e3697 (patch)
tree8fd196d2d2b3ddad6188d72dbfc481395f620d19
parentf3359807242e95f9e94bb35c0d90a73c794f1af0 (diff)
Preserve alignment information when promoting integer loads and stores.
-rw-r--r--lib/Transforms/NaCl/PromoteIntegers.cpp43
-rw-r--r--test/Transforms/NaCl/promote-integer-align.ll29
2 files changed, 67 insertions, 5 deletions
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/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
+}