Index: lib/Target/X86/X86ISelDAGToDAG.cpp =================================================================== --- lib/Target/X86/X86ISelDAGToDAG.cpp +++ lib/Target/X86/X86ISelDAGToDAG.cpp @@ -941,11 +941,12 @@ bool IsRIPRel = N.getOpcode() == X86ISD::WrapperRIP; // Only do this address mode folding for 64-bit if we're in the small code - // model. - // FIXME: But we can do GOTPCREL addressing in the medium code model. + // model or medium code model. CodeModel::Model M = TM.getCodeModel(); - if (Subtarget->is64Bit() && M != CodeModel::Small && M != CodeModel::Kernel) - return true; + if (Subtarget->is64Bit() && M != CodeModel::Small && M != CodeModel::Kernel + && !(M == CodeModel::Medium && IsRIPRel) ) { + return true; + } // Base and index reg must be 0 in order to use %rip as base. if (IsRIPRel && AM.hasBaseOrIndexReg()) Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -4420,14 +4420,14 @@ if (!hasSymbolicDisplacement) return true; - // FIXME: Some tweaks might be needed for medium code model. - if (M != CodeModel::Small && M != CodeModel::Kernel) + if (M != CodeModel::Small && M != CodeModel::Medium && M != CodeModel::Kernel) return false; - // For small code model we assume that latest object is 16MB before end of 31 - // bits boundary. We may also accept pretty large negative constants knowing - // that all objects are in the positive half of address space. - if (M == CodeModel::Small && Offset < 16*1024*1024) + // For small and medium code model we assume that latest object is 16MB before + // end of 31 bits boundary. We may also accept pretty large negative constants + // knowing that all objects are in the positive half of address space. + if ((M == CodeModel::Small || M == CodeModel::Medium) + && Offset < 16*1024*1024) return true; // For kernel code model we know that all object resist in the negative half @@ -15519,7 +15519,7 @@ CodeModel::Model M = getTargetMachine().getCodeModel(); if (Subtarget.isPICStyleRIPRel() && - (M == CodeModel::Small || M == CodeModel::Kernel)) + (M == CodeModel::Small || M == CodeModel::Medium || M == CodeModel::Kernel)) return X86ISD::WrapperRIP; // GOTPCREL references must always use RIP. Index: test/CodeGen/X86/x86-64-codemodel-medium-external.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/x86-64-codemodel-medium-external.ll @@ -0,0 +1,71 @@ +; RUN: llc < %s -code-model=medium -relocation-model=pic | FileCheck -check-prefix CHECK-MEDIUM-PIC %s +; RUN: llc < %s -code-model=medium | FileCheck -check-prefix CHECK-MEDIUM %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +;This is to test the external global access under PIC/no-PIC medium code model +;with different size and offset. This is to enusre the modification not break i +;the other code path on handling the medium code model +; +;for medium code model, +; Small symbols are also assumed to be linked into the low 2GB +; Symbols with sizes larger than -mlarge-data-threshold +; are put into large data or bss sections and can be located above 2GB +; Data is considered large when it's larger than large-data-threshold, +; which is 64KB by default +; on PIC, both generate the same addressing mode + +@global_arr = external global [100 x i32], align 16 +@t = external global i32, align 4 +@global_arr_big = external global [50000 x i32], align 16 + +@x1 = external global [8388608 x i32], align 16 + +define i32 @f_offset_gt_16M() { +entry: +; CHECK-MEDIUM-PIC-LABEL: f_offset_gt_16M: +; CHECK-MEDIUM-PIC: movq x1@GOTPCREL(%rip), %rax +; CHECK-MEDIUM-PIC: movl 20971520(%rax), %eax +; CHECK-MEDIUM-LABEL: f_offset_gt_16M: +; CHECK-MEDIUM: movabsq $x1, %rax +; CHECK-MEDIUM: movl 20971520(%rax), %eax + %0 = load i32, i32* getelementptr inbounds ([8388608 x i32], [8388608 x i32]* @x1, i64 0, i64 5242880), align 16 + ret i32 %0 +} + +;This is for small data +define i32 @foo() { +entry: +; CHECK-MEDIUM-PIC-LABEL: foo: +; CHECK-MEDIUM-PIC: movq global_arr@GOTPCREL(%rip), +; CHECK-MEDIUM-LABEL: foo: +; CHECK-MEDIUM: movabsq $global_arr+28, + %0 = load i32, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @global_arr, i64 0, i64 7), align 4 + %1 = load i32, i32* @t, align 4 + %add = add nsw i32 %1, %0 + store i32 %add, i32* @t, align 4 + %2 = load i32, i32* @t, align 4 + ret i32 %2 +} + +;This is for big data +define i32 @main() { +entry: +; CHECK-MEDIUM-PIC-LABEL: main: +; CHECK-MEDIUM-PIC: movq global_arr_big@GOTPCREL(%rip), +; CHECK-MEDIUM-LABEL: main: +; CHECK-MEDIUM: movabsq $global_arr_big+28, + %retval = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + %call = call i32 @foo() + %0 = load i32, i32* @t, align 4 + %add = add nsw i32 %0, %call + store i32 %add, i32* @t, align 4 + %1 = load i32, i32* getelementptr inbounds ([50000 x i32], [50000 x i32]* @global_arr_big, i64 0, i64 7), align 4 + %2 = load i32, i32* @t, align 4 + %add1 = add nsw i32 %2, %1 + store i32 %add1, i32* @t, align 4 + %3 = load i32, i32* @t, align 4 + ret i32 %3 +} Index: test/CodeGen/X86/x86-64-codemodel-medium-internal.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/x86-64-codemodel-medium-internal.ll @@ -0,0 +1,43 @@ +; RUN: llc < %s -code-model=medium | FileCheck -check-prefix CHECK-MEDIUM %s +; RUN: llc < %s -code-model=medium -relocation-model=pic | FileCheck -check-prefix CHECK-MEDIUM-PIC %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +;This is to test the internal global access under PIC/no-PIC medium code model +;with different sizes +;This is to ensure the current modification not break the other code path on +;medium code model handling +; + +@global_arr = internal global <{ i32, i32, [98 x i32] }> <{ i32 2, i32 3, [98 x i32] zeroinitializer }>, align 16 +@global_arr_big = internal global <{ i32, i32, [49998 x i32] }> <{ i32 5, i32 6, [49998 x i32] zeroinitializer }>, align 16 +@t = external dso_local global i32, align 4 + +define i32 @foo() { +entry: +; CHECK-MEDIUM-LABEL: foo: +; CHECK-MEDIUM: movabsq $global_arr+28, +; CHECK-MEDIUM-PIC-LABEL: foo: +; CHECK-MEDIUM-PIC: addl global_arr+28(%rip), + %0 = load i32, i32* getelementptr inbounds ([100 x i32], [100 x i32]* bitcast (<{ i32, i32, [98 x i32] }>* @global_arr to [100 x i32]*), i64 0, i64 7), align 4 + %1 = load i32, i32* @t, align 4 + %add = add nsw i32 %1, %0 + store i32 %add, i32* @t, align 4 + %2 = load i32, i32* @t, align 4 + ret i32 %2 +} + +define i32 @foo_big() { +entry: +; CHECK-MEDIUM-LABEL: foo_big: +; CHECK-MEDIUM: movabsq $global_arr_big+28, +; CHECK-MEDIUM-PIC-LABEL: foo_big: +; CHECK-MEDIUM-PIC: addl global_arr_big+28(%rip), + %0 = load i32, i32* getelementptr inbounds ([50000 x i32], [50000 x i32]* bitcast (<{ i32, i32, [49998 x i32] }>* @global_arr_big to [50000 x i32]*), i64 0, i64 7), align 4 + %1 = load i32, i32* @t, align 4 + %add = add nsw i32 %1, %0 + store i32 %add, i32* @t, align 4 + %2 = load i32, i32* @t, align 4 + ret i32 %2 +} Index: test/CodeGen/X86/x86-64-pic-medium-codemodel.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/x86-64-pic-medium-codemodel.ll @@ -0,0 +1,26 @@ +; RUN: llc < %s -code-model=medium -relocation-model=pic | FileCheck -check-prefix CHECK-MEDIUM %s +; RUN: llc < %s -code-model=small -relocation-model=pic | FileCheck -check-prefix CHECK-SMALL %s + +; This is to test the common global addressing in PIC medium code model +; The addressing codes should same as the PIC small code model +; Test one scalar type global variable x + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@x = common global i32* null, align 8 + +define i32 @bar() { +entry: +; CHECK-MEDIUM-LABEL: bar: +; CHECK-MEDIUM: movq x@GOTPCREL(%rip), %rax +; CHECK-SMALL-LABEL: bar: +; CHECK-SAMLL: movq x@GOTPCREL(%rip), %rax + %retval = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + %0 = load i32*, i32** @x, align 8 + call void @foo(i32* %0) + ret i32 0 +} + +declare void @foo(i32*)