Index: llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -298,17 +298,23 @@ SDValue &Addr) { assert(N.getNumOperands() == 2 && "Attempting to fold in a non-binary op"); - // WebAssembly constant offsets are performed as unsigned with infinite - // precision, so we need to check for NoUnsignedWrap so that we don't fold an - // offset for an add that needs wrapping. - if (N.getOpcode() == ISD::ADD && !N.getNode()->getFlags().hasNoUnsignedWrap()) - return false; - - // Folds constants in an add into the offset. for (size_t i = 0; i < 2; ++i) { SDValue Op = N.getOperand(i); SDValue OtherOp = N.getOperand(i == 0 ? 1 : 0); + // Fold target global addresses in an add into the offset. + if (!TM.isPositionIndependent()) { + if (Op.getOpcode() == WebAssemblyISD::Wrapper) + Op = Op.getOperand(0); + + if (Op.getOpcode() == ISD::TargetGlobalAddress) { + Offset = Op; + Addr = OtherOp; + return true; + } + } + + // Folds constants in an add into the offset. if (ConstantSDNode *CN = dyn_cast(Op)) { Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), OffsetType); @@ -342,9 +348,12 @@ } // Fold anything inside an add into the offset. - if (N.getOpcode() == ISD::ADD && - SelectAddrAddOperands(AddrType, N, Offset, Addr)) - return true; + // WebAssembly constant offsets are performed as unsigned with infinite + // precision, so we need to check for NoUnsignedWrap so that we don't fold an + // offset for an add that needs wrapping. + if (N.getOpcode() == ISD::ADD && N.getNode()->getFlags().hasNoUnsignedWrap()) + if (SelectAddrAddOperands(AddrType, N, Offset, Addr)) + return true; // Likewise, treat an 'or' node as an 'add' if the or'ed bits are known to be // zero and fold them into the offset too. Index: llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp +++ llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp @@ -75,14 +75,19 @@ if (AddrOperandNum == FIOperandNum) { unsigned OffsetOperandNum = WebAssembly::getNamedOperandIdx( MI.getOpcode(), WebAssembly::OpName::off); - assert(FrameOffset >= 0 && MI.getOperand(OffsetOperandNum).getImm() >= 0); - int64_t Offset = MI.getOperand(OffsetOperandNum).getImm() + FrameOffset; - - if (static_cast(Offset) <= std::numeric_limits::max()) { - MI.getOperand(OffsetOperandNum).setImm(Offset); - MI.getOperand(FIOperandNum) - .ChangeToRegister(FrameRegister, /*isDef=*/false); - return false; + auto &OffsetOp = MI.getOperand(OffsetOperandNum); + // Don't fold offset in if offset is a global address to be resolved later + if (OffsetOp.isImm()) { + assert(FrameOffset >= 0 && OffsetOp.getImm() >= 0); + int64_t Offset = OffsetOp.getImm() + FrameOffset; + + if (static_cast(Offset) <= + std::numeric_limits::max()) { + OffsetOp.setImm(Offset); + MI.getOperand(FIOperandNum) + .ChangeToRegister(FrameRegister, /*isDef=*/false); + return false; + } } } Index: llvm/test/CodeGen/WebAssembly/eh-lsda.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/eh-lsda.ll +++ llvm/test/CodeGen/WebAssembly/eh-lsda.ll @@ -66,9 +66,9 @@ ; CHECK-LABEL: test1: ; In static linking, we load GCC_except_table as a constant directly. -; NOPIC: i[[PTR]].const $push[[CONTEXT:.*]]=, __wasm_lpad_context +; NOPIC: i[[PTR]].const $push[[OFFSET:.*]]=, {{[48]}} ; NOPIC-NEXT: i[[PTR]].const $push[[EXCEPT_TABLE:.*]]=, GCC_except_table1 -; NOPIC-NEXT: i[[PTR]].store {{[48]}}($pop[[CONTEXT]]), $pop[[EXCEPT_TABLE]] +; NOPIC-NEXT: i[[PTR]].store __wasm_lpad_context($pop[[OFFSET]]), $pop[[EXCEPT_TABLE]] ; In case of PIC, we make GCC_except_table symbols a relative on based on ; __memory_base. Index: llvm/test/CodeGen/WebAssembly/exception.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/exception.ll +++ llvm/test/CodeGen/WebAssembly/exception.ll @@ -34,7 +34,7 @@ ; CHECK: call foo ; CHECK: catch $[[EXN:[0-9]+]]=, __cpp_exception ; CHECK: global.set __stack_pointer -; CHECK: i32.{{store|const}} {{.*}} __wasm_lpad_context +; CHECK: i32.{{store|const}} __wasm_lpad_context({{.*}}) ; CHECK: call $drop=, _Unwind_CallPersonality, $[[EXN]] ; CHECK: block ; CHECK: br_if 0 Index: llvm/test/CodeGen/WebAssembly/offset.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/offset.ll +++ llvm/test/CodeGen/WebAssembly/offset.ll @@ -666,3 +666,31 @@ define {i64,i32,i16,i8} @aggregate_return_without_merge() { ret {i64,i32,i16,i8} zeroinitializer } + +;===---------------------------------------------------------------------------- +; Global address loads +;===---------------------------------------------------------------------------- + +@global_i32 = external global i32 +@global_i8 = external global i8 + +; CHECK-LABEL: load_i32_global_address_with_folded_offset: +; CHECK: i32.load $push0=, global_i32($0) +define i32 @load_i32_global_address_with_folded_offset(i32 %n) { + %q = ptrtoint ptr @global_i32 to i32 + %r = add nuw i32 %q, %n + %s = inttoptr i32 %r to ptr + %t = load i32, i32* %s + ret i32 %t +} + +; CHECK-LABEL: load_i8_i32s_global_address_with_folded_offset: +; CHECK: i32.load8_s $push0=, global_i8($0) +define i32 @load_i8_i32s_global_address_with_folded_offset(i32 %n) { + %q = ptrtoint ptr @global_i8 to i32 + %r = add nuw i32 %q, %n + %s = inttoptr i32 %r to ptr + %t = load i8, i8* %s + %u = sext i8 %t to i32 + ret i32 %u +}