diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -970,11 +970,18 @@ bool isMOVZMovAlias() const { if (!isImm()) return false; - const MCConstantExpr *CE = dyn_cast(getImm()); - if (!CE) return false; - uint64_t Value = CE->getValue(); + const MCExpr *E = dyn_cast(getImm()); + if (const MCConstantExpr *CE = dyn_cast(E)) { + uint64_t Value = CE->getValue(); - return AArch64_AM::isMOVZMovAlias(Value, Shift, RegWidth); + return AArch64_AM::isMOVZMovAlias(Value, Shift, RegWidth); + } + if (const MCBinaryExpr *BE = dyn_cast(E)) { + return (BE->getOpcode() == MCBinaryExpr::Opcode::Sub && + BE->getLHS()->getKind() == MCExpr::ExprKind::SymbolRef && + BE->getLHS()->getKind() == MCExpr::ExprKind::SymbolRef); + } + return false; } template @@ -1774,9 +1781,14 @@ void addMOVZMovAliasOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *CE = cast(getImm()); - uint64_t Value = CE->getValue(); - Inst.addOperand(MCOperand::createImm((Value >> Shift) & 0xffff)); + const MCConstantExpr *CE = dyn_cast(getImm()); + if (CE) { + uint64_t Value = CE->getValue(); + Inst.addOperand(MCOperand::createImm((Value >> Shift) & 0xffff)); + } else { + addExpr(Inst, getImm()); + Inst.addOperand(MCOperand::createImm(0)); + } } template diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -239,8 +239,18 @@ Ctx.reportError(Fixup.getLoc(), "fixup must be 16-byte aligned"); return Value >> 4; case AArch64::fixup_aarch64_movw: { + if (!IsResolved) { + // FIXME: Figure out when this can actually happen, and verify our + // behavior. + Ctx.reportError(Fixup.getLoc(), "unresolved movw fixup not yet " + "implemented"); + return Value; + } + // Results of label arithmetic operaitons AArch64MCExpr::VariantKind RefKind = static_cast(Target.getRefKind()); + if (!RefKind) + return Value; if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_ABS && AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_SABS) { // VK_GOTTPREL, VK_TPREL, VK_DTPREL are movw fixups, but they can't @@ -251,13 +261,6 @@ return Value; } - if (!IsResolved) { - // FIXME: Figure out when this can actually happen, and verify our - // behavior. - Ctx.reportError(Fixup.getLoc(), "unresolved movw fixup not yet " - "implemented"); - return Value; - } if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS) { switch (AArch64MCExpr::getAddressFrag(RefKind)) { diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp @@ -569,21 +569,30 @@ if (UImm16MO.isImm()) return EncodedValue; - const AArch64MCExpr *A64E = cast(UImm16MO.getExpr()); - switch (A64E->getKind()) { - case AArch64MCExpr::VK_DTPREL_G2: - case AArch64MCExpr::VK_DTPREL_G1: - case AArch64MCExpr::VK_DTPREL_G0: - case AArch64MCExpr::VK_GOTTPREL_G1: - case AArch64MCExpr::VK_TPREL_G2: - case AArch64MCExpr::VK_TPREL_G1: - case AArch64MCExpr::VK_TPREL_G0: - return EncodedValue & ~(1u << 30); - default: - // Nothing to do for an unsigned fixup. - return EncodedValue; + const MCExpr *E = UImm16MO.getExpr(); + if (const AArch64MCExpr *A64E = dyn_cast(E)) { + switch (A64E->getKind()) { + case AArch64MCExpr::VK_DTPREL_G2: + case AArch64MCExpr::VK_DTPREL_G1: + case AArch64MCExpr::VK_DTPREL_G0: + case AArch64MCExpr::VK_GOTTPREL_G1: + case AArch64MCExpr::VK_TPREL_G2: + case AArch64MCExpr::VK_TPREL_G1: + case AArch64MCExpr::VK_TPREL_G0: + return EncodedValue & ~(1u << 30); + default: + // Nothing to do for an unsigned fixup. + return EncodedValue; + } } + if (const MCBinaryExpr *BE = dyn_cast(E)) { + if (BE->getOpcode() == MCBinaryExpr::Opcode::Sub && + BE->getLHS()->getKind() == MCExpr::ExprKind::SymbolRef && + BE->getLHS()->getKind() == MCExpr::ExprKind::SymbolRef) { + return EncodedValue; + } + } return EncodedValue & ~(1u << 30); }