summaryrefslogtreecommitdiff
path: root/lib/VMCore/InlineAsm.cpp
blob: b36d2128a61e9521841e11eb903de1971de93473 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//===-- InlineAsm.cpp - Implement the InlineAsm class ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the InlineAsm class.
//
//===----------------------------------------------------------------------===//

#include "llvm/InlineAsm.h"
#include "llvm/DerivedTypes.h"
#include <algorithm>
#include <cctype>
using namespace llvm;

// NOTE: when memoizing the function type, we have to be careful to handle the
// case when the type gets refined.

InlineAsm *InlineAsm::get(const FunctionType *Ty, const std::string &AsmString,
                          const std::string &Constraints, bool hasSideEffects) {
  // FIXME: memoize!
  return new InlineAsm(Ty, AsmString, Constraints, hasSideEffects);  
}

InlineAsm::InlineAsm(const FunctionType *Ty, const std::string &asmString,
                     const std::string &constraints, bool hasSideEffects)
  : Value(PointerType::get(Ty), Value::InlineAsmVal), AsmString(asmString), 
    Constraints(constraints), HasSideEffects(hasSideEffects) {

  // Do various checks on the constraint string and type.
  assert(Verify(Ty, constraints) && "Function type not legal for constraints!");
}

const FunctionType *InlineAsm::getFunctionType() const {
  return cast<FunctionType>(getType()->getElementType());
}

/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the
/// fields in this structure.  If the constraint string is not understood,
/// return true, otherwise return false.
bool InlineAsm::ConstraintInfo::Parse(const std::string &Str,
                     std::vector<InlineAsm::ConstraintInfo> &ConstraintsSoFar) {
  std::string::const_iterator I = Str.begin(), E = Str.end();
  
  // Initialize
  Type = isInput;
  isEarlyClobber = false;
  isIndirectOutput = false;
  hasMatchingInput = false;
  isCommutative = false;
  
  // Parse the prefix.
  if (*I == '~') {
    Type = isClobber;
    ++I;
  } else if (*I == '=') {
    ++I;
    Type = isOutput;
    if (I != E && *I == '=') {
      isIndirectOutput = true;
      ++I;
    }
  }
  
  if (I == E) return true;  // Just a prefix, like "==" or "~".
  
  // Parse the modifiers.
  bool DoneWithModifiers = false;
  while (!DoneWithModifiers) {
    switch (*I) {
    default:
      DoneWithModifiers = true;
      break;
    case '&':     // Early clobber.
      if (Type != isOutput ||      // Cannot early clobber anything but output.
          isEarlyClobber)          // Reject &&&&&&
        return true;
      isEarlyClobber = true;
      break;
    case '%':     // Commutative.
      if (Type == isClobber ||     // Cannot commute clobbers.
          isCommutative)           // Reject %%%%%
        return true;
      isCommutative = true;
      break;
    case '#':     // Comment.
    case '*':     // Register preferencing.
      return true;     // Not supported.
    }
    
    if (!DoneWithModifiers) {
      ++I;
      if (I == E) return true;   // Just prefixes and modifiers!
    }
  }
  
  // Parse the various constraints.
  while (I != E) {
    if (*I == '{') {   // Physical register reference.
      // Find the end of the register name.
      std::string::const_iterator ConstraintEnd = std::find(I+1, E, '}');
      if (ConstraintEnd == E) return true;  // "{foo"
      Codes.push_back(std::string(I, ConstraintEnd+1));
      I = ConstraintEnd+1;
    } else if (isdigit(*I)) {     // Matching Constraint
      // Maximal munch numbers.
      std::string::const_iterator NumStart = I;
      while (I != E && isdigit(*I))
        ++I;
      Codes.push_back(std::string(NumStart, I));
      unsigned N = atoi(Codes.back().c_str());
      // Check that this is a valid matching constraint!
      if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput||
          Type != isInput)
        return true;  // Invalid constraint number.
      
      // Note that operand #n has a matching input.
      ConstraintsSoFar[N].hasMatchingInput = true;
    } else {
      // Single letter constraint.
      Codes.push_back(std::string(I, I+1));
      ++I;
    }
  }

  return false;
}

std::vector<InlineAsm::ConstraintInfo>
InlineAsm::ParseConstraints(const std::string &Constraints) {
  std::vector<ConstraintInfo> Result;
  
  // Scan the constraints string.
  for (std::string::const_iterator I = Constraints.begin(), 
       E = Constraints.end(); I != E; ) {
    ConstraintInfo Info;

    // Find the end of this constraint.
    std::string::const_iterator ConstraintEnd = std::find(I, E, ',');

    if (ConstraintEnd == I ||  // Empty constraint like ",,"
        Info.Parse(std::string(I, ConstraintEnd), Result)) {
      Result.clear();          // Erroneous constraint?
      break;
    }

    Result.push_back(Info);
    
    // ConstraintEnd may be either the next comma or the end of the string.  In
    // the former case, we skip the comma.
    I = ConstraintEnd;
    if (I != E) {
      ++I;
      if (I == E) { Result.clear(); break; }    // don't allow "xyz,"
    }
  }
  
  return Result;
}


/// Verify - Verify that the specified constraint string is reasonable for the
/// specified function type, and otherwise validate the constraint string.
bool InlineAsm::Verify(const FunctionType *Ty, const std::string &ConstStr) {
  if (Ty->isVarArg()) return false;
  
  std::vector<ConstraintInfo> Constraints = ParseConstraints(ConstStr);
  
  // Error parsing constraints.
  if (Constraints.empty() && !ConstStr.empty()) return false;
  
  unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;
  
  for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
    switch (Constraints[i].Type) {
    case InlineAsm::isOutput:
      if (!Constraints[i].isIndirectOutput) {
        if (NumInputs || NumClobbers) return false;  // outputs come first.
        ++NumOutputs;
        break;
      }
      // FALLTHROUGH for IndirectOutputs.
    case InlineAsm::isInput:
      if (NumClobbers) return false;               // inputs before clobbers.
      ++NumInputs;
      break;
    case InlineAsm::isClobber:
      ++NumClobbers;
      break;
    }
  }
    
  if (NumOutputs > 1) return false;  // Only one result allowed so far.
  
  if ((Ty->getReturnType() != Type::VoidTy) != NumOutputs)
    return false;   // NumOutputs = 1 iff has a result type.
  
  if (Ty->getNumParams() != NumInputs) return false;
  return true;
}