bool TargetInfo::validateInputConstraint( MutableArrayRef<ConstraintInfo> OutputConstraints, ConstraintInfo &Info) const { const char *Name = Info.ConstraintStr.c_str(); if (!*Name) return false; while (*Name) { switch (*Name) { default: // Check if we have a matching constraint if (*Name >= '0' && *Name <= '9') { const char *DigitStart = Name; while (Name[1] >= '0' && Name[1] <= '9') Name++; const char *DigitEnd = Name; unsigned i; if (StringRef(DigitStart, DigitEnd - DigitStart + 1) .getAsInteger(10, i)) return false; // Check if matching constraint is out of bounds. if (i >= OutputConstraints.size()) return false; // A number must refer to an output only operand. if (OutputConstraints[i].isReadWrite()) return false; // If the constraint is already tied, it must be tied to the // same operand referenced to by the number. if (Info.hasTiedOperand() && Info.getTiedOperand() != i) return false; // The constraint should have the same info as the respective // output constraint. Info.setTiedOperand(i, OutputConstraints[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'. return false; } break; case '[': { unsigned Index = 0; if (!resolveSymbolicName(Name, OutputConstraints, Index)) return false; // If the constraint is already tied, it must be tied to the // same operand referenced to by the number. if (Info.hasTiedOperand() && Info.getTiedOperand() != Index) return false; // A number must refer to an output only operand. if (OutputConstraints[Index].isReadWrite()) return false; Info.setTiedOperand(Index, OutputConstraints[Index]); break; } case '%': // commutative // FIXME: Fail if % is used with the last operand. break; case 'i': // immediate integer. case 'n': // immediate integer with a known value. break; case 'I': // Various constant constraints with target-specific meanings. case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': if (!validateAsmConstraint(Name, Info)) return false; break; case 'r': // general register. Info.setAllowsRegister(); break; case 'm': // memory operand. case 'o': // offsettable memory operand. case 'V': // non-offsettable memory operand. case '<': // autodecrement memory operand. case '>': // autoincrement memory operand. Info.setAllowsMemory(); break; case 'g': // general register, memory operand or immediate integer. case 'X': // any operand. Info.setAllowsRegister(); Info.setAllowsMemory(); break; case 'E': // immediate floating point. case 'F': // immediate floating point. case 'p': // address operand. break; case ',': // multiple alternative constraint. Ignore comma. break; case '#': // Ignore as constraint. while (Name[1] && Name[1] != ',') Name++; break; case '?': // Disparage slightly code. case '!': // Disparage severely. case '*': // Ignore for choosing register preferences. break; // Pass them. } Name++; } return true; }
bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, unsigned NumOutputs, ConstraintInfo &Info) const { const char *Name = Info.ConstraintStr.c_str(); while (*Name) { switch (*Name) { default: // Check if we have a matching constraint if (*Name >= '0' && *Name <= '9') { unsigned i = *Name - '0'; // Check if matching constraint is out of bounds. if (i >= NumOutputs) return false; // The constraint should have the same info as the respective // output constraint. Info.setTiedOperand(i, OutputConstraints[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'. return false; } break; case '[': { unsigned Index = 0; if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index)) return false; break; } case '%': // commutative // FIXME: Fail if % is used with the last operand. break; case 'i': // immediate integer. case 'n': // immediate integer with a known value. break; case 'I': // Various constant constraints with target-specific meanings. case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': break; case 'r': // general register. Info.setAllowsRegister(); break; case 'm': // memory operand. Info.setAllowsMemory(); break; case 'g': // general register, memory operand or immediate integer. case 'X': // any operand. Info.setAllowsRegister(); Info.setAllowsMemory(); break; } Name++; } return true; }