aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/ARM/ARMInstrThumb.td47
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp47
-rw-r--r--test/MC/ARM/basic-thumb-instructions.s22
-rw-r--r--test/MC/ARM/thumb-diagnostics.s19
-rw-r--r--utils/TableGen/EDEmitter.cpp3
5 files changed, 118 insertions, 20 deletions
diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td
index 61b94ccef7..a5ddec3d23 100644
--- a/lib/Target/ARM/ARMInstrThumb.td
+++ b/lib/Target/ARM/ARMInstrThumb.td
@@ -78,8 +78,17 @@ def t_adrlabel : Operand<i32> {
}
// Scaled 4 immediate.
-def t_imm_s4 : Operand<i32> {
+def t_imm0_1020s4_asmoperand: AsmOperandClass { let Name = "Imm0_1020s4"; }
+def t_imm0_1020s4 : Operand<i32> {
let PrintMethod = "printThumbS4ImmOperand";
+ let ParserMatchClass = t_imm0_1020s4_asmoperand;
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
+def t_imm0_508s4_asmoperand: AsmOperandClass { let Name = "Imm0_508s4"; }
+def t_imm0_508s4 : Operand<i32> {
+ let PrintMethod = "printThumbS4ImmOperand";
+ let ParserMatchClass = t_imm0_508s4_asmoperand;
let OperandType = "OPERAND_IMMEDIATE";
}
@@ -305,35 +314,39 @@ def tPICADD : TIt<(outs GPR:$dst), (ins GPR:$lhs, pclabel:$cp), IIC_iALUr, "",
// This is rematerializable, which is particularly useful for taking the
// address of locals.
let isReMaterializable = 1 in
-def tADDrSPi : T1pI<(outs tGPR:$dst), (ins GPRsp:$sp, t_imm_s4:$rhs), IIC_iALUi,
- "add", "\t$dst, $sp, $rhs", []>,
+def tADDrSPi : T1pI<(outs tGPR:$dst), (ins GPRsp:$sp, t_imm0_1020s4:$imm),
+ IIC_iALUi, "add", "\t$dst, $sp, $imm", []>,
T1Encoding<{1,0,1,0,1,?}> {
// A6.2 & A8.6.8
bits<3> dst;
- bits<8> rhs;
+ bits<8> imm;
let Inst{10-8} = dst;
- let Inst{7-0} = rhs;
+ let Inst{7-0} = imm;
let DecoderMethod = "DecodeThumbAddSpecialReg";
}
// ADD sp, sp, #<imm7>
-def tADDspi : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, t_imm_s4:$rhs),
- IIC_iALUi, "add", "\t$Rdn, $rhs", []>,
+def tADDspi : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, t_imm0_508s4:$imm),
+ IIC_iALUi, "add", "\t$Rdn, $imm", []>,
T1Misc<{0,0,0,0,0,?,?}> {
// A6.2.5 & A8.6.8
- bits<7> rhs;
- let Inst{6-0} = rhs;
+ bits<7> imm;
+ let Inst{6-0} = imm;
let DecoderMethod = "DecodeThumbAddSPImm";
}
+// Can optionally specify SP as a three operand instruction.
+def : tInstAlias<"add${p} sp, sp, $imm",
+ (tADDspi SP, t_imm0_508s4:$imm, pred:$p)>;
+
// SUB sp, sp, #<imm7>
// FIXME: The encoding and the ASM string don't match up.
-def tSUBspi : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, t_imm_s4:$rhs),
- IIC_iALUi, "sub", "\t$Rdn, $rhs", []>,
+def tSUBspi : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, t_imm0_508s4:$imm),
+ IIC_iALUi, "sub", "\t$Rdn, $imm", []>,
T1Misc<{0,0,0,0,1,?,?}> {
// A6.2.5 & A8.6.214
- bits<7> rhs;
- let Inst{6-0} = rhs;
+ bits<7> imm;
+ let Inst{6-0} = imm;
let DecoderMethod = "DecodeThumbAddSPImm";
}
@@ -350,13 +363,13 @@ def tADDrSP : T1pIt<(outs GPR:$Rdn), (ins GPR:$Rn, GPRsp:$sp), IIC_iALUr,
}
// ADD sp, <Rm>
-def tADDspr : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, GPR:$rhs), IIC_iALUr,
- "add", "\t$Rdn, $rhs", []>,
+def tADDspr : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, GPR:$Rm), IIC_iALUr,
+ "add", "\t$Rdn, $Rm", []>,
T1Special<{0,0,?,?}> {
// A8.6.9 Encoding T2
- bits<4> Rdn;
+ bits<4> Rm;
let Inst{7} = 1;
- let Inst{6-3} = Rdn;
+ let Inst{6-3} = Rm;
let Inst{2-0} = 0b101;
let DecoderMethod = "DecodeThumbAddSPReg";
}
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 32a4fbbb01..965b39412c 100644
--- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -412,6 +412,22 @@ public:
bool isCondCode() const { return Kind == CondCode; }
bool isCCOut() const { return Kind == CCOut; }
bool isImm() const { return Kind == Immediate; }
+ bool isImm0_1020s4() const {
+ if (Kind != Immediate)
+ return false;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ if (!CE) return false;
+ int64_t Value = CE->getValue();
+ return ((Value & 3) == 0) && Value >= 0 && Value <= 1020;
+ }
+ bool isImm0_508s4() const {
+ if (Kind != Immediate)
+ return false;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ if (!CE) return false;
+ int64_t Value = CE->getValue();
+ return ((Value & 3) == 0) && Value >= 0 && Value <= 508;
+ }
bool isImm0_255() const {
if (Kind != Immediate)
return false;
@@ -791,6 +807,22 @@ public:
addExpr(Inst, getImm());
}
+ void addImm0_1020s4Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ // The immediate is scaled by four in the encoding and is stored
+ // in the MCInst as such. Lop off the low two bits here.
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4));
+ }
+
+ void addImm0_508s4Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ // The immediate is scaled by four in the encoding and is stored
+ // in the MCInst as such. Lop off the low two bits here.
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4));
+ }
+
void addImm0_255Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
addExpr(Inst, getImm());
@@ -2883,6 +2915,21 @@ bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic,
static_cast<ARMOperand*>(Operands[4])->isReg() &&
static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
return true;
+ // Register-register 'add' for thumb does not have a cc_out operand
+ // when it's an ADD Rdm, SP, {Rdm|#imm} instruction.
+ if (isThumb() && Mnemonic == "add" && Operands.size() == 6 &&
+ static_cast<ARMOperand*>(Operands[3])->isReg() &&
+ static_cast<ARMOperand*>(Operands[4])->isReg() &&
+ static_cast<ARMOperand*>(Operands[4])->getReg() == ARM::SP &&
+ static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
+ return true;
+ // Register-register 'add' for thumb does not have a cc_out operand
+ // when it's an ADD SP, #imm.
+ if (isThumb() && Mnemonic == "add" && Operands.size() == 5 &&
+ static_cast<ARMOperand*>(Operands[3])->isReg() &&
+ static_cast<ARMOperand*>(Operands[3])->getReg() == ARM::SP &&
+ static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
+ return true;
return false;
}
diff --git a/test/MC/ARM/basic-thumb-instructions.s b/test/MC/ARM/basic-thumb-instructions.s
index 88500d3dc4..ba02ec2902 100644
--- a/test/MC/ARM/basic-thumb-instructions.s
+++ b/test/MC/ARM/basic-thumb-instructions.s
@@ -45,11 +45,29 @@ _func:
@------------------------------------------------------------------------------
-@ FIXME: ADD (SP plus immediate)
+@ ADD (SP plus immediate)
@------------------------------------------------------------------------------
+ add sp, #4
+ add sp, #508
+ add sp, sp, #4
+ add r2, sp, #8
+ add r2, sp, #1020
+
+@ CHECK: add sp, #4 @ encoding: [0x01,0xb0]
+@ CHECK: add sp, #508 @ encoding: [0x7f,0xb0]
+@ CHECK: add sp, #4 @ encoding: [0x01,0xb0]
+@ CHECK: add r2, sp, #8 @ encoding: [0x02,0xaa]
+@ CHECK: add r2, sp, #1020 @ encoding: [0xff,0xaa]
+
+
@------------------------------------------------------------------------------
-@ FIXME: ADD (SP plus register)
+@ ADD (SP plus register)
@------------------------------------------------------------------------------
+ add sp, r3
+ add r2, sp, r2
+
+@ CHECK: add sp, r3 @ encoding: [0x9d,0x44]
+@ CHECK: add r2, sp, r2 @ encoding: [0x6a,0x44]
@------------------------------------------------------------------------------
diff --git a/test/MC/ARM/thumb-diagnostics.s b/test/MC/ARM/thumb-diagnostics.s
index 650e8cecf3..ea5d115be9 100644
--- a/test/MC/ARM/thumb-diagnostics.s
+++ b/test/MC/ARM/thumb-diagnostics.s
@@ -118,3 +118,22 @@ error: invalid operand for instruction
@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled
@ CHECK-ERRORS: svc #256
@ CHECK-ERRORS: ^
+
+
+@ Out of range immediate for ADD SP instructions
+ add sp, #-1
+ add sp, #3
+ add sp, sp, #512
+ add r2, sp, #1024
+@ CHECK-ERRORS: error: invalid operand for instruction
+@ CHECK-ERRORS: add sp, #-1
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: invalid operand for instruction
+@ CHECK-ERRORS: add sp, #3
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: invalid operand for instruction
+@ CHECK-ERRORS: add sp, sp, #512
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: invalid operand for instruction
+@ CHECK-ERRORS: add r2, sp, #1024
+@ CHECK-ERRORS: ^
diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp
index 852b9bf125..ce59ff730e 100644
--- a/utils/TableGen/EDEmitter.cpp
+++ b/utils/TableGen/EDEmitter.cpp
@@ -603,7 +603,8 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
IMM("pkh_lsl_amt");
IMM("pkh_asr_amt");
IMM("jt2block_operand");
- IMM("t_imm_s4");
+ IMM("t_imm0_1020s4");
+ IMM("t_imm0_508s4");
IMM("pclabel");
IMM("adrlabel");
IMM("t_adrlabel");