MachineInstrBuilder buildAdd(LLT Ty, unsigned Res, unsigned Op0,
unsigned Op1);
+ /// Build and insert \p Res<def>, \p CarryOut = G_ADDE \p Ty \p Op0, \p Op1,
+ /// \p CarryIn
+ ///
+ /// G_ADDE sets \p Res to \p Op0 + \p Op1 + \p CarryIn (truncated to the bit
+ /// width) and sets \p CarryOut to 1 if the result overflowed in 2s-complement
+ /// arithmetic.
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ ///
+ /// \return The newly created instruction.
+ MachineInstrBuilder buildAdde(LLT Ty, unsigned Res, unsigned CarryOut,
+ unsigned Op0, unsigned Op1, unsigned CarryIn);
+
/// Build and insert \p Res<def> = G_ANYEXTEND \p Ty \p Op0
///
/// G_ANYEXTEND produces a register of the specified width, with bits 0 to
/// \return The newly created instruction.
MachineInstrBuilder buildBrCond(LLT Ty, unsigned Tst, MachineBasicBlock &BB);
+ /// Build and insert \p Res = G_CONSTANT \p Ty \p Val
+ ///
+ /// G_CONSTANT is an integer constant with the specified size and value.
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ ///
+ /// \return The newly created instruction.
+ MachineInstrBuilder buildConstant(LLT Ty, unsigned Res, int64_t Val);
+
/// Build and insert \p Res<def> = COPY Op
///
/// Register-to-register COPY sets \p Res to \p Op.
let hasSideEffects = 0;
}
+def G_CONSTANT : Instruction {
+ let OutOperandList = (outs unknown:$dst);
+ let InOperandList = (ins unknown:$imm);
+ let hasSideEffects = 0;
+}
+
//------------------------------------------------------------------------------
// Binary ops.
//------------------------------------------------------------------------------
let isCommutable = 0;
}
+// Generic addition consuming and producing a carry flag.
+def G_ADDE : Instruction {
+ let OutOperandList = (outs unknown:$dst, unknown:$carry_out);
+ let InOperandList = (ins unknown:$src1, unknown:$src2, unknown:$carry_in);
+ let hasSideEffects = 0;
+ let isCommutable = 1;
+}
+
// Generic bitwise and.
def G_AND : Instruction {
let OutOperandList = (outs unknown:$dst);
//------------------------------------------------------------------------------
// Branches.
//------------------------------------------------------------------------------
+
// Generic unconditional branch.
def G_BR : Instruction {
let OutOperandList = (outs);
HANDLE_TARGET_OPCODE(G_ADD)
HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_START, G_ADD)
+/// Generic ADD instruction, consuming the normal operands plus a carry flag,
+/// and similarly producing the result and a carry flag.
+HANDLE_TARGET_OPCODE(G_ADDE)
+
/// Generic SUB instruction. This is an integer sub.
HANDLE_TARGET_OPCODE(G_SUB)
/// Generic Bitwise-AND instruction.
HANDLE_TARGET_OPCODE(G_AND)
-/// Generic Bitwise-OR instruction.
+/// Generic bitwise or instruction.
HANDLE_TARGET_OPCODE(G_OR)
-/// Generic Bitwise-OR instruction.
+/// Generic bitwise exclusive-or instruction.
HANDLE_TARGET_OPCODE(G_XOR)
/// Generic instruction to materialize the address of an alloca or other
/// Generic truncation.
HANDLE_TARGET_OPCODE(G_TRUNC)
+/// Generic integer constant.
+HANDLE_TARGET_OPCODE(G_CONSTANT)
+
/// Generic BRANCH instruction. This is an unconditional branch.
HANDLE_TARGET_OPCODE(G_BR)
return buildInstr(TargetOpcode::COPY).addDef(Res).addUse(Op);
}
+MachineInstrBuilder MachineIRBuilder::buildConstant(LLT Ty, unsigned Res,
+ int64_t Val) {
+ return buildInstr(TargetOpcode::G_CONSTANT, Ty).addDef(Res).addImm(Val);
+}
+
MachineInstrBuilder MachineIRBuilder::buildBrCond(LLT Ty, unsigned Tst,
MachineBasicBlock &Dest) {
return buildInstr(TargetOpcode::G_BRCOND, Ty).addUse(Tst).addMBB(&Dest);
.addMemOperand(&MMO);
}
+MachineInstrBuilder MachineIRBuilder::buildAdde(LLT Ty, unsigned Res,
+ unsigned CarryOut, unsigned Op0,
+ unsigned Op1,
+ unsigned CarryIn) {
+ return buildInstr(TargetOpcode::G_ADDE, Ty)
+ .addDef(Res)
+ .addDef(CarryOut)
+ .addUse(Op0)
+ .addUse(Op1)
+ .addUse(CarryIn);
+}
+
MachineInstrBuilder MachineIRBuilder::buildAnyExtend(LLT Ty, unsigned Res,
unsigned Op) {
return buildInstr(TargetOpcode::G_ANYEXTEND, Ty).addDef(Res).addUse(Op);
MachineLegalizeHelper::LegalizeResult
MachineLegalizeHelper::narrowScalar(MachineInstr &MI, LLT NarrowTy) {
- return UnableToLegalize;
+ switch (MI.getOpcode()) {
+ default:
+ return UnableToLegalize;
+ case TargetOpcode::G_ADD: {
+ // Expand in terms of carry-setting/consuming G_ADDE instructions.
+ unsigned NarrowSize = NarrowTy.getSizeInBits();
+ int NumParts = MI.getType().getSizeInBits() / NarrowSize;
+
+ MIRBuilder.setInstr(MI);
+
+ SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
+ extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
+ extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
+
+ unsigned CarryIn = MRI.createGenericVirtualRegister(1);
+ MIRBuilder.buildConstant(LLT::scalar(1), CarryIn, 0);
+
+ for (int i = 0; i < NumParts; ++i) {
+ unsigned DstReg = MRI.createGenericVirtualRegister(NarrowSize);
+ unsigned CarryOut = MRI.createGenericVirtualRegister(1);
+
+ MIRBuilder.buildAdde(NarrowTy, DstReg, CarryOut, Src1Regs[i], Src2Regs[i],
+ CarryIn);
+
+ DstRegs.push_back(DstReg);
+ CarryIn = CarryOut;
+ }
+ MIRBuilder.buildSequence(MI.getType(), MI.getOperand(0).getReg(), DstRegs);
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ }
}
MachineLegalizeHelper::LegalizeResult
AArch64MachineLegalizer::AArch64MachineLegalizer() {
using namespace TargetOpcode;
+ const LLT s8 = LLT::scalar(8);
+ const LLT s16 = LLT::scalar(16);
const LLT s32 = LLT::scalar(32);
const LLT s64 = LLT::scalar(64);
const LLT v2s32 = LLT::vector(2, 32);
const LLT v4s32 = LLT::vector(4, 32);
const LLT v2s64 = LLT::vector(2, 64);
- for (auto BinOp : {G_ADD, G_SUB, G_AND, G_OR, G_XOR})
+ for (auto BinOp : {G_ADD, G_SUB, G_AND, G_OR, G_XOR}) {
for (auto Ty : {s32, s64, v2s32, v4s32, v2s64})
setAction(BinOp, Ty, Legal);
+ for (auto Ty : {s8, s16})
+ setAction(BinOp, Ty, WidenScalar);
+ }
+
for (auto MemOp : {G_LOAD, G_STORE})
for (auto Ty : {s32, s64})
setAction(MemOp, Ty, Legal);
+
setAction(G_BR, LLT::unsized(), Legal);
computeTables();
--- |
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-apple-ios"
+ define void @test_scalar_add_big() {
+ entry:
+ ret void
+ }
define void @test_scalar_add_small() {
entry:
ret void
...
---
+name: test_scalar_add_big
+isSSA: true
+registers:
+ - { id: 0, class: _ }
+ - { id: 1, class: _ }
+ - { id: 2, class: _ }
+body: |
+ bb.0.entry:
+ liveins: %x0, %x1, %x2, %x3
+ ; CHECK-LABEL: name: test_scalar_add_big
+ ; CHECK-DAG: [[LHS_LO:%.*]](64), [[LHS_HI:%.*]](64) = G_EXTRACT s64 %0, 0, 64
+ ; CHECK-DAG: [[RHS_LO:%.*]](64), [[RHS_HI:%.*]](64) = G_EXTRACT s64 %1, 0, 64
+ ; CHECK-DAG: [[CARRY0:%.*]](1) = G_CONSTANT s1 0
+ ; CHECK: [[RES_LO:%.*]](64), [[CARRY:%.*]](1) = G_ADDE s64 [[LHS_LO]], [[RHS_LO]], [[CARRY0]]
+ ; CHECK: [[RES_HI:%.*]](64), {{%.*}}(1) = G_ADDE s64 [[LHS_HI]], [[RHS_HI]], [[CARRY]]
+ ; CHECK: %2(128) = G_SEQUENCE s128 [[RES_LO]], [[RES_HI]]
+
+ %0(128) = G_SEQUENCE s128 %x0, %x1
+ %1(128) = G_SEQUENCE s128 %x2, %x3
+ %2(128) = G_ADD s128 %0, %1
+ %x0, %x1 = G_EXTRACT s64 %2, 0, 64
+...
+
+---
name: test_scalar_add_small
isSSA: true
registers: