Index: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -727,9 +727,14 @@ || ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12; } - // Otherwise it should be a real immediate in range: - const MCConstantExpr *CE = cast<MCConstantExpr>(Expr); - return CE->getValue() >= 0 && CE->getValue() <= 0xfff; + // If it's a constant, it should be a real immediate in range: + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr); + if (CE) + return CE->getValue() >= 0 && CE->getValue() <= 0xfff; + + // If it's an expression, we hope for the best and let the fixup/relocation + // code deal with it. + return true; } bool isAddSubImmNeg() const { if (!isShiftedImm() && !isImm()) @@ -3572,31 +3577,34 @@ AArch64MCExpr::VariantKind ELFRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind; int64_t Addend; - if (!classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { - return Error(Loc[2], "invalid immediate expression"); - } + if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { - // Only allow these with ADDXri. - if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF || - DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) && - Inst.getOpcode() == AArch64::ADDXri) - return false; + // Only allow these with ADDXri. + if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF || + DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) && + Inst.getOpcode() == AArch64::ADDXri) + return false; - // Only allow these with ADDXri/ADDWri - if ((ELFRefKind == AArch64MCExpr::VK_LO12 || - ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 || - ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || - ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || - ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 || - ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 || - ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC || - ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12) && - (Inst.getOpcode() == AArch64::ADDXri || - Inst.getOpcode() == AArch64::ADDWri)) - return false; + // Only allow these with ADDXri/ADDWri + if ((ELFRefKind == AArch64MCExpr::VK_LO12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || + ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 || + ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC || + ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12) && + (Inst.getOpcode() == AArch64::ADDXri || + Inst.getOpcode() == AArch64::ADDWri)) + return false; - // Don't allow expressions in the immediate field otherwise - return Error(Loc[2], "invalid immediate expression"); + // Don't allow symbol refs in the immediate field otherwise + // Note: Loc.back() may be Loc[1] or Loc[2] depending on the number of + // operands of the original instruction (i.e. 'add w0, w1, borked' vs + // 'cmp w0, 'borked') + return Error(Loc.back(), "invalid immediate expression"); + } + // We don't validate more complex expressions here } return false; } Index: lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp @@ -67,6 +67,11 @@ RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT); return true; case AArch64::fixup_aarch64_add_imm12: + if (Sym->getKind() == MCSymbolRefExpr::VK_None) { + Log2Size = llvm::Log2_32(4); + return true; + } + LLVM_FALLTHROUGH; case AArch64::fixup_aarch64_ldst_imm12_scale1: case AArch64::fixup_aarch64_ldst_imm12_scale2: case AArch64::fixup_aarch64_ldst_imm12_scale4: Index: test/MC/AArch64/basic-a64-diagnostics.s =================================================================== --- test/MC/AArch64/basic-a64-diagnostics.s +++ test/MC/AArch64/basic-a64-diagnostics.s @@ -172,9 +172,14 @@ // A relocation should be provided for symbols add x3, x9, #variable + add x3, x9, #variable-16 // CHECK-ERROR: error: expected compatible register, symbol or integer in range [0, 4095] // CHECK-ERROR-NEXT: add x3, x9, #variable // CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: expected compatible register, symbol or integer in range [0, 4095] +// CHECK-ERROR-NEXT: add x3, x9, #variable-16 +// CHECK-ERROR-NEXT: ^ + //------------------------------------------------------------------------------ Index: test/MC/AArch64/label-arithmetic-darwin.s =================================================================== --- /dev/null +++ test/MC/AArch64/label-arithmetic-darwin.s @@ -0,0 +1,58 @@ +// RUN: llvm-mc -triple aarch64-darwin -filetype=obj %s -o - | llvm-objdump -r -d - | FileCheck %s +// RUN: llvm-mc -triple aarch64-ios -filetype=obj %s -o - | llvm-objdump -r -d - | FileCheck %s + + .section __TEXT, sec_x, regular, pure_instructions +start: + .space 8 +end: + // CHECK-LABEL: end: + add w0, w1, #(end - start) + cmp w0, #(end - start) + // CHECK: [[addr:[0-9a-f]+]]:{{.*}}add w0, w1, #0 + // CHECK-NEXT: [[addr]]: ARM64_RELOC_SUBTRACTOR start + // CHECK-NEXT: [[addr]]: ARM64_RELOC_UNSIGNED end + // CHECK: [[addr:[0-9a-f]+]]:{{.*}}cmp w0, #0 + // CHECK-NEXT: [[addr]]: ARM64_RELOC_SUBTRACTOR start + // CHECK-NEXT: [[addr]]: ARM64_RELOC_UNSIGNED end + + add w0, w1, #(end - start + 12) + cmp w0, #(end - start + 12) + // CHECK: [[addr:[0-9a-f]+]]:{{.*}}add w0, w1, #12 + // CHECK-NEXT: [[addr]]: ARM64_RELOC_SUBTRACTOR start + // CHECK-NEXT: [[addr]]: ARM64_RELOC_UNSIGNED end + // CHECK: [[addr:[0-9a-f]+]]:{{.*}}cmp w0, #12 + // CHECK-NEXT: [[addr]]: ARM64_RELOC_SUBTRACTOR start + // CHECK-NEXT: [[addr]]: ARM64_RELOC_UNSIGNED end + + add w0, w1, #(end - external) + cmp w0, #(end - external) + // CHECK: [[addr:[0-9a-f]+]]:{{.*}}add w0, w1, #0 + // CHECK-NEXT: [[addr]]: ARM64_RELOC_SUBTRACTOR external + // CHECK-NEXT: [[addr]]: ARM64_RELOC_UNSIGNED end + // CHECK: [[addr:[0-9a-f]+]]:{{.*}}cmp w0, #0 + // CHECK-NEXT: [[addr]]: ARM64_RELOC_SUBTRACTOR external + // CHECK-NEXT: [[addr]]: ARM64_RELOC_UNSIGNED end + + add w0, w1, #(. - end) + cmp w0, #(. - end) + // CHECK: add w0, w1, #24 + // CHECK: cmp w0, #28 + +Lstart: + .space 8 +Lend: + add w0, w1, #(Lend - Lstart) + cmp w0, #(Lend - Lstart) + // CHECK: add w0, w1, #8 + // CHECK: cmp w0, #8 + + .section __TEXT, sec_y, regular, pure_instructions +end_across_sec: + add w0, w1, #(end_across_sec - start) + cmp w0, #(end_across_sec - start) + // CHECK: [[addr:[0-9a-f]+]]:{{.*}}add w0, w1, #0 + // CHECK-NEXT: [[addr]]: ARM64_RELOC_SUBTRACTOR start + // CHECK-NEXT: [[addr]]: ARM64_RELOC_UNSIGNED end_across_sec + // CHECK: [[addr:[0-9a-f]+]]:{{.*}}cmp w0, #0 + // CHECK-NEXT: [[addr]]: ARM64_RELOC_SUBTRACTOR start + // CHECK-NEXT: [[addr]]: ARM64_RELOC_UNSIGNED end_across_sec Index: test/MC/AArch64/label-arithmetic-diags-elf.s =================================================================== --- /dev/null +++ test/MC/AArch64/label-arithmetic-diags-elf.s @@ -0,0 +1,61 @@ +// RUN: not llvm-mc -triple aarch64-elf -filetype=obj %s -o /dev/null 2>&1 | FileCheck %s + + .section sec_x +start: + .space 5000 +end: + add w0, w1, #(end - start) + cmp w0, #(end - start) + // CHECK: error: fixup value out of range + // CHECK-NEXT: add w0, w1, #(end - start) + // CHECK-NEXT: ^ + // CHECK: error: fixup value out of range + // CHECK-NEXT: cmp w0, #(end - start) + // CHECK-NEXT: ^ + + add w0, w1, #(end - external) + cmp w0, #(end - external) + // CHECK: error: symbol 'external' can not be undefined in a subtraction expression + // CHECK-NEXT: add w0, w1, #(end - external) + // CHECK-NEXT: ^ + // CHECK: error: symbol 'external' can not be undefined in a subtraction expression + // CHECK-NEXT: cmp w0, #(end - external) + // CHECK-NEXT: ^ + + add w0, w1, #:lo12:external - end + cmp w0, #:lo12:external - end + // CHECK: error: Unsupported pc-relative fixup kind + // CHECK-NEXT: add w0, w1, #:lo12:external - end + // CHECK-NEXT: ^ + // CHECK: error: Unsupported pc-relative fixup kind + // CHECK-NEXT: cmp w0, #:lo12:external - end + // CHECK-NEXT: ^ + + add w0, w1, #:got_lo12:external - end + cmp w0, #:got_lo12:external - end + // CHECK: error: Unsupported pc-relative fixup kind + // CHECK-NEXT: add w0, w1, #:got_lo12:external - end + // CHECK-NEXT: ^ + // CHECK: error: Unsupported pc-relative fixup kind + // CHECK-NEXT: cmp w0, #:got_lo12:external - end + // CHECK-NEXT: ^ + + .section sec_y +end_across_sec: + add w0, w1, #(end_across_sec - start) + cmp w0, #(end_across_sec - start) + // CHECK: error: Cannot represent a difference across sections + // CHECK-NEXT: add w0, w1, #(end_across_sec - start) + // CHECK-NEXT: ^ + // CHECK: error: Cannot represent a difference across sections + // CHECK-NEXT: cmp w0, #(end_across_sec - start) + // CHECK-NEXT: ^ + + add w0, w1, #(sec_y - sec_x) + cmp w0, #(sec_y - sec_x) + // CHECK: error: symbol 'sec_x' can not be undefined in a subtraction expression + // CHECK-NEXT: add w0, w1, #(sec_y - sec_x) + // CHECK-NEXT: ^ + // CHECK: error: symbol 'sec_x' can not be undefined in a subtraction expression + // CHECK-NEXT: cmp w0, #(sec_y - sec_x) + // CHECK-NEXT: ^ Index: test/MC/AArch64/label-arithmetic-elf.s =================================================================== --- /dev/null +++ test/MC/AArch64/label-arithmetic-elf.s @@ -0,0 +1,56 @@ +// RUN: llvm-mc -triple aarch64-elf -filetype=obj %s -o - | llvm-objdump -d - | FileCheck %s + +start: + .space 8 +end: + // CHECK-LABEL: end: + + add w0, w1, #(end - start) + cmp w0, #(end - start) + // CHECK: add w0, w1, #8 + // CHECK: cmp w0, #8 + + add w0, w1, #((end - start) >> 2) + cmp w0, #((end - start) >> 2) + // CHECK: add w0, w1, #2 + // CHECK: cmp w0, #2 + + add w0, w1, #(end - start + 12) + cmp w0, #(end - start + 12) + // CHECK: add w0, w1, #20 + // CHECK: cmp w0, #20 + +.Lstart: + .space 8 +.Lend: + add w0, w1, #(.Lend - .Lstart) + cmp w0, #(.Lend - .Lstart) + // CHECK: add w0, w1, #8 + // CHECK: cmp w0, #8 + + .type foo, @function +foo: + // CHECK-LABEL: foo: + + add w0, w1, #(foo - .Lend) + cmp w0, #(foo - .Lend) + // CHECK: add w0, w1, #8 + // CHECK: cmp w0, #8 + + ret + + .type goo, @function +goo: + // CHECK-LABEL: goo: + + add w0, w1, #(goo - foo) + cmp w0, #(goo - foo) + // CHECK: add w0, w1, #12 + // CHECK: cmp w0, #12 + + add w0, w1, #(. - goo) + cmp w0, #(. - goo) + // CHECK: add w0, w1, #8 + // CHECK: cmp w0, #12 + + ret