// For example, on x86 it will return "ax" when "eax" is passed in.
const char *getNormalizedGCCRegisterName(const char *Name) const;
- enum ConstraintInfo {
- CI_None = 0x00,
- CI_AllowsMemory = 0x01,
- CI_AllowsRegister = 0x02,
- CI_ReadWrite = 0x04
+ struct ConstraintInfo {
+ enum {
+ CI_None = 0x00,
+ CI_AllowsMemory = 0x01,
+ CI_AllowsRegister = 0x02,
+ CI_ReadWrite = 0x04 // "+r" output constraint (read and write).
+ };
+ unsigned Flags;
+ int TiedOperand;
+ public:
+ ConstraintInfo() : Flags(0), TiedOperand(-1) {}
+
+ bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; }
+ bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; }
+ bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; }
+ bool hasTiedOperand() const { return TiedOperand != -1; }
+ unsigned getTiedOperand() const {
+ assert(hasTiedOperand() && "Has no tied operand!");
+ return (unsigned)TiedOperand;
+ }
+
+ void setIsReadWrite() { Flags |= CI_ReadWrite; }
+ void setAllowsMemory() { Flags |= CI_AllowsMemory; }
+ void setAllowsRegister() { Flags |= CI_AllowsRegister; }
+ void setTiedOperand(unsigned N) { TiedOperand = N; }
};
// validateOutputConstraint, validateInputConstraint - Checks that
}
bool TargetInfo::validateOutputConstraint(const char *Name,
- ConstraintInfo &info) const
-{
- info = CI_None;
-
+ ConstraintInfo &Info) const {
// An output constraint must start with '=' or '+'
if (*Name != '=' && *Name != '+')
return false;
if (*Name == '+')
- info = CI_ReadWrite;
- else
- info = CI_None;
+ Info.setIsReadWrite();
Name++;
while (*Name) {
switch (*Name) {
default:
- if (!validateAsmConstraint(Name, info)) {
+ if (!validateAsmConstraint(Name, Info)) {
// FIXME: We temporarily return false
// so we can add more constraints as we hit it.
// Eventually, an unknown constraint should just be treated as 'g'.
case '&': // early clobber.
break;
case 'r': // general register.
- info = (ConstraintInfo)(info|CI_AllowsRegister);
+ Info.setAllowsRegister();
break;
case 'm': // memory operand.
- info = (ConstraintInfo)(info|CI_AllowsMemory);
+ Info.setAllowsMemory();
break;
case 'g': // general register, memory operand or immediate integer.
case 'X': // any operand.
- info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
+ Info.setAllowsRegister();
+ Info.setAllowsMemory();
break;
}
bool TargetInfo::resolveSymbolicName(const char *&Name,
const std::string *OutputNamesBegin,
const std::string *OutputNamesEnd,
- unsigned &Index) const
-{
+ unsigned &Index) const {
assert(*Name == '[' && "Symbolic name did not start with '['");
-
Name++;
const char *Start = Name;
while (*Name && *Name != ']')
bool TargetInfo::validateInputConstraint(const char *Name,
const std::string *OutputNamesBegin,
const std::string *OutputNamesEnd,
- ConstraintInfo* OutputConstraints,
- ConstraintInfo &info) const {
- info = CI_None;
-
+ ConstraintInfo *OutputConstraints,
+ ConstraintInfo &Info) const {
while (*Name) {
switch (*Name) {
default:
// The constraint should have the same info as the respective
// output constraint.
- info = (ConstraintInfo)(info|OutputConstraints[i]);
- } else if (!validateAsmConstraint(Name, info)) {
+ Info = OutputConstraints[i];
+ Info.setTiedOperand(i);
+ } else if (!validateAsmConstraint(Name, Info)) {
// FIXME: This error return is in place temporarily so we can
// add more constraints as we hit it. Eventually, an unknown
// constraint should just be treated as 'g'.
case 'n': // immediate integer with a known value.
break;
case 'r': // general register.
- info = (ConstraintInfo)(info|CI_AllowsRegister);
+ Info.setAllowsRegister();
break;
case 'm': // memory operand.
- info = (ConstraintInfo)(info|CI_AllowsMemory);
+ Info.setAllowsMemory();
break;
case 'g': // general register, memory operand or immediate integer.
case 'X': // any operand.
- info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
+ Info.setAllowsRegister();
+ Info.setAllowsMemory();
break;
}
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const;
virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
+ TargetInfo::ConstraintInfo &Info) const {
switch (*Name) {
default: return false;
case 'O': // Zero
return true;
case 'b': // Base register
case 'f': // Floating point register
- info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister);
+ Info.setAllowsRegister();
return true;
}
}
bool
X86TargetInfo::validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
+ TargetInfo::ConstraintInfo &Info) const {
switch (*Name) {
default: return false;
case 'a': // eax.
// x86_64 instructions.
case 'N': // unsigned 8-bit integer constant for use with in and out
// instructions.
- info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister);
+ Info.setAllowsRegister();
return true;
}
}
NumAliases = 0;
}
virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
+ TargetInfo::ConstraintInfo &Info) const {
// FIXME: Check if this is complete
switch (*Name) {
default:
case 'h': // r8-r15
case 'w': // VFP Floating point register single precision
case 'P': // VFP Floating point register double precision
- info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister);
+ Info.setAllowsRegister();
return true;
}
return false;
const Expr *InputExpr,
std::string &ConstraintStr) {
llvm::Value *Arg;
- if ((Info & TargetInfo::CI_AllowsRegister) ||
- !(Info & TargetInfo::CI_AllowsMemory)) {
+ if (Info.allowsRegister() || !Info.allowsMemory()) {
const llvm::Type *Ty = ConvertType(InputExpr->getType());
if (Ty->isSingleValueType()) {
// If the first output operand is not a memory dest, we'll
// make it the return value.
- if (i == 0 && !(Info & TargetInfo::CI_AllowsMemory) &&
- DestValueType->isSingleValueType()) {
+ if (i == 0 && !Info.allowsMemory() && DestValueType->isSingleValueType()) {
ResultAddr = Dest.getAddress();
ResultType = DestValueType;
Constraints += "=" + OutputConstraint;
Constraints += OutputConstraint;
}
- if (Info & TargetInfo::CI_ReadWrite) {
+ if (Info.isReadWrite()) {
InOutConstraints += ',';
const Expr *InputExpr = S.getOutputExpr(i);
llvm::Value *Arg = EmitAsmInput(S, Info, InputExpr, InOutConstraints);
- if (Info & TargetInfo::CI_AllowsRegister)
+ if (Info.allowsRegister())
InOutConstraints += llvm::utostr(i);
else
InOutConstraints += OutputConstraint;
std::string OutputConstraint(Literal->getStrData(),
Literal->getByteLength());
- TargetInfo::ConstraintInfo info;
- if (!Context.Target.validateOutputConstraint(OutputConstraint.c_str(),info))
+ TargetInfo::ConstraintInfo Info;
+ if (!Context.Target.validateOutputConstraint(OutputConstraint.c_str(),Info))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_invalid_output_constraint) << OutputConstraint);
<< OutputExpr->getSubExpr()->getSourceRange());
}
- OutputConstraintInfos.push_back(info);
+ OutputConstraintInfos.push_back(Info);
}
for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
std::string InputConstraint(Literal->getStrData(),
Literal->getByteLength());
- TargetInfo::ConstraintInfo info;
+ TargetInfo::ConstraintInfo Info;
if (!Context.Target.validateInputConstraint(InputConstraint.c_str(),
&Names[0],
&Names[0] + NumOutputs,
&OutputConstraintInfos[0],
- info)) {
+ Info)) {
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_invalid_input_constraint) << InputConstraint);
}
ParenExpr *InputExpr = cast<ParenExpr>(Exprs[i]);
// Only allow void types for memory constraints.
- if ((info & TargetInfo::CI_AllowsMemory)
- && !(info & TargetInfo::CI_AllowsRegister)) {
+ if (Info.allowsMemory() && !Info.allowsRegister()) {
if (CheckAsmLValue(InputExpr, *this))
return StmtError(Diag(InputExpr->getSubExpr()->getLocStart(),
diag::err_asm_invalid_lvalue_in_input)
- << InputConstraint << InputExpr->getSubExpr()->getSourceRange());
+ << InputConstraint << InputExpr->getSubExpr()->getSourceRange());
}
- if (info & TargetInfo::CI_AllowsRegister) {
+ if (Info.allowsRegister()) {
if (InputExpr->getType()->isVoidType()) {
return StmtError(Diag(InputExpr->getSubExpr()->getLocStart(),
diag::err_asm_invalid_type_in_input)