bool matchSparcAsmModifiers(const MCExpr *&EVal, SMLoc &EndLoc);
bool parseDirectiveWord(unsigned Size, SMLoc L);
- bool is64Bit() const { return STI.getTargetTriple().startswith("sparcv9"); }
+ bool is64Bit() const {
+ return STI.getTargetTriple().getArch() == Triple::sparcv9;
+ }
void expandSET(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
const MCInstrInfo &MII,
const MCTargetOptions &Options)
- : MCTargetAsmParser(), STI(sti), Parser(parser) {
+ : MCTargetAsmParser(Options), STI(sti), Parser(parser) {
// Initialize the set of available features.
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
}
SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27,
SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31};
+ static unsigned IntPairRegs[] = {
+ Sparc::G0_G1, Sparc::G2_G3, Sparc::G4_G5, Sparc::G6_G7,
+ Sparc::O0_O1, Sparc::O2_O3, Sparc::O4_O5, Sparc::O6_O7,
+ Sparc::L0_L1, Sparc::L2_L3, Sparc::L4_L5, Sparc::L6_L7,
+ Sparc::I0_I1, Sparc::I2_I3, Sparc::I4_I5, Sparc::I6_I7};
+
/// SparcOperand - Instances of this class represent a parsed Sparc machine
/// instruction.
class SparcOperand : public MCParsedAsmOperand {
enum RegisterKind {
rk_None,
rk_IntReg,
+ rk_IntPairReg,
rk_FloatReg,
rk_DoubleReg,
rk_QuadReg,
bool isMEMrr() const { return Kind == k_MemoryReg; }
bool isMEMri() const { return Kind == k_MemoryImm; }
+ bool isIntReg() const {
+ return (Kind == k_Register && Reg.Kind == rk_IntReg);
+ }
+
bool isFloatReg() const {
return (Kind == k_Register && Reg.Kind == rk_FloatReg);
}
return Op;
}
+ static bool MorphToIntPairReg(SparcOperand &Op) {
+ unsigned Reg = Op.getReg();
+ assert(Op.Reg.Kind == rk_IntReg);
+ unsigned regIdx = 32;
+ if (Reg >= Sparc::G0 && Reg <= Sparc::G7)
+ regIdx = Reg - Sparc::G0;
+ else if (Reg >= Sparc::O0 && Reg <= Sparc::O7)
+ regIdx = Reg - Sparc::O0 + 8;
+ else if (Reg >= Sparc::L0 && Reg <= Sparc::L7)
+ regIdx = Reg - Sparc::L0 + 16;
+ else if (Reg >= Sparc::I0 && Reg <= Sparc::I7)
+ regIdx = Reg - Sparc::I0 + 24;
+ if (regIdx % 2 || regIdx > 31)
+ return false;
+ Op.Reg.RegNum = IntPairRegs[regIdx / 2];
+ Op.Reg.Kind = rk_IntPairReg;
+ return true;
+ }
+
static bool MorphToDoubleReg(SparcOperand &Op) {
unsigned Reg = Op.getReg();
assert(Op.Reg.Kind == rk_FloatReg);
// the imm operand can be either an expression or an immediate.
bool IsImm = Inst.getOperand(1).isImm();
- uint64_t ImmValue = IsImm ? MCValOp.getImm() : 0;
+ int64_t RawImmValue = IsImm ? MCValOp.getImm() : 0;
+
+ // Allow either a signed or unsigned 32-bit immediate.
+ if (RawImmValue < -2147483648LL || RawImmValue > 4294967295LL) {
+ Error(IDLoc, "set: argument must be between -2147483648 and 4294967295");
+ return;
+ }
+
+ // If the value was expressed as a large unsigned number, that's ok.
+ // We want to see if it "looks like" a small signed number.
+ int32_t ImmValue = RawImmValue;
+ // For 'set' you can't use 'or' with a negative operand on V9 because
+ // that would splat the sign bit across the upper half of the destination
+ // register, whereas 'set' is defined to zero the high 32 bits.
+ bool IsEffectivelyImm13 =
+ IsImm && ((is64Bit() ? 0 : -4096) <= ImmValue && ImmValue < 4096);
const MCExpr *ValExpr;
if (IsImm)
ValExpr = MCConstantExpr::create(ImmValue, getContext());
MCOperand PrevReg = MCOperand::createReg(Sparc::G0);
- if (!IsImm || (ImmValue & ~0x1fff)) {
+ // If not just a signed imm13 value, then either we use a 'sethi' with a
+ // following 'or', or a 'sethi' by itself if there are no more 1 bits.
+ // In either case, start with the 'sethi'.
+ if (!IsEffectivelyImm13) {
MCInst TmpInst;
const MCExpr *Expr =
SparcMCExpr::create(SparcMCExpr::VK_Sparc_HI, ValExpr, getContext());
PrevReg = MCRegOp;
}
- if (!IsImm || ((ImmValue & 0x1fff) != 0 || ImmValue == 0)) {
+ // The low bits require touching in 3 cases:
+ // * A non-immediate value will always require both instructions.
+ // * An effectively imm13 value needs only an 'or' instruction.
+ // * Otherwise, an immediate that is not effectively imm13 requires the
+ // 'or' only if bits remain after clearing the 22 bits that 'sethi' set.
+ // If the low bits are known zeros, there's nothing to do.
+ // In the second case, and only in that case, must we NOT clear
+ // bits of the immediate value via the %lo() assembler function.
+ // Note also, the 'or' instruction doesn't mind a large value in the case
+ // where the operand to 'set' was 0xFFFFFzzz - it does exactly what you mean.
+ if (!IsImm || IsEffectivelyImm13 || (ImmValue & 0x3ff)) {
MCInst TmpInst;
- const MCExpr *Expr =
- SparcMCExpr::create(SparcMCExpr::VK_Sparc_LO, ValExpr, getContext());
+ const MCExpr *Expr;
+ if (IsEffectivelyImm13)
+ Expr = ValExpr;
+ else
+ Expr =
+ SparcMCExpr::create(SparcMCExpr::VK_Sparc_LO, ValExpr, getContext());
TmpInst.setLoc(IDLoc);
TmpInst.setOpcode(SP::ORri);
TmpInst.addOperand(MCRegOp);
case Sparc::PSR:
Op = SparcOperand::CreateToken("%psr", S);
break;
+ case Sparc::FSR:
+ Op = SparcOperand::CreateToken("%fsr", S);
+ break;
case Sparc::WIM:
Op = SparcOperand::CreateToken("%wim", S);
break;
case AsmToken::Minus:
case AsmToken::Integer:
case AsmToken::LParen:
+ case AsmToken::Dot:
if (!getParser().parseExpression(EVal, E))
Op = SparcOperand::CreateImm(EVal, S, E);
break;
return true;
}
+ // %fprs is an alias of %asr6.
+ if (name.equals("fprs")) {
+ RegNo = ASRRegs[6];
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
if (name.equals("icc")) {
RegNo = Sparc::ICC;
RegKind = SparcOperand::rk_Special;
return true;
}
+ if (name.equals("fsr")) {
+ RegNo = Sparc::FSR;
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
if (name.equals("wim")) {
RegNo = Sparc::WIM;
RegKind = SparcOperand::rk_Special;
return false;
}
+// Determine if an expression contains a reference to the symbol
+// "_GLOBAL_OFFSET_TABLE_".
static bool hasGOTReference(const MCExpr *Expr) {
switch (Expr->getKind()) {
case MCExpr::Target:
bool isPIC = getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_;
+ // Ugly: if a sparc assembly expression says "%hi(...)" but the
+ // expression within contains _GLOBAL_OFFSET_TABLE_, it REALLY means
+ // %pc22. Same with %lo -> %pc10. Worse, if it doesn't contain that,
+ // the meaning depends on whether the assembler was invoked with
+ // -KPIC or not: if so, it really means %got22/%got10; if not, it
+ // actually means what it said! Sigh, historical mistakes...
+
switch(VK) {
default: break;
case SparcMCExpr::VK_Sparc_LO:
break;
}
}
+ if (Op.isIntReg() && Kind == MCK_IntPair) {
+ if (SparcOperand::MorphToIntPairReg(Op))
+ return MCTargetAsmParser::Match_Success;
+ }
return Match_InvalidOperand;
}