Commit 4c2153b1 by Karl Schimpf

emit add/sub registers instructions in integrated ARM assembler.

Also cleans up comments and condition violations for all implemented ARM instructions. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1411873002 .
parent 659cc4f2
...@@ -158,6 +158,8 @@ class Operand : public ValueObject { ...@@ -158,6 +158,8 @@ class Operand : public ValueObject {
} }
#endif #endif
#if 0
// Moved to encodeShiftRotateImm5()
// Data-processing operands - Logical shift/rotate by immediate. // Data-processing operands - Logical shift/rotate by immediate.
Operand(Register rm, Shift shift, uint32_t shift_imm) { Operand(Register rm, Shift shift, uint32_t shift_imm) {
ASSERT(shift_imm < (1 << kShiftImmBits)); ASSERT(shift_imm < (1 << kShiftImmBits));
...@@ -166,6 +168,7 @@ class Operand : public ValueObject { ...@@ -166,6 +168,7 @@ class Operand : public ValueObject {
static_cast<uint32_t>(shift) << kShiftShift | static_cast<uint32_t>(shift) << kShiftShift |
static_cast<uint32_t>(rm); static_cast<uint32_t>(rm);
} }
#endif
// Data-processing operands - Logical shift/rotate by register. // Data-processing operands - Logical shift/rotate by register.
Operand(Register rm, Shift shift, Register rs) { Operand(Register rm, Shift shift, Register rs) {
......
...@@ -62,6 +62,11 @@ static constexpr uint32_t kImmed8Shift = 0; ...@@ -62,6 +62,11 @@ static constexpr uint32_t kImmed8Shift = 0;
static constexpr uint32_t kRotateBits = 4; static constexpr uint32_t kRotateBits = 4;
static constexpr uint32_t kRotateShift = 8; static constexpr uint32_t kRotateShift = 8;
// Shift instruction register fields encodings.
static constexpr uint32_t kShiftImmShift = 7;
static constexpr uint32_t kShiftImmBits = 5;
static constexpr uint32_t kShiftShift = 5;
static constexpr uint32_t kImmed12Bits = 12; static constexpr uint32_t kImmed12Bits = 12;
static constexpr uint32_t kImm12Shift = 0; static constexpr uint32_t kImm12Shift = 0;
...@@ -87,6 +92,22 @@ inline uint32_t encodeCondition(CondARM32::Cond Cond) { ...@@ -87,6 +92,22 @@ inline uint32_t encodeCondition(CondARM32::Cond Cond) {
return static_cast<uint32_t>(Cond); return static_cast<uint32_t>(Cond);
} }
uint32_t encodeShift(OperandARM32::ShiftKind Shift) {
// Follows encoding in ARM section A8.4.1 "Constant shifts".
switch (Shift) {
case OperandARM32::kNoShift:
case OperandARM32::LSL:
return 0; // 0b00
case OperandARM32::LSR:
return 1; // 0b01
case OperandARM32::ASR:
return 2; // 0b10
case OperandARM32::ROR:
case OperandARM32::RRX:
return 3; // 0b11
}
}
// Returns the bits in the corresponding masked value. // Returns the bits in the corresponding masked value.
inline uint32_t mask(uint32_t Value, uint32_t Shift, uint32_t Bits) { inline uint32_t mask(uint32_t Value, uint32_t Shift, uint32_t Bits) {
return (Value >> Shift) & ((1 << Bits) - 1); return (Value >> Shift) & ((1 << Bits) - 1);
...@@ -118,6 +139,15 @@ enum DecodedResult { ...@@ -118,6 +139,15 @@ enum DecodedResult {
DecodedAsImmRegOffset DecodedAsImmRegOffset
}; };
// Encodes iiiiitt0mmmm for data-processing (2nd) operands where iiiii=Imm5,
// tt=Shift, and mmmm=Rm.
uint32_t encodeShiftRotateImm5(uint32_t Rm, OperandARM32::ShiftKind Shift,
uint32_t imm5) {
(void)kShiftImmBits;
assert(imm5 < (1 << kShiftImmBits));
return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm;
}
DecodedResult decodeOperand(const Operand *Opnd, uint32_t &Value) { DecodedResult decodeOperand(const Operand *Opnd, uint32_t &Value) {
if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
if (Var->hasReg()) { if (Var->hasReg()) {
...@@ -129,8 +159,8 @@ DecodedResult decodeOperand(const Operand *Opnd, uint32_t &Value) { ...@@ -129,8 +159,8 @@ DecodedResult decodeOperand(const Operand *Opnd, uint32_t &Value) {
const uint32_t Rotate = FlexImm->getRotateAmt(); const uint32_t Rotate = FlexImm->getRotateAmt();
assert((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits))); assert((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)));
// TODO(kschimpf): Remove void casts when MINIMAL build allows. // TODO(kschimpf): Remove void casts when MINIMAL build allows.
(void) kRotateBits; (void)kRotateBits;
(void) kImmed8Bits; (void)kImmed8Bits;
Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift); Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift);
return DecodedAsRotatedImm8; return DecodedAsRotatedImm8;
} }
...@@ -206,7 +236,7 @@ void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type, ...@@ -206,7 +236,7 @@ void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type,
uint32_t Rd, uint32_t Imm12) { uint32_t Rd, uint32_t Imm12) {
assert(isGPRRegisterDefined(Rd)); assert(isGPRRegisterDefined(Rd));
// TODO(kschimpf): Remove void cast when MINIMAL build allows. // TODO(kschimpf): Remove void cast when MINIMAL build allows.
(void) isGPRRegisterDefined(Rd); (void)isGPRRegisterDefined(Rd);
assert(Cond != CondARM32::kNone); assert(Cond != CondARM32::kNone);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) |
...@@ -239,39 +269,69 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, ...@@ -239,39 +269,69 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
uint32_t Rn; uint32_t Rn;
if (decodeOperand(OpRn, Rn) != DecodedAsRegister) if (decodeOperand(OpRn, Rn) != DecodedAsRegister)
break; break;
constexpr uint32_t Add = B2; // 0100
uint32_t Src1Value; uint32_t Src1Value;
// TODO(kschimpf) Other possible decodings of add. // TODO(kschimpf) Other possible decodings of add.
if (decodeOperand(OpSrc1, Src1Value) == DecodedAsRotatedImm8) { switch (decodeOperand(OpSrc1, Src1Value)) {
// ADD (Immediate): See ARM section A8.8.5, rule A1. default:
break;
case DecodedAsRegister: {
// ADD (register) - ARM section A8.8.7, encoding A1:
// add{s}<c> <Rd>, <Rn>, <Rm>{, <shiff>}
// ADD (Sp plus register) - ARM section A8.8.11, encoding A1:
// add{s}<c> sp, <Rn>, <Rm>{, <shiff>}
//
// cccc0000100snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
// mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags
Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, 0);
if (((Rd == RegARM32::Encoded_Reg_pc) && SetFlags))
// Conditions of rule violated.
break;
constexpr uint32_t InstTypeRegister = 0;
emitType01(Cond, InstTypeRegister, Add, SetFlags, Rn, Rd, Src1Value);
return;
}
case DecodedAsRotatedImm8: {
// ADD (Immediate) - ARM section A8.8.5, encoding A1:
// add{s}<c> <Rd>, <Rn>, #<RotatedImm8>
// ADD (SP plus immediate) - ARM section A8.8.9, encoding A1.
// add{s}<c> <Rd>, sp, #<RotatedImm8>
//
// cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value // s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8.
if (!isConditionDefined(Cond) || (Rd == RegARM32::Reg_pc && SetFlags) || if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags))
(Rn == RegARM32::Reg_lr) || (Rn == RegARM32::Reg_pc && SetFlags))
// Conditions of rule violated. // Conditions of rule violated.
break; break;
constexpr uint32_t Add = B2; // 0100 constexpr uint32_t InstTypeImmediate = 1;
constexpr uint32_t InstType = 1; emitType01(Cond, InstTypeImmediate, Add, SetFlags, Rn, Rd, Src1Value);
emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value);
return; return;
} }
}
} while (0); } while (0);
UnimplementedError(Ctx->getFlags()); UnimplementedError(Ctx->getFlags());
} }
void ARM32::AssemblerARM32::bkpt(uint16_t imm16) { void ARM32::AssemblerARM32::bkpt(uint16_t Imm16) {
// BKPT - ARM section A*.8.24 - encoding A1:
// bkpt #<Imm16>
//
// cccc00010010iiiiiiiiiiii0111iiii where cccc=AL and iiiiiiiiiiiiiiii=Imm16
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const uint32_t Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 | const uint32_t Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 |
((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf); ((Imm16 >> 4) << 8) | B6 | B5 | B4 | (Imm16 & 0xf);
emitInst(Encoding); emitInst(Encoding);
} }
void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) {
// BX - ARM section A8.8.27, encoding A1:
// bx<c> <Rm>
//
// cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond. // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond.
// (ARM section A8.8.27, encoding A1).
assert(isGPRRegisterDefined(Rm)); assert(isGPRRegisterDefined(Rm));
// TODO(kschimpf): Remove void cast when MINIMAL build allows. // TODO(kschimpf): Remove void cast when MINIMAL build allows.
(void) isGPRRegisterDefined(Rm); (void)isGPRRegisterDefined(Rm);
assert(isConditionDefined(Cond)); assert(isConditionDefined(Cond));
(void)isConditionDefined(Cond);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 |
B21 | (0xfff << 8) | B4 | B21 | (0xfff << 8) | B4 |
...@@ -289,8 +349,17 @@ void ARM32::AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -289,8 +349,17 @@ void ARM32::AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
uint32_t Address; uint32_t Address;
if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset)
break; break;
// cccc010pu0w1nnnnttttiiiiiiiiiiii (ARM section A8.8.63, encoding A1; and // LDR (immediate) - ARM section A8.8.63, encoding A1:
// section A8.6.68, encoding A1). // ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
// LDRB (immediate) - ARM section A8.8.68, encoding A1:
// ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// cccc010pubw1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, b=1 if STRB, u=1 if +.
constexpr uint32_t InstType = B1; // 010 constexpr uint32_t InstType = B1; // 010
constexpr bool IsLoad = true; constexpr bool IsLoad = true;
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
...@@ -298,8 +367,9 @@ void ARM32::AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -298,8 +367,9 @@ void ARM32::AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
break; break;
const bool IsByte = typeWidthInBytes(Ty) == 1; const bool IsByte = typeWidthInBytes(Ty) == 1;
if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc) || if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc) ||
(!IsByte && !isBitSet(P, Address) && isBitSet(W, Address)) || (!isBitSet(P, Address) && isBitSet(W, Address)) ||
((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && (!IsByte &&
(getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) &&
!isBitSet(P, Address) && !isBitSet(P, Address) &&
isBitSet(U, Address) & !isBitSet(W, Address) && isBitSet(U, Address) & !isBitSet(W, Address) &&
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))) (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)))
...@@ -320,10 +390,14 @@ void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, ...@@ -320,10 +390,14 @@ void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
uint32_t Src; uint32_t Src;
// TODO(kschimpf) Handle other forms of mov. // TODO(kschimpf) Handle other forms of mov.
if (decodeOperand(OpSrc, Src) == DecodedAsRotatedImm8) { if (decodeOperand(OpSrc, Src) == DecodedAsRotatedImm8) {
// cccc0011101s0000ddddiiiiiiiiiiii (ARM section A8.8.102, encoding A1) // MOV (immediate) - ARM section A8.8.102, encoding A1:
// Note: We don't use movs in this assembler. // mov{S}<c> <Rd>, #<RotatedImm8>
//
// cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags, dddd=Rd,
// and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this
// assembler.
constexpr bool SetFlags = false; constexpr bool SetFlags = false;
if (!isConditionDefined(Cond) || (Rd == RegARM32::Reg_pc && SetFlags)) if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags))
// Conditions of rule violated. // Conditions of rule violated.
break; break;
constexpr uint32_t Rn = 0; constexpr uint32_t Rn = 0;
...@@ -346,8 +420,17 @@ void ARM32::AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, ...@@ -346,8 +420,17 @@ void ARM32::AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
uint32_t Address; uint32_t Address;
if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset)
break; break;
// cccc010pub0nnnnttttiiiiiiiiiiii (ARM section A8.8.204, encoding A1; and // STR (immediate) - ARM section A8.8.204, encoding A1:
// section 18.8.207, encoding A1). // str<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// str<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// str<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
// STRB (immediate) - ARM section A8.8.207, encoding A1:
// strb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// strb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// strb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// cccc010pubw0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, b=1 if STRB, u=1 if +.
constexpr uint32_t InstType = B1; // 010 constexpr uint32_t InstType = B1; // 010
constexpr bool IsLoad = false; constexpr bool IsLoad = false;
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
...@@ -362,6 +445,7 @@ void ARM32::AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, ...@@ -362,6 +445,7 @@ void ARM32::AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
isBitSet(P, Address) && !isBitSet(U, Address) && isBitSet(P, Address) && !isBitSet(U, Address) &&
isBitSet(W, Address) && isBitSet(W, Address) &&
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))) (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)))
// Conditions of rule violated.
break; break;
emitMemOp(Cond, InstType, IsLoad, IsByte, Rt, Address); emitMemOp(Cond, InstType, IsLoad, IsByte, Rt, Address);
return; return;
...@@ -380,21 +464,44 @@ void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, ...@@ -380,21 +464,44 @@ void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
uint32_t Rn; uint32_t Rn;
if (decodeOperand(OpRn, Rn) != DecodedAsRegister) if (decodeOperand(OpRn, Rn) != DecodedAsRegister)
break; break;
constexpr uint32_t Sub = B1; // 0010
uint32_t Src1Value; uint32_t Src1Value;
// TODO(kschimpf) Other possible decodings of add. // TODO(kschimpf) Other possible decodings of sub.
if (decodeOperand(OpSrc1, Src1Value) == DecodedAsRotatedImm8) { switch (decodeOperand(OpSrc1, Src1Value)) {
// Sub (Immediate): See ARM section A8.8.222, rule A1. default:
break;
case DecodedAsRegister: {
// SUB (register) - ARM section A8.8.223, encoding A1:
// sub{s}<c> <Rd>, <Rn>, <Rm>{, <shift>}
// SUB (SP minus register): See ARM section 8.8.226, encoding A1:
// sub{s}<c> <Rd>, sp, <Rm>{, <Shift>}
//
// cccc0000010snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
// mmmm=Rm, iiiiii=shift, tt=ShiftKind, and s=SetFlags.
Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, 0);
constexpr uint32_t InstType = 0; // i.e. register
if (((Rd == RegARM32::Encoded_Reg_pc) && SetFlags))
// Conditions of rule violated.
break;
emitType01(Cond, InstType, Sub, SetFlags, Rn, Rd, Src1Value);
return;
}
case DecodedAsRotatedImm8: {
// Sub (Immediate) - ARM section A8.8.222, encoding A1:
// sub{s}<c> <Rd>, <Rn>, #<RotatedImm8>
// Sub (Sp minus immediate) - ARM section A8.*.225, encoding A1:
// sub{s}<c> sp, <Rn>, #<RotatedImm8>
//
// cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value // s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8
if (!isConditionDefined(Cond) || (Rd == RegARM32::Reg_pc && SetFlags) || if (Rd == RegARM32::Encoded_Reg_pc)
(Rn == RegARM32::Reg_lr) || (Rn == RegARM32::Reg_pc && SetFlags))
// Conditions of rule violated. // Conditions of rule violated.
break; break;
constexpr uint32_t Add = B1; // 0010
constexpr uint32_t InstType = 1; constexpr uint32_t InstType = 1;
emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value); emitType01(Cond, InstType, Sub, SetFlags, Rn, Rd, Src1Value);
return; return;
} }
}
} while (0); } while (0);
UnimplementedError(Ctx->getFlags()); UnimplementedError(Ctx->getFlags());
} }
......
; Show that we know how to translate add. ; Show that we know how to translate add.
; TODO(kschimpf) Currently only know how to test add 1 to R0.
; NOTE: We use -O2 to get rid of memory stores. ; NOTE: We use -O2 to get rid of memory stores.
...@@ -16,8 +15,8 @@ define internal i32 @add1ToR0(i32 %p) { ...@@ -16,8 +15,8 @@ define internal i32 @add1ToR0(i32 %p) {
} }
; ASM-LABEL: add1ToR0: ; ASM-LABEL: add1ToR0:
; ASM: add r0, r0, #1 ; ASM: add r0, r0, #1
; ASM: bx lr ; ASM-NEXT: bx lr
; IASM-LABEL: add1ToR0: ; IASM-LABEL: add1ToR0:
; IASM: .byte 0x1 ; IASM: .byte 0x1
...@@ -25,3 +24,18 @@ define internal i32 @add1ToR0(i32 %p) { ...@@ -25,3 +24,18 @@ define internal i32 @add1ToR0(i32 %p) {
; IASM-NEXT: .byte 0x80 ; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
define internal i32 @Add2Regs(i32 %p1, i32 %p2) {
%v = add i32 %p1, %p2
ret i32 %v
}
; ASM-LABEL: Add2Regs:
; ASM: add r0, r0, r1
; ASM-NEXT: bx lr
; IASM-LABEL: Add2Regs:
; IASM: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0xe0
; Show that we know how to translate instruction sub. ; Show that we know how to translate instruction sub.
; TODO(kschimpf) Currently only know how to test subtract 1 from R0.
; NOTE: We use -O2 to get rid of memory stores. ; NOTE: We use -O2 to get rid of memory stores.
...@@ -25,3 +24,20 @@ define internal i32 @sub1FromR0(i32 %p) { ...@@ -25,3 +24,20 @@ define internal i32 @sub1FromR0(i32 %p) {
; IASM-NEXT: .byte 0x40 ; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
define internal i32 @Sub2Regs(i32 %p1, i32 %p2) {
%v = sub i32 %p1, %p2
ret i32 %v
}
; ASM-LABEL: Sub2Regs:
; ASM: sub r0, r0, r1
; ASM-NEXT: bx lr
; IASM-LABEL: Sub2Regs:
; IASM: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0xe0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment