Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(480)

Unified Diff: lib/Transforms/NaCl/ExpandSmallArguments.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Transforms/NaCl/ExpandShuffleVector.cpp ('k') | lib/Transforms/NaCl/ExpandStructRegs.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Transforms/NaCl/ExpandSmallArguments.cpp
diff --git a/lib/Transforms/NaCl/ExpandSmallArguments.cpp b/lib/Transforms/NaCl/ExpandSmallArguments.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b252169d4b75dd237f8f4a02879684e8d8d8a3a9
--- /dev/null
+++ b/lib/Transforms/NaCl/ExpandSmallArguments.cpp
@@ -0,0 +1,248 @@
+//===- ExpandSmallArguments.cpp - Expand out arguments smaller than i32----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LLVM IR allows function return types and argument types such as
+// "zeroext i8" and "signext i8". The Language Reference says that
+// zeroext "indicates to the code generator that the parameter or
+// return value should be zero-extended to the extent required by the
+// target's ABI (which is usually 32-bits, but is 8-bits for a i1 on
+// x86-64) by the caller (for a parameter) or the callee (for a return
+// value)".
+//
+// This can lead to non-portable behaviour when calling functions
+// without C prototypes or with wrong C prototypes.
+//
+// In order to remove this non-portability from PNaCl, and to simplify
+// the language that the PNaCl translator accepts, the
+// ExpandSmallArguments pass widens integer arguments and return types
+// to be at least 32 bits. The pass inserts explicit cast
+// instructions (ZExtInst/SExtInst/TruncInst) as needed.
+//
+// The pass chooses between ZExtInst and SExtInst widening based on
+// whether a "signext" attribute is present. However, in principle
+// the pass could always use zero-extension, because the extent to
+// which either zero-extension or sign-extension is done is up to the
+// target ABI, which is up to PNaCl to specify.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Transforms/NaCl.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+using namespace llvm;
+
+namespace {
+ // This is a ModulePass because the pass recreates functions in
+ // order to change their arguments' types.
+ class ExpandSmallArguments : public ModulePass {
+ public:
+ static char ID; // Pass identification, replacement for typeid
+ ExpandSmallArguments() : ModulePass(ID) {
+ initializeExpandSmallArgumentsPass(*PassRegistry::getPassRegistry());
+ }
+
+ virtual bool runOnModule(Module &M);
+ };
+}
+
+char ExpandSmallArguments::ID = 0;
+INITIALIZE_PASS(ExpandSmallArguments, "expand-small-arguments",
+ "Expand function arguments to be at least 32 bits in size",
+ false, false)
+
+// Returns the normalized version of the given argument/return type.
+static Type *NormalizeType(Type *Ty) {
+ if (IntegerType *IntTy = dyn_cast<IntegerType>(Ty)) {
+ if (IntTy->getBitWidth() < 32) {
+ return IntegerType::get(Ty->getContext(), 32);
+ }
+ }
+ return Ty;
+}
+
+// Returns the normalized version of the given function type.
+static FunctionType *NormalizeFunctionType(FunctionType *FTy) {
+ if (FTy->isVarArg()) {
+ report_fatal_error(
+ "ExpandSmallArguments does not handle varargs functions");
+ }
+ SmallVector<Type *, 8> ArgTypes;
+ for (unsigned I = 0; I < FTy->getNumParams(); ++I) {
+ ArgTypes.push_back(NormalizeType(FTy->getParamType(I)));
+ }
+ return FunctionType::get(NormalizeType(FTy->getReturnType()),
+ ArgTypes, false);
+}
+
+// Convert the given function to use normalized argument/return types.
+static bool ConvertFunction(Function *Func) {
+ FunctionType *FTy = Func->getFunctionType();
+ FunctionType *NFTy = NormalizeFunctionType(FTy);
+ if (NFTy == FTy)
+ return false; // No change needed.
+ Function *NewFunc = RecreateFunction(Func, NFTy);
+
+ // Move the arguments across to the new function.
+ for (Function::arg_iterator Arg = Func->arg_begin(), E = Func->arg_end(),
+ NewArg = NewFunc->arg_begin();
+ Arg != E; ++Arg, ++NewArg) {
+ NewArg->takeName(Arg);
+ if (Arg->getType() == NewArg->getType()) {
+ Arg->replaceAllUsesWith(NewArg);
+ } else {
+ Instruction *Trunc = new TruncInst(
+ NewArg, Arg->getType(), NewArg->getName() + ".arg_trunc",
+ NewFunc->getEntryBlock().getFirstInsertionPt());
+ Arg->replaceAllUsesWith(Trunc);
+ }
+ }
+
+ if (FTy->getReturnType() != NFTy->getReturnType()) {
+ // Fix up return instructions.
+ Instruction::CastOps CastType =
+ Func->getAttributes().hasAttribute(0, Attribute::SExt) ?
+ Instruction::SExt : Instruction::ZExt;
+ for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end();
+ BB != E;
+ ++BB) {
+ for (BasicBlock::iterator Iter = BB->begin(), E = BB->end();
+ Iter != E; ) {
+ Instruction *Inst = Iter++;
+ if (ReturnInst *Ret = dyn_cast<ReturnInst>(Inst)) {
+ Value *Ext = CopyDebug(
+ CastInst::Create(CastType, Ret->getReturnValue(),
+ NFTy->getReturnType(),
+ Ret->getReturnValue()->getName() + ".ret_ext",
+ Ret),
+ Ret);
+ CopyDebug(ReturnInst::Create(Ret->getContext(), Ext, Ret), Ret);
+ Ret->eraseFromParent();
+ }
+ }
+ }
+ }
+
+ Func->eraseFromParent();
+ return true;
+}
+
+// Convert the given call to use normalized argument/return types.
+template <class T> static bool ConvertCall(T *Call, Pass *P) {
+ // Don't try to change calls to intrinsics.
+ if (isa<IntrinsicInst>(Call))
+ return false;
+ FunctionType *FTy = cast<FunctionType>(
+ Call->getCalledValue()->getType()->getPointerElementType());
+ FunctionType *NFTy = NormalizeFunctionType(FTy);
+ if (NFTy == FTy)
+ return false; // No change needed.
+
+ // Convert arguments.
+ SmallVector<Value *, 8> Args;
+ for (unsigned I = 0; I < Call->getNumArgOperands(); ++I) {
+ Value *Arg = Call->getArgOperand(I);
+ if (NFTy->getParamType(I) != FTy->getParamType(I)) {
+ Instruction::CastOps CastType =
+ Call->getAttributes().hasAttribute(I + 1, Attribute::SExt) ?
+ Instruction::SExt : Instruction::ZExt;
+ Arg = CopyDebug(CastInst::Create(CastType, Arg, NFTy->getParamType(I),
+ "arg_ext", Call), Call);
+ }
+ Args.push_back(Arg);
+ }
+ Value *CastFunc =
+ CopyDebug(new BitCastInst(Call->getCalledValue(), NFTy->getPointerTo(),
+ Call->getName() + ".arg_cast", Call), Call);
+ Value *Result = NULL;
+ if (CallInst *OldCall = dyn_cast<CallInst>(Call)) {
+ CallInst *NewCall = CopyDebug(CallInst::Create(CastFunc, Args, "", OldCall),
+ OldCall);
+ NewCall->takeName(OldCall);
+ NewCall->setAttributes(OldCall->getAttributes());
+ NewCall->setCallingConv(OldCall->getCallingConv());
+ NewCall->setTailCall(OldCall->isTailCall());
+ Result = NewCall;
+
+ if (FTy->getReturnType() != NFTy->getReturnType()) {
+ Result = CopyDebug(new TruncInst(NewCall, FTy->getReturnType(),
+ NewCall->getName() + ".ret_trunc", Call),
+ Call);
+ }
+ } else if (InvokeInst *OldInvoke = dyn_cast<InvokeInst>(Call)) {
+ BasicBlock *Parent = OldInvoke->getParent();
+ BasicBlock *NormalDest = OldInvoke->getNormalDest();
+ BasicBlock *UnwindDest = OldInvoke->getUnwindDest();
+
+ if (FTy->getReturnType() != NFTy->getReturnType()) {
+ if (BasicBlock *SplitDest = SplitCriticalEdge(Parent, NormalDest)) {
+ NormalDest = SplitDest;
+ }
+ }
+
+ InvokeInst *New = CopyDebug(InvokeInst::Create(CastFunc, NormalDest,
+ UnwindDest, Args,
+ "", OldInvoke),
+ OldInvoke);
+ New->takeName(OldInvoke);
+
+ if (FTy->getReturnType() != NFTy->getReturnType()) {
+ Result = CopyDebug(new TruncInst(New, FTy->getReturnType(),
+ New->getName() + ".ret_trunc",
+ NormalDest->getTerminator()),
+ OldInvoke);
+ } else {
+ Result = New;
+ }
+
+ New->setAttributes(OldInvoke->getAttributes());
+ New->setCallingConv(OldInvoke->getCallingConv());
+ }
+ Call->replaceAllUsesWith(Result);
+ Call->eraseFromParent();
+ return true;
+}
+
+bool ExpandSmallArguments::runOnModule(Module &M) {
+ bool Changed = false;
+ for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) {
+ Function *Func = Iter++;
+ // Don't try to change intrinsic declarations because intrinsics
+ // will continue to have non-normalized argument types. For
+ // example, memset() takes an i8 argument. It shouldn't matter
+ // whether we modify the types of other function declarations, but
+ // we don't expect to see non-intrinsic function declarations in a
+ // PNaCl pexe.
+ if (Func->empty())
+ continue;
+
+ for (Function::iterator BB = Func->begin(), E = Func->end(); BB != E;
+ ++BB) {
+ for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); Iter != E;) {
+ Instruction *Inst = Iter++;
+ if (CallInst *Call = dyn_cast<CallInst>(Inst)) {
+ Changed |= ConvertCall(Call, this);
+ } else if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Inst)) {
+ Changed |= ConvertCall(Invoke, this);
+ }
+ }
+ }
+
+ Changed |= ConvertFunction(Func);
+ }
+ return Changed;
+}
+
+ModulePass *llvm::createExpandSmallArgumentsPass() {
+ return new ExpandSmallArguments();
+}
« no previous file with comments | « lib/Transforms/NaCl/ExpandShuffleVector.cpp ('k') | lib/Transforms/NaCl/ExpandStructRegs.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698