Chromium Code Reviews| Index: src/IceAssemblerARM32.cpp |
| diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp |
| index dd1e2644ec199290021b42d43c5b50d1a5a76687..49433d8e43b689c1eeddc4d84450d92025e694d2 100644 |
| --- a/src/IceAssemblerARM32.cpp |
| +++ b/src/IceAssemblerARM32.cpp |
| @@ -144,6 +144,25 @@ IValueT encodeCondition(CondARM32::Cond Cond) { |
| return static_cast<IValueT>(Cond); |
| } |
| +// Returns the SIMD encoding of the element type for the vector. |
| +IValueT encodeElmtType(Type ElmtTy) { |
| + switch (ElmtTy) { |
| + case IceType_i8: |
| + case IceType_f32: |
| + return 0; |
| + case IceType_i16: |
| + return 1; |
| + case IceType_i32: |
| + return 2; |
| + case IceType_i64: |
| + return 3; |
| + default: |
| + llvm::report_fatal_error( |
| + std::string("SIMD op: Don't understand element type") + |
|
Jim Stichnoth
2016/02/01 21:00:23
Nit: I think this might be a bit clearer:
...er
Karl
2016/02/01 21:44:53
Since (a) the name is typeString, and (b) c++ stri
Karl
2016/02/01 21:59:00
Ok. I understand the request. Doing in separate Cl
|
| + typeString(ElmtTy)); |
| + } |
| +} |
| + |
| IValueT encodeShift(OperandARM32::ShiftKind Shift) { |
| // Follows encoding in ARM section A8.4.1 "Constant shifts". |
| switch (Shift) { |
| @@ -191,6 +210,10 @@ IValueT getEncodedDRegNum(const Variable *Var) { |
| return RegARM32::getEncodedDReg(Var->getRegNum()); |
| } |
| +IValueT getEncodedQRegNum(const Variable *Var) { |
| + return RegARM32::getEncodedQReg(Var->getRegNum()); |
| +} |
| + |
| IValueT getYInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY & 0x1; } |
| IValueT getXXXXInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY >> 1; } |
| @@ -305,7 +328,7 @@ IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift, |
| } |
| // Defines the set of registers expected in an operand. |
| -enum RegSetWanted { WantGPRegs, WantSRegs, WantDRegs }; |
| +enum RegSetWanted { WantGPRegs, WantSRegs, WantDRegs, WantQRegs }; |
| EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value, |
| RegSetWanted WantedRegSet) { |
| @@ -322,6 +345,9 @@ EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value, |
| case WantDRegs: |
| Value = getEncodedDRegNum(Var); |
| break; |
| + case WantQRegs: |
| + Value = getEncodedQRegNum(Var); |
| + break; |
| } |
| return EncodedAsRegister; |
| } |
| @@ -503,6 +529,11 @@ IValueT encodeDRegister(const Operand *OpReg, const char *RegName, |
| return encodeRegister(OpReg, WantDRegs, RegName, InstName); |
| } |
| +IValueT encodeQRegister(const Operand *OpReg, const char *RegName, |
| + const char *InstName) { |
| + return encodeRegister(OpReg, WantQRegs, RegName, InstName); |
| +} |
| + |
| void verifyPOrNotW(IValueT Address, const char *InstName) { |
| if (BuildDefs::minimal()) |
| return; |
| @@ -1030,6 +1061,29 @@ void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode, |
| emitInst(Encoding); |
| } |
| +void AssemblerARM32::emitSIMD(IValueT Opcode, Type ElmtTy, IValueT Dd, |
| + IValueT Dn, IValueT Dm, bool UseQRegs) { |
| + IValueT Sz = encodeElmtType(ElmtTy); |
| + assert(Utils::IsUint(2, Sz)); |
| + IValueT Encoding = |
| + Opcode | B25 | (encodeCondition(CondARM32::kNone) << kConditionShift) | |
| + (Sz << 20) | (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) | |
| + (getXXXXInRegYXXXX(Dd) << 12) | (getYInRegYXXXX(Dn) << 7) | |
| + (encodeBool(UseQRegs) << 6) | (getYInRegYXXXX(Dm) << 5) | |
| + getXXXXInRegYXXXX(Dm); |
| + emitInst(Encoding); |
| +} |
| + |
| +void AssemblerARM32::emitSIMDqqq(IValueT Opcode, Type ElmtTy, |
| + const Operand *OpQd, const Operand *OpQn, |
| + const Operand *OpQm, const char *OpcodeName) { |
| + IValueT Qd = encodeQRegister(OpQd, "Qd", OpcodeName); |
| + IValueT Qn = encodeQRegister(OpQn, "Qn", OpcodeName); |
| + IValueT Qm = encodeQRegister(OpQm, "Qm", OpcodeName); |
| + constexpr bool UseQRegs = true; |
| + emitSIMD(Opcode, ElmtTy, Qd << 1, Qn << 1, Qm << 1, UseQRegs); |
|
Jim Stichnoth
2016/02/01 21:00:23
The "Qx << 1" is a bit jarring compared to the nor
Karl
2016/02/01 21:44:53
Done.
|
| +} |
| + |
| void AssemblerARM32::emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, |
| IValueT Dd, IValueT Dn, IValueT Dm) { |
| assert(Dd < RegARM32::getNumDRegs()); |
| @@ -2097,6 +2151,29 @@ void AssemblerARM32::vadds(const Operand *OpSd, const Operand *OpSn, |
| emitVFPsss(Cond, VaddsOpcode, OpSd, OpSn, OpSm, Vadds); |
| } |
| +void AssemblerARM32::vaddqi(Type ElmtTy, const Operand *OpQd, |
| + const Operand *OpQm, const Operand *OpQn) { |
| + // VADD (integer) - ARM section A8.8.282, encoding A1: |
| + // vadd.<dt> <Qd>, <Qn>, <Qm> |
| + // |
| + // 111100100Dssnnn0ddd01000NqM0mmm0 where Dddd=OpQd, Nnnn=OpQm, Mmmm=OpQm, |
| + // and dt in [i8, i16, i32, i64] where ss is the index. |
| + constexpr const char *Vaddqi = "vaddqi"; |
| + constexpr IValueT VaddqiOpcode = B11; |
| + emitSIMDqqq(VaddqiOpcode, ElmtTy, OpQd, OpQm, OpQn, Vaddqi); |
| +} |
| + |
| +void AssemblerARM32::vaddqf(const Operand *OpQd, const Operand *OpQn, |
| + const Operand *OpQm) { |
| + // VADD (floating-point) - ARM section A8.8.283, Encoding A1: |
| + // vadd.f32 <Qd>, <Qn>, <Qm> |
| + // |
| + // 111100100D00nnn0ddd01101N1M0mmm0 where Dddd=Qd, Nnnn=Qn, and Mmmm=Qm. |
| + constexpr const char *Vaddqf = "vaddqf"; |
| + constexpr IValueT VaddqfOpcode = B11 | B10 | B8; |
| + emitSIMDqqq(VaddqfOpcode, IceType_f32, OpQd, OpQn, OpQm, Vaddqf); |
| +} |
| + |
| void AssemblerARM32::vaddd(const Operand *OpDd, const Operand *OpDn, |
| const Operand *OpDm, CondARM32::Cond Cond) { |
| // VADD (floating-point) - ARM section A8.8.283, encoding A2: |