1a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//===- NaClBitcodeHeader.cpp ----------------------------------------------===//
2a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//     PNaCl bitcode header reader.
3a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//
4a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//                     The LLVM Compiler Infrastructure
5a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//
6a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth// This file is distributed under the University of Illinois Open Source
7a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth// License. See LICENSE.TXT for details.
8a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//
9a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//===----------------------------------------------------------------------===//
10a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//
11a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth// Implementation of Bitcode abbrevations.
12a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//
13a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth//===----------------------------------------------------------------------===//
14a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
15a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth#include "llvm/Bitcode/NaCl/NaClBitCodes.h"
16a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth#include "llvm/Support/raw_ostream.h"
17a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth#include "llvm/Support/ErrorHandling.h"
18a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
19a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnothusing namespace llvm;
20a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
21a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnothconst bool NaClBitCodeAbbrevOp::HasValueArray[] = {
22a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  true,  // Literal
23a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  true,  // Fixed
24a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  true,  // VBR
25a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  false, // Array
26a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  false  // Char6
27a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth};
28a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
29a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnothconst char *NaClBitCodeAbbrevOp::EncodingNameArray[] = {
30a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  "Literal",
31a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  "Fixed",
32a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  "VBR",
33a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  "Array",
34a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  "Char6"
35a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth};
36a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
37a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim StichnothNaClBitCodeAbbrevOp::NaClBitCodeAbbrevOp(Encoding E, uint64_t Data)
38a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    : Enc(E), Val(Data) {
39a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  if (isValid(E, Data)) return;
40a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  std::string Buffer;
41a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  raw_string_ostream StrBuf(Buffer);
42a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  StrBuf << "Invalid NaClBitCodeAbbrevOp(" << E << ", " << Data << ")";
43a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  report_fatal_error(StrBuf.str());
44a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth}
45a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
46a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnothbool NaClBitCodeAbbrevOp::isValid(Encoding E, uint64_t Val) {
47a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  switch (NaClBitCodeAbbrevOp::Encoding(E)) {
48a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  case Literal:
49a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    return true;
50a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  case Fixed:
51a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  case VBR:
52a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    return Val <= naclbitc::MaxAbbrevWidth;
53a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  case Char6:
54a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  case Array:
55a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    return Val == 0;
56a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  }
57a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  llvm_unreachable("unhandled abbreviation");
58a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth}
59a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
60a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnothvoid NaClBitCodeAbbrevOp::Print(raw_ostream& Stream) const {
61a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  if (Enc == Literal) {
62a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    Stream << getValue();
63a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    return;
64a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  }
65a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  Stream << getEncodingName(Enc);
66a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  if (!hasValue())
67a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    return;
68a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  Stream << "(" << Val << ")";
69a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth}
70a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
71a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnothstatic void PrintExpression(raw_ostream &Stream,
72a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth                            const NaClBitCodeAbbrev *Abbrev,
73a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth                            unsigned &Index) {
74a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  // Bail out early, in case we are incrementally building the
75a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  // expression and the argument is not available yet.
76a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  if (Index >= Abbrev->getNumOperandInfos()) return;
77a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
78a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  const NaClBitCodeAbbrevOp &Op = Abbrev->getOperandInfo(Index);
79a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  Op.Print(Stream);
80a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  if (unsigned NumArgs = Op.NumArguments()) {
81a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    Stream << "(";
82a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    for (unsigned i = 0; i < NumArgs; ++i) {
83a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth      ++Index;
84a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth      if (i > 0) Stream << ",";
85a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth      PrintExpression(Stream, Abbrev, Index);
86a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    }
87a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    Stream << ")";
88a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  }
89a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth}
90a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
91a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnothvoid NaClBitCodeAbbrev::Print(raw_ostream &Stream, bool AddNewLine) const {
92a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  Stream << "[";
93a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  for (unsigned i = 0; i < getNumOperandInfos(); ++i) {
94a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    if (i > 0) Stream << ", ";
95a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    PrintExpression(Stream, this, i);
96a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  }
97a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  Stream << "]";
98a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  if (AddNewLine) Stream << "\n";
99a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth}
100a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
101a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim StichnothNaClBitCodeAbbrev *NaClBitCodeAbbrev::Simplify() const {
102a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  NaClBitCodeAbbrev *Abbrev = new NaClBitCodeAbbrev();
103a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  for (unsigned i = 0; i < OperandList.size(); ++i) {
104a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    const NaClBitCodeAbbrevOp &Op = OperandList[i];
105a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    // Simplify if possible.  Currently, the only simplification known
106a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    // is to remove unnecessary operands appearing immediately before an
107a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    // array operator. That is, apply the simplification:
108a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    //    Op Array(Op) -> Array(Op)
109a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    assert(!Op.isArrayOp() || i == OperandList.size()-2);
110a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    while (Op.isArrayOp() && !Abbrev->OperandList.empty() &&
111a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth           Abbrev->OperandList.back() == OperandList[i+1]) {
112a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth      Abbrev->OperandList.pop_back();
113a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    }
114a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    Abbrev->OperandList.push_back(Op);
115a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  }
116a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  return Abbrev;
117a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth}
118a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth
119a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnothbool NaClBitCodeAbbrev::isValid() const {
120a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  // Verify that an array op appears can only appear if it is the
121a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  // second to last element.
122a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  unsigned NumOperands = getNumOperandInfos();
123a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  if (NumOperands == 0) return false;
124a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  for (unsigned i = 0; i < NumOperands; ++i) {
125a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    const NaClBitCodeAbbrevOp &Op = getOperandInfo(i);
126a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth    if (Op.isArrayOp() && i + 2 != NumOperands)
127a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth      // Note: Unlike LLVM bitcode, we allow literals in arrays!
128a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth      return false;
129a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  }
130a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth  return true;
131a5b16abfebb1d33fa4b4448f1bda1bf02cc0bd58Jim Stichnoth}
132