Index: lib/Target/WebAssembly/WebAssemblyInstrCall.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -93,26 +93,28 @@ defm "" : SIMD_CALL; defm "" : SIMD_CALL; - defm CALL_VOID : I<(outs), (ins function32_op:$callee, variable_ops), - (outs), (ins function32_op:$callee), - [(WebAssemblycall0 (i32 imm:$callee))], - "call \t$callee", "call\t$callee", 0x10>; + let IsCanonical = 1 in { + defm CALL_VOID : I<(outs), (ins function32_op:$callee, variable_ops), + (outs), (ins function32_op:$callee), + [(WebAssemblycall0 (i32 imm:$callee))], + "call \t$callee", "call\t$callee", 0x10>; - let isCodeGenOnly = 1 in { - defm PCALL_INDIRECT_VOID : I<(outs), (ins I32:$callee, variable_ops), - (outs), (ins I32:$callee), - [(WebAssemblycall0 I32:$callee)], - "PSEUDO CALL INDIRECT\t$callee", - "PSEUDO CALL INDIRECT\t$callee">; - } // isCodeGenOnly = 1 + let isCodeGenOnly = 1 in { + defm PCALL_INDIRECT_VOID : I<(outs), (ins I32:$callee, variable_ops), + (outs), (ins I32:$callee), + [(WebAssemblycall0 I32:$callee)], + "PSEUDO CALL INDIRECT\t$callee", + "PSEUDO CALL INDIRECT\t$callee">; + } // isCodeGenOnly = 1 - defm CALL_INDIRECT_VOID : I<(outs), - (ins TypeIndex:$type, i32imm:$flags, - variable_ops), - (outs), (ins TypeIndex:$type, i32imm:$flags), - [], - "call_indirect\t", "call_indirect\t$type", - 0x11>; + defm CALL_INDIRECT_VOID : I<(outs), + (ins TypeIndex:$type, i32imm:$flags, + variable_ops), + (outs), (ins TypeIndex:$type, i32imm:$flags), + [], + "call_indirect\t", "call_indirect\t$type", + 0x11>; + } } // Uses = [SP32,SP64], isCall = 1 // Patterns for matching a direct call to a global address. Index: lib/Target/WebAssembly/WebAssemblyInstrControl.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -81,6 +81,10 @@ defm END_BLOCK : NRI<(outs), (ins), [], "end_block", 0x0b>; defm END_LOOP : NRI<(outs), (ins), [], "end_loop", 0x0b>; defm END_IF : NRI<(outs), (ins), [], "end_if", 0x0b>; +// Generic instruction, for disassembler. +let IsCanonical = 1 in { + defm END : NRI<(outs), (ins), [], "end", 0x0b>; +} let isTerminator = 1, isBarrier = 1 in defm END_FUNCTION : NRI<(outs), (ins), [], "end_function", 0x0b>; } // Uses = [VALUE_STACK], Defs = [VALUE_STACK] Index: lib/Target/WebAssembly/WebAssemblyInstrFormats.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrFormats.td +++ lib/Target/WebAssembly/WebAssemblyInstrFormats.td @@ -22,6 +22,9 @@ let Namespace = "WebAssembly"; let Pattern = []; let AsmString = asmstr; + // When there are multiple instructions that map to the same encoding (in + // e.g. the disassembler use case) prefer the one where IsCanonical == 1. + bit IsCanonical = 0; } // Normal instructions. Default instantiation of a WebAssemblyInst. Index: lib/Target/WebAssembly/WebAssemblyInstrSIMD.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -125,12 +125,14 @@ ImmI16:$i0, ImmI16:$i1, ImmI16:$i2, ImmI16:$i3, ImmI16:$i4, ImmI16:$i5, ImmI16:$i6, ImmI16:$i7), "$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7">; -defm "" : ConstVec; +let IsCanonical = 1 in { + defm "" : ConstVec; +} defm "" : ConstVec(StackString)->getValue() == "true"; - if (IsStackBased && !CGIP.second) { - // this picks the first of many typed variants, which is - // currently the except_ref one, though this shouldn't matter for - // disassembly purposes. - CGIP = std::make_pair(I, &CGI); + if (!IsStackBased) + continue; + if (CGIP.second) { + // We already have an instruction for this slot, so decide which one + // should be the canonical one. This determines which variant gets + // printed in a disassembly. We want e.g. "call" not "i32.call", and + // "end" when we don't know if its "end_loop" or "end_block" etc. + auto IsCanonicalExisting = CGIP.second->TheDef->getValue("IsCanonical") + ->getValue() + ->getAsString() == "1"; + // We already have one marked explicitly as canonical, so keep it. + if (IsCanonicalExisting) + continue; + auto IsCanonicalNew = + Def.getValue("IsCanonical")->getValue()->getAsString() == "1"; + // If the new one is explicitly marked as canonical, take it. + if (!IsCanonicalNew) { + // Neither the existing or new instruction is canonical. + // Pick the one with with the shortest name as heuristic. + // Though ideally IsCanonical is always defined for at least one + // variant so this never has to apply. + if (CGIP.second->AsmString.size() <= CGI.AsmString.size()) + continue; + } } + // Set this instruction as the one to use. + CGIP = std::make_pair(I, &CGI); } OS << "#include \"MCTargetDesc/WebAssemblyMCTargetDesc.h\"\n"; OS << "\n";