From: Tim Northover Date: Thu, 30 Apr 2015 18:28:58 +0000 (+0000) Subject: AArch64: add BFC alias for the BFI/BFM instructions. X-Git-Tag: llvmorg-3.7.0-rc1~5611 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=03b99f66d7189be049ba269bbe9afcb42e34a371;p=platform%2Fupstream%2Fllvm.git AArch64: add BFC alias for the BFI/BFM instructions. Unlike 32-bit ARM, AArch64 can use wzr/xzr to implement this without the need for a separate instruction. rdar://18679590 llvm-svn: 236245 --- diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 063c714..7f7e6c3 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -3644,6 +3644,60 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, Op3.getEndLoc(), getContext()); } } + } else if (NumOperands == 4 && Tok == "bfc") { + // FIXME: Horrible hack to handle BFC->BFM alias. + AArch64Operand &Op1 = static_cast(*Operands[1]); + AArch64Operand LSBOp = static_cast(*Operands[2]); + AArch64Operand WidthOp = static_cast(*Operands[3]); + + if (Op1.isReg() && LSBOp.isImm() && WidthOp.isImm()) { + const MCConstantExpr *LSBCE = dyn_cast(LSBOp.getImm()); + const MCConstantExpr *WidthCE = dyn_cast(WidthOp.getImm()); + + if (LSBCE && WidthCE) { + uint64_t LSB = LSBCE->getValue(); + uint64_t Width = WidthCE->getValue(); + + uint64_t RegWidth = 0; + if (AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains( + Op1.getReg())) + RegWidth = 64; + else + RegWidth = 32; + + if (LSB >= RegWidth) + return Error(LSBOp.getStartLoc(), + "expected integer in range [0, 31]"); + if (Width < 1 || Width > RegWidth) + return Error(WidthOp.getStartLoc(), + "expected integer in range [1, 32]"); + + uint64_t ImmR = 0; + if (RegWidth == 32) + ImmR = (32 - LSB) & 0x1f; + else + ImmR = (64 - LSB) & 0x3f; + + uint64_t ImmS = Width - 1; + + if (ImmR != 0 && ImmS >= ImmR) + return Error(WidthOp.getStartLoc(), + "requested insert overflows register"); + + const MCExpr *ImmRExpr = MCConstantExpr::Create(ImmR, getContext()); + const MCExpr *ImmSExpr = MCConstantExpr::Create(ImmS, getContext()); + Operands[0] = AArch64Operand::CreateToken( + "bfm", false, Op.getStartLoc(), getContext()); + Operands[2] = AArch64Operand::CreateReg( + RegWidth == 32 ? AArch64::WZR : AArch64::XZR, false, SMLoc(), + SMLoc(), getContext()); + Operands[3] = AArch64Operand::CreateImm( + ImmRExpr, LSBOp.getStartLoc(), LSBOp.getEndLoc(), getContext()); + Operands.emplace_back( + AArch64Operand::CreateImm(ImmSExpr, WidthOp.getStartLoc(), + WidthOp.getEndLoc(), getContext())); + } + } } else if (NumOperands == 5) { // FIXME: Horrible hack to handle the BFI -> BFM, SBFIZ->SBFM, and // UBFIZ -> UBFM aliases. @@ -3675,8 +3729,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, "expected integer in range [1, 32]"); uint64_t NewOp3Val = 0; - if (AArch64MCRegisterClasses[AArch64::GPR32allRegClassID].contains( - Op1.getReg())) + if (RegWidth == 32) NewOp3Val = (32 - Op3Val) & 0x1f; else NewOp3Val = (64 - Op3Val) & 0x3f; diff --git a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp index febd332..02bd929 100644 --- a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp +++ b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp @@ -162,11 +162,23 @@ void AArch64InstPrinter::printInst(const MCInst *MI, raw_ostream &O, int ImmR = MI->getOperand(3).getImm(); int ImmS = MI->getOperand(4).getImm(); - // BFI alias - if (ImmS < ImmR) { + if ((Op2.getReg() == AArch64::WZR || Op2.getReg() == AArch64::XZR) && + (ImmR == 0 || ImmS < ImmR)) { + // BFC takes precedence over its entire range, sligtly differently to BFI. int BitWidth = Opcode == AArch64::BFMXri ? 64 : 32; int LSB = (BitWidth - ImmR) % BitWidth; int Width = ImmS + 1; + + O << "\tbfc\t" << getRegisterName(Op0.getReg()) + << ", #" << LSB << ", #" << Width; + printAnnotation(O, Annot); + return; + } else if (ImmS < ImmR) { + // BFI alias + int BitWidth = Opcode == AArch64::BFMXri ? 64 : 32; + int LSB = (BitWidth - ImmR) % BitWidth; + int Width = ImmS + 1; + O << "\tbfi\t" << getRegisterName(Op0.getReg()) << ", " << getRegisterName(Op2.getReg()) << ", #" << LSB << ", #" << Width; printAnnotation(O, Annot); diff --git a/llvm/test/MC/AArch64/basic-a64-diagnostics.s b/llvm/test/MC/AArch64/basic-a64-diagnostics.s index 07e6d01..1d7ba71 100644 --- a/llvm/test/MC/AArch64/basic-a64-diagnostics.s +++ b/llvm/test/MC/AArch64/basic-a64-diagnostics.s @@ -1088,6 +1088,23 @@ // CHECK-ERROR-NEXT: ubfx w3, wsp, #10, #8 // CHECK-ERROR-NEXT: ^ + bfc wsp, #3, #6 + bfc w4, #2, #31 + bfc sp, #0, #1 + bfc x6, #0, #0 +// CHECK-ERROR: error: invalid operand for instruction +// CHECK-ERROR-NEXT: bfc wsp, #3, #6 +// CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: requested insert overflows register +// CHECK-ERROR-NEXT: bfc w4, #2, #31 +// CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: invalid operand for instruction +// CHECK-ERROR-NEXT: bfc sp, #0, #1 +// CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: expected integer in range [1, 32] +// CHECK-ERROR-NEXT: bfc x6, #0, #0 +// CHECK-ERROR-NEXT: ^ + //------------------------------------------------------------------------------ // Compare & branch (immediate) //------------------------------------------------------------------------------ diff --git a/llvm/test/MC/AArch64/basic-a64-instructions.s b/llvm/test/MC/AArch64/basic-a64-instructions.s index dd8dfd4..75c86ef 100644 --- a/llvm/test/MC/AArch64/basic-a64-instructions.s +++ b/llvm/test/MC/AArch64/basic-a64-instructions.s @@ -978,7 +978,7 @@ _func: bfm x5, x6, #12, #63 // CHECK: bfi x4, x5, #52, #11 // encoding: [0xa4,0x28,0x4c,0xb3] // CHECK: bfxil xzr, x4, #0, #1 // encoding: [0x9f,0x00,0x40,0xb3] -// CHECK: bfi x4, xzr, #1, #6 // encoding: [0xe4,0x17,0x7f,0xb3] +// CHECK: bfc x4, #1, #6 // encoding: [0xe4,0x17,0x7f,0xb3] // CHECK: bfxil x5, x6, #12, #52 // encoding: [0xc5,0xfc,0x4c,0xb3] sxtb w1, w2 @@ -1078,7 +1078,7 @@ _func: // CHECK: bfxil w9, w10, #0, #32 // encoding: [0x49,0x7d,0x00,0x33] // CHECK: bfi w11, w12, #31, #1 // encoding: [0x8b,0x01,0x01,0x33] // CHECK: bfi w13, w14, #29, #3 // encoding: [0xcd,0x09,0x03,0x33] -// CHECK: bfi xzr, xzr, #10, #11 // encoding: [0xff,0x2b,0x76,0xb3] +// CHECK: bfc xzr, #10, #11 // encoding: [0xff,0x2b,0x76,0xb3] bfxil w9, w10, #0, #1 bfxil x2, x3, #63, #1 @@ -1132,6 +1132,16 @@ _func: // CHECK: lsr w11, w12, #31 // encoding: [0x8b,0x7d,0x1f,0x53] // CHECK: lsr w13, w14, #29 // encoding: [0xcd,0x7d,0x1d,0x53] // CHECK: ubfx xzr, xzr, #10, #11 // encoding: [0xff,0x53,0x4a,0xd3] + + bfc w3, #0, #32 + bfc wzr, #31, #1 + bfc x0, #5, #9 + bfc xzr, #63, #1 +// CHECK: bfc w3, #0, #32 // encoding: [0xe3,0x7f,0x00,0x33] +// CHECK: bfc wzr, #31, #1 // encoding: [0xff,0x03,0x01,0x33] +// CHECK: bfc x0, #5, #9 // encoding: [0xe0,0x23,0x7b,0xb3] +// CHECK: bfc xzr, #63, #1 // encoding: [0xff,0x03,0x41,0xb3] + //------------------------------------------------------------------------------ // Compare & branch (immediate) //------------------------------------------------------------------------------ diff --git a/llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt b/llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt index 23da001..c777f7a 100644 --- a/llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt +++ b/llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt @@ -622,7 +622,7 @@ # CHECK: bfi x4, x5, #52, #11 # CHECK: bfxil xzr, x4, #0, #1 -# CHECK: bfi x4, xzr, #1, #6 +# CHECK: bfc x4, #1, #6 # CHECK: bfxil x5, x6, #12, #52 0xa4 0x28 0x4c 0xb3 0x9f 0x0 0x40 0xb3 @@ -715,7 +715,7 @@ # CHECK: bfxil w9, w10, #0, #32 # CHECK: bfi w11, w12, #31, #1 # CHECK: bfi w13, w14, #29, #3 -# CHECK: bfi xzr, xzr, #10, #11 +# CHECK: bfc xzr, #10, #11 0x49 0x1 0x0 0x33 0x62 0x0 0x41 0xb3 0x93 0xfe 0x40 0xb3