bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
const GlobalAddressSDNode * /*GA*/) const {
- // The WebAssembly target doesn't support folding offsets into global
- // addresses.
- return false;
+ // All offsets can be folded.
+ return true;
}
MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
SDLoc DL(Op);
const auto *GA = cast<GlobalAddressSDNode>(Op);
EVT VT = Op.getValueType();
- assert(GA->getOffset() == 0 &&
- "offsets on global addresses are forbidden by isOffsetFoldingLegal");
assert(GA->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
if (GA->getAddressSpace() != 0)
fail(DL, DAG, "WebAssembly only expects the 0 address space");
return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
- DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT));
+ DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
+ GA->getOffset()));
}
SDValue
MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
MCSymbol *Sym) const {
+ assert(MO.getTargetFlags() == 0 && "WebAssembly does not use target flags");
const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
- if (!MO.isJTI() && MO.getOffset())
- llvm_unreachable("unknown symbol op");
+ int64_t Offset = MO.getOffset();
+ if (Offset != 0) {
+ assert(!MO.isJTI() && "Unexpected offset with jump table index");
+ Expr =
+ MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx);
+ }
return MCOperand::createExpr(Expr);
}
--- /dev/null
+; RUN: llc < %s -asm-verbose=false | FileCheck %s
+
+; Test that constant offsets can be folded into global addresses.
+
+target datalayout = "e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+@x = external global [0 x i32]
+@y = global [50 x i32] zeroinitializer
+
+; Test basic constant offsets of both defined and external symbols.
+
+; CHECK-LABEL: test0:
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: i32.const $push0=, x+188{{$}}
+; CHECK=NEXT: return $pop0{{$}}
+define i32* @test0() {
+ ret i32* getelementptr ([0 x i32], [0 x i32]* @x, i32 0, i32 47)
+}
+
+; CHECK-LABEL: test1:
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: i32.const $push0=, y+188{{$}}
+; CHECK=NEXT: return $pop0{{$}}
+define i32* @test1() {
+ ret i32* getelementptr ([50 x i32], [50 x i32]* @y, i32 0, i32 47)
+}
+
+; Test zero offsets.
+
+; CHECK-LABEL: test2:
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: i32.const $push0=, x{{$}}
+; CHECK=NEXT: return $pop0{{$}}
+define i32* @test2() {
+ ret i32* getelementptr ([0 x i32], [0 x i32]* @x, i32 0, i32 0)
+}
+
+; CHECK-LABEL: test3:
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: i32.const $push0=, y{{$}}
+; CHECK=NEXT: return $pop0{{$}}
+define i32* @test3() {
+ ret i32* getelementptr ([50 x i32], [50 x i32]* @y, i32 0, i32 0)
+}