Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
285 changes: 73 additions & 212 deletions llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1284,117 +1284,89 @@ bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
return true;
}

static unsigned getSExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64) {
if (I64Result) {
switch (LoadSize) {
default:
return WebAssembly::INSTRUCTION_LIST_END;
case 8:
return A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
case 16:
return A64 ? WebAssembly::LOAD16_S_I64_A64
: WebAssembly::LOAD16_S_I64_A32;
case 32:
return A64 ? WebAssembly::LOAD32_S_I64_A64
: WebAssembly::LOAD32_S_I64_A32;
}
}

switch (LoadSize) {
default:
return WebAssembly::INSTRUCTION_LIST_END;
case 8:
return A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
case 16:
return A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
}
}

static unsigned getZExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64) {
if (I64Result) {
switch (LoadSize) {
default:
return WebAssembly::INSTRUCTION_LIST_END;
case 8:
return A64 ? WebAssembly::LOAD8_U_I64_A64 : WebAssembly::LOAD8_U_I64_A32;
case 16:
return A64 ? WebAssembly::LOAD16_U_I64_A64
: WebAssembly::LOAD16_U_I64_A32;
case 32:
return A64 ? WebAssembly::LOAD32_U_I64_A64
: WebAssembly::LOAD32_U_I64_A32;
}
}

switch (LoadSize) {
default:
return WebAssembly::INSTRUCTION_LIST_END;
case 8:
return A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
case 16:
return A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
}
}

