bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { const char *Name = Info.getConstraintStr().c_str(); // An output constraint must start with '=' or '+' if (*Name != '=' && *Name != '+') return false; if (*Name == '+') Info.setIsReadWrite(); Name++; while (*Name) { switch (*Name) { default: 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'. return false; } break; case '&': // early clobber. Info.setEarlyClobber(); break; case '%': // commutative. // FIXME: Check that there is a another register after this one. break; case 'r': // general register. Info.setAllowsRegister(); break; case 'm': // memory operand. case 'o': // offsetable memory operand. case 'V': // non-offsetable 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 ',': // multiple alternative constraint. Pass it. // Handle additional optional '=' or '+' modifiers. if (Name[1] == '=' || Name[1] == '+') Name++; 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++; } // Early clobber with a read-write constraint which doesn't permit registers // is invalid. if (Info.earlyClobber() && Info.isReadWrite() && !Info.allowsRegister()) return false; // If a constraint allows neither memory nor register operands it contains // only modifiers. Reject it. return Info.allowsMemory() || Info.allowsRegister(); }
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; }