Make .bc en/decoding of AttrKind stable
authorTobias Grosser <tobias@grosser.es>
Fri, 26 Jul 2013 04:16:55 +0000 (04:16 +0000)
committerTobias Grosser <tobias@grosser.es>
Fri, 26 Jul 2013 04:16:55 +0000 (04:16 +0000)
The bitcode representation attribute kinds are encoded into / decoded from
should be independent of the current set of LLVM attributes and their position
in the AttrKind enum. This patch explicitly encodes attributes to fixed bitcode
values.

With this patch applied, LLVM does not silently misread attributes written by
LLVM 3.3. We also enhance the decoding slightly such that an error message is
printed if an unknown AttrKind encoding was dected.

Bonus: Dropping bitcode attributes from AttrKind is now easy, as old AttrKinds
       do not need to be kept to support the Bitcode reader.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187186 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Bitcode/LLVMBitCodes.h
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Reader/BitcodeReader.h
lib/Bitcode/Writer/BitcodeWriter.cpp
test/Bitcode/attributes-3.3.ll [new file with mode: 0644]
test/Bitcode/attributes-3.3.ll.bc [new file with mode: 0644]

index f9690d5b779c0113468753d6f95aefdd9651cb97..463e3b919d929ba2323a6f84f7f771c642420e5e 100644 (file)
@@ -330,6 +330,47 @@ namespace bitc {
   enum UseListCodes {
     USELIST_CODE_ENTRY = 1   // USELIST_CODE_ENTRY: TBD.
   };
+
+  enum AttributeKindCodes {
+    // = 0 is unused
+    ATTR_KIND_ALIGNMENT = 1,
+    ATTR_KIND_ALWAYS_INLINE = 2,
+    ATTR_KIND_BY_VAL = 3,
+    ATTR_KIND_INLINE_HINT = 4,
+    ATTR_KIND_IN_REG = 5,
+    ATTR_KIND_MIN_SIZE = 6,
+    ATTR_KIND_NAKED = 7,
+    ATTR_KIND_NEST = 8,
+    ATTR_KIND_NO_ALIAS = 9,
+    ATTR_KIND_NO_BUILTIN = 10,
+    ATTR_KIND_NO_CAPTURE = 11,
+    ATTR_KIND_NO_DUPLICATE = 12,
+    ATTR_KIND_NO_IMPLICIT_FLOAT = 13,
+    ATTR_KIND_NO_INLINE = 14,
+    ATTR_KIND_NON_LAZY_BIND = 15,
+    ATTR_KIND_NO_RED_ZONE = 16,
+    ATTR_KIND_NO_RETURN = 17,
+    ATTR_KIND_NO_UNWIND = 18,
+    ATTR_KIND_OPTIMIZE_FOR_SIZE = 19,
+    ATTR_KIND_READ_NONE = 20,
+    ATTR_KIND_READ_ONLY = 21,
+    ATTR_KIND_RETURNED = 22,
+    ATTR_KIND_RETURNS_TWICE = 23,
+    ATTR_KIND_S_EXT = 24,
+    ATTR_KIND_STACK_ALIGNMENT = 25,
+    ATTR_KIND_STACK_PROTECT = 26,
+    ATTR_KIND_STACK_PROTECT_REQ = 27,
+    ATTR_KIND_STACK_PROTECT_STRONG = 28,
+    ATTR_KIND_STRUCT_RET = 29,
+    ATTR_KIND_SANITIZE_ADDRESS = 30,
+    ATTR_KIND_SANITIZE_THREAD = 31,
+    ATTR_KIND_SANITIZE_MEMORY = 32,
+    ATTR_KIND_UW_TABLE = 33,
+    ATTR_KIND_Z_EXT = 34,
+    ATTR_KIND_BUILTIN = 35,
+    ATTR_KIND_COLD = 36
+  };
+
 } // End bitc namespace
 } // End llvm namespace
 
index cf827c5d4b08d89012514153d89881ac3813e10b..e6d7b50b4898ee0ce9535a245175474897aa9830 100644 (file)
@@ -12,6 +12,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/AutoUpgrade.h"
+#include "llvm/Bitcode/LLVMBitCodes.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/InlineAsm.h"
@@ -22,6 +23,7 @@
 #include "llvm/Support/DataStream.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
 using namespace llvm;
 
 enum {
@@ -506,6 +508,125 @@ bool BitcodeReader::ParseAttributeBlock() {
   }
 }
 