static bool isFoldableSExtOpcode(unsigned Opc) {
static unsigned getSExtLoadOpcode(unsigned Opc, bool A64) {
switch (Opc) {
default:
return false;
return WebAssembly::INSTRUCTION_LIST_END;
case WebAssembly::I32_EXTEND8_S_I32:
Opc = A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
break;
case WebAssembly::I32_EXTEND16_S_I32:
Opc = A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
break;
case WebAssembly::I64_EXTEND8_S_I64:
Opc = A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
break;
case WebAssembly::I64_EXTEND16_S_I64:
Opc = A64 ? WebAssembly::LOAD16_S_I64_A64 : WebAssembly::LOAD16_S_I64_A32;
break;
case WebAssembly::I64_EXTEND32_S_I64:
case WebAssembly::I64_EXTEND_S_I32:
return true;
Opc = A64 ? WebAssembly::LOAD32_S_I64_A64 : WebAssembly::LOAD32_S_I64_A32;
break;
}

return Opc;
}

static bool isI64SExtResult(unsigned Opc) {
switch (Opc) {
default:
llvm_unreachable("unexpected opcode");
case WebAssembly::I32_EXTEND8_S_I32:
case WebAssembly::I32_EXTEND16_S_I32:
return false;
case WebAssembly::I64_EXTEND8_S_I64:
case WebAssembly::I64_EXTEND16_S_I64:
case WebAssembly::I64_EXTEND32_S_I64:
case WebAssembly::I64_EXTEND_S_I32:
return true;
static unsigned getZExtLoadOpcodeFromAnd(MachineInstr *MI,
MachineRegisterInfo &MRI,
const LoadInst *LI, bool A64) {
uint64_t Mask = 0;
bool IsConstant = false;
for (unsigned I = 1; I <= 2; ++I) {
Register Reg = MI->getOperand(I).getReg();
MachineInstr *DefMI = MRI.getUniqueVRegDef(Reg);
if (DefMI && (DefMI->getOpcode() == WebAssembly::CONST_I32 ||
DefMI->getOpcode() == WebAssembly::CONST_I64)) {
Mask = DefMI->getOperand(1).getImm();
IsConstant = true;
break;
}
}
}

static unsigned getFoldedLoadOpcode(MachineInstr *MI, MachineRegisterInfo &MRI,
const LoadInst *LI, bool A64) {
unsigned Opc = MI->getOpcode();
if (!IsConstant)
return WebAssembly::INSTRUCTION_LIST_END;

unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
if (Mask != llvm::maskTrailingOnes<uint64_t>(LoadSize))
return WebAssembly::INSTRUCTION_LIST_END;

if (isFoldableSExtOpcode(Opc)) {
unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
return getSExtLoadOpcode(LoadSize, isI64SExtResult(Opc), A64);
if (MI->getOpcode() == WebAssembly::AND_I32) {
if (LoadSize == 8)
return A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
if (LoadSize == 16)
return A64 ? WebAssembly::LOAD16_U_I32_A64
: WebAssembly::LOAD16_U_I32_A32;
} else if (MI->getOpcode() == WebAssembly::AND_I64) {
if (LoadSize == 8)
return A64 ? WebAssembly::LOAD8_U_I64_A64 : WebAssembly::LOAD8_U_I64_A32;
if (LoadSize == 16)
return A64 ? WebAssembly::LOAD16_U_I64_A64
: WebAssembly::LOAD16_U_I64_A32;
if (LoadSize == 32)
return A64 ? WebAssembly::LOAD32_U_I64_A64
: WebAssembly::LOAD32_U_I64_A32;
}

return WebAssembly::INSTRUCTION_LIST_END;
}

static unsigned getFoldedI64LoadOpcode(Register DestReg, const LoadInst *LI,
MachineRegisterInfo &MRI, bool A64,
MachineInstr *&OuterUserMI,
unsigned NarrowOpc) {
if (!MRI.hasOneNonDBGUse(DestReg))
return NarrowOpc;

MachineInstr *UserMI = &*MRI.use_instr_nodbg_begin(DestReg);
unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
switch (UserMI->getOpcode()) {
case WebAssembly::I64_EXTEND_U_I32:
OuterUserMI = UserMI;
return getZExtLoadOpcode(LoadSize, /*I64Result=*/true, A64);
static unsigned getFoldedLoadOpcode(MachineInstr *MI, MachineRegisterInfo &MRI,
const LoadInst *LI, bool A64) {
switch (MI->getOpcode()) {
case WebAssembly::I32_EXTEND8_S_I32:
case WebAssembly::I32_EXTEND16_S_I32:
case WebAssembly::I64_EXTEND8_S_I64:
case WebAssembly::I64_EXTEND16_S_I64:
case WebAssembly::I64_EXTEND32_S_I64:
case WebAssembly::I64_EXTEND_S_I32:
OuterUserMI = UserMI;
return getSExtLoadOpcode(LoadSize, /*I64Result=*/true, A64);
return getSExtLoadOpcode(MI->getOpcode(), A64);
case WebAssembly::AND_I32:
case WebAssembly::AND_I64:
return getZExtLoadOpcodeFromAnd(MI, MRI, LI, A64);
default:
return NarrowOpc;
return WebAssembly::INSTRUCTION_LIST_END;
}
}

Expand All @@ -1407,8 +1379,7 @@ static unsigned getFoldedI64LoadOpcode(Register DestReg, const LoadInst *LI,
/// size (32 - LoadBitWidth).
static unsigned matchFoldableShift(MachineInstr *MI, const LoadInst *LI,
MachineRegisterInfo &MRI, bool A64,
MachineInstr *&UserMI,
MachineInstr *&OuterUserMI) {
MachineInstr *&UserMI) {
unsigned Opc = MI->getOpcode();
unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
if (Opc != WebAssembly::SHL_I32)
Expand Down Expand Up @@ -1439,104 +1410,13 @@ static unsigned matchFoldableShift(MachineInstr *MI, const LoadInst *LI,
if (!IsExpectedConst(ShlAmtDef) || !IsExpectedConst(ShrAmtDef))
return NewOpc;

unsigned LoadSize = LoadTy->getIntegerBitWidth();
unsigned NarrowOpc = getSExtLoadOpcode(LoadSize, /*I64Result=*/false, A64);
if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
return WebAssembly::INSTRUCTION_LIST_END;

return getFoldedI64LoadOpcode(UserMI->getOperand(0).getReg(), LI, MRI, A64,
OuterUserMI, NarrowOpc);
}

static unsigned matchFoldableSExtFromPromotedI32(MachineInstr *MI,
const LoadInst *LI,
MachineRegisterInfo &MRI,
bool A64,
MachineInstr *&UserMI) {
if (MI->getOpcode() != WebAssembly::I64_EXTEND_U_I32)
return WebAssembly::INSTRUCTION_LIST_END;

unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
Register DestReg = MI->getOperand(0).getReg();
if (!MRI.hasOneNonDBGUse(DestReg))
return WebAssembly::INSTRUCTION_LIST_END;

UserMI = &*MRI.use_instr_nodbg_begin(DestReg);
switch (UserMI->getOpcode()) {
default:
return WebAssembly::INSTRUCTION_LIST_END;
case WebAssembly::I64_EXTEND8_S_I64:
if (LoadSize != 8)
return WebAssembly::INSTRUCTION_LIST_END;
return getSExtLoadOpcode(LoadSize, true, A64);
case WebAssembly::I64_EXTEND16_S_I64:
if (LoadSize != 16)
return WebAssembly::INSTRUCTION_LIST_END;
return getSExtLoadOpcode(LoadSize, true, A64);
}
}

static unsigned matchFoldableCopyToI64Ext(MachineInstr *MI, const LoadInst *LI,
MachineRegisterInfo &MRI, bool A64,
MachineInstr *&OuterUserMI) {
if (MI->getOpcode() != WebAssembly::COPY)
return WebAssembly::INSTRUCTION_LIST_END;
if (LoadTy->isIntegerTy(8))
NewOpc = A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
else if (LoadTy->isIntegerTy(16))
NewOpc =
A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;

unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
if (LoadSize != 32)
return WebAssembly::INSTRUCTION_LIST_END;

Register CopyDst = MI->getOperand(0).getReg();
if (!MRI.hasOneNonDBGUse(CopyDst))
return WebAssembly::INSTRUCTION_LIST_END;

OuterUserMI = &*MRI.use_instr_nodbg_begin(CopyDst);
switch (OuterUserMI->getOpcode()) {
default:
return WebAssembly::INSTRUCTION_LIST_END;
case WebAssembly::I64_EXTEND_U_I32:
return getZExtLoadOpcode(LoadSize, true, A64);
case WebAssembly::I64_EXTEND_S_I32:
return getSExtLoadOpcode(LoadSize, true, A64);
}
}

static unsigned matchFoldableAnd(MachineInstr *MI, const LoadInst *LI,
MachineRegisterInfo &MRI, bool A64,
MachineInstr *&OuterUserMI) {
if (MI->getOpcode() != WebAssembly::AND_I32 &&
MI->getOpcode() != WebAssembly::AND_I64)
return WebAssembly::INSTRUCTION_LIST_END;

uint64_t Mask = 0;
bool IsConstant = false;
for (unsigned I = 1; I <= 2; ++I) {
Register Reg = MI->getOperand(I).getReg();
MachineInstr *DefMI = MRI.getUniqueVRegDef(Reg);
if (DefMI && (DefMI->getOpcode() == WebAssembly::CONST_I32 ||
DefMI->getOpcode() == WebAssembly::CONST_I64)) {
Mask = DefMI->getOperand(1).getImm();
IsConstant = true;
break;
}
}

if (!IsConstant)
return WebAssembly::INSTRUCTION_LIST_END;

unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
if (Mask != llvm::maskTrailingOnes<uint64_t>(LoadSize))
return WebAssembly::INSTRUCTION_LIST_END;

if (MI->getOpcode() == WebAssembly::AND_I64)
return getZExtLoadOpcode(LoadSize, /*I64Result=*/true, A64);

unsigned NarrowOpc = getZExtLoadOpcode(LoadSize, /*I64Result=*/false, A64);
if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
return WebAssembly::INSTRUCTION_LIST_END;

return getFoldedI64LoadOpcode(MI->getOperand(0).getReg(), LI, MRI, A64,
OuterUserMI, NarrowOpc);
return NewOpc;
}

bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
Expand All @@ -1545,39 +1425,20 @@ bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
MachineRegisterInfo &MRI = FuncInfo.MF->getRegInfo();
Register ResultReg;
MachineInstr *UserMI = nullptr;
MachineInstr *OuterUserMI = nullptr;
unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
if ((NewOpc = matchFoldableSExtFromPromotedI32(MI, LI, MRI, A64, UserMI)) !=
unsigned NewOpc;
if ((NewOpc = getFoldedLoadOpcode(MI, MRI, LI, A64)) !=
WebAssembly::INSTRUCTION_LIST_END) {
ResultReg = UserMI->getOperand(0).getReg();
} else if ((NewOpc =
matchFoldableCopyToI64Ext(MI, LI, MRI, A64, OuterUserMI)) !=
WebAssembly::INSTRUCTION_LIST_END) {
ResultReg = OuterUserMI->getOperand(0).getReg();
} else if ((NewOpc = matchFoldableAnd(MI, LI, MRI, A64, OuterUserMI)) !=
WebAssembly::INSTRUCTION_LIST_END) {
ResultReg = OuterUserMI ? OuterUserMI->getOperand(0).getReg()
: MI->getOperand(0).getReg();
} else if ((NewOpc = getFoldedLoadOpcode(MI, MRI, LI, A64)) !=
WebAssembly::INSTRUCTION_LIST_END) {
ResultReg = MI->getOperand(0).getReg();
} else if ((NewOpc =
matchFoldableShift(MI, LI, MRI, A64, UserMI, OuterUserMI)) !=
} else if ((NewOpc = matchFoldableShift(MI, LI, MRI, A64, UserMI)) !=
WebAssembly::INSTRUCTION_LIST_END) {
ResultReg = OuterUserMI ? OuterUserMI->getOperand(0).getReg()
: UserMI->getOperand(0).getReg();
ResultReg = UserMI->getOperand(0).getReg();
} else {
return false;
}

if (!emitLoad(ResultReg, NewOpc, LI))
return false;

if (OuterUserMI) {
MachineBasicBlock::iterator OuterIter(OuterUserMI);
removeDeadCode(OuterIter, std::next(OuterIter));
}

if (UserMI) {
MachineBasicBlock::iterator UserIter(UserMI);
removeDeadCode(UserIter, std::next(UserIter));
Expand Down
Loading
Loading