Handle variable arguments for ARM/Mips/X86.
Expand va_arg LLVM instruction in a target-specific manner.
Change-Id: Iddf071b7f4026f003df2ad129fd940c506e9ec99
diff --git a/lib/AndroidBitcode/ABCCompiler.cpp b/lib/AndroidBitcode/ABCCompiler.cpp
index 1b7294d..8393d48 100644
--- a/lib/AndroidBitcode/ABCCompiler.cpp
+++ b/lib/AndroidBitcode/ABCCompiler.cpp
@@ -21,9 +21,12 @@
#include <llvm/Target/TargetData.h>
#include <llvm/Target/TargetMachine.h>
+#include "bcc/AndroidBitcode/ABCCompilerDriver.h"
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
#include "bcc/Script.h"
#include "bcc/Source.h"
+
namespace bcc {
bool ABCCompiler::beforeAddCodeGenPasses(Script &pScript,
@@ -39,6 +42,7 @@
}
pm.add(target_data);
+ pm.add(mDriver.createExpandVAArgPass());
pm.run(module);
return true;
diff --git a/lib/AndroidBitcode/ABCCompilerDriver.cpp b/lib/AndroidBitcode/ABCCompilerDriver.cpp
index f8ddfc4..4eb33e6 100644
--- a/lib/AndroidBitcode/ABCCompilerDriver.cpp
+++ b/lib/AndroidBitcode/ABCCompilerDriver.cpp
@@ -17,6 +17,7 @@
#include "bcc/AndroidBitcode/ABCCompilerDriver.h"
#include <llvm/Module.h>
+#include <llvm/Pass.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/raw_ostream.h>
#include <mcld/Config/Config.h>
@@ -44,7 +45,7 @@
namespace bcc {
ABCCompilerDriver::ABCCompilerDriver(const std::string &pTriple)
- : mContext(), mCompiler(), mLinker(),
+ : mContext(), mCompiler(*this), mLinker(),
mCompilerConfig(NULL), mLinkerConfig(NULL),
mTriple(pTriple), mAndroidSysroot("/") {
}
diff --git a/lib/AndroidBitcode/ABCExpandVAArgPass.cpp b/lib/AndroidBitcode/ABCExpandVAArgPass.cpp
new file mode 100644
index 0000000..7b89ced
--- /dev/null
+++ b/lib/AndroidBitcode/ABCExpandVAArgPass.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_ABC_EXPAND_VAARG_H
+#define BCC_ABC_EXPAND_VAARG_H
+
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
+
+#include <llvm/Instructions.h>
+#include <llvm/Support/InstIterator.h>
+
+namespace bcc {
+
+char ABCExpandVAArgPass::ID = 0;
+
+bool ABCExpandVAArgPass::runOnFunction(llvm::Function &pFunc) {
+ bool changed = false;
+
+ mContext = &pFunc.getContext();
+
+ // process va_arg inst
+ for (llvm::inst_iterator inst = llvm::inst_begin(pFunc),
+ inst_end = llvm::inst_end(pFunc); inst != inst_end; inst++) {
+ if (inst->getOpcode() == llvm::Instruction::VAArg) {
+ llvm::Value *v = expandVAArg(&*inst);
+ inst->replaceAllUsesWith(v);
+ inst->eraseFromParent();
+ changed = true;
+ continue;
+ }
+ }
+ return changed;
+}
+
+} // end bcc namespace
+
+#endif // BCC_ABC_EXPAND_VAARG_H
diff --git a/lib/AndroidBitcode/ARM/ARMABCCompilerDriver.h b/lib/AndroidBitcode/ARM/ARMABCCompilerDriver.h
index ff1c91e..29f4f0a 100644
--- a/lib/AndroidBitcode/ARM/ARMABCCompilerDriver.h
+++ b/lib/AndroidBitcode/ARM/ARMABCCompilerDriver.h
@@ -27,6 +27,9 @@
: ABCCompilerDriver(pTriple) { }
virtual ~ARMABCCompilerDriver() { }
+
+private:
+ virtual ABCExpandVAArgPass *createExpandVAArgPass() const;
};
} // end namespace bcc
diff --git a/lib/AndroidBitcode/ARM/ARMABCExpandVAArg.cpp b/lib/AndroidBitcode/ARM/ARMABCExpandVAArg.cpp
new file mode 100644
index 0000000..7f154af
--- /dev/null
+++ b/lib/AndroidBitcode/ARM/ARMABCExpandVAArg.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/Instructions.h>
+#include <llvm/IRBuilder.h>
+#include <llvm/Module.h>
+#include <llvm/Pass.h>
+#include <llvm/Type.h>
+#include <llvm/Target/TargetData.h>
+
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
+
+#include "ARM/ARMABCCompilerDriver.h"
+
+namespace {
+
+class ARMABCExpandVAArg : public bcc::ABCExpandVAArgPass {
+public:
+ virtual const char *getPassName() const {
+ return "ARM LLVM va_arg Instruction Expansion Pass";
+ }
+
+private:
+ // Derivative work from external/clang/lib/CodeGen/TargetInfo.cpp.
+ llvm::Value *expandVAArg(llvm::Instruction *pInst) {
+ llvm::Type *pty = pInst->getType();
+ llvm::Type *ty = pty->getContainedType(0);
+ llvm::Value *va_list_addr = pInst->getOperand(0);
+ llvm::IRBuilder<> builder(pInst);
+ const llvm::TargetData *td = getAnalysisIfAvailable<llvm::TargetData>();
+
+ llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
+ llvm::Type *bpp = bp->getPointerTo(0);
+
+ llvm::Value *va_list_addr_bpp =
+ builder.CreateBitCast(va_list_addr, bpp, "ap");
+ llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
+ // Handle address alignment for type alignment > 32 bits.
+ uint64_t ty_align = td->getABITypeAlignment(ty);
+
+ if (ty_align > 4) {
+ assert((ty_align & (ty_align - 1)) == 0 &&
+ "Alignment is not power of 2!");
+ llvm::Value *addr_as_int =
+ builder.CreatePtrToInt(addr, llvm::Type::getInt32Ty(*mContext));
+ addr_as_int = builder.CreateAdd(addr_as_int,
+ builder.getInt32(ty_align-1));
+ addr_as_int = builder.CreateAnd(addr_as_int,
+ builder.getInt32(~(ty_align-1)));
+ addr = builder.CreateIntToPtr(addr_as_int, bp);
+ }
+ llvm::Value *addr_typed = builder.CreateBitCast(addr, pty);
+
+ uint64_t offset = llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty)/8, 4);
+ llvm::Value *next_addr = builder.CreateGEP(addr,
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), offset),
+ "ap.next");
+ builder.CreateStore(next_addr, va_list_addr_bpp);
+ return addr_typed;
+ }
+
+};
+
+} // end anonymous namespace
+
+namespace bcc {
+
+ABCExpandVAArgPass *ARMABCCompilerDriver::createExpandVAArgPass() const {
+ return new ARMABCExpandVAArg();
+}
+
+} // end namespace bcc
diff --git a/lib/AndroidBitcode/Android.mk b/lib/AndroidBitcode/Android.mk
index f736f58..806202c 100644
--- a/lib/AndroidBitcode/Android.mk
+++ b/lib/AndroidBitcode/Android.mk
@@ -23,15 +23,19 @@
libbcc_androidbitcode_SRC_FILES := \
ABCCompiler.cpp \
+ ABCExpandVAArgPass.cpp \
ABCCompilerDriver.cpp
-libbcc_arm_androidbitcode_SRC_FILES :=
+libbcc_arm_androidbitcode_SRC_FILES := \
+ ARM/ARMABCExpandVAArg.cpp
libbcc_mips_androidbitcode_SRC_FILES := \
- Mips/MipsABCCompilerDriver.cpp
+ Mips/MipsABCCompilerDriver.cpp \
+ Mips/MipsABCExpandVAArg.cpp
libbcc_x86_androidbitcode_SRC_FILES := \
- X86/X86ABCCompilerDriver.cpp
+ X86/X86ABCCompilerDriver.cpp \
+ X86/X86ABCExpandVAArg.cpp
#=====================================================================
diff --git a/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.h b/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.h
index 531fe83..7cfc34f 100644
--- a/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.h
+++ b/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.h
@@ -30,6 +30,8 @@
private:
virtual const char **getNonPortableList() const;
+
+ virtual ABCExpandVAArgPass *createExpandVAArgPass() const;
};
} // end namespace bcc
diff --git a/lib/AndroidBitcode/Mips/MipsABCExpandVAArg.cpp b/lib/AndroidBitcode/Mips/MipsABCExpandVAArg.cpp
new file mode 100644
index 0000000..495cef4
--- /dev/null
+++ b/lib/AndroidBitcode/Mips/MipsABCExpandVAArg.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/Instructions.h>
+#include <llvm/IRBuilder.h>
+#include <llvm/Module.h>
+#include <llvm/Pass.h>
+#include <llvm/Type.h>
+#include <llvm/Target/TargetData.h>
+
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
+
+#include "Mips/MipsABCCompilerDriver.h"
+
+namespace {
+
+class MipsABCExpandVAArg : public bcc::ABCExpandVAArgPass {
+public:
+ virtual const char *getPassName() const {
+ return "Mips LLVM va_arg Instruction Expansion Pass";
+ }
+
+private:
+ // Derivative work from external/clang/lib/CodeGen/TargetInfo.cpp.
+ virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) {
+ llvm::Type *pty = pInst->getType();
+ llvm::Type *ty = pty->getContainedType(0);
+ llvm::Value *va_list_addr = pInst->getOperand(0);
+ llvm::IRBuilder<> builder(pInst);
+ const llvm::TargetData *td = getAnalysisIfAvailable<llvm::TargetData>();
+
+ llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
+ llvm::Type *bpp = bp->getPointerTo(0);
+ llvm::Value *va_list_addr_bpp = builder.CreateBitCast(va_list_addr,
+ bpp, "ap");
+ llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
+ int64_t type_align = td->getABITypeAlignment(ty);
+ llvm::Value *addr_typed;
+ llvm::IntegerType *int_ty = llvm::Type::getInt32Ty(*mContext);
+
+ if (type_align > 4) {
+ llvm::Value *addr_as_int = builder.CreatePtrToInt(addr, int_ty);
+ llvm::Value *inc = llvm::ConstantInt::get(int_ty, type_align - 1);
+ llvm::Value *mask = llvm::ConstantInt::get(int_ty, -type_align);
+ llvm::Value *add_v = builder.CreateAdd(addr_as_int, inc);
+ llvm::Value *and_v = builder.CreateAnd(add_v, mask);
+ addr_typed = builder.CreateIntToPtr(and_v, pty);
+ }
+ else {
+ addr_typed = builder.CreateBitCast(addr, pty);
+ }
+
+ llvm::Value *aligned_addr = builder.CreateBitCast(addr_typed, bp);
+ type_align = std::max((unsigned)type_align, (unsigned) 4);
+ uint64_t offset =
+ llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty) / 8, type_align);
+ llvm::Value *next_addr =
+ builder.CreateGEP(aligned_addr, llvm::ConstantInt::get(int_ty, offset),
+ "ap.next");
+ builder.CreateStore(next_addr, va_list_addr_bpp);
+
+ return addr_typed;
+ }
+
+};
+
+} // end anonymous namespace
+
+namespace bcc {
+
+ABCExpandVAArgPass *MipsABCCompilerDriver::createExpandVAArgPass() const {
+ return new MipsABCExpandVAArg();
+}
+
+} // end namespace bcc
diff --git a/lib/AndroidBitcode/X86/X86ABCCompilerDriver.h b/lib/AndroidBitcode/X86/X86ABCCompilerDriver.h
index 34e9603..af52866 100644
--- a/lib/AndroidBitcode/X86/X86ABCCompilerDriver.h
+++ b/lib/AndroidBitcode/X86/X86ABCCompilerDriver.h
@@ -30,6 +30,8 @@
private:
virtual const char **getNonPortableList() const;
+
+ virtual ABCExpandVAArgPass *createExpandVAArgPass() const;
};
} // end namespace bcc
diff --git a/lib/AndroidBitcode/X86/X86ABCExpandVAArg.cpp b/lib/AndroidBitcode/X86/X86ABCExpandVAArg.cpp
new file mode 100644
index 0000000..6d9acbc
--- /dev/null
+++ b/lib/AndroidBitcode/X86/X86ABCExpandVAArg.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/Instructions.h>
+#include <llvm/IRBuilder.h>
+#include <llvm/Module.h>
+#include <llvm/Pass.h>
+#include <llvm/Type.h>
+#include <llvm/Target/TargetData.h>
+
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
+
+#include "X86/X86ABCCompilerDriver.h"
+
+namespace {
+
+class X86ABCExpandVAArg : public bcc::ABCExpandVAArgPass {
+public:
+ virtual const char *getPassName() const {
+ return "X86 LLVM va_arg Instruction Expansion Pass";
+ }
+
+private:
+ // Derivative work from external/clang/lib/CodeGen/TargetInfo.cpp.
+ virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) {
+ llvm::Type *pty = pInst->getType();
+ llvm::Type *ty = pty->getContainedType(0);
+ llvm::Value *va_list_addr = pInst->getOperand(0);
+ llvm::IRBuilder<> builder(pInst);
+ const llvm::TargetData *td = getAnalysisIfAvailable<llvm::TargetData>();
+
+ llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
+ llvm::Type *bpp = bp->getPointerTo(0);
+ llvm::Value *va_list_addr_bpp = builder.CreateBitCast(va_list_addr,
+ bpp, "ap");
+ llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
+
+ llvm::Value *addr_typed = builder.CreateBitCast(addr, pty);
+
+ // X86-32 stack type alignment is always 4.
+ uint64_t offset = llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty)/8, 4);
+ llvm::Value *next_addr = builder.CreateGEP(addr,
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), offset),
+ "ap.next");
+ builder.CreateStore(next_addr, va_list_addr_bpp);
+
+ return addr_typed;
+ }
+
+}; // end X86ABCExpandVAArg
+
+} // end anonymous namespace
+
+namespace bcc {
+
+ABCExpandVAArgPass *X86ABCCompilerDriver::createExpandVAArgPass() const {
+ return new X86ABCExpandVAArg();
+}
+
+} // end namespace bcc