llvm.org GIT mirror llvm / 1a47d66
Change the ARM assembler to require a :lower16: or :upper16 on non-constant expressions for mov instructions instead of silently truncating by default. For the ARM assembler, we want to avoid misleadingly allowing something like "mov r0, <symbol>" especially when we turn it into a movw and the expression <symbol> does not have a :lower16: or :upper16" as part of the expression. We don't want the behavior of silently truncating, which can be unexpected and lead to bugs that are difficult to find since this is an easy mistake to make. This does change the previous behavior of llvm but actually matches an older gnu assembler that would not allow this but print less useful errors of like “invalid constant (0x927c0) after fixup” and “unsupported relocation on symbol foo”. The error for llvm is "immediate expression for mov requires :lower16: or :upper16" with correct location information on the operand as shown in the added test cases. rdar://12342160 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206669 91177308-0d34-0410-b5e6-96231b3b80d8 Kevin Enderby 6 years ago
6 changed file(s) with 55 addition(s) and 12 deletion(s). Raw diff Collapse all Expand all
58625862 return Error(Operands[Op]->getStartLoc(), "branch target out of range");
58635863 break;
58645864 }
5865 case ARM::MOVi16:
5866 case ARM::t2MOVi16:
5867 case ARM::t2MOVTi16:
5868 {
5869 // We want to avoid misleadingly allowing something like "mov r0, "
5870 // especially when we turn it into a movw and the expression does
5871 // not have a :lower16: or :upper16 as part of the expression. We don't
5872 // want the behavior of silently truncating, which can be unexpected and
5873 // lead to bugs that are difficult to find since this is an easy mistake
5874 // to make.
5875 int i = (Operands[3]->isImm()) ? 3 : 4;
5876 ARMOperand *Op = static_cast(Operands[i]);
5877 const MCConstantExpr *CE = dyn_cast(Op->getImm());
5878 if (CE) break;
5879 const MCExpr *E = dyn_cast(Op->getImm());
5880 if (!E) break;
5881 const ARMMCExpr *ARM16Expr = dyn_cast(E);
5882 if (!ARM16Expr || (ARM16Expr->getKind() != ARMMCExpr::VK_ARM_HI16 &&
5883 ARM16Expr->getKind() != ARMMCExpr::VK_ARM_LO16)) {
5884 return Error(Op->getStartLoc(),
5885 "immediate expression for mov requires :lower16: or :upper16");
5886 break;
5887 }
5888 }
58655889 }
58665890
58675891 return false;
10391039 return 0;
10401040 }
10411041 // If the expression doesn't have :upper16: or :lower16: on it,
1042 // it's just a plain immediate expression, and those evaluate to
1042 // it's just a plain immediate expression, previously those evaluated to
10431043 // the lower 16 bits of the expression regardless of whether
1044 // we have a movt or a movw.
1045 Kind = MCFixupKind(isThumb2(STI) ? ARM::fixup_t2_movw_lo16
1046 : ARM::fixup_arm_movw_lo16);
1047 Fixups.push_back(MCFixup::Create(0, E, Kind, MI.getLoc()));
1044 // we have a movt or a movw, but that led to misleadingly results.
1045 // This is now disallowed in the the AsmParser in validateInstruction()
1046 // so this should never happen.
1047 assert(0 && "expression without :upper16: or :lower16:");
10481048 return 0;
10491049 }
10501050
2525 @ CHECK-BE: movt r9, :upper16:_foo @ encoding: [0xe3,0b0100AAAA,0x90'A',A]
2626 @ CHECK-BE: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_movt_hi16
2727
28 mov r2, fred
28 mov r2, :lower16:fred
2929
30 @ CHECK: movw r2, fred @ encoding: [A,0x20'A',0b0000AAAA,0xe3]
30 @ CHECK: movw r2, :lower16:fred @ encoding: [A,0x20'A',0b0000AAAA,0xe3]
3131 @ CHECK: @ fixup A - offset: 0, value: fred, kind: fixup_arm_movw_lo16
32 @ CHECK-BE: movw r2, fred @ encoding: [0xe3,0b0000AAAA,0x20'A',A]
32 @ CHECK-BE: movw r2, :lower16:fred @ encoding: [0xe3,0b0000AAAA,0x20'A',A]
3333 @ CHECK-BE: @ fixup A - offset: 0, value: fred, kind: fixup_arm_movw_lo16
2020 .global arm_function
2121 .type arm_function,%function
2222 arm_function:
23 mov r0, #(.L_table_end - .L_table_begin) >> 2
23 mov r0, #:lower16:((.L_table_end - .L_table_begin) >> 2)
2424 blx return
2525
2626 @ CHECK-LABEL: arm_function
27 @ CHECK: movw r0, #(.L_table_end-.L_table_begin)>>2
27 @ CHECK: movw r0, :lower16:((.L_table_end-.L_table_begin)>>2)
2828 @ CHECK: blx return
2929
3030 .global thumb_function
3131 .type thumb_function,%function
3232 thumb_function:
33 mov r0, #(.L_table_end - .L_table_begin) >> 2
33 mov r0, #:lower16:((.L_table_end - .L_table_begin) >> 2)
3434 blx return
3535
3636 @ CHECK-LABEL: thumb_function
37 @ CHECK: movw r0, #(.L_table_end-.L_table_begin)>>2
37 @ CHECK: movw r0, :lower16:((.L_table_end-.L_table_begin)>>2)
3838 @ CHECK: blx return
3939
464464 ldm sp!, {r0}^
465465 @ CHECK-ERRORS: error: system STM cannot have writeback register
466466 @ CHECK-ERRORS: error: writeback register only allowed on system LDM if PC in register-list
467
468 foo2:
469 mov r0, foo2
470 movw r0, foo2
471 @ CHECK-ERRORS: error: immediate expression for mov requires :lower16: or :upper16
472 @ CHECK-ERRORS: ^
473 @ CHECK-ERRORS: error: immediate expression for mov requires :lower16: or :upper16
474 @ CHECK-ERRORS: ^
6969 @ CHECK-ERRORS: error: branch target out of range
7070 @ CHECK-ERRORS: error: branch target out of range
7171 @ CHECK-ERRORS: error: branch target out of range
72
73 foo2:
74 mov r0, foo2
75 movw r0, foo2
76 movt r0, foo2
77 @ CHECK-ERRORS: error: immediate expression for mov requires :lower16: or :upper16
78 @ CHECK-ERRORS: ^
79 @ CHECK-ERRORS: error: immediate expression for mov requires :lower16: or :upper16
80 @ CHECK-ERRORS: ^
81 @ CHECK-ERRORS: error: immediate expression for mov requires :lower16: or :upper16
82 @ CHECK-ERRORS: ^