aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/InitializePasses.h1
-rw-r--r--include/llvm/Transforms/NaCl.h1
-rw-r--r--lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp2
-rw-r--r--lib/Analysis/NaCl/PNaClABIVerifyModule.cpp17
-rw-r--r--lib/Transforms/NaCl/CMakeLists.txt1
-rw-r--r--lib/Transforms/NaCl/PNaClABISimplify.cpp6
-rw-r--r--lib/Transforms/NaCl/StripAttributes.cpp152
-rw-r--r--test/NaCl/PNaClABI/abi-call-attributes.ll15
-rw-r--r--test/NaCl/PNaClABI/global-attributes.ll10
-rw-r--r--test/Transforms/NaCl/strip-attributes.ll20
-rw-r--r--tools/opt/opt.cpp1
11 files changed, 226 insertions, 0 deletions
diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h
index dd0c85828a..c339e45302 100644
--- a/include/llvm/InitializePasses.h
+++ b/include/llvm/InitializePasses.h
@@ -299,6 +299,7 @@ void initializeReplacePtrsWithIntsPass(PassRegistry&);
void initializeResolveAliasesPass(PassRegistry&);
void initializeResolvePNaClIntrinsicsPass(PassRegistry&);
void initializeRewritePNaClLibraryCallsPass(PassRegistry&);
+void initializeStripAttributesPass(PassRegistry&);
void initializeStripMetadataPass(PassRegistry&);
// @LOCALMOD-END
}
diff --git a/include/llvm/Transforms/NaCl.h b/include/llvm/Transforms/NaCl.h
index 09d396ce18..e493b48c03 100644
--- a/include/llvm/Transforms/NaCl.h
+++ b/include/llvm/Transforms/NaCl.h
@@ -40,6 +40,7 @@ ModulePass *createReplacePtrsWithIntsPass();
ModulePass *createResolveAliasesPass();
FunctionPass *createResolvePNaClIntrinsicsPass();
ModulePass *createRewritePNaClLibraryCallsPass();
+FunctionPass *createStripAttributesPass();
ModulePass *createStripMetadataPass();
FunctionPass *createInsertDivideCheckPass();
diff --git a/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp b/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp
index 43eef2f6c0..167cad15d0 100644
--- a/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp
+++ b/lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp
@@ -258,6 +258,8 @@ const char *PNaClABIVerifyFunctions::checkInstruction(const Instruction *Inst) {
case Instruction::Call:
if (cast<CallInst>(Inst)->isInlineAsm())
return "inline assembly";
+ if (!cast<CallInst>(Inst)->getAttributes().isEmpty())
+ return "bad call attributes";
// Intrinsic calls can have multiple pointer arguments and
// metadata arguments, so handle them specially.
diff --git a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
index 7daeabd0e8..91f71c949c 100644
--- a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
+++ b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
@@ -305,6 +305,18 @@ static bool isCompoundElement(const Constant *C) {
return true;
}
+static std::string getAttributesAsString(AttributeSet Attrs) {
+ std::string AttrsAsString;
+ for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) {
+ for (AttributeSet::iterator Attr = Attrs.begin(Slot),
+ E = Attrs.end(Slot); Attr != E; ++Attr) {
+ AttrsAsString += " ";
+ AttrsAsString += Attr->getAsString();
+ }
+ }
+ return AttrsAsString;
+}
+
// This checks that the GlobalVariable has the normal form produced by
// the FlattenGlobals pass.
void PNaClABIVerifyModule::checkGlobalIsFlattened(const GlobalVariable *GV) {
@@ -366,6 +378,11 @@ bool PNaClABIVerifyModule::runOnModule(Module &M) {
Reporter->addError() << "Function " << MI->getName()
<< " is declared but not defined (disallowed)\n";
}
+ if (!MI->getAttributes().isEmpty()) {
+ Reporter->addError()
+ << "Function " << MI->getName() << " has disallowed attributes:"
+ << getAttributesAsString(MI->getAttributes()) << "\n";
+ }
}
checkGlobalValueCommon(MI);
diff --git a/lib/Transforms/NaCl/CMakeLists.txt b/lib/Transforms/NaCl/CMakeLists.txt
index 1424f95026..065c3c810b 100644
--- a/lib/Transforms/NaCl/CMakeLists.txt
+++ b/lib/Transforms/NaCl/CMakeLists.txt
@@ -19,6 +19,7 @@ add_llvm_library(LLVMNaClTransforms
ReplacePtrsWithInts.cpp
ResolvePNaClIntrinsics.cpp
RewritePNaClLibraryCalls.cpp
+ StripAttributes.cpp
StripMetadata.cpp
)
diff --git a/lib/Transforms/NaCl/PNaClABISimplify.cpp b/lib/Transforms/NaCl/PNaClABISimplify.cpp
index 684be734c2..db9f9e6ebf 100644
--- a/lib/Transforms/NaCl/PNaClABISimplify.cpp
+++ b/lib/Transforms/NaCl/PNaClABISimplify.cpp
@@ -78,6 +78,12 @@ void llvm::PNaClABISimplifyAddPostOptPasses(PassManager &PM) {
// ConstantExprs have already been expanded out.
PM.add(createReplacePtrsWithIntsPass());
+ // We place StripAttributes after optimization passes because many
+ // analyses add attributes to reflect their results.
+ // StripAttributes must come after ExpandByVal and
+ // ExpandSmallArguments.
+ PM.add(createStripAttributesPass());
+
// Strip dead prototytes to appease the intrinsic ABI checks.
// ExpandVarArgs leaves around vararg intrinsics, and
// ReplacePtrsWithInts leaves the lifetime.start/end intrinsics.
diff --git a/lib/Transforms/NaCl/StripAttributes.cpp b/lib/Transforms/NaCl/StripAttributes.cpp
new file mode 100644
index 0000000000..f5ec0423b4
--- /dev/null
+++ b/lib/Transforms/NaCl/StripAttributes.cpp
@@ -0,0 +1,152 @@
+//===- StripAttributes.cpp - Remove attributes not supported by PNaCl------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass strips out attributes that are not supported by PNaCl's
+// stable ABI. Currently, this strips out attributes from functions
+// and function calls.
+//
+// TODO(mseaborn): Strip out the following too:
+//
+// * Calling conventions from functions and function calls.
+// * "nuw" and "nsw" arithmetic attributes.
+// * "align" attributes from integer memory accesses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/Function.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Transforms/NaCl.h"
+
+using namespace llvm;
+
+namespace {
+ class StripAttributes : public FunctionPass {
+ public:
+ static char ID; // Pass identification, replacement for typeid
+ StripAttributes() : FunctionPass(ID) {
+ initializeStripAttributesPass(*PassRegistry::getPassRegistry());
+ }
+
+ virtual bool runOnFunction(Function &Func);
+ };
+}
+
+char StripAttributes::ID = 0;
+INITIALIZE_PASS(StripAttributes, "nacl-strip-attributes",
+ "Strip out attributes that are not part of PNaCl's ABI",
+ false, false)
+
+// Most attributes are just hints which can safely be removed. A few
+// attributes can break programs if removed, so check all attributes
+// before removing them, in case LLVM adds new attributes.
+static void CheckAttributes(AttributeSet Attrs) {
+ for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) {
+ for (AttributeSet::iterator Attr = Attrs.begin(Slot), E = Attrs.end(Slot);
+ Attr != E; ++Attr) {
+ switch (Attr->getKindAsEnum()) {
+ // The following attributes can affect calling conventions.
+ // Rather than complaining, we just strip these out.
+ // ExpandSmallArguments should have rendered SExt/ZExt
+ // meaningless since the function arguments will be at least
+ // 32-bit.
+ case Attribute::InReg:
+ case Attribute::SExt:
+ case Attribute::ZExt:
+ // These attributes influence ABI decisions that should not be
+ // visible to PNaCl pexes.
+ case Attribute::NonLazyBind: // Only relevant to dynamic linking.
+ case Attribute::NoRedZone:
+ case Attribute::StackAlignment:
+
+ // The following attributes are just hints, which can be
+ // safely removed.
+ case Attribute::AlwaysInline:
+ case Attribute::InlineHint:
+ case Attribute::MinSize:
+ case Attribute::NoAlias:
+ case Attribute::NoBuiltin:
+ case Attribute::NoCapture:
+ case Attribute::NoDuplicate:
+ case Attribute::NoImplicitFloat:
+ case Attribute::NoInline:
+ case Attribute::NoReturn:
+ case Attribute::OptimizeForSize:
+ case Attribute::ReadNone:
+ case Attribute::ReadOnly:
+
+ // PNaCl does not support -fstack-protector in the translator.
+ case Attribute::StackProtect:
+ case Attribute::StackProtectReq:
+ case Attribute::StackProtectStrong:
+ // PNaCl does not support ASan in the translator.
+ case Attribute::SanitizeAddress:
+ case Attribute::SanitizeThread:
+ case Attribute::SanitizeMemory:
+
+ // The Language References cites setjmp() as an example of a
+ // function which returns twice, and says ReturnsTwice is
+ // necessary to disable optimizations such as tail calls.
+ // However, in the PNaCl ABI, setjmp() is an intrinsic, and
+ // user-defined functions are not allowed to return twice.
+ case Attribute::ReturnsTwice:
+
+ // NoUnwind is not a hint if it causes unwind info to be
+ // omitted, since this will prevent C++ exceptions from
+ // propagating. In the future, when PNaCl supports zero-cost
+ // C++ exception handling using unwind info, we might allow
+ // NoUnwind and UWTable. Alternatively, we might continue to
+ // disallow them, and just generate unwind info for all
+ // functions.
+ case Attribute::NoUnwind:
+ case Attribute::UWTable:
+ break;
+
+ case Attribute::ByVal:
+ case Attribute::StructRet:
+ case Attribute::Alignment:
+ Attrs.dump();
+ report_fatal_error(
+ "Attribute should already have been removed by ExpandByVal");
+
+ case Attribute::Naked:
+ case Attribute::Nest:
+ Attrs.dump();
+ report_fatal_error("Unsupported attribute");
+
+ default:
+ Attrs.dump();
+ report_fatal_error("Unrecognized attribute");
+ }
+ }
+ }
+}
+
+bool StripAttributes::runOnFunction(Function &Func) {
+ CheckAttributes(Func.getAttributes());
+ Func.setAttributes(AttributeSet());
+
+ for (Function::iterator BB = Func.begin(), E = Func.end();
+ BB != E; ++BB) {
+ for (BasicBlock::iterator Inst = BB->begin(), E = BB->end();
+ Inst != E; ++Inst) {
+ CallSite Call(Inst);
+ if (Call) {
+ CheckAttributes(Call.getAttributes());
+ Call.setAttributes(AttributeSet());
+ }
+ }
+ }
+
+ return true;
+}
+
+FunctionPass *llvm::createStripAttributesPass() {
+ return new StripAttributes();
+}
diff --git a/test/NaCl/PNaClABI/abi-call-attributes.ll b/test/NaCl/PNaClABI/abi-call-attributes.ll
new file mode 100644
index 0000000000..0e4de4610b
--- /dev/null
+++ b/test/NaCl/PNaClABI/abi-call-attributes.ll
@@ -0,0 +1,15 @@
+; RUN: pnacl-abicheck < %s | FileCheck %s
+
+define void @func(i32 %arg) {
+ ret void
+}
+
+define void @calls() {
+ call void @func(i32 1) noreturn nounwind
+; CHECK: disallowed: bad call attributes: call void @func(i32 1) #
+ call void @func(i32 inreg 1)
+; CHECK-NEXT: disallowed: bad call attributes: call void @func(i32 inreg 1)
+ ret void
+}
+
+; CHECK-NOT: disallowed
diff --git a/test/NaCl/PNaClABI/global-attributes.ll b/test/NaCl/PNaClABI/global-attributes.ll
index 5f7929fb08..4b8d893acb 100644
--- a/test/NaCl/PNaClABI/global-attributes.ll
+++ b/test/NaCl/PNaClABI/global-attributes.ll
@@ -17,6 +17,16 @@
; Function attributes
+; CHECK-NEXT: Function func_with_attrs has disallowed attributes: noreturn nounwind
+define void @func_with_attrs() noreturn nounwind {
+ ret void
+}
+
+; CHECK-NEXT: Function func_with_arg_attrs has disallowed attributes: inreg zeroext
+define void @func_with_arg_attrs(i32 inreg zeroext) {
+ ret void
+}
+
; CHECK-NEXT: Function func_with_section has disallowed "section" attribute
define void @func_with_section() section ".some_section" {
ret void
diff --git a/test/Transforms/NaCl/strip-attributes.ll b/test/Transforms/NaCl/strip-attributes.ll
new file mode 100644
index 0000000000..53d8a30325
--- /dev/null
+++ b/test/Transforms/NaCl/strip-attributes.ll
@@ -0,0 +1,20 @@
+; RUN: opt -S -nacl-strip-attributes %s | FileCheck %s
+
+define void @func_attrs(i32 inreg, i32 zeroext) noreturn nounwind readonly {
+ ret void
+}
+; CHECK: define void @func_attrs(i32, i32) {
+
+define void @call_attrs() {
+ call void @func_attrs(i32 inreg 10, i32 zeroext 20) noreturn nounwind readonly
+ ret void
+}
+; CHECK: define void @call_attrs()
+; CHECK: call void @func_attrs(i32 10, i32 20){{$}}
+
+; We currently don't attempt to strip attributes from intrinsic
+; declarations because the reader automatically inserts attributes
+; based on built-in knowledge of intrinsics, so it is difficult to get
+; rid of them here.
+declare i8* @llvm.nacl.read.tp()
+; CHECK: declare i8* @llvm.nacl.read.tp() #{{[0-9]+}}
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index 81006c3507..490d1bc6e3 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -629,6 +629,7 @@ int main(int argc, char **argv) {
initializeResolveAliasesPass(Registry);
initializeResolvePNaClIntrinsicsPass(Registry);
initializeRewritePNaClLibraryCallsPass(Registry);
+ initializeStripAttributesPass(Registry);
initializeStripMetadataPass(Registry);
// @LOCALMOD-END