
Constant globals can't have been modified, even if a pointer is passed externally. Therefore, don't treat it as such in hasExternalStore. In addition, it doesn't make sense to update values of constant globals after the interp pass is finished. So don't do this. TODO: track whether objects are actually modified and only update the globals if this is the case.
144 строки
4,3 КиБ
LLVM
144 строки
4,3 КиБ
LLVM
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|
target triple = "x86_64--linux"
|
|
|
|
@main.v1 = internal global i64 0
|
|
@main.nonConst1 = global [4 x i64] zeroinitializer
|
|
@main.nonConst2 = global i64 0
|
|
@main.someArray = global [8 x {i16, i32}] zeroinitializer
|
|
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
|
@main.exportedConst = constant i64 42
|
|
@main.exposedValue1 = global i16 0
|
|
@main.exposedValue2 = global i16 0
|
|
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer
|
|
|
|
declare void @runtime.printint64(i64) unnamed_addr
|
|
|
|
declare void @runtime.printnl() unnamed_addr
|
|
|
|
define void @runtime.initAll() unnamed_addr {
|
|
entry:
|
|
call void @runtime.init()
|
|
call void @main.init()
|
|
ret void
|
|
}
|
|
|
|
define void @main() unnamed_addr {
|
|
entry:
|
|
%0 = load i64, i64* @main.v1
|
|
call void @runtime.printint64(i64 %0)
|
|
call void @runtime.printnl()
|
|
ret void
|
|
}
|
|
|
|
define internal void @runtime.init() unnamed_addr {
|
|
entry:
|
|
ret void
|
|
}
|
|
|
|
define internal void @main.init() unnamed_addr {
|
|
entry:
|
|
store i64 3, i64* @main.v1
|
|
call void @"main.init#1"()
|
|
|
|
; test the following pattern:
|
|
; func someValue() int // extern function
|
|
; var nonConst1 = [4]int{someValue(), 0, 0, 0}
|
|
%value1 = call i64 @someValue()
|
|
%gep1 = getelementptr [4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0
|
|
store i64 %value1, i64* %gep1
|
|
|
|
; Test that the global really is marked dirty:
|
|
; var nonConst2 = nonConst1[0]
|
|
%gep2 = getelementptr [4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0
|
|
%value2 = load i64, i64* %gep2
|
|
store i64 %value2, i64* @main.nonConst2
|
|
|
|
; Test that the following GEP works:
|
|
; var someArray
|
|
; modifyExternal(&someArray[3].field1)
|
|
%gep3 = getelementptr [8 x {i16, i32}], [8 x {i16, i32}]* @main.someArray, i32 0, i32 3, i32 1
|
|
call void @modifyExternal(i32* %gep3)
|
|
|
|
; Test that marking a value as external also marks all referenced values.
|
|
call void @modifyExternal(i32* bitcast ([1 x i16*]* @main.exportedValue to i32*))
|
|
store i16 5, i16* @main.exposedValue1
|
|
|
|
; Test that marking a constant as external still allows loading from it.
|
|
call void @readExternal(i32* bitcast (i64* @main.exportedConst to i32*))
|
|
%constLoad = load i64, i64 * @main.exportedConst
|
|
call void @runtime.printint64(i64 %constLoad)
|
|
|
|
; Test that this even propagates through functions.
|
|
call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*))
|
|
store i16 7, i16* @main.exposedValue2
|
|
|
|
; Test that inline assembly is ignored.
|
|
call void @modifyExternal(i32* bitcast (void ()* @hasInlineAsm to i32*))
|
|
|
|
; Test switch statement.
|
|
%switch1 = call i64 @testSwitch(i64 1) ; 1 returns 6
|
|
%switch2 = call i64 @testSwitch(i64 9) ; 9 returns the default value -1
|
|
call void @runtime.printint64(i64 %switch1)
|
|
call void @runtime.printint64(i64 %switch2)
|
|
|
|
; Test extractvalue/insertvalue with multiple operands.
|
|
%agg = call {i8, i32, {float, {i64, i16}}} @nestedStruct()
|
|
%elt = extractvalue {i8, i32, {float, {i64, i16}}} %agg, 2, 1, 0
|
|
call void @runtime.printint64(i64 %elt)
|
|
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
|
|
store {i8, i32, {float, {i64, i16}}} %agg2, {i8, i32, {float, {i64, i16}}}* @main.insertedValue
|
|
|
|
ret void
|
|
}
|
|
|
|
define internal void @"main.init#1"() unnamed_addr {
|
|
entry:
|
|
call void @runtime.printint64(i64 5)
|
|
call void @runtime.printnl()
|
|
ret void
|
|
}
|
|
|
|
declare i64 @someValue()
|
|
|
|
declare void @modifyExternal(i32*)
|
|
|
|
declare void @readExternal(i32*)
|
|
|
|
; This function will modify an external value. By passing this function as a
|
|
; function pointer to an external function, @main.exposedValue2 should be
|
|
; marked as external.
|
|
define void @willModifyGlobal() {
|
|
entry:
|
|
store i16 8, i16* @main.exposedValue2
|
|
ret void
|
|
}
|
|
|
|
; Inline assembly should be ignored in the interp package. While it is possible
|
|
; to modify other globals that way, usually that's not the case and there is no
|
|
; real way to check.
|
|
define void @hasInlineAsm() {
|
|
entry:
|
|
call void asm sideeffect "", ""()
|
|
ret void
|
|
}
|
|
|
|
define i64 @testSwitch(i64 %val) {
|
|
entry:
|
|
; Test switch statement.
|
|
switch i64 %val, label %otherwise [ i64 0, label %zero
|
|
i64 1, label %one
|
|
i64 2, label %two ]
|
|
zero:
|
|
ret i64 5
|
|
|
|
one:
|
|
ret i64 6
|
|
|
|
two:
|
|
ret i64 7
|
|
|
|
otherwise:
|
|
ret i64 -1
|
|
}
|
|
|
|
declare {i8, i32, {float, {i64, i16}}} @nestedStruct()
|