+bool BitcodeReader::ParseAttrKind(uint64_t Code, Attribute::AttrKind *Kind) {
+  switch (Code) {
+  case bitc::ATTR_KIND_ALIGNMENT:
+    *Kind = Attribute::Alignment;
+    return false;
+  case bitc::ATTR_KIND_ALWAYS_INLINE:
+    *Kind = Attribute::AlwaysInline;
+    return false;
+  case bitc::ATTR_KIND_BUILTIN:
+    *Kind = Attribute::Builtin;
+    return false;
+  case bitc::ATTR_KIND_BY_VAL:
+    *Kind = Attribute::ByVal;
+    return false;
+  case bitc::ATTR_KIND_COLD:
+    *Kind = Attribute::Cold;
+    return false;
+  case bitc::ATTR_KIND_INLINE_HINT:
+    *Kind = Attribute::InlineHint;
+    return false;
+  case bitc::ATTR_KIND_IN_REG:
+    *Kind = Attribute::InReg;
+    return false;
+  case bitc::ATTR_KIND_MIN_SIZE:
+    *Kind = Attribute::MinSize;
+    return false;
+  case bitc::ATTR_KIND_NAKED:
+    *Kind = Attribute::Naked;
+    return false;
+  case bitc::ATTR_KIND_NEST:
+    *Kind = Attribute::Nest;
+    return false;
+  case bitc::ATTR_KIND_NO_ALIAS:
+    *Kind = Attribute::NoAlias;
+    return false;
+  case bitc::ATTR_KIND_NO_BUILTIN:
+    *Kind = Attribute::NoBuiltin;
+    return false;
+  case bitc::ATTR_KIND_NO_CAPTURE:
+    *Kind = Attribute::NoCapture;
+    return false;
+  case bitc::ATTR_KIND_NO_DUPLICATE:
+    *Kind = Attribute::NoDuplicate;
+    return false;
+  case bitc::ATTR_KIND_NO_IMPLICIT_FLOAT:
+    *Kind = Attribute::NoImplicitFloat;
+    return false;
+  case bitc::ATTR_KIND_NO_INLINE:
+    *Kind = Attribute::NoInline;
+    return false;
+  case bitc::ATTR_KIND_NON_LAZY_BIND:
+    *Kind = Attribute::NonLazyBind;
+    return false;
+  case bitc::ATTR_KIND_NO_RED_ZONE:
+    *Kind = Attribute::NoRedZone;
+    return false;
+  case bitc::ATTR_KIND_NO_RETURN:
+    *Kind = Attribute::NoReturn;
+    return false;
+  case bitc::ATTR_KIND_NO_UNWIND:
+    *Kind = Attribute::NoUnwind;
+    return false;
+  case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE:
+    *Kind = Attribute::OptimizeForSize;
+    return false;
+  case bitc::ATTR_KIND_READ_NONE:
+    *Kind = Attribute::ReadNone;
+    return false;
+  case bitc::ATTR_KIND_READ_ONLY:
+    *Kind = Attribute::ReadOnly;
+    return false;
+  case bitc::ATTR_KIND_RETURNED:
+    *Kind = Attribute::Returned;
+    return false;
+  case bitc::ATTR_KIND_RETURNS_TWICE:
+    *Kind = Attribute::ReturnsTwice;
+    return false;
+  case bitc::ATTR_KIND_S_EXT:
+    *Kind = Attribute::SExt;
+    return false;
+  case bitc::ATTR_KIND_STACK_ALIGNMENT:
+    *Kind = Attribute::StackAlignment;
+    return false;
+  case bitc::ATTR_KIND_STACK_PROTECT:
+    *Kind = Attribute::StackProtect;
+    return false;
+  case bitc::ATTR_KIND_STACK_PROTECT_REQ:
+    *Kind = Attribute::StackProtectReq;
+    return false;
+  case bitc::ATTR_KIND_STACK_PROTECT_STRONG:
+    *Kind = Attribute::StackProtectStrong;
+    return false;
+  case bitc::ATTR_KIND_STRUCT_RET:
+    *Kind = Attribute::StructRet;
+    return false;
+  case bitc::ATTR_KIND_SANITIZE_ADDRESS:
+    *Kind = Attribute::SanitizeAddress;
+    return false;
+  case bitc::ATTR_KIND_SANITIZE_THREAD:
+    *Kind = Attribute::SanitizeThread;
+    return false;
+  case bitc::ATTR_KIND_SANITIZE_MEMORY:
+    *Kind = Attribute::SanitizeMemory;
+    return false;
+  case bitc::ATTR_KIND_UW_TABLE:
+    *Kind = Attribute::UWTable;
+    return false;
+  case bitc::ATTR_KIND_Z_EXT:
+    *Kind = Attribute::ZExt;
+    return false;
+  default:
+    std::string Buf;
+    raw_string_ostream fmt(Buf);
+    fmt << "Unknown attribute kind (" << Code << ")";
+    fmt.flush();
+    return Error(Buf.c_str());
+  }
+}
+
 bool BitcodeReader::ParseAttributeGroupBlock() {
   if (Stream.EnterSubBlock(bitc::PARAMATTR_GROUP_BLOCK_ID))
     return Error("Malformed block record");
@@ -545,9 +666,16 @@ bool BitcodeReader::ParseAttributeGroupBlock() {
       AttrBuilder B;
       for (unsigned i = 2, e = Record.size(); i != e; ++i) {
         if (Record[i] == 0) {        // Enum attribute
-          B.addAttribute(Attribute::AttrKind(Record[++i]));
+          Attribute::AttrKind Kind;
+          if (ParseAttrKind(Record[++i], &Kind))
+            return true;
+
+          B.addAttribute(Kind);
         } else if (Record[i] == 1) { // Align attribute
-          if (Attribute::AttrKind(Record[++i]) == Attribute::Alignment)
+          Attribute::AttrKind Kind;
+          if (ParseAttrKind(Record[++i], &Kind))
+            return true;
+          if (Kind == Attribute::Alignment)
             B.addAlignmentAttr(Record[++i]);
           else
             B.addStackAlignmentAttr(Record[++i]);
index e4de4ab7c7c505754bad66dc558bf69f72093a72..b095447675a02f4295fec73ecd83b2f138f5ab61 100644 (file)
@@ -321,6 +321,7 @@ private:
     return getFnValueByID(ValNo, Ty);
   }
 
+  bool ParseAttrKind(uint64_t Code, Attribute::AttrKind *Kind);
   bool ParseModule(bool Resume);
   bool ParseAttributeBlock();
   bool ParseAttributeGroupBlock();
index 08b72a4691382b8761dba2e66b738317ea03a78e..311c233024f7360bd71e0aedb6de001676a4d61c 100644 (file)
@@ -161,6 +161,89 @@ static void WriteStringRecord(unsigned Code, StringRef Str,
   Stream.EmitRecord(Code, Vals, AbbrevToUse);
 }
 
+static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
+  switch (Kind) {
+  case Attribute::Alignment:
+    return bitc::ATTR_KIND_ALIGNMENT;
+  case Attribute::AlwaysInline:
+    return bitc::ATTR_KIND_ALWAYS_INLINE;
+  case Attribute::Builtin:
+    return bitc::ATTR_KIND_BUILTIN;
+  case Attribute::ByVal:
+    return bitc::ATTR_KIND_BY_VAL;
+  case Attribute::Cold:
+    return bitc::ATTR_KIND_COLD;
+  case Attribute::InlineHint:
+    return bitc::ATTR_KIND_INLINE_HINT;
+  case Attribute::InReg:
+    return bitc::ATTR_KIND_IN_REG;
+  case Attribute::MinSize:
+    return bitc::ATTR_KIND_MIN_SIZE;
+  case Attribute::Naked:
+    return bitc::ATTR_KIND_NAKED;
+  case Attribute::Nest:
+    return bitc::ATTR_KIND_NEST;
+  case Attribute::NoAlias:
+    return bitc::ATTR_KIND_NO_ALIAS;
+  case Attribute::NoBuiltin:
+    return bitc::ATTR_KIND_NO_BUILTIN;
+  case Attribute::NoCapture:
+    return bitc::ATTR_KIND_NO_CAPTURE;
+  case Attribute::NoDuplicate:
+    return bitc::ATTR_KIND_NO_DUPLICATE;
+  case Attribute::NoImplicitFloat:
+    return bitc::ATTR_KIND_NO_IMPLICIT_FLOAT;
+  case Attribute::NoInline:
+    return bitc::ATTR_KIND_NO_INLINE;
+  case Attribute::NonLazyBind:
+    return bitc::ATTR_KIND_NON_LAZY_BIND;
+  case Attribute::NoRedZone:
+    return bitc::ATTR_KIND_NO_RED_ZONE;
+  case Attribute::NoReturn:
+    return bitc::ATTR_KIND_NO_RETURN;
+  case Attribute::NoUnwind:
+    return bitc::ATTR_KIND_NO_UNWIND;
+  case Attribute::OptimizeForSize:
+    return bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE;
+  case Attribute::ReadNone:
+    return bitc::ATTR_KIND_READ_NONE;
+  case Attribute::ReadOnly:
+    return bitc::ATTR_KIND_READ_ONLY;
+  case Attribute::Returned:
+    return bitc::ATTR_KIND_RETURNED;
+  case Attribute::ReturnsTwice:
+    return bitc::ATTR_KIND_RETURNS_TWICE;
+  case Attribute::SExt:
+    return bitc::ATTR_KIND_S_EXT;
+  case Attribute::StackAlignment:
+    return bitc::ATTR_KIND_STACK_ALIGNMENT;
+  case Attribute::StackProtect:
+    return bitc::ATTR_KIND_STACK_PROTECT;
+  case Attribute::StackProtectReq:
+    return bitc::ATTR_KIND_STACK_PROTECT_REQ;
+  case Attribute::StackProtectStrong:
+    return bitc::ATTR_KIND_STACK_PROTECT_STRONG;
+  case Attribute::StructRet:
+    return bitc::ATTR_KIND_STRUCT_RET;
+  case Attribute::SanitizeAddress:
+    return bitc::ATTR_KIND_SANITIZE_ADDRESS;
+  case Attribute::SanitizeThread:
+    return bitc::ATTR_KIND_SANITIZE_THREAD;
+  case Attribute::SanitizeMemory:
+    return bitc::ATTR_KIND_SANITIZE_MEMORY;
+  case Attribute::UWTable:
+    return bitc::ATTR_KIND_UW_TABLE;
+  case Attribute::ZExt:
+    return bitc::ATTR_KIND_Z_EXT;
+  case Attribute::EndAttrKinds:
+    llvm_unreachable("Can not encode end-attribute kinds marker.");
+  case Attribute::None:
+    llvm_unreachable("Can not encode none-attribute.");
+  }
+
+  llvm_unreachable("Trying to encode unknown attribute");
+}
+
 static void WriteAttributeGroupTable(const ValueEnumerator &VE,
                                      BitstreamWriter &Stream) {
   const std::vector<AttributeSet> &AttrGrps = VE.getAttributeGroups();
@@ -182,10 +265,10 @@ static void WriteAttributeGroupTable(const ValueEnumerator &VE,
         Attribute Attr = *I;
         if (Attr.isEnumAttribute()) {
           Record.push_back(0);
-          Record.push_back(Attr.getKindAsEnum());
+          Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
         } else if (Attr.isAlignAttribute()) {
           Record.push_back(1);
-          Record.push_back(Attr.getKindAsEnum());
+          Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
           Record.push_back(Attr.getValueAsInt());
         } else {
           StringRef Kind = Attr.getKindAsString();
diff --git a/test/Bitcode/attributes-3.3.ll b/test/Bitcode/attributes-3.3.ll
new file mode 100644 (file)
index 0000000..cd70ba1
--- /dev/null
@@ -0,0 +1,236 @@
+; RUN:  llvm-dis < %s.bc| FileCheck %s
+
+; attributes-3.3.ll.bc was generated by passing this file to llvm-as-3.3.
+; The test checks that LLVM does not silently misread attributes of
+; older bitcode files.
+
+define void @f1(i8 zeroext)
+; CHECK: define void @f1(i8 zeroext)
+{
+        ret void;
+}
+
+define void @f2(i8 signext)
+; CHECK: define void @f2(i8 signext)
+{
+        ret void;
+}
+
+define void @f3() noreturn
+; CHECK: define void @f3() #0
+{
+        ret void;
+}
+
+define void @f4(i8 inreg)
+; CHECK: define void @f4(i8 inreg)
+{
+        ret void;
+}
+
+define void @f5(i8* sret)
+; CHECK: define void @f5(i8* sret)
+{
+        ret void;
+}
+
+define void @f6() nounwind
+; CHECK: define void @f6() #1
+{
+        ret void;
+}
+
+define void @f7(i8* noalias)
+; CHECK: define void @f7(i8* noalias)
+{
+        ret void;
+}
+
+define void @f8(i8* byval)
+; CHECK: define void @f8(i8* byval)
+{
+        ret void;
+}
+
+define void @f9(i8* nest)
+; CHECK: define void @f9(i8* nest)
+{
+        ret void;
+}
+
+define void @f10() readnone
+; CHECK: define void @f10() #2
+{
+        ret void;
+}
+
+define void @f11() readonly
+; CHECK: define void @f11() #3
+{
+        ret void;
+}
+
+define void @f12() noinline
+; CHECK: define void @f12() #4
+{
+        ret void;
+}
+
+define void @f13() alwaysinline
+; CHECK: define void @f13() #5
+{
+        ret void;
+}
+
+define void @f14() optsize
+; CHECK: define void @f14() #6
+{
+        ret void;
+}
+
+define void @f15() ssp
+; CHECK: define void @f15() #7
+{
+        ret void;
+}
+
+define void @f16() sspreq
+; CHECK: define void @f16() #8
+{
+        ret void;
+}
+
+define void @f17(i8 align 4)
+; CHECK: define void @f17(i8 align 4)
+{
+        ret void;
+}
+
+define void @f18(i8* nocapture)
+; CHECK: define void @f18(i8* nocapture)
+{
+        ret void;
+}
+
+define void @f19() noredzone
+; CHECK: define void @f19() #9
+{
+        ret void;
+}
+
+define void @f20() noimplicitfloat
+; CHECK: define void @f20() #10
+{
+        ret void;
+}
+
+define void @f21() naked
+; CHECK: define void @f21() #11
+{
+        ret void;
+}
+
+define void @f22() inlinehint
+; CHECK: define void @f22() #12
+{
+        ret void;
+}
+
+define void @f23() alignstack(4)
+; CHECK: define void @f23() #13
+{
+        ret void;
+}
+
+define void @f24() returns_twice
+; CHECK: define void @f24() #14
+{
+        ret void;
+}
+
+define void @f25() uwtable
+; CHECK: define void @f25() #15
+{
+        ret void;
+}
+
+define void @f26() nonlazybind
+; CHECK: define void @f26() #16
+{
+        ret void;
+}
+
+define void @f27() sanitize_address
+; CHECK: define void @f27() #17
+{
+        ret void;
+}
+define void @f28() sanitize_thread
+; CHECK: define void @f28() #18
+{
+        ret void;
+}
+define void @f29() sanitize_memory
+; CHECK: define void @f29() #19
+{
+        ret void;
+}
+
+define void @f30() "cpu"="cortex-a8"
+; CHECK: define void @f30() #20
+{
+        ret void;
+}
+
+define i8 @f31(i8 returned %A)
+; CHECK: define i8 @f31(i8 returned %A)
+{
+        ret i8 %A;
+}
+
+define void @f32() sspstrong
+; CHECK: define void @f32() #21
+{
+        ret void;
+}
+
+define void @f33() minsize
+; CHECK: define void @f33() #22
+{
+        ret void;
+}
+
+declare void @nobuiltin()
+
+define void @f34()
+; CHECK: define void @f34()
+{
+        call void @nobuiltin() nobuiltin
+; CHECK: call void @nobuiltin() #23
+        ret void;
+}
+
+; CHECK: attributes #0 = { noreturn }
+; CHECK: attributes #1 = { nounwind }
+; CHECK: attributes #2 = { readnone }
+; CHECK: attributes #3 = { readonly }
+; CHECK: attributes #4 = { noinline }
+; CHECK: attributes #5 = { alwaysinline }
+; CHECK: attributes #6 = { optsize }
+; CHECK: attributes #7 = { ssp }
+; CHECK: attributes #8 = { sspreq }
+; CHECK: attributes #9 = { noredzone }
+; CHECK: attributes #10 = { noimplicitfloat }
+; CHECK: attributes #11 = { naked }
+; CHECK: attributes #12 = { inlinehint }
+; CHECK: attributes #13 = { alignstack=4 }
+; CHECK: attributes #14 = { returns_twice }
+; CHECK: attributes #15 = { uwtable }
+; CHECK: attributes #16 = { nonlazybind }
+; CHECK: attributes #17 = { sanitize_address }
+; CHECK: attributes #18 = { sanitize_thread }
+; CHECK: attributes #19 = { sanitize_memory }
+; CHECK: attributes #20 = { "cpu"="cortex-a8" }
+; CHECK: attributes #21 = { sspstrong }
+; CHECK: attributes #22 = { minsize }
+; CHECK: attributes #23 = { nobuiltin }
diff --git a/test/Bitcode/attributes-3.3.ll.bc b/test/Bitcode/attributes-3.3.ll.bc
new file mode 100644 (file)
index 0000000..5dd7186
Binary files /dev/null and b/test/Bitcode/attributes-3.3.ll.bc differ