summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuiling Song <ruiling.song@intel.com>2015-02-11 15:08:15 +0800
committerZhigang Gong <zhigang.gong@intel.com>2015-02-11 16:32:40 +0800
commite830f258d0fdd91392eaf44dd5e64642b2ff3118 (patch)
treef047547115486ef26788a409d1bf684807c9cbf0
parent80a77ec73811a14625122b71ebc21a8a8c670d66 (diff)
GBE: Import PromoteIntegers pass from pNaCl
This is used to solve the integer bitwidth that is not power of two. Signed-off-by: Ruiling Song <ruiling.song@intel.com> Reviewed-by: Zhigang Gong <zhigang.gong@linux.intel.com>
-rw-r--r--backend/src/CMakeLists.txt1
-rw-r--r--backend/src/llvm/PromoteIntegers.cpp655
-rw-r--r--backend/src/llvm/llvm_gen_backend.hpp1
-rw-r--r--backend/src/llvm/llvm_to_gen.cpp1
4 files changed, 658 insertions, 0 deletions
diff --git a/backend/src/CMakeLists.txt b/backend/src/CMakeLists.txt
index 04f39180..a21918c8 100644
--- a/backend/src/CMakeLists.txt
+++ b/backend/src/CMakeLists.txt
@@ -86,6 +86,7 @@ set (GBE_SRC
llvm/llvm_printf_parser.cpp
llvm/ExpandConstantExpr.cpp
llvm/ExpandUtils.cpp
+ llvm/PromoteIntegers.cpp
llvm/ExpandLargeIntegers.cpp
llvm/llvm_to_gen.cpp
llvm/llvm_loadstore_optimization.cpp
diff --git a/backend/src/llvm/PromoteIntegers.cpp b/backend/src/llvm/PromoteIntegers.cpp
new file mode 100644
index 00000000..aba42b9e
--- /dev/null
+++ b/backend/src/llvm/PromoteIntegers.cpp
@@ -0,0 +1,655 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// Copyright (c) 2003-2014 University of Illinois at Urbana-Champaign.
+// All rights reserved.
+//
+// Developed by:
+//
+// LLVM Team
+//
+// University of Illinois at Urbana-Champaign
+//
+// http://llvm.org
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal with
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimers.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimers in the
+// documentation and/or other materials provided with the distribution.
+//
+// * Neither the names of the LLVM Team, University of Illinois at
+// Urbana-Champaign, nor the names of its contributors may be used to
+// endorse or promote products derived from this Software without specific
+// prior written permission.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+// SOFTWARE.
+
+//===- PromoteIntegers.cpp - Promote illegal integers for PNaCl ABI -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License.
+//
+// A limited set of transformations to promote illegal-sized int types.
+//
+//===----------------------------------------------------------------------===//
+//
+// Legal sizes are currently 1, 8, 16, 32, 64 (and higher, see note below).
+// Operations on illegal integers are changed to operate on the next-higher
+// legal size.
+// It maintains no invariants about the upper bits (above the size of the
+// original type); therefore before operations which can be affected by the
+// value of these bits (e.g. cmp, select, lshr), the upper bits of the operands
+// are cleared.
+//
+// Limitations:
+// 1) It can't change function signatures or global variables
+// 2) It won't promote (and can't expand) types larger than i64
+// 3) Doesn't support div operators
+// 4) Doesn't handle arrays or structs with illegal types
+// 5) Doesn't handle constant expressions (it also doesn't produce them, so it
+// can run after ExpandConstantExpr)
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm_gen_backend.hpp"
+
+using namespace llvm;
+
+namespace {
+class PromoteIntegers : public FunctionPass {
+ public:
+ static char ID;
+ PromoteIntegers() : FunctionPass(ID) {
+ }
+ virtual bool runOnFunction(Function &F);
+};
+}
+
+char PromoteIntegers::ID = 0;
+
+// Legal sizes are currently 1, 8, 16, 32, and 64.
+// We can't yet expand types above 64 bit, so don't try to touch them for now.
+// TODO(dschuff): expand >64bit types or disallow >64bit packed bitfields.
+// There are currently none in our tests that use the ABI checker.
+// See https://code.google.com/p/nativeclient/issues/detail?id=3360
+static bool isLegalSize(unsigned Size) {
+ if (Size > 64) return true;
+ return Size == 1 || Size == 8 || Size == 16 || Size == 32 || Size == 64;
+}
+
+static Type *getPromotedIntType(IntegerType *Ty) {
+ unsigned Width = Ty->getBitWidth();
+ assert(Width <= 64 && "Don't know how to legalize >64 bit types yet");
+ if (isLegalSize(Width))
+ return Ty;
+ return IntegerType::get(Ty->getContext(),
+ Width < 8 ? 8 : NextPowerOf2(Width));
+}
+
+// Return a legal integer type, promoting to a larger size if necessary.
+static Type *getPromotedType(Type *Ty) {
+ assert(isa<IntegerType>(Ty) && "Trying to convert a non-integer type");
+ return getPromotedIntType(cast<IntegerType>(Ty));
+}
+
+// Return true if Val is an int which should be converted.
+static bool shouldConvert(Value *Val) {
+ if (IntegerType *ITy = dyn_cast<IntegerType>(Val->getType())) {
+ if (!isLegalSize(ITy->getBitWidth())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Return a constant which has been promoted to a legal size.
+static Value *convertConstant(Constant *C, bool SignExt=false) {
+ assert(shouldConvert(C));
+ if (isa<UndefValue>(C)) {
+ return UndefValue::get(getPromotedType(C->getType()));
+ } else if (ConstantInt *CInt = dyn_cast<ConstantInt>(C)) {
+ return ConstantInt::get(
+ getPromotedType(C->getType()),
+ SignExt ? CInt->getSExtValue() : CInt->getZExtValue(),
+ /*isSigned=*/SignExt);
+ } else {
+ errs() << "Value: " << *C << "\n";
+ report_fatal_error("Unexpected constant value");
+ }
+}
+
+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)
+// a new instruction is created, and the pass calls getConverted to get its
+// operands. If the original operand has already been converted, the new value
+// is returned. Otherwise, a placeholder is created and used in the new
+// instruction. After a new instruction is created to replace an illegal one,
+// recordConverted is called to register the replacement. All users are updated,
+// and if there is a placeholder, its users are also updated.
+// recordConverted also queues the old value for deletion.
+// This strategy avoids the need for recursion or worklists for conversion.
+class ConversionState {
+ public:
+ // Return the promoted value for Val. If Val has not yet been converted,
+ // return a placeholder, which will be converted later.
+ Value *getConverted(Value *Val) {
+ if (!shouldConvert(Val))
+ return Val;
+ if (isa<GlobalVariable>(Val))
+ report_fatal_error("Can't convert illegal GlobalVariables");
+ if (RewrittenMap.count(Val))
+ return RewrittenMap[Val];
+
+ // Directly convert constants.
+ if (Constant *C = dyn_cast<Constant>(Val))
+ return convertConstant(C, /*SignExt=*/false);
+
+ // No converted value available yet, so create a placeholder.
+ Value *P = new Argument(getPromotedType(Val->getType()));
+
+ RewrittenMap[Val] = P;
+ Placeholders[Val] = P;
+ return P;
+ }
+
+ // Replace the uses of From with To, replace the uses of any
+ // placeholders for From, and optionally give From's name to To.
+ // Also mark To for deletion.
+ void recordConverted(Instruction *From, Value *To, bool TakeName=true) {
+ ToErase.push_back(From);
+ if (!shouldConvert(From)) {
+ // From does not produce an illegal value, update its users in place.
+ From->replaceAllUsesWith(To);
+ } else {
+ // From produces an illegal value, so its users will be replaced. When
+ // replacements are created they will use values returned by getConverted.
+ if (Placeholders.count(From)) {
+ // Users of the placeholder can be updated in place.
+ Placeholders[From]->replaceAllUsesWith(To);
+ Placeholders.erase(From);
+ }
+ RewrittenMap[From] = To;
+ }
+ if (TakeName) {
+ To->takeName(From);
+ }
+ }
+
+ void eraseReplacedInstructions() {
+ for (SmallVectorImpl<Instruction *>::iterator I = ToErase.begin(),
+ E = ToErase.end(); I != E; ++I)
+ (*I)->dropAllReferences();
+ for (SmallVectorImpl<Instruction *>::iterator I = ToErase.begin(),
+ E = ToErase.end(); I != E; ++I)
+ (*I)->eraseFromParent();
+ }
+
+ private:
+ // Maps illegal values to their new converted values (or placeholders
+ // if no new value is available yet)
+ DenseMap<Value *, Value *> RewrittenMap;
+ // Maps illegal values with no conversion available yet to their placeholders
+ DenseMap<Value *, Value *> Placeholders;
+ // Illegal values which have already been converted, will be erased.
+ 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) {
+ if (Inst->isVolatile() || Inst->isAtomic())
+ report_fatal_error("Can't split volatile/atomic loads");
+ if (cast<IntegerType>(Inst->getType())->getBitWidth() % 8 != 0)
+ report_fatal_error("Loads must be a multiple of 8 bits");
+
+ unsigned AddrSpace = Inst->getPointerAddressSpace();
+ Value *OrigPtr = State.getConverted(Inst->getPointerOperand());
+ // OrigPtr is a placeholder in recursive calls, and so has no name
+ if (OrigPtr->getName().empty())
+ OrigPtr->setName(Inst->getPointerOperand()->getName());
+ unsigned Width = cast<IntegerType>(Inst->getType())->getBitWidth();
+ Type *NewType = getPromotedType(Inst->getType());
+ unsigned LoWidth = Width;
+
+ while (!isLegalSize(LoWidth)) LoWidth -= 8;
+ IntegerType *LoType = IntegerType::get(Inst->getContext(), LoWidth);
+ IntegerType *HiType = IntegerType::get(Inst->getContext(), Width - LoWidth);
+ IRBuilder<> IRB(Inst);
+
+ Value *BCLo = IRB.CreateBitCast(
+ OrigPtr,
+ LoType->getPointerTo(AddrSpace),
+ OrigPtr->getName() + ".loty");
+ Value *LoadLo = IRB.CreateAlignedLoad(
+ BCLo, Inst->getAlignment(), Inst->getName() + ".lo");
+ Value *LoExt = IRB.CreateZExt(LoadLo, NewType, LoadLo->getName() + ".ext");
+ Value *GEPHi = IRB.CreateConstGEP1_32(BCLo, 1, OrigPtr->getName() + ".hi");
+ Value *BCHi = IRB.CreateBitCast(
+ GEPHi,
+ HiType->getPointerTo(AddrSpace),
+ OrigPtr->getName() + ".hity");
+
+ Value *LoadHi = IRB.CreateLoad(BCHi, Inst->getName() + ".hi");
+ if (!isLegalSize(Width - LoWidth)) {
+ LoadHi = splitLoad(cast<LoadInst>(LoadHi), State);
+ }
+
+ Value *HiExt = IRB.CreateZExt(LoadHi, NewType, LoadHi->getName() + ".ext");
+ Value *HiShift = IRB.CreateShl(HiExt, LoWidth, HiExt->getName() + ".sh");
+ Value *Result = IRB.CreateOr(LoExt, HiShift);
+
+ State.recordConverted(Inst, Result);
+
+ return Result;
+}
+
+static Value *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
+ != 0)
+ report_fatal_error("Stores must be a multiple of 8 bits");
+
+ unsigned AddrSpace = Inst->getPointerAddressSpace();
+ Value *OrigPtr = State.getConverted(Inst->getPointerOperand());
+ // OrigPtr is now a placeholder in recursive calls, and so has no name.
+ if (OrigPtr->getName().empty())
+ OrigPtr->setName(Inst->getPointerOperand()->getName());
+ Value *OrigVal = State.getConverted(Inst->getValueOperand());
+ unsigned Width = cast<IntegerType>(
+ Inst->getValueOperand()->getType())->getBitWidth();
+ unsigned LoWidth = Width;
+
+ while (!isLegalSize(LoWidth)) LoWidth -= 8;
+ IntegerType *LoType = IntegerType::get(Inst->getContext(), LoWidth);
+ IntegerType *HiType = IntegerType::get(Inst->getContext(), Width - LoWidth);
+ IRBuilder<> IRB(Inst);
+
+ Value *BCLo = IRB.CreateBitCast(
+ OrigPtr,
+ LoType->getPointerTo(AddrSpace),
+ OrigPtr->getName() + ".loty");
+ Value *LoTrunc = IRB.CreateTrunc(
+ OrigVal, LoType, OrigVal->getName() + ".lo");
+ IRB.CreateAlignedStore(LoTrunc, BCLo, Inst->getAlignment());
+
+ Value *HiLShr = IRB.CreateLShr(
+ OrigVal, LoWidth, OrigVal->getName() + ".hi.sh");
+ Value *GEPHi = IRB.CreateConstGEP1_32(BCLo, 1, OrigPtr->getName() + ".hi");
+ Value *HiTrunc = IRB.CreateTrunc(
+ HiLShr, HiType, OrigVal->getName() + ".hi");
+ Value *BCHi = IRB.CreateBitCast(
+ GEPHi,
+ HiType->getPointerTo(AddrSpace),
+ OrigPtr->getName() + ".hity");
+
+ Value *StoreHi = IRB.CreateStore(HiTrunc, BCHi);
+
+ if (!isLegalSize(Width - LoWidth)) {
+ // HiTrunc is still illegal, and is redundant with the truncate in the
+ // recursive call, so just get rid of it.
+ State.recordConverted(cast<Instruction>(HiTrunc), HiLShr,
+ /*TakeName=*/false);
+ StoreHi = splitStore(cast<StoreInst>(StoreHi), State);
+ }
+ State.recordConverted(Inst, StoreHi, /*TakeName=*/false);
+ return StoreHi;
+}
+
+// Return a converted value with the bits of the operand above the size of the
+// original type cleared.
+static Value *getClearConverted(Value *Operand, Instruction *InsertPt,
+ ConversionState &State) {
+ Type *OrigType = Operand->getType();
+ Instruction *OrigInst = dyn_cast<Instruction>(Operand);
+ Operand = State.getConverted(Operand);
+ // If the operand is a constant, it will have been created by
+ // ConversionState.getConverted, which zero-extends by default.
+ if (isa<Constant>(Operand))
+ return Operand;
+ Instruction *NewInst = BinaryOperator::Create(
+ Instruction::And,
+ Operand,
+ ConstantInt::get(
+ getPromotedType(OrigType),
+ APInt::getLowBitsSet(getPromotedType(OrigType)->getIntegerBitWidth(),
+ OrigType->getIntegerBitWidth())),
+ Operand->getName() + ".clear",
+ InsertPt);
+ if (OrigInst)
+ CopyDebug(NewInst, OrigInst);
+ return NewInst;
+}
+
+// Return a value with the bits of the operand above the size of the original
+// type equal to the sign bit of the original operand. The new operand is
+// assumed to have been legalized already.
+// This is done by shifting the sign bit of the smaller value up to the MSB
+// position in the larger size, and then arithmetic-shifting it back down.
+static Value *getSignExtend(Value *Operand, Value *OrigOperand,
+ Instruction *InsertPt) {
+ // If OrigOperand was a constant, NewOperand will have been created by
+ // ConversionState.getConverted, which zero-extends by default. But that is
+ // wrong here, so replace it with a sign-extended constant.
+ if (Constant *C = dyn_cast<Constant>(OrigOperand))
+ return convertConstant(C, /*SignExt=*/true);
+ Type *OrigType = OrigOperand->getType();
+ ConstantInt *ShiftAmt = ConstantInt::getSigned(
+ cast<IntegerType>(getPromotedType(OrigType)),
+ getPromotedType(OrigType)->getIntegerBitWidth() -
+ OrigType->getIntegerBitWidth());
+ BinaryOperator *Shl = BinaryOperator::Create(
+ Instruction::Shl,
+ Operand,
+ ShiftAmt,
+ Operand->getName() + ".getsign",
+ InsertPt);
+ if (Instruction *Inst = dyn_cast<Instruction>(OrigOperand))
+ CopyDebug(Shl, Inst);
+ return CopyDebug(BinaryOperator::Create(
+ Instruction::AShr,
+ Shl,
+ ShiftAmt,
+ Operand->getName() + ".signed",
+ InsertPt), Shl);
+}
+
+static void convertInstruction(Instruction *Inst, ConversionState &State) {
+ if (SExtInst *Sext = dyn_cast<SExtInst>(Inst)) {
+ Value *Op = Sext->getOperand(0);
+ Value *NewInst = NULL;
+ // If the operand to be extended is illegal, we first need to fill its
+ // upper bits with its sign bit.
+ if (shouldConvert(Op)) {
+ NewInst = getSignExtend(State.getConverted(Op), Op, Sext);
+ }
+ // If the converted type of the operand is the same as the converted
+ // type of the result, we won't actually be changing the type of the
+ // variable, just its value.
+ if (getPromotedType(Op->getType()) !=
+ getPromotedType(Sext->getType())) {
+ NewInst = CopyDebug(new SExtInst(
+ NewInst ? NewInst : State.getConverted(Op),
+ getPromotedType(cast<IntegerType>(Sext->getType())),
+ Sext->getName() + ".sext", Sext), Sext);
+ }
+ assert(NewInst && "Failed to convert sign extension");
+ State.recordConverted(Sext, NewInst);
+ } else if (ZExtInst *Zext = dyn_cast<ZExtInst>(Inst)) {
+ Value *Op = Zext->getOperand(0);
+ Value *NewInst = NULL;
+ if (shouldConvert(Op)) {
+ NewInst = getClearConverted(Op, Zext, State);
+ }
+ // If the converted type of the operand is the same as the converted
+ // type of the result, we won't actually be changing the type of the
+ // variable, just its value.
+ if (getPromotedType(Op->getType()) !=
+ getPromotedType(Zext->getType())) {
+ NewInst = CopyDebug(CastInst::CreateZExtOrBitCast(
+ NewInst ? NewInst : State.getConverted(Op),
+ getPromotedType(cast<IntegerType>(Zext->getType())),
+ "", Zext), Zext);
+ }
+ assert(NewInst);
+ State.recordConverted(Zext, NewInst);
+ } else if (TruncInst *Trunc = dyn_cast<TruncInst>(Inst)) {
+ Value *Op = Trunc->getOperand(0);
+ Value *NewInst;
+ // If the converted type of the operand is the same as the converted
+ // type of the result, we don't actually need to change the type of the
+ // variable, just its value. However, because we don't care about the values
+ // of the upper bits until they are consumed, truncation can be a no-op.
+ if (getPromotedType(Op->getType()) !=
+ getPromotedType(Trunc->getType())) {
+ NewInst = CopyDebug(new TruncInst(
+ State.getConverted(Op),
+ getPromotedType(cast<IntegerType>(Trunc->getType())),
+ State.getConverted(Op)->getName() + ".trunc",
+ Trunc), Trunc);
+ } else {
+ NewInst = State.getConverted(Op);
+ }
+ State.recordConverted(Trunc, NewInst);
+ } else if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
+ if (shouldConvert(Load)) {
+ splitLoad(Load, State);
+ }
+ } else if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
+ if (shouldConvert(Store->getValueOperand())) {
+ splitStore(Store, State);
+ }
+ } else if (isa<CallInst>(Inst)) {
+ report_fatal_error("can't convert calls with illegal types");
+ } else if (BinaryOperator *Binop = dyn_cast<BinaryOperator>(Inst)) {
+ Value *NewInst = NULL;
+ switch (Binop->getOpcode()) {
+ case Instruction::AShr: {
+ // The AShr operand needs to be sign-extended to the promoted size
+ // before shifting. Because the sign-extension is implemented with
+ // with AShr, it can be combined with the original operation.
+ Value *Op = Binop->getOperand(0);
+ Value *ShiftAmount = NULL;
+ APInt SignShiftAmt = APInt(
+ getPromotedType(Op->getType())->getIntegerBitWidth(),
+ getPromotedType(Op->getType())->getIntegerBitWidth() -
+ Op->getType()->getIntegerBitWidth());
+ NewInst = CopyDebug(BinaryOperator::Create(
+ Instruction::Shl,
+ State.getConverted(Op),
+ ConstantInt::get(getPromotedType(Op->getType()), SignShiftAmt),
+ State.getConverted(Op)->getName() + ".getsign",
+ Binop), Binop);
+ if (ConstantInt *C = dyn_cast<ConstantInt>(
+ State.getConverted(Binop->getOperand(1)))) {
+ ShiftAmount = ConstantInt::get(getPromotedType(Op->getType()),
+ SignShiftAmt + C->getValue());
+ } else {
+ // Clear the upper bits of the original shift amount, and add back the
+ // amount we shifted to get the sign bit.
+ ShiftAmount = getClearConverted(Binop->getOperand(1), Binop, State);
+ ShiftAmount = CopyDebug(BinaryOperator::Create(
+ Instruction::Add,
+ ShiftAmount,
+ ConstantInt::get(
+ getPromotedType(Binop->getOperand(1)->getType()),
+ SignShiftAmt),
+ State.getConverted(Op)->getName() + ".shamt", Binop), Binop);
+ }
+ NewInst = CopyDebug(BinaryOperator::Create(
+ Instruction::AShr,
+ NewInst,
+ ShiftAmount,
+ Binop->getName() + ".result", Binop), Binop);
+ break;
+ }
+
+ case Instruction::LShr:
+ case Instruction::Shl: {
+ // For LShr, clear the upper bits of the operand before shifting them
+ // down into the valid part of the value.
+ Value *Op = Binop->getOpcode() == Instruction::LShr
+ ? getClearConverted(Binop->getOperand(0), Binop, State)
+ : State.getConverted(Binop->getOperand(0));
+ NewInst = BinaryOperator::Create(
+ Binop->getOpcode(), Op,
+ // Clear the upper bits of the shift amount.
+ getClearConverted(Binop->getOperand(1), Binop, State),
+ Binop->getName() + ".result", Binop);
+ break;
+ }
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Mul:
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ // These operations don't care about the state of the upper bits.
+ NewInst = CopyDebug(BinaryOperator::Create(
+ Binop->getOpcode(),
+ State.getConverted(Binop->getOperand(0)),
+ State.getConverted(Binop->getOperand(1)),
+ Binop->getName() + ".result", Binop), Binop);
+ break;
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ case Instruction::FMul:
+ case Instruction::UDiv:
+ case Instruction::SDiv:
+ case Instruction::FDiv:
+ case Instruction::URem:
+ case Instruction::SRem:
+ case Instruction::FRem:
+ case Instruction::BinaryOpsEnd:
+ // We should not see FP operators here.
+ // We don't handle div.
+ errs() << *Inst << "\n";
+ llvm_unreachable("Cannot handle binary operator");
+ break;
+ }
+
+ if (isa<OverflowingBinaryOperator>(NewInst)) {
+ cast<BinaryOperator>(NewInst)->setHasNoUnsignedWrap(
+ Binop->hasNoUnsignedWrap());
+ cast<BinaryOperator>(NewInst)->setHasNoSignedWrap(
+ Binop->hasNoSignedWrap());
+ }
+ State.recordConverted(Binop, NewInst);
+ } else if (ICmpInst *Cmp = dyn_cast<ICmpInst>(Inst)) {
+ Value *Op0, *Op1;
+ // For signed compares, operands are sign-extended to their
+ // promoted type. For unsigned or equality compares, the upper bits are
+ // cleared.
+ if (Cmp->isSigned()) {
+ Op0 = getSignExtend(State.getConverted(Cmp->getOperand(0)),
+ Cmp->getOperand(0),
+ Cmp);
+ Op1 = getSignExtend(State.getConverted(Cmp->getOperand(1)),
+ Cmp->getOperand(1),
+ Cmp);
+ } else {
+ Op0 = getClearConverted(Cmp->getOperand(0), Cmp, State);
+ Op1 = getClearConverted(Cmp->getOperand(1), Cmp, State);
+ }
+ Instruction *NewInst = CopyDebug(new ICmpInst(
+ Cmp, Cmp->getPredicate(), Op0, Op1, ""), Cmp);
+ State.recordConverted(Cmp, NewInst);
+ } else if (SelectInst *Select = dyn_cast<SelectInst>(Inst)) {
+ Instruction *NewInst = CopyDebug(SelectInst::Create(
+ Select->getCondition(),
+ State.getConverted(Select->getTrueValue()),
+ State.getConverted(Select->getFalseValue()),
+ "", Select), Select);
+ State.recordConverted(Select, NewInst);
+ } else if (PHINode *Phi = dyn_cast<PHINode>(Inst)) {
+ PHINode *NewPhi = PHINode::Create(
+ getPromotedType(Phi->getType()),
+ Phi->getNumIncomingValues(),
+ "", Phi);
+ CopyDebug(NewPhi, Phi);
+ for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; ++I) {
+ NewPhi->addIncoming(State.getConverted(Phi->getIncomingValue(I)),
+ Phi->getIncomingBlock(I));
+ }
+ State.recordConverted(Phi, NewPhi);
+ } else if (SwitchInst *Switch = dyn_cast<SwitchInst>(Inst)) {
+ Value *Condition = getClearConverted(Switch->getCondition(), Switch, State);
+ SwitchInst *NewInst = SwitchInst::Create(
+ Condition,
+ Switch->getDefaultDest(),
+ Switch->getNumCases(),
+ Switch);
+ CopyDebug(NewInst, Switch);
+ for (SwitchInst::CaseIt I = Switch->case_begin(),
+ E = Switch->case_end();
+ I != E; ++I) {
+ NewInst->addCase(cast<ConstantInt>(convertConstant(I.getCaseValue())),
+ I.getCaseSuccessor());
+ }
+ Switch->eraseFromParent();
+ } else {
+ errs() << *Inst<<"\n";
+ llvm_unreachable("unhandled instruction");
+ }
+}
+
+bool PromoteIntegers::runOnFunction(Function &F) {
+ // 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) {
+ Value *Arg = I;
+ if (shouldConvert(Arg)) {
+ errs() << "Function " << F.getName() << ": " << *Arg << "\n";
+ llvm_unreachable("Function has illegal integer/pointer argument");
+ }
+ }
+
+ ConversionState State;
+ bool Modified = false;
+ for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
+ for (BasicBlock::iterator BBI = FI->begin(), BBE = FI->end(); BBI != BBE;) {
+ Instruction *Inst = BBI++;
+ // Only attempt to convert an instruction if its result or any of its
+ // operands are illegal.
+ bool ShouldConvert = shouldConvert(Inst);
+ for (User::op_iterator OI = Inst->op_begin(), OE = Inst->op_end();
+ OI != OE; ++OI)
+ ShouldConvert |= shouldConvert(cast<Value>(OI));
+
+ if (ShouldConvert) {
+ convertInstruction(Inst, State);
+ Modified = true;
+ }
+ }
+ }
+ State.eraseReplacedInstructions();
+ return Modified;
+}
+
+FunctionPass *llvm::createPromoteIntegersPass() {
+ return new PromoteIntegers();
+}
diff --git a/backend/src/llvm/llvm_gen_backend.hpp b/backend/src/llvm/llvm_gen_backend.hpp
index b8ed9fa5..91a1166d 100644
--- a/backend/src/llvm/llvm_gen_backend.hpp
+++ b/backend/src/llvm/llvm_gen_backend.hpp
@@ -49,6 +49,7 @@ namespace llvm {
FunctionPass *createExpandConstantExprPass();
FunctionPass *createExpandLargeIntegersPass();
+ FunctionPass *createPromoteIntegersPass();
// Copy debug information from Original to New, and return New.
template <typename T> T *CopyDebug(T *New, llvm::Instruction *Original) {
New->setDebugLoc(Original->getDebugLoc());
diff --git a/backend/src/llvm/llvm_to_gen.cpp b/backend/src/llvm/llvm_to_gen.cpp
index 08978087..3dbdf559 100644
--- a/backend/src/llvm/llvm_to_gen.cpp
+++ b/backend/src/llvm/llvm_to_gen.cpp
@@ -279,6 +279,7 @@ namespace gbe
passes.add(createInstructionCombiningPass()); // legalize will generate some silly instructions
passes.add(createConstantPropagationPass()); // propagate constant after scalarize/legalize
passes.add(createExpandConstantExprPass()); // constant prop may generate ConstantExpr
+ passes.add(createPromoteIntegersPass()); // align integer size to power of two
passes.add(createRemoveGEPPass(unit)); // Constant prop may generate gep
passes.add(createDeadInstEliminationPass()); // Remove simplified instructions
passes.add(createCFGSimplificationPass()); // Merge & remove BBs