CI_ReadWrite = 0x04, // "+r" output constraint (read and write).
CI_HasMatchingInput = 0x08, // This output operand has a matching input.
CI_ImmediateConstant = 0x10, // This operand must be an immediate constant
+ CI_EarlyClobber = 0x20, // "&" output constraint (early clobber).
};
unsigned Flags;
int TiedOperand;
const std::string &getConstraintStr() const { return ConstraintStr; }
const std::string &getName() const { return Name; }
bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; }
+ bool earlyClobber() { return (Flags & CI_EarlyClobber) != 0; }
bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; }
bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; }
int getImmConstantMax() const { return ImmRange.Max; }
void setIsReadWrite() { Flags |= CI_ReadWrite; }
+ void setEarlyClobber() { Flags |= CI_EarlyClobber; }
void setAllowsMemory() { Flags |= CI_AllowsMemory; }
void setAllowsRegister() { Flags |= CI_AllowsRegister; }
void setHasMatchingInput() { Flags |= CI_HasMatchingInput; }
// 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.
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();
: [l] "=r"(l)
: "[l],m"(l)); // expected-error {{asm constraint has an unexpected number of alternatives: 1 vs 2}}
}
+
+void fn2() {
+ int l;
+ __asm__(""
+ : "+&m"(l)); // expected-error {{invalid output constraint '+&m' in asm}}
+}