llvm.org GIT mirror llvm / ffa3225
ARM assembly parsing for MOV (immediate). Add range checking for the immediate operand and handle the "mov" mnemonic choosing between encodings based on the value of the immediate. Add tests for fixups, encoding choice and values, and diagnostic for out of range values. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@135500 91177308-0d34-0410-b5e6-96231b3b80d8 Jim Grosbach 9 years ago
7 changed file(s) with 100 addition(s) and 22 deletion(s). Raw diff Collapse all Expand all
493493 let EncoderMethod = "getImmMinusOneOpValue";
494494 }
495495
496 // i32imm_hilo16 - For movt/movw - sets the MC Encoder method.
497 // The imm is split into imm{15-12}, imm{11-0}
498 //
499 def i32imm_hilo16 : Operand {
496 // imm0_65535_expr - For movt/movw - 16-bit immediate that can also reference
497 // a relocatable expression.
498 //
499 // FIXME: This really needs a Thumb version separate from the ARM version.
500 // While the range is the same, and can thus use the same match class,
501 // the encoding is different so it should have a different encoder method.
502 def Imm0_65535ExprAsmOperand: AsmOperandClass { let Name = "Imm0_65535Expr"; }
503 def imm0_65535_expr : Operand {
500504 let EncoderMethod = "getHiLo16ImmOpValue";
505 let ParserMatchClass = Imm0_65535ExprAsmOperand;
501506 }
502507
503508 /// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield
21222127 }
21232128
21242129 let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
2125 def MOVi16 : AI1<0b1000, (outs GPR:$Rd), (ins i32imm_hilo16:$imm),
2130 def MOVi16 : AI1<0b1000, (outs GPR:$Rd), (ins imm0_65535_expr:$imm),
21262131 DPFrm, IIC_iMOVi,
21272132 "movw", "\t$Rd, $imm",
21282133 [(set GPR:$Rd, imm0_65535:$imm)]>,
21362141 let Inst{25} = 1;
21372142 }
21382143
2144 def : InstAlias<"mov${p} $Rd, $imm",
2145 (MOVi16 GPR:$Rd, imm0_65535_expr:$imm, pred:$p)>,
2146 Requires<[IsARM]>;
2147
21392148 def MOVi16_ga_pcrel : PseudoInst<(outs GPR:$Rd),
21402149 (ins i32imm:$addr, pclabel:$id), IIC_iMOVi, []>;
21412150
21422151 let Constraints = "$src = $Rd" in {
2143 def MOVTi16 : AI1<0b1010, (outs GPR:$Rd), (ins GPR:$src, i32imm_hilo16:$imm),
2152 def MOVTi16 : AI1<0b1010, (outs GPR:$Rd), (ins GPR:$src, imm0_65535_expr:$imm),
21442153 DPFrm, IIC_iMOVi,
21452154 "movt", "\t$Rd, $imm",
21462155 [(set GPR:$Rd,
32593268
32603269 let isMoveImm = 1 in
32613270 def MOVCCi16 : ARMPseudoInst<(outs GPR:$Rd),
3262 (ins GPR:$false, i32imm_hilo16:$imm, pred:$p),
3271 (ins GPR:$false, imm0_65535_expr:$imm, pred:$p),
32633272 4, IIC_iMOVi,
32643273 []>,
32653274 RegConstraint<"$false = $Rd">, Requires<[IsARM, HasV6T2]>;
16141614 Requires<[IsThumb2]>;
16151615
16161616 let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
1617 def t2MOVi16 : T2I<(outs rGPR:$Rd), (ins i32imm_hilo16:$imm), IIC_iMOVi,
1617 def t2MOVi16 : T2I<(outs rGPR:$Rd), (ins imm0_65535_expr:$imm), IIC_iMOVi,
16181618 "movw", "\t$Rd, $imm",
16191619 [(set rGPR:$Rd, imm0_65535:$imm)]> {
16201620 let Inst{31-27} = 0b11110;
16381638
16391639 let Constraints = "$src = $Rd" in {
16401640 def t2MOVTi16 : T2I<(outs rGPR:$Rd),
1641 (ins rGPR:$src, i32imm_hilo16:$imm), IIC_iMOVi,
1641 (ins rGPR:$src, imm0_65535_expr:$imm), IIC_iMOVi,
16421642 "movt", "\t$Rd, $imm",
16431643 [(set rGPR:$Rd,
16441644 (or (and rGPR:$src, 0xffff), lo16AllZero:$imm))]> {
27222722 // FIXME: Pseudo-ize these. For now, just mark codegen only.
27232723 let isCodeGenOnly = 1 in {
27242724 let isMoveImm = 1 in
2725 def t2MOVCCi16 : T2I<(outs rGPR:$Rd), (ins rGPR:$false, i32imm_hilo16:$imm),
2725 def t2MOVCCi16 : T2I<(outs rGPR:$Rd), (ins rGPR:$false, imm0_65535_expr:$imm),
27262726 IIC_iCMOVi,
27272727 "movw", "\t$Rd, $imm", []>,
27282728 RegConstraint<"$false = $Rd"> {
406406 int64_t Value = CE->getValue();
407407 return Value >= 0 && Value < 65536;
408408 }
409 bool isImm0_65535Expr() const {
410 if (Kind != Immediate)
411 return false;
412 const MCConstantExpr *CE = dyn_cast(getImm());
413 // If it's not a constant expression, it'll generate a fixup and be
414 // handled later.
415 if (!CE) return true;
416 int64_t Value = CE->getValue();
417 return Value >= 0 && Value < 65536;
418 }
409419 bool isARMSOImm() const {
410420 if (Kind != Immediate)
411421 return false;
616626 }
617627
618628 void addImm0_65535Operands(MCInst &Inst, unsigned N) const {
629 assert(N == 1 && "Invalid number of operands!");
630 addExpr(Inst, getImm());
631 }
632
633 void addImm0_65535ExprOperands(MCInst &Inst, unsigned N) const {
619634 assert(N == 1 && "Invalid number of operands!");
620635 addExpr(Inst, getImm());
621636 }
20622077 SmallVectorImpl &Operands) {
20632078 // Create the leading tokens for the mnemonic, split by '.' characters.
20642079 size_t Start = 0, Next = Name.find('.');
2065 StringRef Head = Name.slice(Start, Next);
2080 StringRef Mnemonic = Name.slice(Start, Next);
20662081
20672082 // Split out the predication code and carry setting flag from the mnemonic.
20682083 unsigned PredicationCode;
20692084 unsigned ProcessorIMod;
20702085 bool CarrySetting;
2071 Head = SplitMnemonic(Head, PredicationCode, CarrySetting,
2086 Mnemonic = SplitMnemonic(Mnemonic, PredicationCode, CarrySetting,
20722087 ProcessorIMod);
20732088
2074 Operands.push_back(ARMOperand::CreateToken(Head, NameLoc));
2089 Operands.push_back(ARMOperand::CreateToken(Mnemonic, NameLoc));
2090
2091 // FIXME: This is all a pretty gross hack. We should automatically handle
2092 // optional operands like this via tblgen.
20752093
20762094 // Next, add the CCOut and ConditionCode operands, if needed.
20772095 //
20812099 // the matcher deal with finding the right instruction or generating an
20822100 // appropriate error.
20832101 bool CanAcceptCarrySet, CanAcceptPredicationCode;
2084 GetMnemonicAcceptInfo(Head, CanAcceptCarrySet, CanAcceptPredicationCode);
2102 GetMnemonicAcceptInfo(Mnemonic, CanAcceptCarrySet, CanAcceptPredicationCode);
20852103
20862104 // If we had a carry-set on an instruction that can't do that, issue an
20872105 // error.
20882106 if (!CanAcceptCarrySet && CarrySetting) {
20892107 Parser.EatToEndOfStatement();
2090 return Error(NameLoc, "instruction '" + Head +
2108 return Error(NameLoc, "instruction '" + Mnemonic +
20912109 "' can not set flags, but 's' suffix specified");
20922110 }
20932111
21352153 // Read the remaining operands.
21362154 if (getLexer().isNot(AsmToken::EndOfStatement)) {
21372155 // Read the first operand.
2138 if (ParseOperand(Operands, Head)) {
2156 if (ParseOperand(Operands, Mnemonic)) {
21392157 Parser.EatToEndOfStatement();
21402158 return true;
21412159 }
21442162 Parser.Lex(); // Eat the comma.
21452163
21462164 // Parse and remember the operand.
2147 if (ParseOperand(Operands, Head)) {
2165 if (ParseOperand(Operands, Mnemonic)) {
21482166 Parser.EatToEndOfStatement();
21492167 return true;
21502168 }
21572175 }
21582176
21592177 Parser.Lex(); // Consume the EndOfStatement
2178
2179
2180 // The 'mov' mnemonic is special. One variant has a cc_out operand, while
2181 // another does not. Specifically, the MOVW instruction does not. So we
2182 // special case it here and remove the defaulted (non-setting) cc_out
2183 // operand if that's the instruction we're trying to match.
2184 //
2185 // We do this post-processing of the explicit operands rather than just
2186 // conditionally adding the cc_out in the first place because we need
2187 // to check the type of the parsed immediate operand.
2188 if (Mnemonic == "mov" && Operands.size() > 4 &&
2189 !static_cast(Operands[4])->isARMSOImm() &&
2190 static_cast(Operands[4])->isImm0_65535Expr()) {
2191 ARMOperand *Op = static_cast(Operands[1]);
2192 Operands.erase(Operands.begin() + 1);
2193 delete Op;
2194 }
2195
2196
2197
21602198 return false;
21612199 }
21622200
None // RUN: llvm-mc -triple arm-unknown-unknown %s --show-encoding > %t
1 // RUN: FileCheck < %t %s
0 @ RUN: llvm-mc -triple armv7-unknown-unknown %s --show-encoding > %t
1 @ RUN: FileCheck < %t %s
22
3 // CHECK: bl _printf @ encoding: [A,A,A,0xeb]
4 // CHECK: @ fixup A - offset: 0, value: _printf, kind: fixup_arm_uncondbranch
5 bl _printf
3 bl _printf
4 @ CHECK: bl _printf @ encoding: [A,A,A,0xeb]
5 @ CHECK: @ fixup A - offset: 0, value: _printf, kind: fixup_arm_uncondbranch
66
7 mov r9, :lower16:(_foo)
8 movw r9, :lower16:(_foo)
9 movt r9, :upper16:(_foo)
10
11 @ CHECK: movw r9, :lower16:_foo @ encoding: [A,0x90'A',0b0000AAAA,0xe3]
12 @ CHECK: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_movw_lo16
13 @ CHECK: movw r9, :lower16:_foo @ encoding: [A,0x90'A',0b0000AAAA,0xe3]
14 @ CHECK: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_movw_lo16
15 @ CHECK: movt r9, :upper16:_foo @ encoding: [A,0x90'A',0b0100AAAA,0xe3]
16 @ CHECK: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_movt_hi16
670670 @ CHECK: mlsne r2, r5, r6, r3 @ encoding: [0x95,0x36,0x62,0x10]
671671
672672 @------------------------------------------------------------------------------
673 @ MOV (immediate)
674 @------------------------------------------------------------------------------
675 mov r3, #7
676 mov r4, #0xff0
677 mov r5, #0xff0000
678 mov r6, #0xffff
679 movw r9, #0xffff
680
681 @ CHECK: mov r3, #7 @ encoding: [0x07,0x30,0xa0,0xe3]
682 @ CHECK: mov r4, #4080 @ encoding: [0xff,0x4e,0xa0,0xe3]
683 @ CHECK: mov r5, #16711680 @ encoding: [0xff,0x58,0xa0,0xe3]
684 @ CHECK: movw r6, #65535 @ encoding: [0xff,0x6f,0x0f,0xe3]
685 @ CHECK: movw r9, #65535 @ encoding: [0xff,0x9f,0x0f,0xe3]
686
687 @------------------------------------------------------------------------------
673688 @ STM*
674689 @------------------------------------------------------------------------------
675690 stm r2, {r1,r3-r6,sp}
8787 @ CHECK-ERRORS: error: invalid operand for instruction
8888 @ CHECK-ERRORS: error: invalid operand for instruction
8989 @ CHECK-ERRORS: error: invalid operand for instruction
90
91
92 @ Out of range immediate for MOV
93 movw r9, 0x10000
94 @ CHECK-ERRORS: error: invalid operand for instruction
592592 IMM("imm0_255");
593593 IMM("imm0_4095");
594594 IMM("imm0_65535");
595 IMM("imm0_65535_expr");
595596 IMM("jt2block_operand");
596597 IMM("t_imm_s4");
597598 IMM("pclabel");