[WebAssembly] Avoid unused function imports in PIC mode
authorSam Clegg <sbc@chromium.org>
Thu, 19 Aug 2021 02:20:55 +0000 (22:20 -0400)
committerSam Clegg <sbc@chromium.org>
Thu, 19 Aug 2021 02:31:04 +0000 (22:31 -0400)
In PIC mode we import function address via `GOT.mem` imports but for
direct function calls we still import the first class function.
However, if the function is never directly called we can avoid the first
class import completely.

Differential Revision: https://reviews.llvm.org/D108345

lld/test/wasm/shared.s
lld/test/wasm/shared64.s
lld/wasm/SymbolTable.cpp
lld/wasm/Writer.cpp

index 3299d84..29cf8f6 100644 (file)
@@ -167,10 +167,6 @@ get_local_func_address:
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         GlobalType:      I32
 # CHECK-NEXT:         GlobalMutable:   false
-# CHECK-NEXT:       - Module:          env
-# CHECK-NEXT:         Field:           func_external
-# CHECK-NEXT:         Kind:            FUNCTION
-# CHECK-NEXT:         SigIndex:        1
 # CHECK-NEXT:       - Module:          GOT.mem
 # CHECK-NEXT:         Field:           indirect_func
 # CHECK-NEXT:         Kind:            GLOBAL
@@ -197,7 +193,7 @@ get_local_func_address:
 # CHECK-NEXT:     Exports:
 # CHECK-NEXT:       - Name:            __wasm_call_ctors
 # CHECK-NEXT:         Kind:            FUNCTION
-# CHECK-NEXT:         Index:           1
+# CHECK-NEXT:         Index:           0
 
 # check for elem segment initialized with __table_base global as offset
 
@@ -206,17 +202,17 @@ get_local_func_address:
 # CHECK-NEXT:       - Offset:
 # CHECK-NEXT:           Opcode:          GLOBAL_GET
 # CHECK-NEXT:           Index:           2
-# CHECK-NEXT:         Functions:       [ 4, 3 ]
+# CHECK-NEXT:         Functions:       [ 3, 2 ]
 
 # check the generated code in __wasm_call_ctors and __wasm_apply_data_relocs functions
 # TODO(sbc): Disassemble and verify instructions.
 
 # CHECK:        - Type:            CODE
 # CHECK-NEXT:     Functions:
-# CHECK-NEXT:       - Index:           1
+# CHECK-NEXT:       - Index:           0
 # CHECK-NEXT:         Locals:          []
-# CHECK-NEXT:         Body:            10020B
-# CHECK-NEXT:       - Index:           2
+# CHECK-NEXT:         Body:            10010B
+# CHECK-NEXT:       - Index:           1
 # CHECK-NEXT:         Locals:          []
 # CHECK-NEXT:         Body:            230141046A2304360200230141086A230241016A3602002301410C6A230141006A360200230141106A2305360200230141146A230641046A3602000B
 
index 36528e1..d441dd3 100644 (file)
@@ -174,10 +174,6 @@ get_local_func_address:
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         GlobalType:      I32
 # CHECK-NEXT:         GlobalMutable:   false
-# CHECK-NEXT:       - Module:          env
-# CHECK-NEXT:         Field:           func_external
-# CHECK-NEXT:         Kind:            FUNCTION
-# CHECK-NEXT:         SigIndex:        1
 # CHECK-NEXT:       - Module:          GOT.mem
 # CHECK-NEXT:         Field:           indirect_func
 # CHECK-NEXT:         Kind:            GLOBAL
@@ -204,7 +200,7 @@ get_local_func_address:
 # CHECK-NEXT:     Exports:
 # CHECK-NEXT:       - Name:            __wasm_call_ctors
 # CHECK-NEXT:         Kind:            FUNCTION
-# CHECK-NEXT:         Index:           1
+# CHECK-NEXT:         Index:           0
 
 # check for elem segment initialized with __table_base global as offset
 
@@ -213,17 +209,17 @@ get_local_func_address:
 # CHECK-NEXT:       - Offset:
 # CHECK-NEXT:           Opcode:          GLOBAL_GET
 # CHECK-NEXT:           Index:           3
-# CHECK-NEXT:         Functions:       [ 4, 3 ]
+# CHECK-NEXT:         Functions:       [ 3, 2 ]
 
 # check the generated code in __wasm_call_ctors and __wasm_apply_data_relocs functions
 # TODO(sbc): Disassemble and verify instructions.
 
 # CHECK:        - Type:            CODE
 # CHECK-NEXT:     Functions:
-# CHECK-NEXT:       - Index:           1
+# CHECK-NEXT:       - Index:           0
 # CHECK-NEXT:         Locals:          []
-# CHECK-NEXT:         Body:            10020B
-# CHECK-NEXT:       - Index:           2
+# CHECK-NEXT:         Body:            10010B
+# CHECK-NEXT:       - Index:           1
 # CHECK-NEXT:         Locals:          []
 # CHECK-NEXT:         Body:            230142047C23053702002301420C7C230242017C370200230142147C230141006A360200230142187C2306370200230142207C230741046A3602000B
 
index 1a52133..89fb481 100644 (file)
@@ -548,9 +548,12 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef name,
       else if (getFunctionVariant(s, sig, file, &s))
         replaceSym();
     }
-    if (existingUndefined)
+    if (existingUndefined) {
       setImportAttributes(existingUndefined, importName, importModule, flags,
                           file);
+      if (isCalledDirectly)
+        existingUndefined->isCalledDirectly = true;
+    }
   }
 
   return s;
index cf9356b..efe64e6 100644 (file)
@@ -562,6 +562,14 @@ static bool shouldImport(Symbol *sym) {
   if (isa<DataSymbol>(sym))
     return false;
 
+  // In PIC mode we only need to import functions when they are called directly.
+  // Indirect usage all goes via GOT imports.
+  if (config->isPic) {
+    if (auto *f = dyn_cast<UndefinedFunction>(sym))
+      if (!f->isCalledDirectly)
+        return false;
+  }
+
   if (config->isPic || config->relocatable || config->importUndefined)
     return true;
   if (config->allowUndefinedSymbols.count(sym->getName()) != 0)